Commit Graph

111 Commits

Author SHA1 Message Date
Justin C. Miller
723f7d0330 [kernel] Delete processes & threads only via refcounts
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.
2023-02-19 14:37:31 -08:00
Justin C. Miller
274891854f [kernel] Simplify event and wait_queue
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.
2023-02-19 14:34:03 -08:00
Justin C. Miller
94b2a79f79 [kernel] Remove process & thread self-handles
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".
2023-02-19 11:23:23 -08:00
Justin C. Miller
d2a6113fb7 [kernel] Fix frame allocation for multiple pages
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
2023-02-19 01:07:13 -08:00
Justin C. Miller
42db1e8899 [kernel] Add lock-releasing version of thread::block()
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.
2023-02-18 17:21:39 -08:00
Justin C. Miller
38ca7004a6 [util] Add thread id to kernel spinlocks
Expose a function __current_thread_id() and use it to record the thread
id on a spinlock waiter when called from the kernel.
2023-02-18 15:21:56 -08:00
Justin C. Miller
8817766469 [kernel] Keep other threads out of idle priority
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.
2023-02-18 14:17:57 -08:00
Justin C. Miller
e250aaef30 [kernel] Exit the current thread last on process exit
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.
2023-02-18 14:05:22 -08:00
Justin C. Miller
2c2398b549 [kernel] Protect process::m_threads with a lock
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.
2023-02-14 20:25:19 -08:00
Justin C. Miller
094b54d728 [tests] Get mailbox test running again
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.
2023-02-08 23:16:22 -08:00
Justin C. Miller
4125175870 [kernel] Give threads initial arguments
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.
2023-02-08 23:10:17 -08:00
Justin C. Miller
ada660deeb [kernel] Move log buffer to its own memory section
In prep for the coming change to keep log entries as a true ring buffer,
move the log buffer from bss into its own memory section.

Related changes in this commit:
- New vm_area_ring, which maps a set of pages twice to allow easy linear
  reading of data from a ring buffer when it wraps around the end.
- logger_init() went away, and the logger ctor is called from
  mem::initialize()
- Instead of an event object, the logger just has a bare wait_queue
- util::counted::from template type changed slightly to allow easy
  conversion from an intptr_t as well as a pointer
- Previously added debugcon_logger code removed - this will be added in
  a separate file in a followup commit
2023-02-08 09:21:52 -08:00
Justin C. Miller
e93f48e2f7 [kernel] Track capability reference counts
First pass at reference-counting capabilities.
2023-01-14 15:43:07 -08:00
Justin C. Miller
6ac4ec601d [kernel] standardize static constexpr order in kobject headers
The kobject headers flip-flopped the class constants between "static
constexpr" and "constexpr static".
2023-01-14 15:43:07 -08:00
Justin C. Miller
372bc1d2e6 [kernel] Store object ids instead of full koids
In preparation for futexes, I wanted to make kobjects a bit lighter.
Storing 32 bits of object id, and 8 bits of type (and not ending the
class in a ushort for handle count, which meant all kobjects were likely
to have a bunch of pad bytes), the kobject class data is now just one 8
byte word.

Also from this, change logs that mention threads or processes from
printing the full koid to just 2 bytes of object id from both process
and thread, which makes following the logs much easier.
2022-10-20 22:41:16 -07:00
Justin C. Miller
2703080df2 [kernel] Add thread_join syscall
Thread joining is an important primitive that I seem to have totally
forgotten to implement previously.
2022-10-20 21:58:10 -07:00
Justin C. Miller
194776d226 [kernel] Remove status code from thread exit
The status code from thread exit had too many issues, (eg, how does it
relate to process exit code? what happens when different threads exit
with different exit codes?) and not enough value, so I'm getting rid of
it.
2022-10-20 21:49:40 -07:00
Justin C. Miller
1a04310f80 [kernel] Simplify mailbox code, and messages
A number of simplifications of mailboxes now that the interface is much
simpler, and synchronous.

* call and respond can now only transfer one handle at a time
* mailbox objects got rid of the message queue, and just have
  wait_queues of blocked threads, and a reply_to map.
* threads now have a message_data struct on them for use by mailboxes
2022-10-14 01:02:56 -07:00
Justin C. Miller
e830a3d37b [kernel] Move slab_allocated items to the heap
Allocate the slabs for slab-allocated items to the heap, now that heap
regions are aligned. This also lets the slab sizes be non-page-sized.
2022-10-11 18:52:19 -07:00
Justin C. Miller
c9bcc87511 [kernel] Simplify mailbox interface to call/respond
The only real usage of mailbox was mailbox_call or
mailbox_respond_receive. This change simplifies the interface to just
these syscalls.
2022-10-11 17:42:04 -07:00
Justin C. Miller
9ac4e51224 [kernel] Make capabilities/handles global
Instead of handles / capabilities having numeric ids that are only valid
for the owning process, they are now global in a system capabilities
table. This will allow for specifying capabilities in IPC that doesn't
need to be kernel-controlled.

