Initial support for XSAVE, but not XSAVEOPT or XSAVEC:
- Enable XSAVE and set up xcr0 for all CPUs
- Allocate XSAVE area for all non-kernel threads
- Call XSAVE and XRSTOR on task switch
Well god damnit, when i converted the `cpu::cpu_id::regs` struct to a
union, i was super sloppy and forgot to wrap the existing fields in
their own anonymous struct. I have been wrong about CPUID vales for
ages.
The libc CRT _start function had a stray pop left in it, which was
causing the stack to never be 16-byte aligned and thus causing crashes
when SSE instructions were called.
When used in kernel vs. non-kernel code the assert macros were not
working as expected. Other util code does not use assert like this, so
I'm just dropping it from bitset.
This commit does a number of things to start the transition of channels
from kernel to user space:
- Remove channel objects / syscalls from the kernel
- Add mutex type in libj6
- Add condition type in libj6
- Add a `ring` type flag for VMA syscalls to create ring buffers
- Implement a rudimentary shared memory channel using all of the above
Add the syscalls j6_futex_wait and j6_futex_wake. Currently marking this
as WIP as they need more testing.
Added to support futexes:
- vm_area and vm_space support for looking up physical address for a
virtual address
- libj6 mutex implementation using futex system calls
There are some SSE instructions (moveaps, moveups) in userland code that
QEMU software emulation seems to be fine with but generate `#UD` on KVM.
So let's finally get floating-point support working. This is the first
step, just setting the control regs to try to fix that error.
This was kept in the kernel as a way to keep exercising the code, but it
doesn't belong there. This moves it to init, which doesn't do anything
but probe for devices currently - but at least it's executing the code
in userspace now.
For now, using VNC, I want to keep the framebuffer mode small, so I'm
commenting out the bootloader's loop to pick the biggest video mode.
I'll revisit this as a bootconfig option later.
init still uses a custom _start to set up the stack, but then jumps to
_libc_crt0_start. The modules data passed to it is taken from the
j6_init_args instead of having it stashed into a global variable.
Also replace several uses of snprintf/j6_log with j6::syslog.
Clang will complain if main() is not declared with 0, 2, or 3 arguments.
In order to allow an extra 4th parameter, a new weak main() symbol which
just jumps to driver_main is defined, and _start passes the extra init
pointer to main.
Additionally, libc's crt0.s _start is made weak, and a matching
_libc_crt0_start symbol is defined for implementations that wish to
override _start but still call libc's _start. (Will be used by init.)
Previously processes and threads would be deleted by the scheduler. Now,
only delete them based on refcounts - this allows joining an
already-exited thread, for instance.
Previously event tried to read its value in event::wake_observer, which
required jumping through some hoops in how wait_queue was designed, so
that a value wouldn't be wasted if the wait_queue was empty. Now, read
the event value in event::wait after returning from the thread::block
call instead, which simplifies the whole process and lets us simplify
the wait_queue API as well.
For the coming switch to cap/handle ref-counting being the main lifetime
determiner of objects, get rid of self handles for threads and processes
to avoid circular references. Instead, passing 0 to syscalls expecting a
thread or process handle signifies "this process/thread".
There was an inverted boolean logic in determining how many consecutive
pages were available.
Also adding some memory debugging tools I added to track down the recent
memory bugs:
- A direct debugcon::write call, for logging to the debugcon without the
possible page faults with the logger.
- A new vm_space::lock call, to make a page not fillable in memory
debugging mode
- A mode in heap_allocator to always alloc new pages, and lock freed
pages to cause page faults for use-after-free bugs.
- Logging in kobject on creation and deletion
- Page table cache structs are now page-sized for easy pointer math
Yet again burned by the fack that integer literals are assumed to be of
type int, so `1 << n` is 0 for any n >= 32. This burned me in the frame
allocator, but I also grepped for all instances of `1 <<` and fixed
those too.
Add a version of thread::block() that takes a lock and releases it after
marking the thread as unready, but before calling the scheduler.
Use this version of block() in the wait_queue.
Split out different constants for scheduler::idle_priority and
scheduler::max_priority, so that threads never fall to the same priority
level as the idle threads.
Previously process::exit() was going through the threads in order
calling thread::exit() - which blocks and never wakes if called on the
current thread. Since the current thread likely belongs to the process
which is exiting, and the current thread wasn't guaranteed to be last in
the list, this could leave threads not cleaned up.
Worse, no matter what, this caused the m_threads_lock to always be held
forever on exit, keeping the scheduler from ever finishing a call to
process::thread_exited() on its threads.
The `s_cache_count` counter had the potential to get out of sync with
the cache itself. Since we only call `fill_table_page_cache()` when the
cache is empty, the counter was not useful. After chasing the bug for
hours to figure out how they were getting out of sync, I just ripped it
out.
Another spot I meant to go back and clean up with a lock - found it when
a process with threads running on two CPUs exited, and the scheduler
tried to delete the process on both CPUs.
Several minor changes related to debug output.
- Colorize the debugcon logger like the userspace one.
- Display the process and thread for each cpu in the panic display
- Skip the panic() frame in panic back traces
- Don't try to follow obviously bad (non-canonical) stack frame pointers
Two minor debugging helpers:
- the GDB script was still referencing m_koid on objects, switched to
the replacement m_obj_id instead.
- finally gave in and made panic print 1-based CPU ids like GDB uses
instead of 0-based like the hardware and LITERALLY EVERYTHING ELSE
In order to pass along arguments like the framebuffer, it's far simpler
to have that data stored along with the modules than mapping new pages
for every structure. Also now optionally pass a module's data to a
driver as init starts it.
This commit fixes the mailbox tests in test_runner, which broke when
mailbox was simplified to just use call and respond. It also fixes a
bug the tests uncovered: if the mailbox is closed while a caller is in
the reply map (ie, when its call data has been passed on to a thread
calling respond, but has yet to be responded to itself), that caller is
never awoken.
This commit changes the add_user_thunk to point to a new routine,
initialize_user_cpu, which sets all the registers that were previously
unset when starting a new user thread. The values for rdi and rsi are
popped off the initial stack values that add_user_thunk sets up, so that
user thread procs can take up to two arguments.
To suppor this, j6_thread_create gained two new arguments, which are
passed on to the thread.
This also let me finally get rid of the hack of passing an argument in
rsp when starting init.
This commit re-adds testapp to the default manifest and does some
housecleaning on the module:
- Remove the old serial.* and io.*
- Update it to use current syscall APIs
- Update it to use libj6's higher-level thread API
The debugcon logger is now separate from logger::output, and is instead
a kernel-internal thread that watches for logs and prints them to the
deubcon device.