Some hardware/software configurations crash KVM as soon as we try to
start Serenity. The exact cause is currently unknown, so just fully
revert it for now.
This reverts commit 897c4e5145.
Process created performance events for kernel processes are only ever
emitted for the kernel processes that exist when profiling is enabled.
Any new kernel processes created after profiling is enabled will not
have corresponding process created performance events, so all kernel
processes should be created before enabling profiling.
NetworkTask was the only kernel process being created after enabling
profiling, so we now just create it before enabling profiling. This
fixes an issue where Profiler was failing to parse boot profiles as a
result of NetworkTask not having a process created event.
The new baked image is a Prekernel and a Kernel baked together now, so
essentially we no longer need to pass the Prekernel as -kernel and the
actual kernel image as -initrd to QEMU, leaving the option to pass an
actual initrd or initramfs module later on with multiboot.
is_sharing_with_others API was never really put to use properly since
it was introduced. The only place where it is used in Interrupts.cpp is
in conjuction with is_shared_handler() which is only true for
SharedIRQHandler and is_sharing_with_others will always return false.
Remove that API.
If IRQHandler's IRQ is shared, then disable_irq() should not call the
controller to disable that IRQ as some other device might be using it.
IRQHandler had a private variable to indicate if it is being shared:
m_shared_with_others but it was never modified even if the IRQ was
shared.
Add a new member function set_shared_with_others() to enable/disable
m_shared_with_others member of IRQHandler class. This function is
called when an IRQHandler is being added/removed as a part of
SharedIRQHandler.
This is done mainly by implementing safe locking on the data structure
keeping the pointers to the PerContextState objects. Therefore, this now
eliminates the need for using LockRefPtr, as SpinlockProtected is enough
for the whole list.
The usage of HashMap in this class was questionable, and according to
Sahan Fernando (the original contributor to the VirGL work also known as
ccapitalK) there was no deep research on which data structure to use for
keeping all pointers to PerContextState objects.
Therefore, this structure is changed to IntrusiveList as the main reason
and advantage to use it is that handling OOM conditions is much more
simple, because if we succeeded to create a PerContextState object, we
can be sure now that inserting it to the list will not cause OOM error
condition.
This is quite useful for userspace applications that can't cope with the
restriction, but it's still useful to impose other non-configurable
restrictions by using jails.
Instead of storing x86_64 register names in `SC_create_thread_params`,
let the Kernel figure out how to pass the parameters to
`pthread_create_helper`.
This was the last change that was needed to be able boot with the flag
of LOCK_IN_CRITICAL_DEBUG. That flag is not always enabled because there
are still other issues in which we hold a spinlock and still try to lock
a mutex.
Instead of using one global mutex we can protect internal structures of
the InodeWatcher class with SpinlockProtected wrappers. This in turn
allows the InodeWatcher code to be called from other parts in the kernel
while holding a prior spinlock properly.
`process.fds()` is protected by a Mutex, which causes issues when we try
to acquire it while holding a Spinlock. Since nothing seems to use this
value, let's just remove it entirely for now.
This should not affect boot times on qemu, as that does not use
dynamic transfer delays in its adma code path.
On real hardware this could potentially double the data throughput,
decreasing load times.
This has been broken on x86_64 since its introduction, as it features
more registers to be saved, and we never held up the "rbp has to be the
last pushed register" there.
Instead, just copy rbp from the thread structure, which is now properly
updated since the last commit.
The existing `read_entire` is quite slow due to allocating and copying
multiple times, but it is simultaneously quite hard to get rid of in a
single step. As a replacement, add a new function that reads as much as
possible directly into a user-provided buffer.
Currently we do not use interrupts for the SD driver, yet we
had enabled the signaling of all of them.
Since we were never acknowledging them, we were getting spammed by
unnecessary interrupts, causing the system to slow down to a crawl.
This commit makes the system boot in less than 1 minute with PIO,
compared to the old 30+ minute boot.
There is a big mix of LockRefPtrs all over the Networking subsystem, as
well as lots of room for improvements with our locking patterns, which
this commit will not pursue, but will give a good start for such work.
To deal with this situation, we change the following things:
- Creating instances of NetworkAdapter should always yield a non-locking
NonnullRefPtr. Acquiring an instance from the NetworkingManagement
should give a simple RefPtr,as giving LockRefPtr does not really
protect from concurrency problems in such case.
- Since NetworkingManagement works with normal RefPtrs we should
protect all instances of RefPtr<NetworkAdapter> with SpinlockProtected
to ensure references are gone unexpectedly.
- Protect the so_error class member with a proper spinlock. This happens
to be important because the clear_so_error() method lacked any proper
locking measures. It also helps preventing a possible TOCTOU when we
might do a more fine-grained locking in the Socket code, so this could
be definitely a start for this.
- Change unnecessary LockRefPtr<PacketWithTimestamp> in the structure
of OutgoingPacket to a simple RefPtr<PacketWithTimestamp> as the whole
list should be MutexProtected.
To do this we also need to get rid of LockRefPtrs in the USB code as
well.
Most of the SysFS nodes are statically generated during boot and are not
mutated afterwards.
The same goes for general device code - once we generate the appropriate
SysFS nodes, we almost never mutate the node pointers afterwards, making
locking unnecessary.
While doing this, we can also just return a normal RefPtr instead of a
LockRefPtr, because we create these channels when initializing an audio
controller, and never change the pointer in AudioController instances
after their initialization, hence no locking is necessary.
Instead of enumerating all available controllers and then ask each to
find its audio channels, we change the initialization sequence to match
what happens in the Networking subsystem and Graphics subsystem - we
essentially probe for a matching driver on a PCI device, create a device
instance, and immediately initialize it.
This in fact allows us to immediately find any hardware initialization
issues and report it, and then dropping the created instance, as usually
being done in other initialization paths in the Kernel.
This also opens the opportunity to propagate errors when failed to
initialize an AudioChannel instance, and it will be addressed in a
future commit.
This is done by 2 ways which both fit very well together:
- We stop use LockRefPtrs. We also don't allow expansion of the
m_channels member, by setting it to be a fixed Array of 2
IDEChannels.
- More error propagation through the code, in the construction point of
IDEChannel(s). This means that in the future we could technically do
something meaningful with OOM conditions when initializing an IDE
controller.
We were crashing on the VERIFY_INTERRUPTS_DISABLED() in
RecursiveSpinlock::unlock, which was caused by the compiler reordering
instructions in `sys$get_root_session_id`. In this function, a SpinLock
is locked and quickly unlocked again, and since the lock and unlock
functions were inlined into `sys$get_root_session_id` and the DAIF::read
was missing the `volatile` keyword, the compiler was free to reorder the
reads from the DAIF register to the top of this function. This caused
the CPU to read the interrupts state at the beginning of the function,
and storing the result on the stack, which in turn caused the
VERIFY_INTERRUPTS_DISABLED() assertion to fail. By adding the `volatile`
modifier to the inline assembly, the compiler will not reorder the
instructions.
In aa40cef2b7, I mistakenly assumed that the crash was related to the
initial interrupts state of the kernel threads, but it turns out that
the missing `volatile` keyword was the actual problem. This commit also
removes that code again.
We have a problem with the original utimensat syscall because when we
do call LibC futimens function, internally we provide an empty path,
and the Kernel get_syscall_path_argument method will detect this as an
invalid path.
This happens to spit an error for example in the touch utility, so if a
user is running "touch non_existing_file", it will create that file, but
the user will still see an error coming from LibC futimens function.
This new syscall gets an open file description and it provides the same
functionality as utimensat, on the specified open file description.
The new syscall will be used later by LibC to properly implement LibC
futimens function so the situation described with relation to the
"touch" utility could be fixed.
We were detaching from the jail process list too early. To ensure we
detach properly, leverage the remove_from_secondary_lists method
so the possibly jailed parent process can still see the dying process
and therefore clean it properly.