Processes will still need to be granted access to given capabilities,
but that can become a simpler system call than the current method of
sending them through mailbox messages (and worse, having to translate
every one into a new capability like was the case before). In order to
track which handles a process has access to, a new node_set based on
node_map allows for an efficient storage and lookup of handles.
2022-10-10 21:19:25 -07:00
Justin C. Miller
11b61ab345 [kernel] Change kernel log levels
The kernel log levels are now numerically reversed so that more-verbose
levels can be added to the end. Replaced 'debug' with 'verbose', and
added new 'spam' level.
2022-09-25 17:25:43 -07:00
Justin C. Miller
7b8fd76af0 [libj6] Move caps.h to cap_flags.h
This file is just the generated cap flag constants. Move it to not
collide with more capability code to be added.
2022-09-25 17:23:14 -07:00
Justin C. Miller
a2b876825a [kernel] Move mispalced slab_allocated.h
slab_allocated.h had accidentally been placed in src/kernel/objects
2022-09-25 17:15:00 -07:00
Justin C. Miller
7fd39e91c1 [kernel] Pull block_allocator out into separate class
The vm_area_guarded code to keep a list of used/free block addresses
will be useful elsewhere.
2022-09-11 14:12:18 -07:00
Justin C. Miller
ef307e8ec6 [kernel] Fix mailbox bugs
This commit contains a number of related mailbox issues:

- Add extra parameters to mailbox_respond_receive to allow both the
  number of bytes/handles passed in, and the size of the byte/handle
  buffers to be passed in.
- Don't delete mailbox messages on receipt if the caller is waiting on
  reply
- Correctly pass status messages along with a mailbox::replyer object
- Actually wake the calling thread in the mailbox::replyer dtor
- Make sure to release locks _before_ calling thread::wake() on blocked
  threads, as that may cause them to be scheduled ahead of the current
  thread.
2022-02-28 20:16:42 -08:00
Justin C. Miller
b8684777e0 [kernel] Allow blocking on empty channels
This commit adds a new flag, j6_channel_block, and a new flags param to
the channel_receive syscall. When the block flag is specified, the
caller will block waiting for data on the channel if the channel is
empty.
2022-02-28 20:10:56 -08:00
Justin C. Miller
446025fb65 [kernel] Add clear() method to wait_queue
Allow objects to clear out the wait_queue earlier than waiting for the
destructor by moving that functionality into wait_queue::clear().
2022-02-28 20:06:49 -08:00
Justin C. Miller
f87a4fcd4e [kernel] Don't delete system object on no handles
The system object should never be deleted, so override on_no_handles()
to do nothing.
2022-02-28 18:50:59 -08:00
Justin C. Miller
982442eb00 [kernel] Add an IPI to tell a CPU to run the scheduler
When waking another thread, if that thread has a more urgent priority
than the current thread on the same CPU, send that CPU an IPI to tell it
to run its scheduler.

Related changes in this commit:

- Addition of the ipiSchedule isr (vector 0xe4) and its handler in
  isr_handler().
- Change the APIC's send_ipi* functions to take an isr enum and not an
  int for their vector parameter
- Thread TCBs now contain a pointer to their current CPU's cpu_data
  structure
- Add the maybe_schedule() call to the scheduler, which sends the
  schedule IPI to the given thread's CPU only when that CPU is running a
  less-urgent thread.
- Move the locking of a run queue lock earlier in schedule() instead of
  taking the lock in steal_work() and again in schedule().
2022-02-26 14:04:14 -08:00
Justin C. Miller
30aed15090 [kernel] Replace endpoint with new mailbox API
The new mailbox kernel object API offers asynchronous message-based IPC
for sending data and handles between threads, as opposed to endpoint's
synchronous model.
2022-02-22 00:06:14 -08:00
Justin C. Miller
f7ae2e2220 [kernel] Re-design thread blocking
In preparation for the new mailbox IPC model, blocking threads needed an
overhaul. The `wait_on_*` and `wake_on_*` methods are gone, and the
`block()` and `wake()` calls on threads now pass a value between the
waker and the blocked thread.

As part of this change, the concept of signals on the base kobject class
was removed, along with the queue of blocked threads waiting on any
given object. Signals are now exclusively the domain of the event object
type, and the new wait_queue utility class helps manage waiting threads
when an object does actually need this functionality. In some cases (eg,
logger) an event object is used instead of the lower-level wait_queue.

Since this change has a lot of ramifications, this large commit includes
the following additional changes:

- The j6_object_wait, j6_object_wait_many, and j6_thread_pause syscalls
  have been removed.
- The j6_event_clear syscall has been removed - events are "cleared" by
  reading them now. A new j6_event_wait syscall has been added to read
  events.
- The generic close() method on kobject has been removed.
- The on_no_handles() method on kobject now deletes the object by
  default, and needs to be overridden by classes that should not be.
- The j6_system_bind_irq syscall now takes an event handle, as well as a
  signal that the IRQ should set on the event. IRQs will cause a waiting
  thread to be woken with the appropriate bit set.
- Threads waking due to timeout is simplified to just having a
  wake_timeout() accessor that returns a timestamp.
- The new wait_queue uses util::deque, which caused the disovery of two
  bugs in the deque implementation: empty deques could still have a
  single array allocated and thus return true for empty(), and new
  arrays getting allocated were not being zeroed first.
- Exposed a new erase() method on util::map that takes a node pointer
  instead of a key, skipping lookup.
2022-02-22 00:00:15 -08:00
Justin C. Miller
401e662f0b [kernel] Have threads return status from wait_on_*
If the thread waiting is the current thread, it should have the result
when it wakes. Might as well return it, so that syscalls that know
they're putting the current thread to sleep can get the result easily.
2022-02-03 00:06:58 -08:00
Justin C. Miller
ad5ebae304 [kernel] Let process::add_handle take a handle argument
The process::add_handle() method takes an id and an object. This change
adds an overridden version that accecpts an actual handle object to
copy.
2022-02-03 00:04:09 -08:00
Justin C. Miller
7d5feb943f [kernel] Add handle badge to ctor/assignment
Handles already had a field for badge, but did not touch it in the
constructors or in assignment operators.
2022-02-03 00:02:46 -08:00
Justin C. Miller
9945ebab34 [kernel] Get rid of obsolete thread loading state
The thread::state::loading flag was left over from a time when the
kernel did elf loading for all processes.
2022-01-30 20:50:48 -08:00
Justin C. Miller
dd535158f2 [kernel] Re-add slab_allocated mixin
The return of slab_allocated! Now after the kutil/util/kernel giant
cleanup, this belongs squarely in the kernel, and works much better
there. Slabs are allocated via a bump pointer into a new kernel VMA,
instead of using kalloc() or allocating pages directly.
2022-01-30 20:46:19 -08:00
Justin C. Miller
a7245116b6 [util] Add util::deque container
Adding the util::deque container, implemented with the util::linked_list
of arrays of items.

Also, use the deque for a kobject's blocked thread list to maintain
order instead of a vector using remove_swap().
2022-01-30 20:42:49 -08:00
Justin C. Miller
bdae812274 [kernel] Add handle_clone syscall
Added the handle_clone syscall which allows for cloning a handle with
a subset of the original handle's capabilities.

Related changes:

- srv.init now calls handle_clone on its system handle, and load_program
  was changed to allow this second system handle to be passed to loaded
  programs instead. However, as drv.uart is still a driver AND a log
  reader, this new handle is not actually passed yet.
- The definition parser was using a set for the cap list, which meant
  the order (and thus values) of caps was not static.
- Some code in objects/handle.h was made more explicit about what bits
  meant what.
2022-01-28 23:40:21 -08:00
Justin C. Miller
f1246f84e0 [kernel] Add capabilities to handles
This change finally adds capabilities to handles. Included changes:

- j6_handle_t is now again 64 bits, with the highest 8 bits being a type
  code, and the next highest 24 bits being the capability mask, so that
  programs can check type/caps without calling the kernel.
- The definitions grammar now includes a `capabilities [ ]` section on
  objects, to list what capabilities are relevant.
- j6/caps.h is auto-generated from object capability lists
- init_libj6 again sets __handle_self and __handle_sys, this is a bit
  of a hack.
- A new syscall, j6_handle_list, will return the list of existing
  handles owned by the calling process.
- syscall_verify.cpp.cog now actually checks that the needed
  capabilities exist on handles before allowing the call.
2022-01-28 01:54:45 -08:00
Justin C. Miller
9b75acf0b5 [kernel] Re-add channel syscalls
Channels were unused, and while they were listed in syscalls.def, they
had no syscalls listed in their interface. This change adds them back,
and updates them to the curren syscall style.
2022-01-27 22:37:04 -08:00
Justin C. Miller
3f8dfbd5b2 [kernel] Add locking to endpoint
Endpoints could previously crash if two senders were concurrently
writing to them, so this change adds a spinlock and protects functions
that touch the signals and blocked list.
2022-01-23 19:42:37 -08:00
Justin C. Miller
75e7fe941b [kernel] Fix thread-wait scoped lock scoping bug
A spinlock was recenly added to thread wait states, so that they
couldn't get stuck if their wake event happened while setting the wake
state, and cause the thread to deadlock. But the scoped_lock objects
locking that spinlock were being instantiated as temporaries and
immediately being thrown away because I forgot to name them.
2022-01-23 00:32:06 -08:00
Justin C. Miller
1d30322820 [kernel] Pass objects not handles to syscall impls
This commit contains a couple large, interdependent changes:

- In preparation for capability checking, the _syscall_verify_*
  functions now load most handles passed in, and verify that they exist
  and are of the correct type. Lists and out-handles are not converted
  to objects.
- Also in preparation for capability checking, the internal
  representation of handles has changed. j6_handle_t is now 32 bits, and
  a new j6_cap_t (also 32 bits) is added. Handles of a process are now a
  util::map<j6_handle_t, handle> where handle is a new struct containing
  the id, capabilities, and object pointer.
- The kernel object definition DSL gained a few changes to support auto
  generating the handle -> object conversion in the _syscall_verify_*
  functions, mostly knowing the object type, and an optional "cname"
  attribute on objects where their names differ from C++ code.
  (Specifically vma/vm_area)
- Kernel object code and other code under kernel/objects is now in a new
  obj:: namespace, because fuck you <cstdlib> for putting "system" in
  the global namespace. Why even have that header then?
- Kernel object types constructed with the construct_handle helper now
  have a creation_caps static member to declare what capabilities a
  newly created object's handle should have.
2022-01-17 23:23:04 -08:00
Justin C. Miller
e845379b1e [kernel] Use the hpet clock source in scheduler
There has been a global clock object for a while now, but scheduler was
never using it, instead still using its simple increment clock. Now it
uses the hpet clock.
2022-01-15 22:31:00 -08:00
Justin C. Miller
c631ec5ef5 [uart] Add first pass UART driver and logger
First attempt at a UART driver. I'm not sure it's the most stable. Now
that userspace is handling displaying logs, also removed serial and log
output support from the kernel.
2022-01-15 18:20:37 -08:00
Justin C. Miller
19f9496889 [kernel] Add a timeout to endpoint recieve syscalls
This also required adding support for multiple wait conditions on a
thread, so wait_type is an enum_bitfield now.

I really need a real clock.
2022-01-15 17:48:19 -08:00
Justin C. Miller
2dd78beb92 [tools] Add j6threads gdb command
The j6threads command shows the current thread, ready threads, and
blocked threads for a given CPU.

To support this, TCB structs gained a pointer to their thread (instead
of trying to do offset magic) and threads gained a pointer to their
creator. Also removed thread::from_tcb() now that the TCB has a pointer.
2022-01-15 17:45:12 -08:00
Justin C. Miller
411c8c4cb3 [util] Move enum_bitfields into util
Continuing on the cleaning up of the src/include 'junk drawer', the
enum_bitfields.h and its dependency basic_types.h are now in util.
2022-01-03 21:42:20 -08:00
Justin C. Miller
c1d9b35e7c [bootproto] Create new bootproto lib
This is a rather large commit that is widely focused on cleaning things
out of the 'junk drawer' that is src/include. Most notably, several
things that were put in there because they needed somewhere where both
the kernel, boot, and init could read them have been moved to a new lib,
'bootproto'.

- Moved kernel_args.h and init_args.h to bootproto as kernel.h and
  init.h, respectively.

- Moved counted.h and pointer_manipulation.h into util, renaming the
  latter to util/pointers.h.

- Created a new src/include/arch for very arch-dependent definitions,
  and moved some kernel_memory.h constants like frame size, page table
  entry count, etc to arch/amd64/memory.h. Also created arch/memory.h
  which detects platform and includes the former.

- Got rid of kernel_memory.h entirely in favor of a new, cog-based
  approach. The new definitions/memory_layout.csv lists memory regions
  in descending order from the top of memory, their sizes, and whether
  they are shared outside the kernel (ie, boot needs to know them). The
  new header bootproto/memory.h exposes the addresses of the shared
  regions, while the kernel's memory.h gains the start and size of all
  the regions. Also renamed the badly-named page-offset area the linear
  area.

- The python build scripts got a few new features: the ability to parse
  the csv mentioned above in a new memory.py module; the ability to add
  dependencies to existing source files (The list of files that I had to
  pull out of the main list just to add them with the dependency on
  memory.h was getting too large. So I put them back into the sources
  list, and added the dependency post-hoc.); and the ability to
  reference 'source_root', 'build_root', and 'module_root' variables in
  .module files.

- Some utility functions that were in the kernel's memory.h got moved to
  util/pointers.h and util/misc.h, and misc.h's byteswap was renamed
  byteswap32 to be more specific.
2022-01-03 17:44:13 -08:00