Compare commits

..

573 Commits

Author SHA1 Message Date
1bf5e6a051 WindowServer: Fix xbanan access check 2026-04-15 16:40:30 +03:00
394719a909 userspace: Fix some includes found when compiling to linux 2026-04-15 16:39:36 +03:00
3ebadc5c74 LibDEFLATE: Optimize decompression
Instead of calculating bit-by-bit crc32, we now calculate a lookup table
during compile time. The old crc32 calculation was taking almost 50% of
the decompression time.

Also handle multiple symbols at once without outputting to user. It is
much more efficient to output many bytes instead of the up to 258 that a
single symbol can decode to :^)
2026-04-14 01:50:30 +03:00
d471bbf856 Kernel: Cleanup bootloader headers
Also add custom load addresses for x86_64 target. This allows qemu to
load the kernel with -kernel argument. Without these addresses qemu
would refuse to load as it only supports 32 bit ELFs, but as our kernel
starts in 32 bit mode anyway, we can just load it!
2026-04-13 16:48:57 +03:00
c849293f3d Kernel: Add support for loading gzip compressed initrd 2026-04-13 16:48:57 +03:00
0156d06cdc LibDEFLATE: Support decompressing to/from partial buffer
We no longer require the user to pass full compressed data in one go,
instead the decompressor reports to the user if it needs more input or
output space.
2026-04-13 03:04:55 +03:00
ad12bf3e1d LibC: Cleanup environment variable code 2026-04-13 00:36:13 +03:00
42964ad0b4 Kernel: Remove concept of OpenFile
This was just RefPtr<OpenFileDescription> and descriptor flags.
Descriptor flags only define O_CLOEXEC, so we can just store fd's
cloexec status in a bitmap rather than separate fields. This cuts down
the size of OpenFileDescriptorSet to basically half!
2026-04-12 04:42:08 +03:00
87979b1627 LibImage: Don't allocate zlib stream to a contiguous buffer
We can now pass multiple buffers to the decoder!
2026-04-11 19:48:46 +03:00
fed9dbefdf LibDEFLATE: Allow decompression from multiple byte spans
Before we required the compressed data to live in a single contiguous
chunch of memory.
2026-04-11 19:47:44 +03:00
2984927be5 WindowServer: Block without timeout when there is no damaged regions 2026-04-11 08:41:21 +03:00
2e654b53fa WindowServer: Use rectangular framebuffer syncs 2026-04-11 08:30:15 +03:00
ac6e6f3ec1 Kernel: Add ioctl to sync rectangular areas in framebuffer
msync is not really the best API for framebuffer synchronization
2026-04-11 08:29:10 +03:00
2b97587e9f WindowServer: Rewrite damaged region tracking
Instead of immediately doing rerender of client data and syncing 60 Hz,
we now only keep track of the damaged regions and also do the rerender
step 60 Hz.
2026-04-11 08:26:22 +03:00
4bde088b28 WindowServer: Store rectangles as min and max bounds
This makes some math easier than x,y and w,h
2026-04-11 06:35:45 +03:00
2a9dad2dd8 LibC: Add SSE2 non-temporal memset and memcpy
Also cleanup other assembly by using local labels to emit them from the
assembled program.
2026-04-11 03:30:52 +03:00
d11160d2f7 Kernel: Fix si_addr reporting
Meaning of this is signal specific and not the instruction pointer
2026-04-11 03:30:52 +03:00
7333008f40 LibC: Use IP instead of si_addr for faulting instruction
si_addr only means faulting instruction for SIGILL. For SIGSEGV it is
the faulting memory address.
2026-04-11 03:30:52 +03:00
cd7d309fd1 Kernel: Push missing IP and SP to mcontext in signal handler
I was missing these two registers, messing up the whole siginfo_t
structure. This fixes libc's stack trace dump crashing :D
2026-04-11 03:30:52 +03:00
a4ba1da65a LibGUI/WindowServer: Rework packet serialization
Instead of sending while serializing (what even was that), we serialize
the whole packet into a buffer which can be sent in one go. First of all
this reduces the number of sends by a lot. This also fixes WindowServer
ending up sending partial packets when client is not responsive.
Previously we would just try sending once, if any send failed the send
was aborted while partial packet was already transmitted. This lead to
packet stream being out of sync leading to the client killing itself.
Now we allow 64 KiB outgoing buffer per client. If this buffer ever fills
up, we will not send partial packets.
2026-04-11 03:30:52 +03:00
2f9b8b6fc9 Kernel/LibC: Rework userspace syscall interface
Kernel syscall API no longer zeros all unused argument registers and
libc now uses inlined syscall macro internally. This significantly
cleans up generated code for basic syscall wrapper functions.
2026-04-11 03:30:52 +03:00
279ac6b2b6 BAN: Implement some macro utilities
This contains stuff to count arguments, stringify, concatinate, for_each
2026-04-11 03:30:52 +03:00
9084d9305c Kernel: Change preemption condition
Instead of keeping track of the current time and rescheduling when
interval has passed, keep track of the next expected reschedule time.
This prevents theoretically missing every second pre-emption when
scheduler's timer is interrupting at same rate as the interval.
2026-04-11 03:30:52 +03:00
80c4213501 LibC: Make errno macro directly access uthread
This allows inlining errno usages

This breaks libc ABI and requires toolchain rebuild
2026-04-11 03:30:32 +03:00
e0af23a924 LibC: Move uthread definition to its own header
Use `__asm__` instead of `asm` to allow compilation with --std=c99 and
before
2026-04-11 03:30:32 +03:00
7e907b70f6 Kernel: Store memory region size as uint64_t
On 32 bit target, we were storing 32 bit physical region sizes which
would truncate regions > 4 GiB
2026-04-07 03:41:25 +03:00
7fb27b16e8 LibC: Fix pthread cancellation
Install SIGCANCEL handler for all threads.

Remove unneeded atomic stores and loads. States are only changed within
the thread itself.

Define pthread_testcancel as a macro so it gets inlined inside
cancellation points
2026-04-07 03:41:25 +03:00
3fb903d991 LibGUI: Optimize invalidate and set alpha channel
If the window does not have an alpha channel, we now set every pixel's
alpha to 0xFF. This is needed by the WindowServer when it does alpha
blending, there used to be some weird stuff happening on overlapping
windows.

Also when we are invalidating a region with width of the whole window,
we can do a single memcpy instead of a memcpy for each row separately.
2026-04-06 19:29:34 +03:00
2a4a688c2d WindowServer: Optimize rendering
We now use SSE2 to do alpha blending on 4 pixels at a time where
possible and use memcpy instead of manual loops for non blended regions.
2026-04-06 19:29:34 +03:00
1487c86262 Kernel: Resolve \\_S5 package elements on poweroff 2026-04-06 19:29:34 +03:00
4d3751028b LibInput: Honor chroot and credentials when loading keymap 2026-04-06 19:29:34 +03:00
e4c6539964 Kernel: Be more clever with physical memory
Initially allocate all physical memory except kernel memory and boot
modules. Before we just skipped all memory before kernel boot modules.
Also release memory used by boot modules after the kernel is up and
running. Once the boot modules are loaded, there is no need to keep them
in memory.
2026-04-06 19:29:34 +03:00
34b59f062b LibC: Implement blocking pthread_rwlock
pthread_rwlock now uses a mutex and condition variable internally so it
doesn't need to yield while waiting!
2026-04-06 19:29:34 +03:00
ec4aa8d0b6 LibC: Fix shared pthread_barrier init
Initialize internal lock and cond as shared when the barrier is shared
2026-04-05 12:06:18 +03:00
1eebe85071 LibC: Fix pthread_cond_timedwait
If timeout occurred, I was not removing the entry from block list
2026-04-05 11:31:16 +03:00
db0507e670 LibC: Mark pthread_exit noreturn 2026-04-05 11:30:45 +03:00
1e3ca7dc18 Kernel: Fix signal related syscalls
There were missing locks, out of order sigprocmask, incorrect signal
masking...
2026-04-05 02:31:30 +03:00
8ca3c5d778 Kernel: Clean up signal handling
We now appreciate sa_mask and SA_NODEFER and change the signal mask for
the duration of signal handler. This is done by making a sigprocmask
syscall at the end of the signal handler. Back-to-back signals will
still grow stack as original registers are popped AFTER the block mask
is updated. I guess this is why linux has sigreturn(?).
2026-04-05 02:25:59 +03:00
df257755f7 Kernel: If userspace sets fs or gs, dont overwrite it
Current cpu index is stored at either segment. If userspace sets that
segment, kernel will not overwrite it on every reschedule. This is fine
as long as user program does not use anything that relies on it :)
2026-04-04 23:48:43 +03:00
d7e292a9f8 Kernel: Drop 32 bit userspace stack to 4 MiB
32 bit userspace only has 256 MiB reserved for stacks, so with 32 MiB
stacks it only allowed total of 7 threads. Now we can have up to 62
threads
2026-04-04 23:48:43 +03:00
9fce114e8e Kernel: Don't clone entire kernel stack on fork
We only need to copy area between [ret_sp, stack_end]. This range is
always very small compared to the whole stack (64 KiB).
2026-04-04 23:48:43 +03:00
9d83424346 Kernel: Remove unnecessary stack pointer loading
Any time I started a thread I was loading the stack pointer which is
already correctly passed :D
2026-04-04 23:48:43 +03:00
a29681a524 Kernel: Fix signal generation
We need to have interrupts enabled when signal kills the process as
process does mutex locking. Also signals are now only checked when
returning to userspace in the same place where userspace segments are
loaded.
2026-04-04 23:48:43 +03:00
47d85eb281 Kernel: Pass the actual vaddr range to reserve pages 2026-04-04 23:48:43 +03:00
85f676c30a DynamicLoader: Calulate max loaded file count based on dtv size
dtv should be dynamic but i dont care right now :)
2026-04-04 23:48:43 +03:00
8c5fa1c0b8 DynamicLoader: Fix R_386_PC32 relocation
I was not accounting elf base with offset
2026-04-04 23:48:43 +03:00
c7690053ae LibC: Don't crash on 32 bit pthread_create 2026-04-04 23:48:43 +03:00
3f55be638d Kernel: Allow reserve_free_page{,s} to fail
Apparently I was asserting here before :D
2026-04-04 23:48:43 +03:00
664c824bc0 Kernel: Keep fast page always reserved
There was a bug where 32 bit target's reserve_free_page was allocating
the fast page address
2026-04-04 23:48:43 +03:00
e239d9ca55 ports/SDL2: Use 48 kHz floats instead of 44.1 kHz PCM16 2026-04-03 16:17:16 +03:00
bf1d9662d7 LibAudio: Use floats instead of doubles for samples 2026-04-03 16:15:02 +03:00
675c215e6a Kernel: Add CoW support to MemoryBackedRegion
This speeds up fork by A LOT. Forking WindowServer took ~90 ms before
this and now its ~5 ms.
2026-04-03 01:54:59 +03:00
c09bca56f9 Kernel: Add fast write perm remove to page tables 2026-04-03 01:54:22 +03:00
7d8f7753d5 Kernel: Cleanup and fix page tables and better TLB shootdown 2026-04-03 01:53:30 +03:00
f77aa65dc5 Kernel: Cleanup accessing userspace memory
Instead of doing page validiation and loading manually we just do simple
memcpy and handle the possible page faults
2026-04-02 16:36:33 +03:00
9589b5984d Kernel: Move USERSPACE_END to lower half
This allows calculating distance to USERSPACE_END from lower half
address
2026-04-02 16:34:47 +03:00
32806a5af3 LibC: Allow "t" in stdio mode 2026-04-02 15:44:50 +03:00
876fbe3d7c LibC: Fix sem_{,timed}wait 2026-04-02 15:43:34 +03:00
c1b8f5e475 LibC: Add and cleanup network definitions 2026-04-02 15:42:00 +03:00
cf31ea9cbe LibC: Add _SC_PHYS_PAGES and _SC_AVPHYS_PAGES 2026-04-02 15:41:26 +03:00
7e6b8c93b4 LibC: Implement strsep 2026-04-02 15:40:23 +03:00
dd2bbe4588 LibC: Implement sched_getcpu 2026-04-02 15:39:36 +03:00
e01e35713b LibC: Allow including assert.h multiple times
Some shit seems to depend on this
2026-04-02 15:38:06 +03:00
82d5d9ba58 LibC: Write memchr, memcmp and strlen with sse 2026-04-02 15:35:03 +03:00
d168492462 WindowServer: bind volume up/down to volume control 2026-04-02 15:24:02 +03:00
6f2e8320a9 TaskBar: Show current volume level 2026-04-02 15:22:42 +03:00
bf4831f468 AudioServer: Add support for volume control 2026-04-02 15:21:38 +03:00
5647cf24d2 Kernel: Implement volume control to audio drivers 2026-04-02 15:14:27 +03:00
85f61aded5 BAN: Use builtins for math overflow 2026-04-02 14:49:12 +03:00
21639071c2 kill: Allow killing with process name 2026-04-02 05:02:05 +03:00
68506a789a Kernel: Add support for volume control keys 2026-04-02 05:02:05 +03:00
d9ca25b796 LibC: Add FNM_CASEFOLD and FNM_IGNORECASE
These are part of POSIX issue 8
2026-03-25 04:27:00 +02:00
e9c81477d7 BAN/LibC: Implement remainder
This is basically just fmod but with fprem1 instead of fprem
2026-03-25 01:06:45 +02:00
5c20d5e291 Kernel: HDAudio hide unusable pins and cleanup path finding 2026-03-24 01:16:47 +02:00
f89d690716 Kernel: HDAudio only probe codecs in STATESTS
This removes unnecessary probing that lead to timeouts. Also cap codec
address at 14 instead of 15. My test laptop was duplicating codec 0 at
address 15 leading to duplicate devices.
2026-03-24 00:49:47 +02:00
c563efcd1c AudioServer: Query pins of the asked device and not the current one 2026-03-23 22:57:49 +02:00
dedeebbfbe Kernel: Use ByteRingBuffer with audio buffers 2026-03-23 22:12:40 +02:00
35e2a70de0 AudioServer: Handle client data before disconnecting clients 2026-03-23 20:41:13 +02:00
81d5c86a7a WindowServer: Automatically launch xbanan if installed 2026-03-23 19:39:08 +02:00
db6644bae9 BuildSystem: Set glib-compile- binaries in meson cross file 2026-03-23 19:34:00 +02:00
14f1c1a358 LibC: Implement vsyslog 2026-03-23 19:13:38 +02:00
5be9bc64a2 ports/libxml2: Configure with -shared-libgcc
otherwise it doesn't seem to find libiconv due to __divdc3
2026-03-23 19:09:33 +02:00
64d3a5c8b7 ports: Update zlib 1.3.1->1.3.2
1.3.1 is no longer available at zlib.net
2026-03-23 18:54:57 +02:00
ccb4d13a82 Kernel: Compile EventFD file 2026-03-23 18:25:18 +02:00
cbe835a2c8 DynamicLoader: Add missing strlen definition 2026-03-23 18:23:31 +02:00
6a77754adf LibC: Don't link against libstdc++
This prevented building the toolchain
2026-03-23 18:22:42 +02:00
7d7d5ba734 LibC: Compile eventfd file 2026-03-23 18:22:04 +02:00
684fa1c4b0 ports: Add pixman port
This fixes cairo dependencies
2026-03-23 17:58:39 +02:00
a98d851fde ports: Add gtk3 port 2026-03-23 17:58:39 +02:00
9c3e2dab40 ports: Add pango port 2026-03-23 17:58:39 +02:00
eddb68f2fa ports/mesa: Build with x support 2026-03-23 17:55:57 +02:00
791091174a ports/cairo: Build with x support 2026-03-23 17:50:35 +02:00
dd9280c6ea ports/expat: Add support for shared libraries 2026-03-23 17:48:19 +02:00
a4d83f9fdb ports: Add xbanan port
This allows running x apps on top of my own GUI interface!
2026-03-23 17:47:11 +02:00
f42c5c4a5b ports: Add a lot of x library ports + xeyes/xclock 2026-03-23 17:45:59 +02:00
186fa4f1a1 ports: Update git 2.52.0->2.53.0 2026-03-23 17:35:08 +02:00
09292bb87e BAN: Cleanup math code and add SSE sqrt
We should prefer SSE instructions when they are easily available. For
other functions x87 is just simpler. It's hard to write faster and close
to as accurate approximations with SSE.

This does not use xmmintrin.h as clangd does not like that file and
starts throwing errors in every file that includes this :)
2026-03-22 22:07:48 +02:00
d18a0de879 Kernel: Fix mprotext for partial regions
if mprotected are did not contain the start of the region, mprotect
would exit early
2026-03-17 23:33:05 +02:00
cdc45935b5 Kernel: Don't allow chdir into non-directories 2026-03-17 22:57:17 +02:00
43e18148a6 LibC: Define SSP things 2026-03-17 20:30:25 +02:00
b0db645248 LibC: Add basic elf.h 2026-03-17 20:25:38 +02:00
07712758a7 BAN: Add default constructor to ipv4address 2026-03-17 20:24:48 +02:00
c1a424a635 Kernel: Implement linux's eventfd 2026-03-17 20:24:06 +02:00
a49588dbc7 DynamicLoader: Fix library lookup for already loaded files 2026-03-17 20:05:05 +02:00
1f22b9b982 DynamicLinker: Implement RTLD_NOLOAD 2026-03-17 20:04:48 +02:00
1d07d8e08e LibC/DynamicLoader: Add support for dynamically loaded TLS
Previously I failed to dlopen if any of the objects contained TLS
section
2026-03-17 20:01:51 +02:00
05b2424fca LibC: Implement more proper random number generator 2026-03-17 19:53:43 +02:00
07201c711e LibC: set endp in string to float conversion error 2026-03-17 19:50:12 +02:00
8fac88c9a6 LibC: Add sincos{,f,l} 2026-03-17 19:42:53 +02:00
c9aafa78ec DynamicLoader: Fix RO section mprotect arguments 2026-03-05 17:57:03 +02:00
e1c337a483 LibC: Fix compile and link flags
We were linking with -nostdlib and manually linked against libgcc. This
does not link with crtbegin and crtend which provides __dso_handle
preventing use of some global C++ constructors inside libc.

Now we just don't link against libc fixing this issue
2026-03-05 16:25:06 +02:00
acebe68dfa DynamicLoader: Fix copy relocation and TLS initialization 2026-03-04 23:04:19 +02:00
eeef945c25 Kernel: Make tty use the new byte ring buffer 2026-02-28 14:53:15 +02:00
a602753bda Kernel: Add front/back/pop_back to ByteRingBuffer 2026-02-28 14:51:35 +02:00
812ae77cd7 Kernel: Make TCP sockets use the new ring buffer
Also fix race condition that sometimes prevented window updates not
being sent after zero window effectively hanging the whole socket
2026-02-28 14:22:08 +02:00
8b8af1a9d9 Kernel: Rewrite pipes using the new ring buffer 2026-02-28 14:20:52 +02:00
493b5cb9b1 Kernel: Implement byte ring buffer
This maps the ring twice right next to each other so we don't have to
care about wrapping around when doing memcpy or accessing the data
2026-02-28 14:18:23 +02:00
1ecd7cc2fe Kernel: Allow protocol specific socket options
I had forgot to remove this condition on the syscall
2026-02-27 19:20:22 +02:00
5c38832456 Kernel: use wake_with_waketime in epoll
We already have the wake time so there is no reason to calculate the
timeout
2026-02-27 19:14:35 +02:00
d16f07a547 Kernel: Print thread id when writing to /dev/debug 2026-02-27 19:12:35 +02:00
54acb05131 Kernel: Don't print "./" prefix with debug functions 2026-02-27 19:10:51 +02:00
9ddf19f605 Kernel: Optimize networking code
Remove buffering from network layer and rework loopback interface.
loopback now has a separate recieve thread to allow concurrent sends and
prevent deadlocks
2026-02-27 19:08:08 +02:00
ff378e4538 Kernel: Cleanup and optimize TCP
We now only send enough data to fill other ends window, not past that.
Previous logic had a but that allowed sending too much data leading to
retransmissions.

When the target sends zero window and later updates window size,
immediately retransmit non-acknowledged bytes.

Don't validate packets through listeing socket twice. The actual socket
will already verify the checksum so the listening socket does not have
to.
2026-02-24 16:20:23 +02:00
2ea0a24795 Kernel: Fix TCP SYN option propagation
Listening socket now forwards TCP options to the newly created socket
2026-02-23 23:00:47 +02:00
acf28d8170 Kernel: Use ring buffers for TCP windows
This speeds up TCP networkign a ton as it doesnt have to do unnecessary
memmoves for each send/receive
2026-02-23 21:10:13 +02:00
666a7bb826 Kernel: Rework TCP window size reporting
We now report actually available window size when sending packets. If
the available window size grows significantly we send an ACK to reflect
this to the remote.
2026-02-23 21:10:13 +02:00
1ac20251cf Kernel: Fix TCP stack crash on retransmission 2026-02-23 17:48:16 +02:00
a318a19fe2 LibGUI/WindowServer: Add fullscreen events
When window's fullscreen state changes we now generate events!
2026-02-23 16:06:48 +02:00
f4a7aec167 LibGUI/WindowServer: Add support for custom cursor origin 2026-02-23 16:06:48 +02:00
9445332499 Kernel: Remove unnecessary interface lookup
This prevented connecting to local sockets listening on INADDR_ANY
2026-02-23 16:06:48 +02:00
8edd63d115 Kernel: Cleanup {set,get}sockopt debug prints 2026-02-23 16:06:48 +02:00
304ace1172 LibInput: Export keyboard layout keymaps 2026-02-23 16:06:48 +02:00
a5cdf0640f BAN: Add value_type to String{,View} 2026-02-23 16:06:48 +02:00
1fc2e43881 BAN: Add support for string format padding 2026-02-23 16:06:48 +02:00
0964c9f928 BAN: Remove unnecessary assert from span 2026-02-23 16:06:48 +02:00
8b1e820869 BAN: Add reallocator support to Vector 2026-02-21 04:03:11 +02:00
9edc6966db BAN: Add reallocator definition
for the moment this does not exist in kernel, kmalloc rewrite soon™️
2026-02-21 04:03:11 +02:00
12207dcb77 BAN: Add is_trivially_copyable trait 2026-02-21 04:03:11 +02:00
2255e36810 LibDEFLATE: Add GZip support
This allows compressing and decompressing with data using GZip headers
and footers
2026-02-21 04:03:11 +02:00
5abddd448e LibC: Fix typo/bug in fnmatch
* would stop matching at '0' instead of end of string
2026-02-19 22:12:59 +02:00
f022a1b08f Shell: Fix crash when executing semicolon
This fixes #4
2026-02-13 17:52:54 +02:00
b3bbfaeff0 LibC: Fix posix_spawnattr_t definition 2026-02-10 01:22:25 +02:00
679a3d4209 LibGUI: Add Texture::clear{,_rect} 2026-02-08 19:45:01 +02:00
a0211d88e7 Kernel: Don't include TCP header in MSS 2026-02-08 19:44:30 +02:00
e216fc7798 Kernel: Fix port allocation endianness 2026-02-08 19:43:08 +02:00
c648ea12f2 Kernel: Cleanup and fix UNIX sockets
EPOLLOUT is now sent to the correct socket and buffer is now a ring
buffer to avoid unnecessary memmove on every packet
2026-02-08 19:38:28 +02:00
2e59373a1e Kernel: Fix non blocking sockets blocking :D 2026-02-08 19:33:28 +02:00
a51a81b6cd Kernel: Move {set,get}sockopt to sockets
Sockets can now actually implement socket options :D
2026-02-08 19:27:16 +02:00
9809f87010 LibC: Fix {read,write}v return value for partial actions 2026-02-08 18:45:29 +02:00
8794122c2d BAN: Variant allow copy/move from empty 2026-02-07 18:54:31 +02:00
8fb2270ecf DynamicLoader: map RO sections actually read only
I was mapping everything RW as i did not have mprotect when I
implemented the dynamic loader.
2026-02-04 23:21:06 +02:00
c304133224 LibC: Indicate regex support in unistd.h 2026-01-25 01:47:30 +02:00
7843d3de62 LibC: Support attrs and file actions in posix spawn
Apparently GCC wants to use posix_spawn now that it is available, this
patch adds support for the missing fields. POSIX Issue 8 did add some
fields that are not supported here
2026-01-25 01:45:47 +02:00
aef536fff3 Kernel: Fix SharedMemoryObject cloning on deleted keys 2026-01-25 01:42:17 +02:00
d472e1ac0e Kernel: Remove obsolete FIXMEs and null pointer checks 2026-01-24 22:42:18 +02:00
120c08fb75 Kernel: Implement fcntl based locks 2026-01-24 22:38:34 +02:00
ba6229b92d Kernel: Fix TCP accept bind address
I was accidentally binding the new socket to the target address instead
of the listening socket's address
2026-01-24 00:33:05 +02:00
3d2362cb5f ports/xash3d-fwgs: Don't apply vorbis patch
I removed the pathes a while ago
2026-01-21 19:20:02 +02:00
a08b9b82a6 Kernel: Fix yield stack pointer value
Stack pointer was pointing to value of return address on return instead
of past it. This did not affect anything as ig Processor::yield() didn't
use stack after calling the trampoline
2026-01-19 00:47:00 +02:00
5d62fa3f10 Kernel: Clenup stacktrace printing on exception
Start from current ip and bp. This removes kernel call stack to debug
printing function from the stack trace
2026-01-16 16:31:35 +02:00
d3df00f0ba Kernel: Make Processor structure default to zero
This moves processor info to bss instead of having it in data section
2026-01-16 16:24:47 +02:00
34e84f8b07 Kernel: Reduce the number of TLB invalidations
Invalidations are not done if mapping or unmapping previously unmapped
page. TLB invalidate IPIs are now ignored if they don't affect the
currently mapped address space
2026-01-16 16:22:29 +02:00
1143dc3cae Kernel: Rework syscall memory validation and locking
Process's memory regions are now behind an rwlock instead of using the
full process lock. This allows most pointer validations to not block as
write operations to memory regions are rare.

Thread's userspace stack is now part of process's memory regions. This
simplifies code that explicitly looped over threads to see if the
accessed address was inside a thread's stack.

Only drawback of this is that MemoryRegions don't support guard pages,
so userspace stackoverflow will be handeled as cleanly as it was prior
to this.

This patch also fixes some unnecessary locking of the process lock and
moves locking to the internal helper functions instead of asserting that
the lock is held. Also we now make sure loaded ELF regions are in sorted
order as we previously expected.
2026-01-16 16:09:38 +02:00
0299d4d44e Kernel/LibC: remove SYS_TERMID
This syscall is not needed. /dev/tty is already a symlink to the
controlling terminal. Also this syscall did not handle pseudo terminals
2026-01-16 15:57:36 +02:00
1d07151743 ports/xash-fwgs: Cleanup patches
Remove patches that are no longer needed and cleanup the general support
patch
2026-01-13 20:51:58 +02:00
a83fa6f4c6 Kernel: Optimize futexes
Eeach futex object now has its own mutex to prevent unnecessary locking
of the process/global futex lock. This basically removes sys_futex from
profiles when running software with llvmpipe
2026-01-13 19:18:52 +02:00
c30fc9d60f LibGUI: Rewrite using epoll
select is slow :^)
2026-01-12 23:53:11 +02:00
311a68160c Kernel: Don't delete futex objects after they are not used anymore
Hashmap insertions and deletions made futex very slow to use. When
running SuperTuxKart, ~15% of cpu time was spent doing these.

Never freeing objects is not great either but at least the performance
is usable now :)
2026-01-12 23:52:04 +02:00
343aef31c3 AudioServer: Rewrite using epoll
select is slow :^)
2026-01-12 23:46:51 +02:00
3ac8f7e14f WindowServer: Rewrite using epoll
Looking at profiles, select is a very slow syscall as it has to allocate
a temporary epoll instance
2026-01-12 23:46:03 +02:00
0cef66d155 Kernel: Fix epoll reporting multiple of the same event 2026-01-12 23:45:17 +02:00
9ffbb9fbf0 LibC: Fix clock_gettime return value 2026-01-11 22:44:03 +02:00
c9a8f5b456 Kernel: Fix ext2 fileystem super block backups
Check if rev >= 1 sets sparse superblock feature instead of assuming it
is set
2026-01-11 19:55:10 +02:00
4e3831e380 Kernel: ACHI use ext commands for LBAs >=24 bits
AFAICS non extended commands are supposed to support 27 bit LBAs but
qemu seems to ignore bits 27:24. Maybe I'm just doing something wrong
but this seems to fix this.

This fixes using big disks :D ATM using using disks >= 8 GiB (with 512
byte LBAs) returned wrong data on reads, failing the boot :D
2026-01-11 15:15:58 +02:00
cae2b3bd14 Kernel: Cleanup ext2 indirect block lookup
If we are not allocating and the block is null, add a fast path to
delete it. This also prevents possibly blocking filesystem block wrapper
allocation
2026-01-11 04:00:04 +02:00
5637b8602b Kernel: Fix setting ext2 symbolic link target
If a link was >= 60 bytes but got shrinked to 60 bytes, reading it would
rebort garbage and unlinking it would leak blocks
2026-01-11 03:58:48 +02:00
4af9699b22 Kernel: Only save/load sse state when it is used
There is no need to save and load sse state on every interrupt. Instead
we can use CR0.TS to make threads trigger an interrupt when they use sse
instructions. This can be used to only save and load sse state when
needed.

Processor now keeps track of its current "sse thread" and the scheduler
either enabled or disabled sse based on which thread it is starting up.
When a thread dies, it checks if it was the current sse thread to avoid
use after free bugs. When load balancing, processor has to save the
thread's sse state before sending it to a new processor (if it was the
current sse thread). This ensures thread's sse state will be correct
when the new processor ends up loading it.
2026-01-11 03:06:39 +02:00
35c97e2ff8 Kernel: optimize yielding
Doing a yield no longer raises a software interrupt. Instead it just
saves all the callee saved registers, ip, sp and return value. Because
yield is only called in the kernel, it can just restore registers and
jump to the target address. There is never a need to use iret :)
2026-01-11 01:31:09 +02:00
83e5cb81e8 ports: Cleanup projects using cmake
There is no need to use $BANAN_CMAKE because our own toolchain directory
is added to path.
2026-01-10 19:32:48 +02:00
7a49a0d986 BuildSystem: Install meson as part of the toolchain
Debian based distros have meson 0.6x in their repositories. These cause
some obscure error messages when building meson based ports.
2026-01-10 19:32:48 +02:00
78cd054d59 BuildSystem: Write my own disk image perm updater
If user's bash does not have bultin stat, updating image perms was
terribly slow. This patch adds a simple c program that does the job
without exec overhead
2026-01-10 17:57:21 +02:00
d33a8eac9c ports/mesa: Download prebuilt llvm instead of building it
compiling llvm takes too long :D
2026-01-10 16:40:12 +02:00
9355ab1656 ports: Add cairo port
This is needed by harfbuzz
2026-01-10 16:21:12 +02:00
1f87bfbf2e ports/SuperTuxKart: Don't disable configure :D 2026-01-10 16:00:24 +02:00
e06429da87 ports: Add SuperTuxKart port 2026-01-10 13:35:07 +02:00
26058763df ports: Add harfbuzz port 2026-01-10 13:32:20 +02:00
1f03d23dae Kernel: Fix load balancing
My code to find least loaded processor used processor index instead of
processor id to index the array. Most of the time this lead to wrong
processor returned as the least loaded, leaving some processors
basically idle.
2026-01-10 01:46:08 +02:00
2eea074473 Kernel: Remove unnecessary page table loads
loading a page table is slow as it invalidates the whole tlb
2026-01-10 01:13:48 +02:00
ed82a18e2a Kernel: Fix deadlock in ext2 filesystem
If multiple threads were waiting for more block buffers without anyone
releasing them, they ended up in a deadlock.

Now we store 6 blocks for 8 threads. If a thread already has a block
buffer, it will not have to wait for a new one. Only if there are more
than 8 threads using blocks, will it block until there are free slots
for a thread available.
2026-01-10 00:30:30 +02:00
2961a49dc7 Kernel: Optimize futexes
Add support for processor local futexes. These work the exact same way
as global ones, but only lock a process specific lock and use a process
specific hash map.

Also reduce the time futex lock is held. There was no need to hold the
global lock while validating addresses in the process' address space.
2026-01-09 22:27:59 +02:00
5c9151d3e9 LibC: Add stubs for {init,set}state
Some port wanted these as it detected we had {,s}random
2026-01-09 22:08:32 +02:00
90deb9fb43 BAN: Make debug output thread safe
Now file lock is only acquired once per message, not once per character
2026-01-09 20:30:35 +02:00
12489a4c6b Kernel: Fix 32 bit target compile and runtime
Apparently I have to reload stack in the fork trampoline. Not sure why
or why not on x86_64. Also sse builtins did not compile
2026-01-09 17:06:57 +02:00
74f70ae4bd Kernel/LibC: Use builtin functions over inline asm
Getting flags and saving/restoring sse state and reading TSC can be done
using compiler builtins
2026-01-09 15:39:19 +02:00
a9ceab0415 Kernel: Use syscall/sysret for syscalls in x86_64 2026-01-09 15:18:58 +02:00
94bd74d0bb BuildSystem: Update qemu script
Default to intel-hda instead of ac97 for audio

If we are accelerating with kvm, use host cpu and disable migratable to
allow invariant TSC
2026-01-08 17:16:20 +02:00
b2d8199480 ports/openal-soft: Add SDL2 as a dependency 2026-01-08 17:13:59 +02:00
e60f3711f8 ports: Update openssl 3.3.1->3.6.0 2026-01-08 17:13:59 +02:00
6ec9e4f7b8 ports: Update freetype 2.13.3->2.14.1 2026-01-08 17:13:59 +02:00
9eb3834ae5 Kernel: Add syscall-less clock_gettime
If the processor has invariant TSC it can be used to measure time. We
keep track of the last nanosecond and TSC values and offset them based
on the current TSC. This allows getting current time in userspace.

The implementation maps a single RO page to every processes' address
space. The page contains the TSC info which gets updated every 100 ms.
If the processor does not have invariant TSC, this page will not
indicate the capability for TSC based timing.

There was the problem about how does a processor know which cpu it is
running without doing syscall. TSC counters may or may not be
synchronized between cores, so we need a separate TSC info for each
processor. I ended up adding sequence of bytes 0..255 at the start of
the shared page. When a scheduler gets a new thread, it updates the
threads gs/fs segment to point to the byte corresponding to the current
cpu.

This TSC based timing is also used in kernel. With 64 bit HPET this
probably does not bring much of a benefit, but on PIT or 32 bit HPET
this removes the need to aquire a spinlock to get the current time.

This change does force the userspace to not use gs/fs themselves and
they are both now reserved. Other one is used for TLS (this can be
technically used if user does not call libc code) and the other for
the current processor index (cannot be used as kernel unconditionally
resets it after each load balance).

I was looking at how many times timer's current time was polled
(userspace and kernel combined). When idling in window manager, it was
around 8k times/s. When running doom it peaked at over 1 million times
per second when loading and settled at ~30k times/s.
2026-01-08 17:13:59 +02:00
ee57cf3e9a Kernel: Expose usb device's device descriptor
This is used by the joystick detection code but i forgot to commit this
:D
2026-01-08 13:46:11 +02:00
fea5d1d82b BAN: Fix wrong include in heap 2026-01-07 22:12:20 +02:00
c84a30d4dd ports/SDL2: Update to new joystick interface 2026-01-07 19:07:42 +02:00
24d91eee90 Kernel/LibInput: Rework Joystick handling
Joystick axis and buttons are now named to standard values, this allows
interfacing multiple different controllers (only DS3 is supported)

Add ioctl calls for userspace to set joystick player leds and rumble

Only use DS3 code paths when we detect that the attached device is
actually an DS3 controller

update test-joystick program to the new interface and add support to
control rumble and player leds
2026-01-07 19:01:07 +02:00
a5318448f5 userspace: Add audioctl utility to configure audio server 2026-01-06 22:26:11 +02:00
b7c40eeb57 AudioServer: Handle multiple audio devices with multiple pins
This makes audio server configurable during runtime!
2026-01-06 22:26:11 +02:00
e7c9be1875 AudioServer: Increase send buffer size and hardcode volume to 20% 2026-01-06 22:26:11 +02:00
8f1b314802 Kernel: Add ioctls to select audio device's output pin 2026-01-06 22:26:11 +02:00
da6794c8ce Kernel: Implement HD audio driver
This is very basic and does not support a lot of stuff (like changing
the output pin :D)
2026-01-06 22:26:10 +02:00
e926beba5a test-mouse: Fix mouse fd cleanup
I was creating a local variable shadowing the global one. This prevented
cleanup to close it. (this is not really necessary as the program dies
anyway)
2026-01-06 21:58:56 +02:00
3ad053cf6d image: Add option to change resize algoritm
Also benchmark timing is now done cpu clock, not monotonic one
2026-01-06 21:58:56 +02:00
bc11469a0b mkdir: Fix mkdir error handling 2026-01-06 21:58:56 +02:00
a00695bdac LibC: Add stubs that I have locally
I'm not sure if these are used by anything but I would assume so as I
have added them :D

functions added:
- getprotobyname
- open_memstream
- munlock
- lockf
- nice
- crypt
- getsid
- wcstoul
2026-01-06 21:58:56 +02:00
89959b800c LibC: Implement random and srandom 2026-01-06 21:58:56 +02:00
3e19c3b62e LibC: Fix timeradd and timersub overflow/underflow 2026-01-06 21:58:56 +02:00
d970debb4d LibC: Define MAXPATHLEN in sys/param.h
This file is not POSIX, but some software seems to rely on it
2026-01-06 21:58:56 +02:00
d0ba52073f LibC: Add stubs for shm_* functions 2026-01-06 21:58:56 +02:00
943e3b6f51 LibC: Define IN_CLASS* macros
These are not POSIX but some software seems to rely on them
2026-01-06 21:58:56 +02:00
25d43682aa LibC: Bump FOPEN_MAX 16->64 2026-01-06 21:58:56 +02:00
ad16de59f8 Kernel: Implement basic F_{GET,SET}LK{,W}
At the moment these lock the whole file which is not what is supposed to
happen. Some port was trying to use these and this seems to work for
that. This may cause deadlocks but that should be easy enough to find
the reason because of the debug warnings
2026-01-06 21:58:56 +02:00
8634bbb792 Kernel: Don't save/restore sse or reschedule on spurious interrupts
I think these should be just fully ignored :D
2026-01-06 21:58:56 +02:00
60ec5d30fd init: Start Clipboard server on startup
I had forgotten to commit this when I added the clipboard server :D
2026-01-06 21:58:56 +02:00
7667fe6ca5 LibC: Implement sem_timedwait 2026-01-06 21:58:56 +02:00
4b5a8196c3 Kernel: Fix bitmap byte index calculation in PMM
No idea how I had not crashed here earlier, but running on real hw with
a bit initrd ended up crashing :D
2026-01-04 01:16:43 +02:00
706c0816dd Kernel: Move smp_initialized flag after schedulers are initialized
Before this real hardware failed to boot with smp enabled. Allocating
the idle thread does a page mapping which ends up broadcasting TLB
shootdown to other processes. This ends up failing somewhere halting the
processors never allowing them to initialize their scheduler
2026-01-03 23:39:07 +02:00
a8aa89362d ports/SDL2: Add support for game controllers
SuperTux and tuxracer now work with controller support!
2026-01-03 20:42:42 +02:00
7964698ae5 userspace: Add simple joystick test app 2026-01-03 20:42:42 +02:00
65664b0d65 Kernel: Add support for DualShock 3 controllers
This driver accepts any HID joystick devices but button and axis
mappings will only work on a PS3 controller
2026-01-03 20:07:08 +02:00
08bfa0971e Kernel: Rework storage device and disk cache locking
Syncing the disk cache no longer blocks the underlying storage device
and the disk cache itself during sync
2026-01-02 18:06:56 +02:00
912c5ea0bf Kernel: Implement basic RWLock 2026-01-02 17:50:22 +02:00
6cdf5a5a7f Kernel: Make AHCI controller thread safe 2026-01-02 17:50:22 +02:00
50ba743faf Terminal: Cleanup CSI handling and add =c,>c,c,E,F 2026-01-02 17:13:46 +02:00
e26aac3067 Kernel: Decrease the number of syncs done by ext2 inodes
Each allocated inode used to call sync(). Each sync reads and writes
a block from the filesystem. Doing a 1 MiB write ended up syncing around
257 times
2026-01-01 23:54:09 +02:00
941e8aa5d5 Kernel: Optimize ext2 filesystem
block lookup can now also allocate blocks so there is no need to do
multiple lookups of the block did not exist
2026-01-01 23:15:35 +02:00
33b6536e6b Kernel: Make disk cache entry lookup O(log n)
I have absolutely no idea why i was doing a linear lookup here :D
2026-01-01 20:40:38 +02:00
9fbd9288b2 Kernel: Fix symlink deletion from tmpfs
Small symlinks store their target in inline storage of data block
indices. Freeing blocks did not account for this and tried to interpret
the link target as block inidices to delete
2026-01-01 20:40:38 +02:00
bef1a56007 ports: Update git 2.48.1->2.52.0
also remove curl link hack as updating curl port fixed the issue
2026-01-01 20:40:38 +02:00
bc71ff5e81 ports: Update curl 8.11.1->8.17.0
This fixes broken DT_NEEDED dependencies in curl!
2026-01-01 20:40:38 +02:00
bd50444d06 ports: Update ca-certificates 2024-07-02 -> 2025-12-02 2025-12-31 19:28:55 +02:00
2efd6f92b2 rm: add -f and -i options
rm *should* now be posix compatible
2025-12-31 19:28:55 +02:00
7fdfad4088 Kernel: Mount /tmp with sticky bit set 2025-12-31 19:28:55 +02:00
31a1968798 Kernel: Cleanup scheduling while idling
If there are no threads in the run queue and we are idle, attempt to
wake up threads from the sleep queue
2025-12-31 19:28:55 +02:00
b0bd4ad546 Kernel: Fix dup2 return value
We returned the wrong fd number :D
2025-12-31 19:28:55 +02:00
dc454b9a6a Kernel: Fix SA_RESETHAND handling order
if SA_RESETHAND was set, alt stack would not get used
2025-12-31 19:28:55 +02:00
f06e5d33e7 Kernel: Rework socket binding to an address
Sockets are no longer bound to an interface, but an ipv4 address. This
allows servers at 0.0.0.0 talk to multiple different interfaces
2025-12-31 19:28:55 +02:00
efdbd1576f ports/SDL2: disable static lib and enable semaphores
Also add libiconv as a dep so SDL_iconv_string etc works
2025-12-28 15:30:02 +02:00
0421fbdc25 LibC: Implement sem_getvalue 2025-12-28 15:29:37 +02:00
bd426199f8 Kernel: Remove unused (and broken) code from signal trampoline 2025-12-28 03:53:38 +02:00
8e00b3d110 ports: Add ffmpeg port
This allows basic video and audio playback on banan-os!
2025-12-28 00:12:03 +02:00
6fbf1469aa LibC: define static_assert in assert.h
This is needed from C11 until C23
2025-12-28 00:12:03 +02:00
280d3fd919 LibC: Fix assert.h include guard 2025-12-28 00:12:03 +02:00
40ce95b87f LibC: Add definition for TCP_MAXSEG
This is not implemented yet
2025-12-27 23:37:03 +02:00
e7d644b874 AudioServer: Fix rounding the number of samples when resampling
If client tried to play a single sample at lower frequency as the
kenrel, audio server would never play it leading to the client hanging

This makes calculations round the number of samples always up to fix
this
2025-12-18 16:05:28 +02:00
c64159d5c3 AudioServer: Fix resampling math
This caused resampled audio to freeze the whole audio system after few
minutes of playing (like doom)
2025-12-18 14:59:55 +02:00
e2ccc3026f BAN: Remove unnecessary c++ header inclusion 2025-12-16 16:44:42 +02:00
2af6066ee3 LibC: Fix sysconf(_SC_OPEN_MAX) 2025-12-16 05:20:18 +02:00
fc16b5331c LibC: Fix backtrace compilation
Also dump backtrace on SIGABRT
2025-12-16 05:20:00 +02:00
b2723a0c5f aoc2025: Implement day12 solution 2025-12-15 19:06:17 +02:00
01042a24f0 aoc2025: Implement day11 solution 2025-12-15 17:57:45 +02:00
f9643b3881 aoc2025: Implement day10 solution 2025-12-15 14:42:03 +02:00
d2d18bea5d aoc2025: Implement day9 solution 2025-12-13 03:09:15 +02:00
87e595b83e aoc2025: Implement day8 solution 2025-12-12 22:37:03 +02:00
08031b1227 aoc2025: Implement day7 solution 2025-12-12 21:15:22 +02:00
9a87c1f734 aoc2025: Implement day6 solution 2025-12-12 20:17:12 +02:00
edeb667ead aoc2025: Implement day5 solution 2025-12-12 06:30:03 +02:00
db2aa495b8 aoc2025: Implement day4 solution 2025-12-12 06:08:00 +02:00
ddfb591094 aoc2025: Implement day3 solution 2025-12-12 04:34:40 +02:00
e8f1ba3722 aoc2025: Implement day2 solution 2025-12-12 02:49:33 +02:00
19c4f34ccb aoc2025: Implement day1 solution 2025-12-12 02:49:10 +02:00
5d9e9c021a aoc2025: Prepare programming environment 2025-12-12 02:48:40 +02:00
6a924db68c Kernel: Implement FIONREAD for tty and pty 2025-11-24 18:15:10 +02:00
9d0990e5e8 Kernel: Implement /proc/<n>/fd 2025-11-24 00:19:51 +02:00
3207f5d61f Kernel: Fix possible page fault on file lookup 2025-11-23 19:49:07 +02:00
c72b351bba LibC: Implement glob{,free} 2025-11-23 05:33:44 +02:00
1f9b296ae7 cp: Add -r/--recursive flag 2025-11-23 02:25:05 +02:00
e3e2e7b4df userspace: Implement mv utility 2025-11-23 02:24:52 +02:00
4ec8f4a4bf Kernel/LibC: Implement rename{,at} 2025-11-22 23:55:10 +02:00
05d59a05df Kernel: Remove obsolete kprint
This hasn't been in use in 3 years :)
2025-11-22 06:21:50 +02:00
11ccbe6506 ports/SDL2: Add clipboard support 2025-11-22 01:24:06 +02:00
673711a246 ports/mesa: Require llvm
I dont't really even want to suppot softpipe as that is so slow
2025-11-22 00:40:14 +02:00
fff5139d80 Kernel: Add /proc/<n>/cwd
Also update /proc/<n>/* permissions to match what linux does :D
2025-11-18 05:40:36 +02:00
812e70c626 ports: Add zsh port 2025-11-18 05:40:36 +02:00
db7ffcf9d5 Kernel/Terminal: Add support for bracketed paste mode
This gets rid of annoying warnings when running some programs like bash
2025-11-18 05:40:36 +02:00
8f6cb9c057 Terminal: Add selection and clipboard support
text can now be copied with ctrl+shift+c and pasted with ctrl+shift+v
2025-11-18 05:40:36 +02:00
291f298d19 userspace: Implement LibClipboard and ClipboardServer
programs can now connect to the clipboard server using libclipboard and
get and set the clipboard of the current user
2025-11-18 05:40:36 +02:00
d60f12d3b8 Kernel: Add support for SCM_CREDENTIALS and fix recvmsg
recvmsg was broken when receiving into more than a single iovec
2025-11-18 05:40:36 +02:00
b8a2573bb4 userspace: Implement ImageViewer utility
This supports viewing images and doing basic zooming and panning
2025-11-17 20:58:12 +02:00
7ce8e610f5 stat: Fix handling of symlinks 2025-11-17 05:26:07 +02:00
839b9c8f07 Kernel: Check parent's sticky bit in unlink 2025-11-17 05:26:07 +02:00
db20801521 Shell: Add exec builtin 2025-11-17 05:26:07 +02:00
160a9278c9 LibC: Fix RTLD_* definitions 2025-11-17 05:26:07 +02:00
ee507de154 LibC: Implement posix regex
This is an almost complete implementation, it does not support
alternations or collating elements and it is restricted to the ASCII
character set
2025-11-17 05:26:07 +02:00
dc0fa49de2 ports/tuxracer: Add sound support and fix compiling 2025-11-17 05:26:07 +02:00
b678541427 ports: Add SDL_mixer port 2025-11-17 05:26:07 +02:00
6c4cd0d8cb ports: Add libmikmod port 2025-11-17 05:26:07 +02:00
c096d3cd42 ports/sdl12-compat: Define that banan-os has alloca.h 2025-11-17 05:26:07 +02:00
dcdab4df21 ports/sdl12-compat: Remove unnecessary patch
This is not needed as our SDL2 library is in the expected form
2025-11-17 05:26:07 +02:00
9803209ba1 WindowServer: Make clients nonblock
Also dont allow freezed windows to "steal" focus and lock up the window
server :D
2025-11-17 05:26:07 +02:00
f166cb09ec Kernel: Fail xHCI initialization if page size != 4096
Also zero out scratchapd buffers as the spec says
2025-11-17 05:26:07 +02:00
2dd8b76289 BuildSystem: Automatically delete libtool files
Half of the ports had a manual post_install step to delete libtool files
this is now done automatically and there is no need for it!

Libtool files have to be deleted as libtool doesn't work while
cross-compiling (at least out of the box)
2025-11-17 05:26:07 +02:00
2bf7c67767 LibC: Add backtrace signal handlers for SIG{FPE,ILL,BUS,SEGV}
This allows programs to dump better backtraces on crashes compared to
what kernel can as libc can resolve symbols and libraries' dynamic bases
2025-11-17 05:26:07 +02:00
dd636ffcb2 Kernel: Add support for SA_SIGINFO 2025-11-17 05:26:07 +02:00
a44c45ff9e LibC: Cleanup signal.h
Make sa_handler and sa_sigaction be part of an union

Add definitions of SIGIO TRAP_BRKPT TRAP_TRACE
2025-11-17 05:26:07 +02:00
dc2a455395 Kernel: Optimize processes' memory management
Memory regions are now stored in a sorted array. This allows O(nlogn)
lookup for address validation instead of the old linear lookup.

Now inserting new regions is also O(nlogn) instead of the old constant
time, but lookups are **much** more frequent
2025-11-17 05:26:07 +02:00
c700d9f714 Kernel: Implement connect for UDP socket 2025-11-17 05:26:07 +02:00
59cfc339b0 Kernel: Ignore MSG_NOSIGNAL and invalid flags 2025-11-17 05:26:07 +02:00
e06c07ca89 ports: Update binutils 2.44->2.45
Now we don't have to keep patches for both versions around :D
2025-11-17 05:26:07 +02:00
6facd54a7e LibC: Add ru_maxrss to struct rusage
This is not required by posix but some ports use it
2025-11-17 05:26:07 +02:00
6f8d850726 BuildSystem: Cleanup port building script
All dependencies are now installed only ones. If a port depends on for
examle zlib and one of its other dependencies depends on zlib, zlib will
now get installe only once.

Accept .tgz archives as the main download file
2025-11-17 05:26:07 +02:00
f3beee9874 Kernel: Cleanup userspace pointer validation 2025-11-17 02:33:00 +02:00
35e063bdaf Kernel: Dump r8-r15 on x86_64 exceptions 2025-11-17 02:33:00 +02:00
09175d1799 Kernel: Fix 32 bit target
Rewrite some assembly and add some required casts
2025-11-17 02:33:00 +02:00
46f9a9053f DynamicLoader: Use canonical path for the main executable 2025-11-13 04:20:53 +02:00
bb86520094 Kernel: Set message flags in UDP and TCP recvmsg 2025-11-13 04:20:53 +02:00
c1e2c660bf LibC: Define caddr_t
This is used by some ports
2025-11-13 04:20:53 +02:00
89c0ff1a9d Kernel/LibC: Replace SYS_{GET,SET}_TLS with SYS_{SET,GET}_{FS,GS}BASE
This allows userspace to use both registers
2025-11-13 04:20:53 +02:00
7a68ce7e94 DynamicLoader: Fix testing for possible base address
Replace MAP_FIXED with MAP_FIXED_NOREPLACE and only attempt to map
program headers with PT_LOAD
2025-11-13 04:20:53 +02:00
9537922acc Kernel: Implement proper memory region splitting
Memory regions are now splitted when they get munmapped, mprotected, or
mmapped with MAP_FIXED. This is used by couple of ports, and without
this we were just leaking up memory or straight up crashing programs.
2025-11-13 04:20:53 +02:00
a39aa73e21 Kernel: Allow munmap on non-page aligned address 2025-11-12 00:06:36 +02:00
f1d12c330e Kernel/LibC: Implement MMAP_FIXED_NOREPLACE
This is a handy thing from linux

Also fix MMAP_FIXED validation and error reporting
2025-11-12 00:06:36 +02:00
82c8eeb4be ports/openssh: Update to 10.2p1 and enable fd passing 2025-11-12 00:06:36 +02:00
3a951f4830 LibC: Define IN_LOOPBACKNET
some ports expect this to exist
2025-11-12 00:06:36 +02:00
998ea25fb9 LibC: Add netinet/in_systm.h compatibility header 2025-11-12 00:06:36 +02:00
7b580b8f56 Kernel: Implement fd passing with SCM_RIGTHS 2025-11-12 00:06:36 +02:00
641ccfdd47 LibC: Add BSD compatibility defines S_I{READ,WRITE,EXEC}
These just map to S_I{R,W,X}USR respectively
2025-11-10 01:40:33 +02:00
4288f70d04 LibC: Make poll and epoll macros match with each other
This was an assertion in one of my ports and I couldn't be bothered to
write a patch for it :D
2025-11-10 01:40:33 +02:00
95fda5dfb7 LibC: Add definitions for IPPROTO_ICMPV6 and IP_TOS 2025-11-10 01:40:33 +02:00
1903c5e0c6 Kernel: Use user given address hint in mmap if possible 2025-11-10 01:40:33 +02:00
362501a097 LibC: Make x86_64 crt0 PIE compatible
Instead of pushing addresses of functions directly, use rip relative
addressing
2025-11-10 01:40:33 +02:00
72982e3c2b Kernel/LibC: Take fcntl extra field as uintptr_t
This allows passing pointers to fcntl
2025-11-10 01:40:33 +02:00
04d24bce70 Kernel/LibC: Implement {recv,send}msg as syscalls
This also removes the now old recvfrom and sendto syscalls. These are
now implemented as wrappers around recvmsg and sendmsg.

Also replace unnecessary spinlocks from unix socket with mutexes
2025-11-10 01:40:33 +02:00
2f38306c6b LibC: Implement simple posix_spawn{,p}
This does not support file_actions or attributes
2025-11-10 01:40:33 +02:00
4b36e5197d LibC: Implement execvpe
This is not part of posix but it seems handy
2025-11-09 16:12:29 +02:00
b755cf3e42 LibC: Add sockatmark stub 2025-11-07 14:57:00 +02:00
3acad7c911 LibC: Add ifreq.ifr_{flags,mtu} and fix defines
compatibility defines for ifr_{netmask,gwaddr,hwaddr} were wrong
2025-11-07 14:55:30 +02:00
f3319016c4 LibC: Implement if_{,free}nameindex 2025-11-07 14:54:53 +02:00
4e14f7d483 LibC: Implement {,l,ll}{abs,div} 2025-11-06 23:20:35 +02:00
979059c804 Kernel: Implement ext2 symlinks with >= 60 byte target 2025-11-06 17:21:36 +02:00
bdf4423512 ports/freetype: Add missing dependencies 2025-11-04 23:06:13 +02:00
c6ef4b5840 userspace: Implement kill utility 2025-11-04 19:19:46 +02:00
acd792d8b4 userspace: Implement pwd utility 2025-11-04 18:46:13 +02:00
fc730679ed userspace: Implement uname utility 2025-11-04 18:45:20 +02:00
00e5749e20 ports: Add SuperTux port 2025-11-02 22:47:02 +02:00
7b4d349574 ports: Add glm port 2025-11-02 22:47:02 +02:00
dc0cccfb6c ports: Add physfs port 2025-11-02 22:47:02 +02:00
fdc1daefb6 ports: Add libvorbis port 2025-11-02 22:47:02 +02:00
c9159b81c8 ports: Add libogg port 2025-11-02 22:47:02 +02:00
9233049356 ports: Add openal-soft port 2025-11-02 22:47:02 +02:00
bd9015e474 ports: Add libsndfile port 2025-11-02 22:47:02 +02:00
3a79540d2d ports: Add SDL2_image port 2025-11-02 22:47:02 +02:00
9e500dc387 ports: Add boost port 2025-11-02 22:47:02 +02:00
e05a735589 DynamicLoader: Honour STB_LOCAL binding 2025-11-02 22:47:02 +02:00
0be18c4a53 DynamicLoader: Make everything thread safe
This is kinda dumb implementation, but it works. We grap a global lock
on functions :)
2025-11-02 22:47:02 +02:00
e258fde25a LibC: Implement unnamed semaphores 2025-11-02 21:11:16 +02:00
7367672570 Kernel: Default initialize flock as unlocked
This caused unlocked flock's to hang on lock
2025-11-02 21:10:13 +02:00
b822d42889 LibC: Define ESHUTDOWN
This is not used but some ports expect it to exist
2025-11-02 21:09:48 +02:00
10084ff1bb LibC: Define FIONBIO
This doesn't do anything but some ports expect it to exist
2025-11-02 21:07:26 +02:00
c3c69ac727 LibC: Update _POSIX_* definitions and extern environ
environ is externed by other operating systems so some ports expect it
to be there
2025-10-30 16:49:12 +02:00
0cfda6f6a7 LibC: Add posix_fadvise as no-op 2025-10-30 16:34:03 +02:00
dc51ce9e92 LibC: Implement readdir_r and fix memory leak 2025-10-30 16:33:17 +02:00
aa0de2b00e LibC: Fix stack_t::ss_sp type from void** -> void* 2025-10-30 15:43:25 +02:00
5f61581e1d Kernel: Show QR code with panic logs on kernel panic
This makes debugging on real hardware easier!
2025-10-28 05:50:19 +02:00
f519cb2cc0 Kernel: Expose boot framebuffer device 2025-10-28 05:50:19 +02:00
37aef630d2 BAN: Fix Array and Vector span constness 2025-10-28 05:50:19 +02:00
d93fcff5db userspace: Add LibQR
This library can be used to generate QR codes
2025-10-28 05:50:19 +02:00
4952a82af5 LibImage: Use LibDEFLATE instead of builtin DEFLATE decompressor 2025-10-28 05:50:19 +02:00
fecda6a034 userspace: Add LibDEFLATE
This can be used to compress and decompress DEFLATE data either in raw
or zlib format
2025-10-28 05:50:19 +02:00
9f0addbd8b BAN: Implement simple priority queue
This is just a wrapper around BAN::Vector and heap functions
2025-10-26 00:32:00 +03:00
7f8ea6b8e0 BAN: Move heap functions to Heap.h
This also adds push_heap and pop_heap, similar to what C++ standard
library provides
2025-10-26 00:31:06 +03:00
9d3ea6fed7 BAN: Use new it_value_type_t in sorting functions 2025-10-26 00:30:51 +03:00
703b3eda56 BAN: Add it_value_type_t
This is a template that resolves into T for pointers to T and T::value_type otherwise. It allows using the underlaying type of an iterator or pointer for range based algorithms
2025-10-26 00:22:35 +03:00
84006e1e77 BuildSystem: Don't set symlink mode
Only call chmod if the file is not a symlink. Older versions of chmod
(shipped with ubuntu) don't support the -h flag.
2025-10-02 17:05:20 +03:00
73fb085a41 LibC: Add inet_pton for IPv4 addresses 2025-10-02 16:19:49 +03:00
c89780178f LibC: Add sys/polls.h as wrapper for poll.h
some ports require this
2025-10-02 16:02:07 +03:00
2ac3976924 ports/libiconv: Fix download url
remove /pub/ part of url as mirrors don't seem to accept it
2025-10-02 15:54:55 +03:00
ac9dbd24e4 ports/vim: Fix compilation on new toolchain 2025-09-30 16:15:05 +03:00
3af9830a2e ports/tuxraces: Cleanup cflag passing 2025-09-30 16:14:40 +03:00
da6b8eb2ab BuildSystem: Use ftpmirror.gnu.org for downloads
ftp.gnu.org is really slow :(
2025-09-30 16:13:38 +03:00
da39e98adf Kernel: Make F11 drop disk cache
This can be useful to detect memory leaks or something
2025-08-31 00:36:59 +03:00
791a541381 Kernel: Implement process stopping and continuing 2025-08-31 00:34:52 +03:00
56684e753b Kernel: Fix PS/2 legacy controller detection
This was wrong for devices without FADT or pre revision 3 FADT
2025-08-29 21:07:33 +03:00
c7298edf65 Kernel: Clone executable path on fork
Before this forked processes had empty executables
2025-08-29 01:41:18 +03:00
30215963b2 Kernel: Fix /proc/<pid>/exe permissions 2025-08-29 01:40:56 +03:00
f15f88ebd6 TaskBar: Don't leak fds when reading battery info 2025-08-28 15:57:10 +03:00
391fc0c4c2 Kernel: Don't crash if Ext2 filesystem doing too many fileops
I had a hardlimit of 10 block buffers and if they ran out, the kernel
would crash. this patchs increases the number of buffers to 16 and
removes the crash condition when they run out :D
2025-08-28 15:55:40 +03:00
948ef2c820 Kernel: Fix race condition when destroying threads 2025-08-28 15:55:40 +03:00
c1b6b6b76a Kernel: Fix string validation in unlink syscall 2025-08-28 15:55:40 +03:00
a8bb07052e Kernel: Rewrite SMP message code
Remove locks and map smp buffer as uncached
2025-08-28 15:55:40 +03:00
6976a2dae7 Kernel: Add hardlink support to USTAR
Also handle file types L and K for long file names and link names
2025-08-28 15:55:40 +03:00
51cd951b4c Kernel: Add hardlink support to tmpfs 2025-08-28 15:55:40 +03:00
16a5a234c1 Kernel: Cleanup hardlink creation 2025-08-28 15:55:40 +03:00
f994210927 LibC: Fix sigsetjmp (again)
I was using a wrong register for signal mask storage...
2025-08-28 15:55:40 +03:00
aaa8760d09 Kernel: Don't wait for ps2 timeout when flushing buffer
This speeds up boot time by a second :dd:
2025-08-28 15:55:40 +03:00
cea19ecc31 Kernel: Fix possible crash during exec 2025-08-28 15:55:40 +03:00
706cfeb443 Kernel: Allow file backed mapping be larger than inode size
This is only allowed if the mapping does **not** exceed a page boundary.
Some port was doing an exactly two-page-mapping on a file that was one
and a half page long
2025-08-28 15:55:40 +03:00
d9c91589f0 Kernel: Don't limit /tmp max size 2025-08-28 15:55:40 +03:00
9854691265 LibC: Don't leak fds on rename 2025-08-28 15:55:40 +03:00
32afa33a06 LibC: Make sure FILE's buffer does not get overflown 2025-08-28 15:55:40 +03:00
c6946d0145 LibC: Use pthread_mutex on FILE instead of atomics 2025-08-28 15:55:40 +03:00
abbe7b79d6 Kernel: Add /proc/<pid>/exe 2025-08-28 15:55:40 +03:00
e4abe75043 Kernel: Add /proc/self 2025-08-28 15:55:40 +03:00
b904503691 ports: Update GCC 15.1.0->15.2.0 2025-08-28 15:55:40 +03:00
2db42dfb2e BuildSystem: Don't download config.sub every hour
There isn't really any need to :D
2025-08-25 22:16:23 +03:00
10bd24e585 Kernel: Fix signal delivery without an alternate stack
I had only tested that sigaltstack worked, so I didn't notice my normal
signals broke :D
2025-08-25 22:16:23 +03:00
f926e599fa Kernel: Zero initialize Processors
This moves processor array to .bss reducing data size by 8192 bytes :)

This needed GCC updated to 15.2.0 because of an internal compiler error
I found :)
2025-08-25 18:29:14 +03:00
e7b518ba67 BuildSystem: binutils 2.44->2.45, gcc 15.1.0->15.2.0 2025-08-25 18:25:36 +03:00
a4698f0bde Kernel: Fix IOAPIC max redirection entry fetching
Also max redirection entry is an index, not count so comparisons should
check for equality :)
2025-08-25 17:15:55 +03:00
9a6eae69ba Kernel: Replace all occurances of BSB with BSP 2025-08-25 17:11:32 +03:00
0ff365c7f0 ports: Add qemu port 2025-08-21 03:11:16 +03:00
214e7a5672 ports: Add glib port 2025-08-21 03:11:16 +03:00
24b69a6dea ports: Add libffi port 2025-08-21 03:11:16 +03:00
699235147c ports: Add pcre2 port 2025-08-21 03:11:16 +03:00
72ad413a61 ports/SDL2: Handle window focus events 2025-08-21 03:11:16 +03:00
f11bb082e4 WindowServer/LibGUI: Add window focus events 2025-08-21 03:11:16 +03:00
2f3fd6867d Kernel: Add VERY HACKY MAP_FIXED fix
This definitely will break stuff but I don't think anything depends on
this (except maybe dynamic loader)

This WILL get fixed soon (I hope :D)
2025-08-21 03:11:16 +03:00
350ae90bb6 Kernel: Make all futexes shared
Some stuff tries to use shared futexes so make them all shared. Private
futexes would be faster as they are process specific but supporting both
would need some reworks
2025-08-21 02:56:17 +03:00
fb61cab70d LibC: Rewrite pthread_mutex using a futex 2025-08-21 02:52:49 +03:00
1d6c08478d LibC: Fix sigsetjmp
the call from C sigsetjmp messed up rbp, now sigsetjmp is also written
in assembly.

I did not test the 32 bit code, just ported the tested 64 bit version
over :D
2025-08-21 02:52:49 +03:00
0dfe0b7023 Kernel/LibC: Implement sigaltstack 2025-08-21 02:52:49 +03:00
def236b7cd Kernel/LibC: Implement sigwait 2025-08-20 20:16:19 +03:00
247743ef9c Kernel/LibC: Implement sigsuspend 2025-08-20 20:14:54 +03:00
49122cf729 Kernel: Allow adding signals to thread that are blocked 2025-08-20 18:35:18 +03:00
84f579be81 ports: Add nano port 2025-08-19 17:00:14 +03:00
3d5f23a1b2 LibC: Implement wctomb 2025-08-19 16:44:18 +03:00
8b26b6604d LibC: Make mbstate_t into int
This is not used, but makes more sense than an empty struct
2025-08-19 16:29:46 +03:00
f88e55ffa8 ports: Add nyancat port 2025-08-19 16:23:30 +03:00
34bdcb12e5 Kernel: Fix termios and enter key handling
Enter key now produces expected \r which gets converted to \n by default
by the ICRNL input flag.

Also input flags are now handled always, not just when ICANON is set.
I don't know why I though ICANON should disable input handling
2025-08-19 16:23:30 +03:00
95b353dae5 LibInput: Fix numpad keycode generation
I had made this function with broken PS/2 scancode set 3, so it seemed
like it worked
2025-08-19 16:23:30 +03:00
6560f229b1 Kernel: Fix PS/2 scancode set 3 numpad keys 2025-08-19 16:23:30 +03:00
8c9ab2d68c WindowServer: Fix crash when window closes while being "button window" 2025-08-19 16:23:30 +03:00
8496726ab1 Terminal: Ignore some control characters 2025-08-19 16:23:30 +03:00
32d7f429f8 Kernel: Fix default ignored signals
SIGWINCH and SIGCANCEL ended up interrupting functions even when they
were marked as SIG_DFL. Now resizing the userspace terminal emulator
does not get interrupted!
2025-08-19 16:23:30 +03:00
0f52f49188 Terminal: Remove unused code 2025-08-19 16:23:30 +03:00
b334259a07 AudioServer: Don't allow client to fully halt audio 2025-08-19 16:23:30 +03:00
74af4e9150 ports/SDL2_mixer: Add MIDI support 2025-08-19 16:23:30 +03:00
8b7790ded2 Kernel: Fix userspace pointer checks
Some syscalls were unconditionally validating optional paramenters which
were allowed to be null pointers
2025-08-19 16:23:30 +03:00
3e97a82af0 Kernel: Allow getgroups with size
This can be used to query the number of groups
2025-08-19 16:23:30 +03:00
0066b20413 Kernel: Fix spinlock leaks with unix sockets 2025-08-19 16:23:30 +03:00
9d6656451a LibC: Make time_t signed integer
Some port like python3 assumes this is the case
2025-08-19 16:23:30 +03:00
32f980e259 Kernel: Fix ACPI namespace lookup for multi segment names 2025-08-19 16:23:30 +03:00
ca9361abc1 DynamicLoader: Add support for dladdr 2025-08-19 16:23:30 +03:00
36cb3d56fe LibC: Define Dl_info_t and add stub for dladdr 2025-08-19 16:23:30 +03:00
0bece8a54c Kernel: Add missing ACPI resource header 2025-08-19 16:23:30 +03:00
70bbdbd8f5 LibC: Cleanup syslog output
add ": " after the identification and formatted output. syslog does not
require trailing newline so add it in case it is missing.
2025-08-16 22:56:03 +03:00
df8365f0c7 ports/openssh: Configure with --disable-fd-passing
I though this wasn't needed because of my patch, but I didn't actually
test the code
2025-08-16 22:55:53 +03:00
974aae2ebe ports: Add openssh port 2025-08-16 22:32:37 +03:00
ceca93c8b1 LibC: Cleanup memmove and memcpy for x86_64 2025-08-16 14:05:21 +03:00
b6793cc6f2 Kernel: Add AML ConcatResOp 2025-08-15 18:54:17 +03:00
809d07546a Kernel: Remove minimum timeout of 100 ms from epoll
This is not actually needed and was just temporary code to make sure i
notified the epoll everywhere
2025-08-15 18:28:11 +03:00
804cbeb1a7 Kernel: Increment kmalloc storage size to 64 MiB
I really don't want to do this, but rewriting kmalloc to be dynamic
would require me to rewrite 32 bit paging and I really don't want to.
2025-08-15 17:02:15 +03:00
c07188a60e Kernel: Look for PS/2 devices in the ACPI namespace
This allows finding the PS/2 controller on newer machines that don't
have the 8042 bit set in FADT.
2025-08-15 17:02:15 +03:00
3804d4332b Kernel: Make _SEG, _BBN and _ADR lookup absolute 2025-08-15 17:02:15 +03:00
064aaef6c3 Kernel: Don't fail on creating reserved opregion 2025-08-15 17:02:15 +03:00
ce262a5d2d Kernel: Allow ReturnOp in global scope 2025-08-15 17:02:15 +03:00
d128f4d70b Kernel: Fix AML CreateField debug print 2025-08-15 17:02:15 +03:00
46d1ada708 Kernel: Allow AML package->package conversion 2025-08-15 17:02:15 +03:00
2819e5f647 Kernel: Make _STA and _INI lookup absolute 2025-08-15 17:02:15 +03:00
c2017a5181 Kernel: Allow looking up devices with multiple eisa ids
Also match against _CIDs in addition to _HID
2025-08-15 17:02:15 +03:00
58ad839136 Kernel: Add support for ACPI Embedded Controllers 2025-08-15 17:02:15 +03:00
8ed5a71c45 Kernel: Register IDT handlers from a vector
This drops code size by a lot :D
2025-08-13 18:27:46 +03:00
57050a83ba ports/timidity: Fix compilation
Precalculating newton coefficients does not work as the buildsystem
tries to run a banan-os binary. This patch enables coefficient
calculation code for the runtime!
2025-08-13 12:20:21 +03:00
6ed0e84421 LibC: Fix mktime argument updating 2025-08-11 19:00:23 +03:00
9b09d2b47a LibC: Update struct tm to be POSIX issue 8 compliant 2025-08-11 18:59:20 +03:00
1a6c5deb4b LibC: Add {AF,PF}_LOCAL as aliases to {AF,PF}_UNIX 2025-08-11 18:48:24 +03:00
45a73b00de LibC: Make glob_t a typedef 2025-08-11 18:47:55 +03:00
59fff26a5f LibC: Remove our iconv.h header and add libiconv port
If I ever end up writing my own iconv, i will drop the port :D
2025-08-11 18:46:15 +03:00
fde4d4662e LibC: Implement getopt_long{,_only}
Few ports attempt to use this so lets add them :D
2025-08-11 18:36:46 +03:00
c9355ad94a BuildSystem: Fix file permission bits on image creation
If a file had setuid/setgid/sticky bits set, they were not copied to the
sysroot
2025-08-11 14:48:57 +03:00
bad3b8b3e2 ports/binutils: Fix compilation when zstd is installed
binutils uses pkg-config to find zstd for the host when building. If our
zstd port is installed, it finds it instead and ends up including our
own sysroot which is incompatible with host's.

unsetting pkg-config related variables fixes this and allows binutils to
build fine even when zstd is installed. We can now make it a dependency.
2025-08-11 14:07:37 +03:00
0b81bb9b10 ports/quake2: Use SDL2 instead of our own frontend 2025-08-11 14:07:37 +03:00
f61c78efd5 ports/tinygb: Use SDL2 instead of our own frontend 2025-08-11 14:07:37 +03:00
6b2307ab22 ports/doom: Use SDL2 instead of our own frontend
This allows doom to play sounds!
2025-08-11 14:07:37 +03:00
9ccb381c31 ports: Add SDL2_mixer port
This allows some ports to use audio :D

I did not port any audio libraries so loading sounds probably doesn't
work :D
2025-08-11 14:07:37 +03:00
71133236f8 ports: Add timidity port 2025-08-11 14:07:37 +03:00
e5786fe435 init: Start AudioServer on boot 2025-08-11 14:07:37 +03:00
ef6ee78fd1 Kernel/LibC: Implement chroot 2025-08-11 14:07:37 +03:00
695262624d Kernel: Fix potential UB in AML OpRegion initialization 2025-08-11 03:45:38 +03:00
c96c264801 LibC: Implement fnmatch 2025-08-10 19:57:31 +03:00
af0bca74e4 Kernel/LibC: Implement {get,set,init}groups
This allows dropping /etc/group parsing from the kernel :D
2025-08-10 19:57:31 +03:00
f41e254e35 Kernel: Fix dead lock on process exit 2025-08-10 19:57:31 +03:00
7e472a9c1d Kernel: Fix USB FS device default max packet size
Apparently this is a common non spec compliant issue on many
controllers/devices.

thanks @sasdallas
2025-08-10 19:57:31 +03:00
ee3f10313a BuildSystem: Flip USB_ARGS and DISK_ARGS in qemu.sh
This allows attaching usb disk :D
2025-08-10 19:57:31 +03:00
5b587d199e Kernel/LibC: Implement FIONREAD for tcp and udp sockets 2025-08-10 19:57:31 +03:00
009b073892 LibC: Add IN6_IS_ADDR_* and IN_MULTICAST macros
These are assumed to exist by some ports
2025-08-10 19:57:31 +03:00
92e962430b LibC: Make sockaddr and sockaddr_in compatible with other systems
sockaddr:
make sa_data is 14 bytes on all systems

sockaddr_in:
add sin_zero
2025-08-10 19:57:31 +03:00
3aa20a3a32 Kernel: Fix ACPI _GPE calling
This adds patch adds support for extended GPEs and the second GPE
register block.
2025-08-07 19:35:13 +03:00
de7c3d3d29 Kernel: Don't try to create . in USTAR
Our build system adds . entry to the tar archive and it should be
handled as an no-op
2025-08-07 19:35:13 +03:00
3f89df338e IDT: Remove stack OOB check
This makes debugging easier when you can see the actual register values
and what is mapped and where
2025-08-07 19:35:13 +03:00
c7f89c9b77 ports: Update SDL2 2.30.11 -> 2.32.8 2025-08-07 16:43:05 +03:00
a107e463e8 ports/SDL2: Add audio support 2025-08-07 16:43:05 +03:00
7a5cfe1728 LibAudio/AudioServer: Add support for playing real time audio 2025-08-07 16:43:05 +03:00
7ad3f967db Kernel: Don't stop audio processing after each entry in AC97 2025-08-07 16:43:05 +03:00
d1c814cf9d Kernel: Optimize consecutive absolute mouse move events
This is a hack to make window server usable without kvm :D
2025-08-07 16:43:05 +03:00
72f85dce2b Kernel: Make userspace stack on-demand allocated
Also bump the hardlimit of stack size from 512 KiB->32 MiB. This still
feels quite low but is much better than before :D
2025-08-07 16:43:05 +03:00
f5bbcc017c Kernel: Only send one smp message when reserving a range
This was causing some kernel panic because processors ran out of smp
message storage when reserving large areas.

Also most of the time there is no need to actually send the SMP message.
If process is mapping something to just its own address space, there is
no need for a TLB shootdown. Maybe this should be only limited to kernel
memory and threads across the same process. I'm not sure what the best
approach here and it is better to send too many invalidations that too
few!
2025-08-07 16:43:05 +03:00
2980173c8e ports: Fix config.sub downloading 2025-08-07 16:28:09 +03:00
a84c348045 LibC: Add shm_{open,unlink} stubs
These are needed for our llvm port
2025-08-07 16:28:09 +03:00
d845ecc811 LibC: Add wcstok, wcstol and swprintf stubs
These are needed for our python3 port
2025-08-07 16:28:09 +03:00
064d9009a2 LibC: Add clock_getres stub
This is needed for our python3 port
2025-08-07 02:50:24 +03:00
b6aa5bdfab LibC: Implement if_indextoname and if_nametoindex
These are needed for our cmake port
2025-08-07 02:50:24 +03:00
a3bdf0456e LibC: Add getpriority stub
This is needed for our cmake port
2025-08-07 02:50:24 +03:00
e3ecf05866 LibC: Add stubs for {get,free}ifaddrs
These are needed for our libuv port
2025-08-07 02:50:24 +03:00
6240374dd1 LibC: Add semaphore stubs
These are needed for our bochs port
2025-08-07 02:50:24 +03:00
e17ee831a7 LibC: Add times stub
This is needed for our openssl port
2025-08-07 02:50:24 +03:00
aef9bd6357 LibC: Add mk{nod,fifo}{,at} stubs
These are needed for our tcl port
2025-08-07 02:50:24 +03:00
8857227a35 LibC: Add getservbyname stub
This is needed by our tcl port
2025-08-07 02:50:24 +03:00
937250c681 userspace: Add dummy libdl
This allows ports to link against without needing to patch it out
2025-08-07 02:50:24 +03:00
66d3a1d025 ls: Output in columns 2025-08-07 02:50:24 +03:00
647fedfa19 Kernel: Add missing multiboot.h 2025-08-05 17:12:26 +03:00
c593d3ed75 LibC: Add missing libintl.h 2025-08-05 17:10:43 +03:00
bd885a01e5 ports/expat: Remove libtool file 2025-08-05 03:47:52 +03:00
628825fdff ports: Don't set CMAKE_TOOLCHAIN_FILE environment variable
This doesn't allow llvm to build native tablegen
2025-08-05 03:47:16 +03:00
46dd411273 LibC: fflush stdout when reading from stdin
This is the *intended behaviour* per ISO C specification
2025-08-05 03:32:59 +03:00
2e2ee11452 LibC: Add more reasonable values to stack size constants 2025-08-05 03:32:59 +03:00
ce0df333b3 LibC: Make sa_data in sock_addr zero sized 2025-08-05 03:32:59 +03:00
8bbda78272 ports/xash3d-fwgs: Don't disable opengl and patch output
Manually link against libxash.so. My current dlopen does not support
loading ELF files that contain TLS
2025-08-05 03:32:59 +03:00
945509fc93 ports/mesa: Use llvm pipe instead of softpipe if llvm is compiled 2025-08-05 03:32:59 +03:00
b586917930 ports: Add llvm port
This can be compiled before mesa to make mesa use llvmpipe instead of
softpipe. llvmpipe is at least 10x faster :D
2025-08-05 03:09:24 +03:00
45ad6082bc DynamicLoader: Support dlopen(NULL, ...) 2025-08-05 03:09:24 +03:00
f27823babe Kernel: Move stacks to the top of userspace address space 2025-08-05 03:09:24 +03:00
95cfac471a Kernel: Rename loopback adapter lo0 -> lo 2025-08-05 03:09:24 +03:00
f7c1084c3e Kernel: Expose boot command line in /proc/cmdline 2025-08-05 03:09:24 +03:00
cf96bb6cc3 Kernel: Add support for multiboot
I don't know why I did it but it works now :D
2025-08-05 03:09:24 +03:00
f1369c8fd6 Kernel/LibC: Implement mprotect
There may be some race conditions with this but i think this is good
enough to start with
2025-08-05 03:09:24 +03:00
eb7922ab88 LibC: Implement pthread_cond_* using a futex 2025-08-05 03:09:24 +03:00
dfdfb7cdaf Kernel: check all threads in validate_pointer_access 2025-08-05 03:09:24 +03:00
1cc0fb9c01 Kernel: Reschedule if idle after IPI
This allows starting thread execution right after thread is received
from load balancing
2025-08-05 03:09:24 +03:00
a51b589bc9 Kernel: Allow any signal flags and support SA_RESETHAND 2025-08-05 03:09:24 +03:00
5940e912b3 Kernel/LibC: Implement simple futex 2025-08-05 03:09:24 +03:00
658a001d91 LibC: Make pthread_barrier safe
It used to deadlock and it was not safe if more threads than the target
were attempting to wait on it.
2025-08-05 03:09:24 +03:00
57c9f5a8a8 LibC: lock mutex when pthread_cond_timedwait times out 2025-08-05 03:09:24 +03:00
fa7b58057c LibC: Add MAP_ANON as synonym for MAP_ANONYMOUS
This is part of POSIX issue 8 and some things only check MAP_ANON
2025-08-05 03:09:24 +03:00
0e0f5295cf LibC: Make {,__cxa_}atexit thread safe 2025-08-05 03:09:24 +03:00
284c9e5f61 Kernel: Don't kill process if stack pointer is OOB
This can be valid if process is using green threads or for some other
reason using its own stack
2025-08-05 03:09:24 +03:00
927fbda1e8 Kernel: Make on-demand paging thread safe 2025-08-05 03:09:24 +03:00
d25a5034db LibC: Update thread id on fork 2025-08-05 03:09:24 +03:00
f197d39aaf LibC: Don't allow pthread_join to return EINTR 2025-08-05 03:09:24 +03:00
4a95343936 LibC: Make _get_uthread a macro
This allows nice inlining :)
2025-08-05 03:09:24 +03:00
4e705a91af LibC: Fix pthread keys
I had misunderstood how these are supposed to work :D
2025-08-05 03:09:24 +03:00
82b351469b DynamicLoader: Setup thread id when initializing TLS
This allows pre-libc code use pthread functions

(__cxa_guard_release calls pthread_cond_broadcast)
2025-08-05 03:09:24 +03:00
ea91bdcce7 WindowServer: Make relative mouse no-op with absolute mouse 2025-08-05 03:09:24 +03:00
256c9daefd ports/SDL2: Optimize rendering and fix cursor
Remove the unnecessary framebuffer layer, we can just use the window's
own framebuffer.

Set default cursor on mouse initialization, this fixes cursor hiding in
tuxracer

defined SetRelativeMouseMode instead of SetMouseCapture. This is what
the behaviour was :D
2025-08-05 03:09:24 +03:00
af0a46e79c LibGUI/WindowServer: Rename mouse capture -> mouse relative
My terminology was incorrect and this is more correct
2025-08-05 03:09:24 +03:00
4519c48284 WindowServer: Fix custom cursors
Custom cursor is now only set if the cursor is in the client area
instead of anyehere in the window. This makes hidden cursor visible
when it is on top of the title bar!
2025-08-05 03:09:24 +03:00
8ea32c7650 WindowServer: Fix relative mouse vertical flip 2025-08-05 03:09:24 +03:00
5972d40ced ports: Update zstd 1.5.6 -> 1.5.7
Also build using cmake because we can :)
2025-08-05 03:09:24 +03:00
f35a6b3922 BuildSystem: Fix meson toolchain file
sed to replace SYSROOT did not work because paths contain /

also add cmake to allow cmake based library detection
2025-08-05 03:09:24 +03:00
21009c37b4 BuildSystem: Remove unnecessary variables from cmake toolchain 2025-08-05 03:09:24 +03:00
11a2d15003 BuildSystem: Optimize disk image creation
disk image is now created with rsync so there is no need for copying the
whole sysroot twice.
2025-08-05 03:09:24 +03:00
d8a695a88d Kernel: Don't fail ustar unpack when creation fails 2025-08-05 03:09:24 +03:00
f82390424b ports: Add cmake port 2025-08-05 03:09:24 +03:00
08ed405a5b ports: Add libuv port 2025-08-05 03:09:24 +03:00
8c598a6902 LibC: Include stdint.h instead of inttypes.h in network headers 2025-08-05 03:09:24 +03:00
8e9c40caa4 LibC: Pump OPEN_MAX to 128
cmake seems to use around 70 when checking compiler. That seems quite a
lot but could be "normal"
2025-07-31 22:47:40 +03:00
8c29036fbf Kernel: Fix EAGAIN on hungup pipe 2025-07-31 22:47:40 +03:00
b46337d376 BuildSystem: Add banan-os cmake platform 2025-07-31 22:47:40 +03:00
56d701492b ports/ncurses: Add c++ bindings 2025-07-31 22:47:40 +03:00
07e4e764a0 LibC: Implement mbtowc 2025-07-31 22:47:40 +03:00
66fe2f2e50 LibC: Fix readv and writev 2025-07-31 22:47:40 +03:00
fda0ced72e LibC: Implement getpw{nam,uid}_r 2025-07-31 22:47:40 +03:00
654e8bb7f6 LibC: Implement getgr{gid,nam}_r 2025-07-31 22:47:40 +03:00
80ffde5e1e LibC: Implement aligned_malloc
This is part of POSIX issue 8
2025-07-31 22:47:40 +03:00
52309e0754 LibC: Add in6addr_{any,loopback} definitions 2025-07-31 22:47:40 +03:00
31e411f8f1 LibC: Implement recvmsg and sendmsg
These just wrap recvfrom and sendto so ancillary data is not supported
2025-07-31 22:47:40 +03:00
de45b760b5 LibC: Implement alphasort and scandir 2025-07-31 22:47:40 +03:00
ff29e9c4d6 LibC: Implement {,f}pathconf
This just return minimum values specified by posix
2025-07-31 22:47:40 +03:00
cc04bd0f06 LibC/Kernel: Implement ttyname_r 2025-07-31 22:47:40 +03:00
e72e1e4e43 LibC: Add _SC_NPROCESSORS_{CONF,ONLN) 2025-07-31 22:47:40 +03:00
987cc3c237 3000th COMMIT: ports: Add halflife port 2025-07-31 22:47:34 +03:00
935f69e011 ports: Add freetype port 2025-07-31 22:47:29 +03:00
9f0c2fb6e2 ports: Apply only patches ending in .patch 2025-07-31 22:47:29 +03:00
9b18bda9c8 Kernel: Make epoll always check for HUP and ERR 2025-07-31 22:47:29 +03:00
7831c74e8c DynamicLoader: Add support for LD_LIBRARY_PATH
Also fix a bug with dlopen with TLS
2025-07-31 22:47:29 +03:00
620 changed files with 33143 additions and 8747 deletions

1
.gitignore vendored
View File

@@ -3,3 +3,4 @@
build/ build/
base/ base/
script/fakeroot-context script/fakeroot-context
tools/update-image-perms

View File

@@ -35,7 +35,7 @@ namespace BAN
constexpr T& front(); constexpr T& front();
Span<T> span() { return Span(m_data, size()); } Span<T> span() { return Span(m_data, size()); }
const Span<T> span() const { return Span(m_data, size()); } Span<const T> span() const { return Span(m_data, size()); }
constexpr size_type size() const; constexpr size_type size() const;

View File

@@ -9,29 +9,35 @@
#include <BAN/Formatter.h> #include <BAN/Formatter.h>
#include <stdio.h> #include <stdio.h>
#define __debug_putchar [](int c) { putc(c, stddbg); } #define __debug_putchar [](int c) { putc_unlocked(c, stddbg); }
#define dprintln(...) \ #define dprintln(...) \
do { \ do { \
flockfile(stddbg); \
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \ BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
BAN::Formatter::print(__debug_putchar,"\n"); \ BAN::Formatter::print(__debug_putchar,"\n"); \
fflush(stddbg); \ fflush(stddbg); \
funlockfile(stddbg); \
} while (false) } while (false)
#define dwarnln(...) \ #define dwarnln(...) \
do { \ do { \
flockfile(stddbg); \
BAN::Formatter::print(__debug_putchar, "\e[33m"); \ BAN::Formatter::print(__debug_putchar, "\e[33m"); \
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \ BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
BAN::Formatter::print(__debug_putchar, "\e[m\n"); \ BAN::Formatter::print(__debug_putchar, "\e[m\n"); \
fflush(stddbg); \ fflush(stddbg); \
funlockfile(stddbg); \
} while(false) } while(false)
#define derrorln(...) \ #define derrorln(...) \
do { \ do { \
flockfile(stddbg); \
BAN::Formatter::print(__debug_putchar, "\e[31m"); \ BAN::Formatter::print(__debug_putchar, "\e[31m"); \
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \ BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
BAN::Formatter::print(__debug_putchar, "\e[m\n"); \ BAN::Formatter::print(__debug_putchar, "\e[m\n"); \
fflush(stddbg); \ fflush(stddbg); \
funlockfile(stddbg); \
} while(false) } while(false)
#define dprintln_if(cond, ...) \ #define dprintln_if(cond, ...) \

89
BAN/include/BAN/Heap.h Normal file
View File

@@ -0,0 +1,89 @@
#pragma once
#include <BAN/Iterators.h>
#include <BAN/Swap.h>
#include <BAN/Traits.h>
namespace BAN
{
namespace detail
{
template<typename It, typename Comp>
void heapify_up(It begin, size_t index, Comp comp)
{
size_t parent = (index - 1) / 2;
while (parent < index)
{
if (comp(*(begin + index), *(begin + parent)))
break;
swap(*(begin + parent), *(begin + index));
index = parent;
parent = (index - 1) / 2;
}
}
template<typename It, typename Comp>
void heapify_down(It begin, size_t index, size_t len, Comp comp)
{
for (;;)
{
const size_t lchild = 2 * index + 1;
const size_t rchild = 2 * index + 2;
size_t child = 0;
if (lchild < len && !comp(*(begin + lchild), *(begin + index)))
{
if (rchild < len && !comp(*(begin + rchild), *(begin + lchild)))
child = rchild;
else
child = lchild;
}
else if (rchild < len && !comp(*(begin + rchild), *(begin + index)))
child = rchild;
else
break;
swap(*(begin + child), *(begin + index));
index = child;
}
}
}
template<typename It, typename Comp = less<it_value_type_t<It>>>
void make_heap(It begin, It end, Comp comp = {})
{
const size_t len = distance(begin, end);
if (len <= 1)
return;
size_t index = (len - 2) / 2;
while (index < len)
detail::heapify_down(begin, index--, len, comp);
}
template<typename It, typename Comp = less<it_value_type_t<It>>>
void push_heap(It begin, It end, Comp comp = {})
{
const size_t len = distance(begin, end);
detail::heapify_up(begin, len - 1, comp);
}
template<typename It, typename Comp = less<it_value_type_t<It>>>
void pop_heap(It begin, It end, Comp comp = {})
{
const size_t len = distance(begin, end);
swap(*begin, *(begin + len - 1));
detail::heapify_down(begin, 0, len - 1, comp);
}
template<typename It, typename Comp = less<it_value_type_t<It>>>
void sort_heap(It begin, It end, Comp comp = {})
{
while (begin != end)
pop_heap(begin, end--, comp);
}
}

View File

@@ -9,6 +9,10 @@ namespace BAN
struct IPv4Address struct IPv4Address
{ {
constexpr IPv4Address()
: IPv4Address(0)
{ }
constexpr IPv4Address(uint32_t u32_address) constexpr IPv4Address(uint32_t u32_address)
{ {
raw = u32_address; raw = u32_address;

View File

@@ -0,0 +1,46 @@
#pragma once
#define _ban_count_args_impl(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, ...) _9
#define _ban_count_args(...) _ban_count_args_impl(__VA_ARGS__ __VA_OPT__(,) 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define _ban_concat_impl(a, b) a##b
#define _ban_concat(a, b) _ban_concat_impl(a, b)
#define _ban_stringify_impl(x) #x
#define _ban_stringify(x) _ban_stringify_impl(x)
#define _ban_fe_0(f)
#define _ban_fe_1(f, _0) f(0, _0)
#define _ban_fe_2(f, _0, _1) f(0, _0) f(1, _1)
#define _ban_fe_3(f, _0, _1, _2) f(0, _0) f(1, _1) f(2, _2)
#define _ban_fe_4(f, _0, _1, _2, _3) f(0, _0) f(1, _1) f(2, _2) f(3, _3)
#define _ban_fe_5(f, _0, _1, _2, _3, _4) f(0, _0) f(1, _1) f(2, _2) f(3, _3) f(4, _4)
#define _ban_fe_6(f, _0, _1, _2, _3, _4, _5) f(0, _0) f(1, _1) f(2, _2) f(3, _3) f(4, _4) f(5, _5)
#define _ban_fe_7(f, _0, _1, _2, _3, _4, _5, _6) f(0, _0) f(1, _1) f(2, _2) f(3, _3) f(4, _4) f(5, _5) f(6, _6)
#define _ban_fe_8(f, _0, _1, _2, _3, _4, _5, _6, _7) f(0, _0) f(1, _1) f(2, _2) f(3, _3) f(4, _4) f(5, _5) f(6, _6) f(7, _7)
#define _ban_fe_9(f, _0, _1, _2, _3, _4, _5, _6, _7, _8) f(0, _0) f(1, _1) f(2, _2) f(3, _3) f(4, _4) f(5, _5) f(6, _6) f(7, _7) f(8, _8)
#define _ban_for_each(f, ...) _ban_concat(_ban_fe_, _ban_count_args(__VA_ARGS__))(f __VA_OPT__(,) __VA_ARGS__)
#define _ban_fe_comma_0(f)
#define _ban_fe_comma_1(f, _0) f(0, _0)
#define _ban_fe_comma_2(f, _0, _1) f(0, _0), f(1, _1)
#define _ban_fe_comma_3(f, _0, _1, _2) f(0, _0), f(1, _1), f(2, _2)
#define _ban_fe_comma_4(f, _0, _1, _2, _3) f(0, _0), f(1, _1), f(2, _2), f(3, _3)
#define _ban_fe_comma_5(f, _0, _1, _2, _3, _4) f(0, _0), f(1, _1), f(2, _2), f(3, _3), f(4, _4)
#define _ban_fe_comma_6(f, _0, _1, _2, _3, _4, _5) f(0, _0), f(1, _1), f(2, _2), f(3, _3), f(4, _4), f(5, _5)
#define _ban_fe_comma_7(f, _0, _1, _2, _3, _4, _5, _6) f(0, _0), f(1, _1), f(2, _2), f(3, _3), f(4, _4), f(5, _5), f(6, _6)
#define _ban_fe_comma_8(f, _0, _1, _2, _3, _4, _5, _6, _7) f(0, _0), f(1, _1), f(2, _2), f(3, _3), f(4, _4), f(5, _5), f(6, _6), f(7, _7)
#define _ban_fe_comma_9(f, _0, _1, _2, _3, _4, _5, _6, _7, _8) f(0, _0), f(1, _1), f(2, _2), f(3, _3), f(4, _4), f(5, _5), f(6, _6), f(7, _7), f(8, _8)
#define _ban_for_each_comma(f, ...) _ban_concat(_ban_fe_comma_, _ban_count_args(__VA_ARGS__))(f __VA_OPT__(,) __VA_ARGS__)
#define _ban_get_0(a0, ...) a0
#define _ban_get_1(a0, a1, ...) a1
#define _ban_get_2(a0, a1, a2, ...) a2
#define _ban_get_3(a0, a1, a2, a3, ...) a3
#define _ban_get_4(a0, a1, a2, a3, a4, ...) a4
#define _ban_get_5(a0, a1, a2, a3, a4, a5, ...) a5
#define _ban_get_6(a0, a1, a2, a3, a4, a5, a6, ...) a6
#define _ban_get_7(a0, a1, a2, a3, a4, a5, a6, a7, ...) a7
#define _ban_get_8(a0, a1, a2, a3, a4, a5, a6, a7, a8, ...) a8
#define _ban_get_9(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, ...) a9
#define _ban_get(n, ...) _ban_concat(_ban_get_, n)(__VA_ARGS__)

View File

@@ -36,12 +36,11 @@ namespace BAN::Math
template<integral T> template<integral T>
inline constexpr T gcd(T a, T b) inline constexpr T gcd(T a, T b)
{ {
T t;
while (b) while (b)
{ {
t = b; T temp = b;
b = a % b; b = a % b;
a = t; a = temp;
} }
return a; return a;
} }
@@ -66,25 +65,20 @@ namespace BAN::Math
return (x & (x - 1)) == 0; return (x & (x - 1)) == 0;
} }
template<BAN::integral T> template<integral T>
static constexpr bool will_multiplication_overflow(T a, T b) __attribute__((always_inline))
inline constexpr bool will_multiplication_overflow(T a, T b)
{ {
if (a == 0 || b == 0) T dummy;
return false; return __builtin_mul_overflow(a, b, &dummy);
if ((a > 0) == (b > 0))
return a > BAN::numeric_limits<T>::max() / b;
else
return a < BAN::numeric_limits<T>::min() / b;
} }
template<BAN::integral T> template<integral T>
static constexpr bool will_addition_overflow(T a, T b) __attribute__((always_inline))
inline constexpr bool will_addition_overflow(T a, T b)
{ {
if (a > 0 && b > 0) T dummy;
return a > BAN::numeric_limits<T>::max() - b; return __builtin_add_overflow(a, b, &dummy);
if (a < 0 && b < 0)
return a < BAN::numeric_limits<T>::min() - b;
return false;
} }
template<typename T> template<typename T>
@@ -98,6 +92,19 @@ namespace BAN::Math
return sizeof(T) * 8 - __builtin_clzll(x) - 1; return sizeof(T) * 8 - __builtin_clzll(x) - 1;
} }
// This is ugly but my clangd does not like including
// intrinsic headers at all
#if !defined(__SSE__) || !defined(__SSE2__)
#pragma GCC push_options
#ifndef __SSE__
#pragma GCC target("sse")
#endif
#ifndef __SSE2__
#pragma GCC target("sse2")
#endif
#define BAN_MATH_POP_OPTIONS
#endif
template<floating_point T> template<floating_point T>
inline constexpr T floor(T x) inline constexpr T floor(T x)
{ {
@@ -159,7 +166,23 @@ namespace BAN::Math
"jne 1b;" "jne 1b;"
: "+t"(a) : "+t"(a)
: "u"(b) : "u"(b)
: "ax" : "ax", "cc"
);
return a;
}
template<floating_point T>
inline constexpr T remainder(T a, T b)
{
asm(
"1:"
"fprem1;"
"fnstsw %%ax;"
"testb $4, %%ah;"
"jne 1b;"
: "+t"(a)
: "u"(b)
: "ax", "cc"
); );
return a; return a;
} }
@@ -167,7 +190,7 @@ namespace BAN::Math
template<floating_point T> template<floating_point T>
static T modf(T x, T* iptr) static T modf(T x, T* iptr)
{ {
const T frac = BAN::Math::fmod<T>(x, 1); const T frac = BAN::Math::fmod<T>(x, (T)1.0);
*iptr = x - frac; *iptr = x - frac;
return frac; return frac;
} }
@@ -175,15 +198,15 @@ namespace BAN::Math
template<floating_point T> template<floating_point T>
inline constexpr T frexp(T num, int* exp) inline constexpr T frexp(T num, int* exp)
{ {
if (num == 0.0) if (num == (T)0.0)
{ {
*exp = 0; *exp = 0;
return 0.0; return (T)0.0;
} }
T _exp; T e;
asm("fxtract" : "+t"(num), "=u"(_exp)); asm("fxtract" : "+t"(num), "=u"(e));
*exp = (int)_exp + 1; *exp = (int)e + 1;
return num / (T)2.0; return num / (T)2.0;
} }
@@ -251,6 +274,7 @@ namespace BAN::Math
"fstp %%st(1);" "fstp %%st(1);"
: "+t"(x) : "+t"(x)
); );
return x; return x;
} }
@@ -263,18 +287,9 @@ namespace BAN::Math
template<floating_point T> template<floating_point T>
inline constexpr T pow(T x, T y) inline constexpr T pow(T x, T y)
{ {
asm( if (x == (T)0.0)
"fyl2x;" return (T)0.0;
"fld1;" return exp2<T>(y * log2<T>(x));
"fld %%st(1);"
"fprem;"
"f2xm1;"
"faddp;"
"fscale;"
: "+t"(x), "+u"(y)
);
return x;
} }
template<floating_point T> template<floating_point T>
@@ -310,16 +325,27 @@ namespace BAN::Math
template<floating_point T> template<floating_point T>
inline constexpr T sqrt(T x) inline constexpr T sqrt(T x)
{ {
asm("fsqrt" : "+t"(x)); if constexpr(BAN::is_same_v<T, float>)
return x; {
using v4sf = float __attribute__((vector_size(16)));
return __builtin_ia32_sqrtss((v4sf) { x, 0.0f, 0.0f, 0.0f })[0];
}
else if constexpr(BAN::is_same_v<T, double>)
{
using v2df = double __attribute__((vector_size(16)));
return __builtin_ia32_sqrtsd((v2df) { x, 0.0 })[0];
}
else if constexpr(BAN::is_same_v<T, long double>)
{
asm("fsqrt" : "+t"(x));
return x;
}
} }
template<floating_point T> template<floating_point T>
inline constexpr T cbrt(T value) inline constexpr T cbrt(T value)
{ {
if (value == 0.0) return pow<T>(value, (T)1.0 / (T)3.0);
return 0.0;
return pow<T>(value, 1.0 / 3.0);
} }
template<floating_point T> template<floating_point T>
@@ -346,30 +372,21 @@ namespace BAN::Math
inline constexpr T tan(T x) inline constexpr T tan(T x)
{ {
T one, ret; T one, ret;
asm( asm("fptan" : "=t"(one), "=u"(ret) : "0"(x));
"fptan"
: "=t"(one), "=u"(ret)
: "0"(x)
);
return ret; return ret;
} }
template<floating_point T> template<floating_point T>
inline constexpr T atan2(T y, T x) inline constexpr T atan2(T y, T x)
{ {
asm( asm("fpatan" : "+t"(x) : "u"(y) : "st(1)");
"fpatan"
: "+t"(x)
: "u"(y)
: "st(1)"
);
return x; return x;
} }
template<floating_point T> template<floating_point T>
inline constexpr T atan(T x) inline constexpr T atan(T x)
{ {
return atan2<T>(x, 1.0); return atan2<T>(x, (T)1.0);
} }
template<floating_point T> template<floating_point T>
@@ -378,10 +395,10 @@ namespace BAN::Math
if (x == (T)0.0) if (x == (T)0.0)
return (T)0.0; return (T)0.0;
if (x == (T)1.0) if (x == (T)1.0)
return numbers::pi_v<T> / (T)2.0; return +numbers::pi_v<T> / (T)2.0;
if (x == (T)-1.0) if (x == (T)-1.0)
return -numbers::pi_v<T> / (T)2.0; return -numbers::pi_v<T> / (T)2.0;
return (T)2.0 * atan<T>(x / (T(1.0) + sqrt<T>((T)1.0 - x * x))); return (T)2.0 * atan<T>(x / ((T)1.0 + sqrt<T>((T)1.0 - x * x)));
} }
template<floating_point T> template<floating_point T>
@@ -411,7 +428,7 @@ namespace BAN::Math
template<floating_point T> template<floating_point T>
inline constexpr T tanh(T x) inline constexpr T tanh(T x)
{ {
const T exp_px = exp<T>(x); const T exp_px = exp<T>(+x);
const T exp_nx = exp<T>(-x); const T exp_nx = exp<T>(-x);
return (exp_px - exp_nx) / (exp_px + exp_nx); return (exp_px - exp_nx) / (exp_px + exp_nx);
} }
@@ -440,4 +457,9 @@ namespace BAN::Math
return sqrt<T>(x * x + y * y); return sqrt<T>(x * x + y * y);
} }
#ifdef BAN_MATH_POP_OPTIONS
#undef BAN_MATH_POP_OPTIONS
#pragma GCC pop_options
#endif
} }

View File

@@ -9,10 +9,12 @@
namespace BAN namespace BAN
{ {
#if defined(__is_kernel) #if defined(__is_kernel)
static constexpr void*(&allocator)(size_t) = kmalloc; static constexpr void*(*allocator)(size_t) = kmalloc;
static constexpr void(&deallocator)(void*) = kfree; static constexpr void*(*reallocator)(void*, size_t) = nullptr;
static constexpr void(*deallocator)(void*) = kfree;
#else #else
static constexpr void*(&allocator)(size_t) = malloc; static constexpr void*(*allocator)(size_t) = malloc;
static constexpr void(&deallocator)(void*) = free; static constexpr void*(*reallocator)(void*, size_t) = realloc;
static constexpr void(*deallocator)(void*) = free;
#endif #endif
} }

View File

@@ -0,0 +1,64 @@
#pragma once
#include "BAN/Errors.h"
#include <BAN/Vector.h>
#include <BAN/Heap.h>
namespace BAN
{
template<typename T, typename Comp = less<T>>
class PriorityQueue
{
public:
PriorityQueue() = default;
PriorityQueue(Comp comp)
: m_comp(comp)
{ }
ErrorOr<void> push(const T& value)
{
TRY(m_data.push_back(value));
push_heap(m_data.begin(), m_data.end());
return {};
}
ErrorOr<void> push(T&& value)
{
TRY(m_data.push_back(move(value)));
push_heap(m_data.begin(), m_data.end());
return {};
}
template<typename... Args>
ErrorOr<void> emplace(Args&&... args) requires is_constructible_v<T, Args...>
{
TRY(m_data.emplace_back(forward<Args>(args)...));
push_heap(m_data.begin(), m_data.end());
return {};
}
void pop()
{
pop_heap(m_data.begin(), m_data.end());
m_data.pop_back();
}
BAN::ErrorOr<void> reserve(Vector<T>::size_type size)
{
return m_data.reserve(size);
}
T& top() { return m_data.front(); }
const T& top() const { return m_data.front(); }
bool empty() const { return m_data.empty(); }
Vector<T>::size_type size() const { return m_data.size(); }
Vector<T>::size_type capacity() const { return m_data.capacity(); }
private:
Comp m_comp;
Vector<T> m_data;
};
}

View File

@@ -1,5 +1,6 @@
#pragma once #pragma once
#include <BAN/Heap.h>
#include <BAN/Math.h> #include <BAN/Math.h>
#include <BAN/Swap.h> #include <BAN/Swap.h>
#include <BAN/Traits.h> #include <BAN/Traits.h>
@@ -8,7 +9,7 @@
namespace BAN::sort namespace BAN::sort
{ {
template<typename It, typename Comp = less<typename It::value_type>> template<typename It, typename Comp = less<it_value_type_t<It>>>
void exchange_sort(It begin, It end, Comp comp = {}) void exchange_sort(It begin, It end, Comp comp = {})
{ {
for (It lhs = begin; lhs != end; ++lhs) for (It lhs = begin; lhs != end; ++lhs)
@@ -42,7 +43,7 @@ namespace BAN::sort
} }
template<typename It, typename Comp = less<typename It::value_type>> template<typename It, typename Comp = less<it_value_type_t<It>>>
void quick_sort(It begin, It end, Comp comp = {}) void quick_sort(It begin, It end, Comp comp = {})
{ {
if (distance(begin, end) <= 1) if (distance(begin, end) <= 1)
@@ -52,14 +53,14 @@ namespace BAN::sort
quick_sort(++mid, end, comp); quick_sort(++mid, end, comp);
} }
template<typename It, typename Comp = less<typename It::value_type>> template<typename It, typename Comp = less<it_value_type_t<It>>>
void insertion_sort(It begin, It end, Comp comp = {}) void insertion_sort(It begin, It end, Comp comp = {})
{ {
if (distance(begin, end) <= 1) if (distance(begin, end) <= 1)
return; return;
for (It it1 = next(begin, 1); it1 != end; ++it1) for (It it1 = next(begin, 1); it1 != end; ++it1)
{ {
typename It::value_type x = move(*it1); auto x = move(*it1);
It it2 = it1; It it2 = it1;
for (; it2 != begin && comp(x, *prev(it2, 1)); --it2) for (; it2 != begin && comp(x, *prev(it2, 1)); --it2)
*it2 = move(*prev(it2, 1)); *it2 = move(*prev(it2, 1));
@@ -67,83 +68,7 @@ namespace BAN::sort
} }
} }
namespace detail template<typename It, typename Comp = less<it_value_type_t<It>>>
{
template<typename It, typename Comp>
void push_heap(It begin, size_t hole_index, size_t top_index, typename It::value_type value, Comp comp)
{
size_t parent = (hole_index - 1) / 2;
while (hole_index > top_index && comp(*next(begin, parent), value))
{
*next(begin, hole_index) = move(*next(begin, parent));
hole_index = parent;
parent = (hole_index - 1) / 2;
}
*next(begin, hole_index) = move(value);
}
template<typename It, typename Comp>
void adjust_heap(It begin, size_t hole_index, size_t len, typename It::value_type value, Comp comp)
{
const size_t top_index = hole_index;
size_t child = hole_index;
while (child < (len - 1) / 2)
{
child = 2 * (child + 1);
if (comp(*next(begin, child), *next(begin, child - 1)))
child--;
*next(begin, hole_index) = move(*next(begin, child));
hole_index = child;
}
if (len % 2 == 0 && child == (len - 2) / 2)
{
child = 2 * (child + 1);
*next(begin, hole_index) = move(*next(begin, child - 1));
hole_index = child - 1;
}
push_heap(begin, hole_index, top_index, move(value), comp);
}
}
template<typename It, typename Comp = less<typename It::value_type>>
void make_heap(It begin, It end, Comp comp = {})
{
const size_t len = distance(begin, end);
if (len <= 1)
return;
size_t parent = (len - 2) / 2;
while (true)
{
detail::adjust_heap(begin, parent, len, move(*next(begin, parent)), comp);
if (parent == 0)
break;
parent--;
}
}
template<typename It, typename Comp = less<typename It::value_type>>
void sort_heap(It begin, It end, Comp comp = {})
{
const size_t len = distance(begin, end);
if (len <= 1)
return;
size_t last = len;
while (last > 1)
{
last--;
typename It::value_type x = move(*next(begin, last));
*next(begin, last) = move(*begin);
detail::adjust_heap(begin, 0, last, move(x), comp);
}
}
template<typename It, typename Comp = less<typename It::value_type>>
void heap_sort(It begin, It end, Comp comp = {}) void heap_sort(It begin, It end, Comp comp = {})
{ {
make_heap(begin, end, comp); make_heap(begin, end, comp);
@@ -167,7 +92,7 @@ namespace BAN::sort
} }
template<typename It, typename Comp = less<typename It::value_type>> template<typename It, typename Comp = less<it_value_type_t<It>>>
void intro_sort(It begin, It end, Comp comp = {}) void intro_sort(It begin, It end, Comp comp = {})
{ {
const size_t len = distance(begin, end); const size_t len = distance(begin, end);
@@ -190,10 +115,10 @@ namespace BAN::sort
} }
template<typename It, size_t radix = 256> template<typename It, size_t radix = 256>
requires is_unsigned_v<typename It::value_type> && (radix > 0 && (radix & (radix - 1)) == 0) requires is_unsigned_v<it_value_type_t<It>> && (radix > 0 && (radix & (radix - 1)) == 0)
BAN::ErrorOr<void> radix_sort(It begin, It end) BAN::ErrorOr<void> radix_sort(It begin, It end)
{ {
using value_type = typename It::value_type; using value_type = it_value_type_t<It>;
const size_t len = distance(begin, end); const size_t len = distance(begin, end);
if (len <= 1) if (len <= 1)
@@ -231,7 +156,7 @@ namespace BAN::sort
return {}; return {};
} }
template<typename It, typename Comp = less<typename It::value_type>> template<typename It, typename Comp = less<it_value_type_t<It>>>
void sort(It begin, It end, Comp comp = {}) void sort(It begin, It end, Comp comp = {})
{ {
return intro_sort(begin, end, comp); return intro_sort(begin, end, comp);

View File

@@ -69,7 +69,6 @@ namespace BAN
value_type* data() const value_type* data() const
{ {
ASSERT(m_data);
return m_data; return m_data;
} }
@@ -84,7 +83,6 @@ namespace BAN
Span slice(size_type start, size_type length = ~size_type(0)) const Span slice(size_type start, size_type length = ~size_type(0)) const
{ {
ASSERT(m_data);
ASSERT(start <= m_size); ASSERT(start <= m_size);
if (length == ~size_type(0)) if (length == ~size_type(0))
length = m_size - start; length = m_size - start;

View File

@@ -14,6 +14,7 @@ namespace BAN
{ {
public: public:
using size_type = size_t; using size_type = size_t;
using value_type = char;
using iterator = IteratorSimple<char, String>; using iterator = IteratorSimple<char, String>;
using const_iterator = ConstIteratorSimple<char, String>; using const_iterator = ConstIteratorSimple<char, String>;
static constexpr size_type sso_capacity = 15; static constexpr size_type sso_capacity = 15;
@@ -352,10 +353,9 @@ namespace BAN::Formatter
{ {
template<typename F> template<typename F>
void print_argument(F putc, const String& string, const ValueFormat&) void print_argument(F putc, const String& string, const ValueFormat& format)
{ {
for (String::size_type i = 0; i < string.size(); i++) print_argument(putc, string.sv(), format);
putc(string[i]);
} }
} }

View File

@@ -14,6 +14,7 @@ namespace BAN
{ {
public: public:
using size_type = size_t; using size_type = size_t;
using value_type = char;
using const_iterator = ConstIteratorSimple<char, StringView>; using const_iterator = ConstIteratorSimple<char, StringView>;
public: public:
@@ -246,10 +247,12 @@ namespace BAN::Formatter
{ {
template<typename F> template<typename F>
void print_argument(F putc, const StringView& sv, const ValueFormat&) void print_argument(F putc, const StringView& sv, const ValueFormat& format)
{ {
for (StringView::size_type i = 0; i < sv.size(); i++) for (StringView::size_type i = 0; i < sv.size(); i++)
putc(sv[i]); putc(sv[i]);
for (int i = sv.size(); i < format.fill; i++)
putc(' ');
} }
} }

View File

@@ -61,6 +61,9 @@ namespace BAN
template<typename T> struct is_move_constructible { static constexpr bool value = is_constructible_v<T, T&&>; }; template<typename T> struct is_move_constructible { static constexpr bool value = is_constructible_v<T, T&&>; };
template<typename T> inline constexpr bool is_move_constructible_v = is_move_constructible<T>::value; template<typename T> inline constexpr bool is_move_constructible_v = is_move_constructible<T>::value;
template<typename T> struct is_trivially_copyable { static constexpr bool value = __is_trivially_copyable(T); };
template<typename T> inline constexpr bool is_trivially_copyable_v = is_trivially_copyable<T>::value;
template<typename T> struct is_integral { static constexpr bool value = requires (T t, T* p, void (*f)(T)) { reinterpret_cast<T>(t); f(0); p + t; }; }; template<typename T> struct is_integral { static constexpr bool value = requires (T t, T* p, void (*f)(T)) { reinterpret_cast<T>(t); f(0); p + t; }; };
template<typename T> inline constexpr bool is_integral_v = is_integral<T>::value; template<typename T> inline constexpr bool is_integral_v = is_integral<T>::value;
template<typename T> concept integral = is_integral_v<T>; template<typename T> concept integral = is_integral_v<T>;
@@ -139,6 +142,10 @@ namespace BAN
template<typename T> using make_signed_t = typename make_signed<T>::type; template<typename T> using make_signed_t = typename make_signed<T>::type;
#undef __BAN_TRAITS_MAKE_SIGNED_CV #undef __BAN_TRAITS_MAKE_SIGNED_CV
template<typename T> struct it_value_type { using value_type = T::value_type; };
template<typename T> struct it_value_type<T*> { using value_type = T; };
template<typename T> using it_value_type_t = typename it_value_type<T>::value_type;
template<typename T> struct less { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs < rhs; } }; template<typename T> struct less { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs < rhs; } };
template<typename T> struct equal { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs == rhs; } }; template<typename T> struct equal { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs == rhs; } };
template<typename T> struct greater { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs > rhs; } }; template<typename T> struct greater { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs > rhs; } };

View File

@@ -126,14 +126,16 @@ namespace BAN
Variant(Variant&& other) Variant(Variant&& other)
: m_index(other.m_index) : m_index(other.m_index)
{ {
detail::move_construct<Ts...>(other.m_index, other.m_storage, m_storage); if (other.has_value())
detail::move_construct<Ts...>(other.m_index, other.m_storage, m_storage);
other.clear(); other.clear();
} }
Variant(const Variant& other) Variant(const Variant& other)
: m_index(other.m_index) : m_index(other.m_index)
{ {
detail::copy_construct<Ts...>(other.m_index, other.m_storage, m_storage); if (other.has_value())
detail::copy_construct<Ts...>(other.m_index, other.m_storage, m_storage);
} }
template<typename T> template<typename T>
@@ -157,12 +159,13 @@ namespace BAN
Variant& operator=(Variant&& other) Variant& operator=(Variant&& other)
{ {
if (m_index == other.m_index) if (m_index == other.m_index && m_index != invalid_index())
detail::move_assign<Ts...>(m_index, other.m_storage, m_storage); detail::move_assign<Ts...>(m_index, other.m_storage, m_storage);
else else
{ {
clear(); clear();
detail::move_construct<Ts...>(other.m_index, other.m_storage, m_storage); if (other.has_value())
detail::move_construct<Ts...>(other.m_index, other.m_storage, m_storage);
m_index = other.m_index; m_index = other.m_index;
} }
other.clear(); other.clear();
@@ -171,12 +174,13 @@ namespace BAN
Variant& operator=(const Variant& other) Variant& operator=(const Variant& other)
{ {
if (m_index == other.m_index) if (m_index == other.m_index && m_index != invalid_index())
detail::copy_assign<Ts...>(m_index, other.m_storage, m_storage); detail::copy_assign<Ts...>(m_index, other.m_storage, m_storage);
else else
{ {
clear(); clear();
detail::copy_construct<Ts...>(other.m_index, other.m_storage, m_storage); if (other.has_value())
detail::copy_construct<Ts...>(other.m_index, other.m_storage, m_storage);
m_index = other.m_index; m_index = other.m_index;
} }
return *this; return *this;

View File

@@ -56,7 +56,7 @@ namespace BAN
bool contains(const T&) const; bool contains(const T&) const;
Span<T> span() { return Span(m_data, m_size); } Span<T> span() { return Span(m_data, m_size); }
const Span<T> span() const { return Span(m_data, m_size); } Span<const T> span() const { return Span(m_data, m_size); }
const T& operator[](size_type) const; const T& operator[](size_type) const;
T& operator[](size_type); T& operator[](size_type);
@@ -381,19 +381,46 @@ namespace BAN
template<typename T> template<typename T>
ErrorOr<void> Vector<T>::ensure_capacity(size_type size) ErrorOr<void> Vector<T>::ensure_capacity(size_type size)
{ {
static_assert(alignof(T) <= alignof(max_align_t), "over aligned types not supported");
if (m_capacity >= size) if (m_capacity >= size)
return {}; return {};
size_type new_cap = BAN::Math::max<size_type>(size, m_capacity * 2);
T* new_data = (T*)BAN::allocator(new_cap * sizeof(T)); const size_type new_cap = BAN::Math::max<size_type>(size, m_capacity * 2);
if (new_data == nullptr)
return Error::from_errno(ENOMEM); if constexpr (BAN::is_trivially_copyable_v<T>)
for (size_type i = 0; i < m_size; i++)
{ {
new (new_data + i) T(move(m_data[i])); if constexpr (BAN::reallocator)
m_data[i].~T(); {
auto* new_data = static_cast<T*>(BAN::reallocator(m_data, new_cap * sizeof(T)));
if (new_data == nullptr)
return Error::from_errno(ENOMEM);
m_data = new_data;
}
else
{
auto* new_data = static_cast<T*>(BAN::allocator(new_cap * sizeof(T)));
if (new_data == nullptr)
return Error::from_errno(ENOMEM);
memcpy(new_data, m_data, m_size * sizeof(T));
BAN::deallocator(m_data);
m_data = new_data;
}
} }
BAN::deallocator(m_data); else
m_data = new_data; {
auto* new_data = static_cast<T*>(BAN::allocator(new_cap * sizeof(T)));
if (new_data == nullptr)
return Error::from_errno(ENOMEM);
for (size_type i = 0; i < m_size; i++)
{
new (new_data + i) T(move(m_data[i]));
m_data[i].~T();
}
BAN::deallocator(m_data);
m_data = new_data;
}
m_capacity = new_cap; m_capacity = new_cap;
return {}; return {};
} }

Binary file not shown.

View File

@@ -5,9 +5,12 @@ set(KERNEL_SOURCES
kernel/ACPI/AML/Node.cpp kernel/ACPI/AML/Node.cpp
kernel/ACPI/AML/OpRegion.cpp kernel/ACPI/AML/OpRegion.cpp
kernel/ACPI/BatterySystem.cpp kernel/ACPI/BatterySystem.cpp
kernel/ACPI/EmbeddedController.cpp
kernel/APIC.cpp kernel/APIC.cpp
kernel/Audio/AC97/Controller.cpp kernel/Audio/AC97/Controller.cpp
kernel/Audio/Controller.cpp kernel/Audio/Controller.cpp
kernel/Audio/HDAudio/AudioFunctionGroup.cpp
kernel/Audio/HDAudio/Controller.cpp
kernel/BootInfo.cpp kernel/BootInfo.cpp
kernel/CPUID.cpp kernel/CPUID.cpp
kernel/Credentials.cpp kernel/Credentials.cpp
@@ -22,6 +25,7 @@ set(KERNEL_SOURCES
kernel/Epoll.cpp kernel/Epoll.cpp
kernel/Errors.cpp kernel/Errors.cpp
kernel/FS/DevFS/FileSystem.cpp kernel/FS/DevFS/FileSystem.cpp
kernel/FS/EventFD.cpp
kernel/FS/Ext2/FileSystem.cpp kernel/FS/Ext2/FileSystem.cpp
kernel/FS/Ext2/Inode.cpp kernel/FS/Ext2/Inode.cpp
kernel/FS/FAT/FileSystem.cpp kernel/FS/FAT/FileSystem.cpp
@@ -47,6 +51,7 @@ set(KERNEL_SOURCES
kernel/InterruptController.cpp kernel/InterruptController.cpp
kernel/kernel.cpp kernel/kernel.cpp
kernel/Lock/SpinLock.cpp kernel/Lock/SpinLock.cpp
kernel/Memory/ByteRingBuffer.cpp
kernel/Memory/DMARegion.cpp kernel/Memory/DMARegion.cpp
kernel/Memory/FileBackedRegion.cpp kernel/Memory/FileBackedRegion.cpp
kernel/Memory/Heap.cpp kernel/Memory/Heap.cpp
@@ -107,6 +112,7 @@ set(KERNEL_SOURCES
kernel/USB/Controller.cpp kernel/USB/Controller.cpp
kernel/USB/Device.cpp kernel/USB/Device.cpp
kernel/USB/HID/HIDDriver.cpp kernel/USB/HID/HIDDriver.cpp
kernel/USB/HID/Joystick.cpp
kernel/USB/HID/Keyboard.cpp kernel/USB/HID/Keyboard.cpp
kernel/USB/HID/Mouse.cpp kernel/USB/HID/Mouse.cpp
kernel/USB/Hub/HubDriver.cpp kernel/USB/Hub/HubDriver.cpp
@@ -133,6 +139,8 @@ if("${BANAN_ARCH}" STREQUAL "x86_64")
arch/x86_64/Signal.S arch/x86_64/Signal.S
arch/x86_64/Syscall.S arch/x86_64/Syscall.S
arch/x86_64/Thread.S arch/x86_64/Thread.S
arch/x86_64/User.S
arch/x86_64/Yield.S
) )
elseif("${BANAN_ARCH}" STREQUAL "i686") elseif("${BANAN_ARCH}" STREQUAL "i686")
set(KERNEL_SOURCES set(KERNEL_SOURCES
@@ -143,6 +151,8 @@ elseif("${BANAN_ARCH}" STREQUAL "i686")
arch/i686/Signal.S arch/i686/Signal.S
arch/i686/Syscall.S arch/i686/Syscall.S
arch/i686/Thread.S arch/i686/Thread.S
arch/i686/User.S
arch/i686/Yield.S
) )
else() else()
message(FATAL_ERROR "unsupported architecure ${BANAN_ARCH}") message(FATAL_ERROR "unsupported architecure ${BANAN_ARCH}")
@@ -158,10 +168,13 @@ set(BAN_SOURCES
set(KLIBC_SOURCES set(KLIBC_SOURCES
klibc/ctype.cpp klibc/ctype.cpp
klibc/string.cpp klibc/string.cpp
klibc/arch/${BANAN_ARCH}/string.S
)
# Ehhh don't do this but for now libc uses the same stuff kernel can use set(LIBDEFLATE_SOURCE
# This won't work after libc starts using sse implemetations tho ../userspace/libraries/LibDEFLATE/Compressor.cpp
../userspace/libraries/LibC/arch/${BANAN_ARCH}/string.S ../userspace/libraries/LibDEFLATE/Decompressor.cpp
../userspace/libraries/LibDEFLATE/HuffmanTree.cpp
) )
set(LIBFONT_SOURCES set(LIBFONT_SOURCES
@@ -174,18 +187,25 @@ set(LIBINPUT_SOURCE
../userspace/libraries/LibInput/KeyEvent.cpp ../userspace/libraries/LibInput/KeyEvent.cpp
) )
set(LIBQR_SOURCE
../userspace/libraries/LibQR/QRCode.cpp
)
set(KERNEL_SOURCES set(KERNEL_SOURCES
${KERNEL_SOURCES} ${KERNEL_SOURCES}
${BAN_SOURCES} ${BAN_SOURCES}
${KLIBC_SOURCES} ${KLIBC_SOURCES}
${LIBDEFLATE_SOURCE}
${LIBFONT_SOURCES} ${LIBFONT_SOURCES}
${LIBINPUT_SOURCE} ${LIBINPUT_SOURCE}
${LIBQR_SOURCE}
) )
add_executable(kernel ${KERNEL_SOURCES}) add_executable(kernel ${KERNEL_SOURCES})
target_compile_definitions(kernel PRIVATE __is_kernel) target_compile_definitions(kernel PRIVATE __is_kernel)
target_compile_definitions(kernel PRIVATE __arch=${BANAN_ARCH}) target_compile_definitions(kernel PRIVATE __arch=${BANAN_ARCH})
target_compile_definitions(kernel PRIVATE LIBDEFLATE_AVOID_STACK=1)
target_compile_options(kernel PRIVATE target_compile_options(kernel PRIVATE
-O2 -g -O2 -g
@@ -239,9 +259,11 @@ add_custom_command(
banan_include_headers(kernel ban) banan_include_headers(kernel ban)
banan_include_headers(kernel libc) banan_include_headers(kernel libc)
banan_include_headers(kernel libfont) banan_include_headers(kernel libdeflate)
banan_include_headers(kernel libelf) banan_include_headers(kernel libelf)
banan_include_headers(kernel libfont)
banan_include_headers(kernel libinput) banan_include_headers(kernel libinput)
banan_include_headers(kernel libqr)
banan_install_headers(kernel) banan_install_headers(kernel)
set_target_properties(kernel PROPERTIES OUTPUT_NAME banan-os.kernel) set_target_properties(kernel PROPERTIES OUTPUT_NAME banan-os.kernel)

View File

@@ -21,6 +21,11 @@ namespace Kernel
SpinLock PageTable::s_fast_page_lock; SpinLock PageTable::s_fast_page_lock;
constexpr uint64_t s_page_flag_mask = 0x8000000000000FFF;
constexpr uint64_t s_page_addr_mask = ~s_page_flag_mask;
static bool s_is_post_heap_done = false;
static PageTable* s_kernel = nullptr; static PageTable* s_kernel = nullptr;
static bool s_has_nxe = false; static bool s_has_nxe = false;
static bool s_has_pge = false; static bool s_has_pge = false;
@@ -67,7 +72,7 @@ namespace Kernel
void PageTable::initialize_post_heap() void PageTable::initialize_post_heap()
{ {
// NOTE: this is no-op as our 32 bit target does not use hhdm s_is_post_heap_done = true;
} }
void PageTable::initial_load() void PageTable::initial_load()
@@ -141,9 +146,9 @@ namespace Kernel
} }
template<typename T> template<typename T>
static vaddr_t P2V(const T paddr) static uint64_t* P2V(const T paddr)
{ {
return (paddr_t)paddr - g_boot_info.kernel_paddr + KERNEL_OFFSET; return reinterpret_cast<uint64_t*>(reinterpret_cast<paddr_t>(paddr) - g_boot_info.kernel_paddr + KERNEL_OFFSET);
} }
void PageTable::initialize_kernel() void PageTable::initialize_kernel()
@@ -193,13 +198,18 @@ namespace Kernel
{ {
constexpr uint64_t pdpte = (fast_page() >> 30) & 0x1FF; constexpr uint64_t pdpte = (fast_page() >> 30) & 0x1FF;
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF; constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct)); const uint64_t* pdpt = P2V(m_highest_paging_struct);
ASSERT(pdpt[pdpte] & Flags::Present); ASSERT(pdpt[pdpte] & Flags::Present);
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte]) & PAGE_ADDR_MASK); uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
ASSERT(!(pd[pde] & Flags::Present)); ASSERT(!(pd[pde] & Flags::Present));
pd[pde] = V2P(allocate_zeroed_page_aligned_page()) | Flags::ReadWrite | Flags::Present; pd[pde] = V2P(allocate_zeroed_page_aligned_page()) | Flags::ReadWrite | Flags::Present;
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
ASSERT(pt[pte] == 0);
pt[pte] = Flags::Reserved;
} }
void PageTable::map_fast_page(paddr_t paddr) void PageTable::map_fast_page(paddr_t paddr)
@@ -214,14 +224,14 @@ namespace Kernel
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF; constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF; constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(s_kernel->m_highest_paging_struct)); uint64_t* pdpt = P2V(s_kernel->m_highest_paging_struct);
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK)); uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK)); uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
ASSERT(!(pt[pte] & Flags::Present)); ASSERT(!(pt[pte] & Flags::Present));
pt[pte] = paddr | Flags::ReadWrite | Flags::Present; pt[pte] = paddr | Flags::ReadWrite | Flags::Present;
invalidate(fast_page(), false); asm volatile("invlpg (%0)" :: "r"(fast_page()) : "memory");
} }
void PageTable::unmap_fast_page() void PageTable::unmap_fast_page()
@@ -234,14 +244,14 @@ namespace Kernel
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF; constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF; constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(s_kernel->m_highest_paging_struct)); uint64_t* pdpt = P2V(s_kernel->m_highest_paging_struct);
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK)); uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK)); uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
ASSERT(pt[pte] & Flags::Present); ASSERT(pt[pte] & Flags::Present);
pt[pte] = 0; pt[pte] = Flags::Reserved;
invalidate(fast_page(), false); asm volatile("invlpg (%0)" :: "r"(fast_page()) : "memory");
} }
BAN::ErrorOr<PageTable*> PageTable::create_userspace() BAN::ErrorOr<PageTable*> PageTable::create_userspace()
@@ -263,7 +273,7 @@ namespace Kernel
m_highest_paging_struct = V2P(kmalloc(32, 32, true)); m_highest_paging_struct = V2P(kmalloc(32, 32, true));
ASSERT(m_highest_paging_struct); ASSERT(m_highest_paging_struct);
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct)); uint64_t* pdpt = P2V(m_highest_paging_struct);
pdpt[0] = 0; pdpt[0] = 0;
pdpt[1] = 0; pdpt[1] = 0;
pdpt[2] = 0; pdpt[2] = 0;
@@ -276,18 +286,17 @@ namespace Kernel
if (m_highest_paging_struct == 0) if (m_highest_paging_struct == 0)
return; return;
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct)); uint64_t* pdpt = P2V(m_highest_paging_struct);
for (uint32_t pdpte = 0; pdpte < 3; pdpte++) for (uint32_t pdpte = 0; pdpte < 3; pdpte++)
{ {
if (!(pdpt[pdpte] & Flags::Present)) if (!(pdpt[pdpte] & Flags::Present))
continue; continue;
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK)); uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
for (uint32_t pde = 0; pde < 512; pde++) for (uint32_t pde = 0; pde < 512; pde++)
{ {
if (!(pd[pde] & Flags::Present)) if (!(pd[pde] & Flags::Present))
continue; continue;
kfree(reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK))); kfree(P2V(pd[pde] & s_page_addr_mask));
} }
kfree(pd); kfree(pd);
} }
@@ -298,15 +307,43 @@ namespace Kernel
{ {
SpinLockGuard _(m_lock); SpinLockGuard _(m_lock);
ASSERT(m_highest_paging_struct < 0x100000000); ASSERT(m_highest_paging_struct < 0x100000000);
const uint32_t pdpt_lo = m_highest_paging_struct; asm volatile("movl %0, %%cr3" :: "r"(static_cast<uint32_t>(m_highest_paging_struct)));
asm volatile("movl %0, %%cr3" :: "r"(pdpt_lo));
Processor::set_current_page_table(this); Processor::set_current_page_table(this);
} }
void PageTable::invalidate(vaddr_t vaddr, bool send_smp_message) void PageTable::invalidate_range(vaddr_t vaddr, size_t pages, bool send_smp_message)
{ {
ASSERT(vaddr % PAGE_SIZE == 0); ASSERT(vaddr % PAGE_SIZE == 0);
asm volatile("invlpg (%0)" :: "r"(vaddr) : "memory");
const bool is_userspace = (vaddr < KERNEL_OFFSET);
if (is_userspace && this != &PageTable::current())
;
else if (pages <= 32 || !s_is_post_heap_done)
{
for (size_t i = 0; i < pages; i++, vaddr += PAGE_SIZE)
asm volatile("invlpg (%0)" :: "r"(vaddr));
}
else if (is_userspace || !s_has_pge)
{
asm volatile("movl %0, %%cr3" :: "r"(static_cast<uint32_t>(m_highest_paging_struct)));
}
else
{
asm volatile(
"movl %%cr4, %%eax;"
"andl $~0x80, %%eax;"
"movl %%eax, %%cr4;"
"movl %0, %%cr3;"
"orl $0x80, %%eax;"
"movl %%eax, %%cr4;"
:
: "r"(static_cast<uint32_t>(m_highest_paging_struct))
: "eax"
);
}
if (send_smp_message) if (send_smp_message)
{ {
@@ -314,13 +351,14 @@ namespace Kernel
.type = Processor::SMPMessage::Type::FlushTLB, .type = Processor::SMPMessage::Type::FlushTLB,
.flush_tlb = { .flush_tlb = {
.vaddr = vaddr, .vaddr = vaddr,
.page_count = 1 .page_count = pages,
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
} }
}); });
} }
} }
void PageTable::unmap_page(vaddr_t vaddr, bool send_smp_message) void PageTable::unmap_page(vaddr_t vaddr, bool invalidate)
{ {
ASSERT(vaddr); ASSERT(vaddr);
ASSERT(vaddr % PAGE_SIZE == 0); ASSERT(vaddr % PAGE_SIZE == 0);
@@ -339,12 +377,16 @@ namespace Kernel
if (is_page_free(vaddr)) if (is_page_free(vaddr))
Kernel::panic("trying to unmap unmapped page 0x{H}", vaddr); Kernel::panic("trying to unmap unmapped page 0x{H}", vaddr);
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct)); uint64_t* pdpt = P2V(m_highest_paging_struct);
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK)); uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK)); uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
const paddr_t old_paddr = pt[pte] & s_page_addr_mask;
pt[pte] = 0; pt[pte] = 0;
invalidate(vaddr, send_smp_message);
if (invalidate && old_paddr != 0)
invalidate_page(vaddr, true);
} }
void PageTable::unmap_range(vaddr_t vaddr, size_t size) void PageTable::unmap_range(vaddr_t vaddr, size_t size)
@@ -356,17 +398,10 @@ namespace Kernel
SpinLockGuard _(m_lock); SpinLockGuard _(m_lock);
for (vaddr_t page = 0; page < page_count; page++) for (vaddr_t page = 0; page < page_count; page++)
unmap_page(vaddr + page * PAGE_SIZE, false); unmap_page(vaddr + page * PAGE_SIZE, false);
invalidate_range(vaddr, page_count, true);
Processor::broadcast_smp_message({
.type = Processor::SMPMessage::Type::FlushTLB,
.flush_tlb = {
.vaddr = vaddr,
.page_count = page_count
}
});
} }
void PageTable::map_page_at(paddr_t paddr, vaddr_t vaddr, flags_t flags, MemoryType memory_type, bool send_smp_message) void PageTable::map_page_at(paddr_t paddr, vaddr_t vaddr, flags_t flags, MemoryType memory_type, bool invalidate)
{ {
ASSERT(vaddr); ASSERT(vaddr);
ASSERT(vaddr != fast_page()); ASSERT(vaddr != fast_page());
@@ -401,11 +436,11 @@ namespace Kernel
SpinLockGuard _(m_lock); SpinLockGuard _(m_lock);
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct)); uint64_t* pdpt = P2V(m_highest_paging_struct);
if (!(pdpt[pdpte] & Flags::Present)) if (!(pdpt[pdpte] & Flags::Present))
pdpt[pdpte] = V2P(allocate_zeroed_page_aligned_page()) | Flags::Present; pdpt[pdpte] = V2P(allocate_zeroed_page_aligned_page()) | Flags::Present;
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK)); uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
if ((pd[pde] & uwr_flags) != uwr_flags) if ((pd[pde] & uwr_flags) != uwr_flags)
{ {
if (!(pd[pde] & Flags::Present)) if (!(pd[pde] & Flags::Present))
@@ -416,10 +451,14 @@ namespace Kernel
if (!(flags & Flags::Present)) if (!(flags & Flags::Present))
uwr_flags &= ~Flags::Present; uwr_flags &= ~Flags::Present;
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK)); uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
const paddr_t old_paddr = pt[pte] & s_page_addr_mask;
pt[pte] = paddr | uwr_flags | extra_flags; pt[pte] = paddr | uwr_flags | extra_flags;
invalidate(vaddr, send_smp_message); if (invalidate && old_paddr != 0)
invalidate_page(vaddr, true);
} }
void PageTable::map_range_at(paddr_t paddr, vaddr_t vaddr, size_t size, flags_t flags, MemoryType memory_type) void PageTable::map_range_at(paddr_t paddr, vaddr_t vaddr, size_t size, flags_t flags, MemoryType memory_type)
@@ -433,14 +472,49 @@ namespace Kernel
SpinLockGuard _(m_lock); SpinLockGuard _(m_lock);
for (size_t page = 0; page < page_count; page++) for (size_t page = 0; page < page_count; page++)
map_page_at(paddr + page * PAGE_SIZE, vaddr + page * PAGE_SIZE, flags, memory_type, false); map_page_at(paddr + page * PAGE_SIZE, vaddr + page * PAGE_SIZE, flags, memory_type, false);
invalidate_range(vaddr, page_count, true);
}
Processor::broadcast_smp_message({ void PageTable::remove_writable_from_range(vaddr_t vaddr, size_t size)
.type = Processor::SMPMessage::Type::FlushTLB, {
.flush_tlb = { ASSERT(vaddr);
.vaddr = vaddr, ASSERT(vaddr % PAGE_SIZE == 0);
.page_count = page_count
uint32_t pdpte = (vaddr >> 30) & 0x1FF;
uint32_t pde = (vaddr >> 21) & 0x1FF;
uint32_t pte = (vaddr >> 12) & 0x1FF;
const uint32_t e_pdpte = ((vaddr + size - 1) >> 30) & 0x1FF;
const uint32_t e_pde = ((vaddr + size - 1) >> 21) & 0x1FF;
const uint32_t e_pte = ((vaddr + size - 1) >> 12) & 0x1FF;
SpinLockGuard _(m_lock);
const uint64_t* pdpt = P2V(m_highest_paging_struct);
for (; pdpte <= e_pdpte; pdpte++)
{
if (!(pdpt[pdpte] & Flags::Present))
continue;
const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
for (; pde < 512; pde++)
{
if (pdpte == e_pdpte && pde > e_pde)
break;
if (!(pd[pde] & Flags::ReadWrite))
continue;
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
for (; pte < 512; pte++)
{
if (pdpte == e_pdpte && pde == e_pde && pte > e_pte)
break;
pt[pte] &= ~static_cast<uint64_t>(Flags::ReadWrite);
}
pte = 0;
} }
}); pde = 0;
}
invalidate_range(vaddr, size / PAGE_SIZE, true);
} }
uint64_t PageTable::get_page_data(vaddr_t vaddr) const uint64_t PageTable::get_page_data(vaddr_t vaddr) const
@@ -453,15 +527,15 @@ namespace Kernel
SpinLockGuard _(m_lock); SpinLockGuard _(m_lock);
uint64_t* pdpt = (uint64_t*)P2V(m_highest_paging_struct); const uint64_t* pdpt = P2V(m_highest_paging_struct);
if (!(pdpt[pdpte] & Flags::Present)) if (!(pdpt[pdpte] & Flags::Present))
return 0; return 0;
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK); const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
if (!(pd[pde] & Flags::Present)) if (!(pd[pde] & Flags::Present))
return 0; return 0;
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK); const uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
if (!(pt[pte] & Flags::Used)) if (!(pt[pte] & Flags::Used))
return 0; return 0;
@@ -475,8 +549,7 @@ namespace Kernel
paddr_t PageTable::physical_address_of(vaddr_t vaddr) const paddr_t PageTable::physical_address_of(vaddr_t vaddr) const
{ {
uint64_t page_data = get_page_data(vaddr); return get_page_data(vaddr) & s_page_addr_mask;
return (page_data & PAGE_ADDR_MASK) & ~(1ull << 63);
} }
bool PageTable::is_page_free(vaddr_t vaddr) const bool PageTable::is_page_free(vaddr_t vaddr) const
@@ -497,13 +570,13 @@ namespace Kernel
return true; return true;
} }
bool PageTable::reserve_page(vaddr_t vaddr, bool only_free) bool PageTable::reserve_page(vaddr_t vaddr, bool only_free, bool send_smp_message)
{ {
SpinLockGuard _(m_lock); SpinLockGuard _(m_lock);
ASSERT(vaddr % PAGE_SIZE == 0); ASSERT(vaddr % PAGE_SIZE == 0);
if (only_free && !is_page_free(vaddr)) if (only_free && !is_page_free(vaddr))
return false; return false;
map_page_at(0, vaddr, Flags::Reserved); map_page_at(0, vaddr, Flags::Reserved, MemoryType::Normal, send_smp_message);
return true; return true;
} }
@@ -517,7 +590,9 @@ namespace Kernel
if (only_free && !is_range_free(vaddr, bytes)) if (only_free && !is_range_free(vaddr, bytes))
return false; return false;
for (size_t offset = 0; offset < bytes; offset += PAGE_SIZE) for (size_t offset = 0; offset < bytes; offset += PAGE_SIZE)
reserve_page(vaddr + offset); reserve_page(vaddr + offset, true, false);
invalidate_range(vaddr, bytes / PAGE_SIZE, true);
return true; return true;
} }
@@ -530,48 +605,47 @@ namespace Kernel
if (size_t rem = last_address % PAGE_SIZE) if (size_t rem = last_address % PAGE_SIZE)
last_address -= rem; last_address -= rem;
const uint32_t s_pdpte = (first_address >> 30) & 0x1FF; uint32_t pdpte = (first_address >> 30) & 0x1FF;
const uint32_t s_pde = (first_address >> 21) & 0x1FF; uint32_t pde = (first_address >> 21) & 0x1FF;
const uint32_t s_pte = (first_address >> 12) & 0x1FF; uint32_t pte = (first_address >> 12) & 0x1FF;
const uint32_t e_pdpte = (last_address >> 30) & 0x1FF; const uint32_t e_pdpte = ((last_address - 1) >> 30) & 0x1FF;
const uint32_t e_pde = (last_address >> 21) & 0x1FF; const uint32_t e_pde = ((last_address - 1) >> 21) & 0x1FF;
const uint32_t e_pte = (last_address >> 12) & 0x1FF; const uint32_t e_pte = ((last_address - 1) >> 12) & 0x1FF;
SpinLockGuard _(m_lock); SpinLockGuard _(m_lock);
// Try to find free page that can be mapped without // Try to find free page that can be mapped without
// allocations (page table with unused entries) // allocations (page table with unused entries)
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct)); const uint64_t* pdpt = P2V(m_highest_paging_struct);
for (uint32_t pdpte = s_pdpte; pdpte < 4; pdpte++) for (; pdpte <= e_pdpte; pdpte++)
{ {
if (pdpte > e_pdpte)
break;
if (!(pdpt[pdpte] & Flags::Present)) if (!(pdpt[pdpte] & Flags::Present))
continue; continue;
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK)); const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
for (uint32_t pde = s_pde; pde < 512; pde++) for (; pde < 512; pde++)
{ {
if (pdpte == e_pdpte && pde > e_pde) if (pdpte == e_pdpte && pde > e_pde)
break; break;
if (!(pd[pde] & Flags::Present)) if (!(pd[pde] & Flags::Present))
continue; continue;
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK); const uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
for (uint32_t pte = s_pte; pte < 512; pte++) for (; pte < 512; pte++)
{ {
if (pdpte == e_pdpte && pde == e_pde && pte >= e_pte) if (pdpte == e_pdpte && pde == e_pde && pte > e_pte)
break; break;
if (!(pt[pte] & Flags::Used)) if (pt[pte] & Flags::Used)
{ continue;
vaddr_t vaddr = 0; vaddr_t vaddr = 0;
vaddr |= (vaddr_t)pdpte << 30; vaddr |= (vaddr_t)pdpte << 30;
vaddr |= (vaddr_t)pde << 21; vaddr |= (vaddr_t)pde << 21;
vaddr |= (vaddr_t)pte << 12; vaddr |= (vaddr_t)pte << 12;
ASSERT(reserve_page(vaddr)); ASSERT(reserve_page(vaddr));
return vaddr; return vaddr;
}
} }
pte = 0;
} }
pde = 0;
} }
// Find any free page // Find any free page
@@ -584,7 +658,7 @@ namespace Kernel
} }
} }
ASSERT_NOT_REACHED(); return 0;
} }
vaddr_t PageTable::reserve_free_contiguous_pages(size_t page_count, vaddr_t first_address, vaddr_t last_address) vaddr_t PageTable::reserve_free_contiguous_pages(size_t page_count, vaddr_t first_address, vaddr_t last_address)
@@ -617,7 +691,7 @@ namespace Kernel
} }
} }
ASSERT_NOT_REACHED(); return 0;
} }
static void dump_range(vaddr_t start, vaddr_t end, PageTable::flags_t flags) static void dump_range(vaddr_t start, vaddr_t end, PageTable::flags_t flags)
@@ -640,7 +714,7 @@ namespace Kernel
flags_t flags = 0; flags_t flags = 0;
vaddr_t start = 0; vaddr_t start = 0;
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct)); const uint64_t* pdpt = P2V(m_highest_paging_struct);
for (uint32_t pdpte = 0; pdpte < 4; pdpte++) for (uint32_t pdpte = 0; pdpte < 4; pdpte++)
{ {
if (!(pdpt[pdpte] & Flags::Present)) if (!(pdpt[pdpte] & Flags::Present))
@@ -649,7 +723,7 @@ namespace Kernel
start = 0; start = 0;
continue; continue;
} }
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK); const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
for (uint64_t pde = 0; pde < 512; pde++) for (uint64_t pde = 0; pde < 512; pde++)
{ {
if (!(pd[pde] & Flags::Present)) if (!(pd[pde] & Flags::Present))
@@ -658,7 +732,7 @@ namespace Kernel
start = 0; start = 0;
continue; continue;
} }
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK); const uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
for (uint64_t pte = 0; pte < 512; pte++) for (uint64_t pte = 0; pte < 512; pte++)
{ {
if (parse_flags(pt[pte]) != flags) if (parse_flags(pt[pte]) != flags)

View File

@@ -1,16 +1,41 @@
.section .userspace, "ax" .section .userspace, "ax"
// stack contains // stack contains
// return address // (4 bytes) return address (on return stack)
// signal number // (4 bytes) return stack
// signal handler // (4 bytes) return rflags
// (8 bytes) restore sigmask
// (36 bytes) siginfo_t
// (4 bytes) signal number
// (4 bytes) signal handler
.global signal_trampoline .global signal_trampoline
signal_trampoline: signal_trampoline:
pusha pushl %esi // gregs
pushl %edi
pushl %edx
pushl %ecx
pushl %ebx
pushl %eax
pushl %ebp
movl 40(%esp), %edi movl 80(%esp), %eax
movl 36(%esp), %eax pushl %eax; addl $4, (%esp)
pushl (%eax)
// FIXME: populate these
xorl %eax, %eax
pushl %eax // stack
pushl %eax
pushl %eax
pushl %eax // sigset
pushl %eax
pushl %eax // link
movl %esp, %edx // ucontext
leal 68(%esp), %esi // siginfo
movl 64(%esp), %edi // signal number
movl 60(%esp), %eax // handlers
// align stack to 16 bytes // align stack to 16 bytes
movl %esp, %ebp movl %esp, %ebp
@@ -19,7 +44,9 @@ signal_trampoline:
subl $512, %esp subl $512, %esp
fxsave (%esp) fxsave (%esp)
subl $12, %esp subl $4, %esp
pushl %edx
pushl %esi
pushl %edi pushl %edi
call *%eax call *%eax
addl $16, %esp addl $16, %esp
@@ -29,9 +56,31 @@ signal_trampoline:
// restore stack // restore stack
movl %ebp, %esp movl %ebp, %esp
popa addl $24, %esp
// restore sigmask
movl $83, %eax // SYS_SIGPROCMASK
movl $3, %ebx // SIG_SETMASK
leal 72(%esp), %ecx // set
xorl %edx, %edx // oset
int $0xF0
// restore registers
addl $8, %esp addl $8, %esp
popl %ebp
popl %eax
popl %ebx
popl %ecx
popl %edx
popl %edi
popl %esi
// skip handler, number, siginfo_t, sigmask
addl $52, %esp
// restore flags
popf popf
movl (%esp), %esp
ret ret

View File

@@ -1,12 +1,6 @@
// arguments in EAX, EBX, ECX, EDX, ESI, EDI // arguments in EAX, EBX, ECX, EDX, ESI, EDI
.global asm_syscall_handler .global asm_syscall_handler
asm_syscall_handler: asm_syscall_handler:
# save segment registers
pushw %ds
pushw %es
pushw %fs
pushw %gs
# save general purpose registers # save general purpose registers
pushl %ebx pushl %ebx
pushl %ecx pushl %ecx
@@ -18,13 +12,10 @@ asm_syscall_handler:
# align stack # align stack
movl %esp, %ebp movl %esp, %ebp
subl $15, %esp andl $-16, %esp
andl $0xFFFFFFF0, %esp
# push arguments # push arguments
subl $4, %esp subl $8, %esp
pushl %ebp
addl $32, (%esp)
pushl %edi pushl %edi
pushl %esi pushl %esi
pushl %edx pushl %edx
@@ -44,6 +35,15 @@ asm_syscall_handler:
movl %ebp, %esp movl %ebp, %esp
# restore userspace segments
movw $(0x20 | 3), %bx
movw %bx, %ds
movw %bx, %es
movw $(0x30 | 3), %bx
movw %bx, %fs
movw $(0x38 | 3), %bx
movw %bx, %gs
# restore general purpose registers # restore general purpose registers
popl %ebp popl %ebp
popl %esi popl %esi
@@ -52,12 +52,6 @@ asm_syscall_handler:
popl %ecx popl %ecx
popl %ebx popl %ebx
# restore segment registers
popw %gs
popw %fs
popw %es
popw %ds
iret iret
.global sys_fork_trampoline .global sys_fork_trampoline
@@ -69,7 +63,7 @@ sys_fork_trampoline:
call read_ip call read_ip
testl %eax, %eax testl %eax, %eax
jz .reload_stack jz .done
movl %esp, %ebx movl %esp, %ebx
@@ -85,9 +79,3 @@ sys_fork_trampoline:
popl %ebx popl %ebx
popl %ebp popl %ebp
ret ret
.reload_stack:
call get_thread_start_sp
movl %eax, %esp
xorl %eax, %eax
jmp .done

View File

@@ -7,9 +7,6 @@ read_ip:
# void start_kernel_thread() # void start_kernel_thread()
.global start_kernel_thread .global start_kernel_thread
start_kernel_thread: start_kernel_thread:
call get_thread_start_sp
movl %eax, %esp
# STACK LAYOUT # STACK LAYOUT
# on_exit arg # on_exit arg
# on_exit func # on_exit func
@@ -31,25 +28,15 @@ start_kernel_thread:
subl $12, %esp subl $12, %esp
pushl %edi pushl %edi
call *%esi call *%esi
addl $16, %esp
.global start_userspace_thread .global start_userspace_thread
start_userspace_thread: start_userspace_thread:
call load_thread_sse
call get_thread_start_sp
movl %eax, %esp
# ds, es = user data
movw $(0x20 | 3), %bx movw $(0x20 | 3), %bx
movw %bx, %ds movw %bx, %ds
movw %bx, %es movw %bx, %es
# gs = thread local
movw $(0x30 | 3), %bx movw $(0x30 | 3), %bx
movw %bx, %gs
# fs = 0
xorw %bx, %bx
movw %bx, %fs movw %bx, %fs
movw $(0x38 | 3), %bx
movw %bx, %gs
iret iret

54
kernel/arch/i686/User.S Normal file
View File

@@ -0,0 +1,54 @@
# bool safe_user_memcpy(void*, const void*, size_t)
.global safe_user_memcpy
.global safe_user_memcpy_end
.global safe_user_memcpy_fault
safe_user_memcpy:
xorl %eax, %eax
xchgl 4(%esp), %edi
xchgl 8(%esp), %esi
movl 12(%esp), %ecx
movl %edi, %edx
rep movsb
movl 4(%esp), %edi
movl 8(%esp), %esi
incl %eax
safe_user_memcpy_fault:
ret
safe_user_memcpy_end:
# bool safe_user_strncpy(void*, const void*, size_t)
.global safe_user_strncpy
.global safe_user_strncpy_end
.global safe_user_strncpy_fault
safe_user_strncpy:
xchgl 4(%esp), %edi
xchgl 8(%esp), %esi
movl 12(%esp), %ecx
testl %ecx, %ecx
jz safe_user_strncpy_fault
.safe_user_strncpy_loop:
movb (%esi), %al
movb %al, (%edi)
testb %al, %al
jz .safe_user_strncpy_done
incl %edi
incl %esi
decl %ecx
jnz .safe_user_strncpy_loop
safe_user_strncpy_fault:
xorl %eax, %eax
jmp .safe_user_strncpy_return
.safe_user_strncpy_done:
movl $1, %eax
.safe_user_strncpy_return:
movl 4(%esp), %edi
movl 8(%esp), %esi
ret
safe_user_strncpy_end:

25
kernel/arch/i686/Yield.S Normal file
View File

@@ -0,0 +1,25 @@
.global asm_yield_trampoline
asm_yield_trampoline:
leal 4(%esp), %ecx
movl 4(%esp), %esp
pushl -4(%ecx)
pushl %ecx
pushl %eax
pushl %ebx
pushl %esi
pushl %edi
pushl %ebp
pushl %esp
call scheduler_on_yield
addl $4, %esp
popl %ebp
popl %edi
popl %esi
popl %ebx
popl %eax
movl 4(%esp), %ecx
movl 0(%esp), %esp
jmp *%ecx

View File

@@ -11,9 +11,28 @@
.code32 .code32
# multiboot2 header // video mode info, page align modules
.set multiboot_flags, (1 << 2) | (1 << 0)
.section .multiboot, "aw" .section .multiboot, "aw"
.align 8 multiboot_start:
.long 0x1BADB002
.long multiboot_flags
.long -(0x1BADB002 + multiboot_flags)
.long 0
.long 0
.long 0
.long 0
.long 0
.long 0
.long FB_WIDTH
.long FB_HEIGHT
.long FB_BPP
multiboot_end:
.section .multiboot2, "aw"
multiboot2_start: multiboot2_start:
.long 0xE85250D6 .long 0xE85250D6
.long 0 .long 0
@@ -49,7 +68,6 @@ multiboot2_start:
multiboot2_end: multiboot2_end:
.section .bananboot, "aw" .section .bananboot, "aw"
.align 8
bananboot_start: bananboot_start:
.long 0xBABAB007 .long 0xBABAB007
.long -(0xBABAB007 + FB_WIDTH + FB_HEIGHT + FB_BPP) .long -(0xBABAB007 + FB_WIDTH + FB_HEIGHT + FB_BPP)
@@ -167,6 +185,13 @@ enable_sse:
movl %eax, %cr4 movl %eax, %cr4
ret ret
enable_tsc:
# allow userspace to use RDTSC
movl %cr4, %ecx
andl $0xFFFFFFFB, %ecx
movl %ecx, %cr4
ret
initialize_paging: initialize_paging:
# enable PAE # enable PAE
movl %cr4, %ecx movl %cr4, %ecx
@@ -209,6 +234,7 @@ gdt_flush:
# do processor initialization # do processor initialization
call check_requirements call check_requirements
call enable_sse call enable_sse
call enable_tsc
call initialize_paging call initialize_paging
# load higher half stack pointer # load higher half stack pointer
@@ -285,6 +311,7 @@ ap_protected_mode:
movb $1, AP_V2P(ap_stack_loaded) movb $1, AP_V2P(ap_stack_loaded)
leal V2P(enable_sse), %ecx; call *%ecx leal V2P(enable_sse), %ecx; call *%ecx
leal V2P(enable_tsc), %ecx; call *%ecx
leal V2P(initialize_paging), %ecx; call *%ecx leal V2P(initialize_paging), %ecx; call *%ecx
# load boot gdt and enter long mode # load boot gdt and enter long mode

View File

@@ -1,66 +1,67 @@
.macro push_userspace .macro intr_header, n
pushw %gs
pushw %fs
pushw %es
pushw %ds
pushal pushal
.endm testb $3, \n+8*4(%esp)
jz 1f
.macro load_kernel_segments
movw $0x10, %ax movw $0x10, %ax
movw %ax, %ds movw %ax, %ds
movw %ax, %es movw %ax, %es
movw %ax, %fs movw %ax, %fs
movw $0x28, %ax movw $0x28, %ax
movw %ax, %gs movw %ax, %gs
1: cld
.endm .endm
.macro pop_userspace .macro intr_footer, n
popal testb $3, \n+8*4(%esp)
popw %ds jz 1f
popw %es call cpp_check_signal
popw %fs movw $(0x20 | 3), %bx
popw %gs movw %bx, %ds
movw %bx, %es
movw $(0x30 | 3), %bx
movw %bx, %fs
movw $(0x38 | 3), %bx
movw %bx, %gs
1: popal
.endm .endm
isr_stub: isr_stub:
push_userspace intr_header 12
load_kernel_segments
cld
movl %cr0, %eax; pushl %eax movl %cr0, %eax; pushl %eax
movl %cr2, %eax; pushl %eax movl %cr2, %eax; pushl %eax
movl %cr3, %eax; pushl %eax movl %cr3, %eax; pushl %eax
movl %cr4, %eax; pushl %eax movl %cr4, %eax; pushl %eax
movl %esp, %eax // register ptr movl 48(%esp), %edi // isr number
leal 64(%esp), %ebx // interrupt stack ptr movl 52(%esp), %esi // error code
movl 60(%esp), %ecx // error code leal 56(%esp), %edx // interrupt stack ptr
movl 56(%esp), %edx // isr number movl %esp, %ecx // register ptr
# stack frame for stack trace
leal 56(%esp), %eax
pushl (%eax)
pushl %ebp
movl %esp, %ebp movl %esp, %ebp
andl $-16, %esp andl $-16, %esp
pushl %eax
pushl %ebx
pushl %ecx pushl %ecx
pushl %edx pushl %edx
pushl %esi
pushl %edi
call cpp_isr_handler call cpp_isr_handler
movl %ebp, %esp movl %ebp, %esp
addl $16, %esp addl $24, %esp
pop_userspace intr_footer 12
addl $8, %esp addl $8, %esp
iret iret
irq_stub: irq_stub:
push_userspace intr_header 12
load_kernel_segments
cld
movl 40(%esp), %edi # interrupt number movl 32(%esp), %edi # interrupt number
movl %esp, %ebp movl %esp, %ebp
andl $-16, %esp andl $-16, %esp
@@ -71,37 +72,13 @@ irq_stub:
movl %ebp, %esp movl %ebp, %esp
pop_userspace intr_footer 12
addl $8, %esp addl $8, %esp
iret iret
.global asm_yield_handler
asm_yield_handler:
# This can only be called from kernel, so no segment saving is needed
pushal
cld
leal 32(%esp), %edi # interrupt stack ptr
movl %esp, %esi # interrupt registers ptr
movl %esp, %ebp
andl $-16, %esp
subl $8, %esp
pushl %esi
pushl %edi
call cpp_yield_handler
movl %ebp, %esp
popal
iret
.global asm_ipi_handler .global asm_ipi_handler
asm_ipi_handler: asm_ipi_handler:
push_userspace intr_header 4
load_kernel_segments
cld
movl %esp, %ebp movl %esp, %ebp
andl $-16, %esp andl $-16, %esp
@@ -110,14 +87,12 @@ asm_ipi_handler:
movl %ebp, %esp movl %ebp, %esp
pop_userspace intr_footer 4
iret iret
.global asm_timer_handler .global asm_timer_handler
asm_timer_handler: asm_timer_handler:
push_userspace intr_header 4
load_kernel_segments
cld
movl %esp, %ebp movl %esp, %ebp
andl $-16, %esp andl $-16, %esp
@@ -126,7 +101,7 @@ asm_timer_handler:
movl %ebp, %esp movl %ebp, %esp
pop_userspace intr_footer 4
iret iret
.macro isr n .macro isr n

View File

@@ -11,6 +11,7 @@ SECTIONS
{ {
g_kernel_execute_start = .; g_kernel_execute_start = .;
*(.multiboot) *(.multiboot)
*(.multiboot2)
*(.bananboot) *(.bananboot)
*(.text.*) *(.text.*)
} }

View File

@@ -23,7 +23,7 @@ namespace Kernel
SpinLock PageTable::s_fast_page_lock; SpinLock PageTable::s_fast_page_lock;
static constexpr vaddr_t s_hhdm_offset = 0xFFFF800000000000; static constexpr vaddr_t s_hhdm_offset = 0xFFFF800000000000;
static bool s_is_hddm_initialized = false; static bool s_is_post_heap_done = false;
constexpr uint64_t s_page_flag_mask = 0x8000000000000FFF; constexpr uint64_t s_page_flag_mask = 0x8000000000000FFF;
constexpr uint64_t s_page_addr_mask = ~s_page_flag_mask; constexpr uint64_t s_page_addr_mask = ~s_page_flag_mask;
@@ -376,7 +376,7 @@ namespace Kernel
V2P = &FuncsHHDM::V2P; V2P = &FuncsHHDM::V2P;
P2V = &FuncsHHDM::P2V; P2V = &FuncsHHDM::P2V;
s_is_hddm_initialized = true; s_is_post_heap_done = true;
// This is a hack to unmap fast page. fast page pt is copied // This is a hack to unmap fast page. fast page pt is copied
// while it is mapped, so we need to manually unmap it // while it is mapped, so we need to manually unmap it
@@ -485,6 +485,7 @@ namespace Kernel
constexpr uint64_t pml4e = (uc_vaddr >> 39) & 0x1FF; constexpr uint64_t pml4e = (uc_vaddr >> 39) & 0x1FF;
constexpr uint64_t pdpte = (uc_vaddr >> 30) & 0x1FF; constexpr uint64_t pdpte = (uc_vaddr >> 30) & 0x1FF;
constexpr uint64_t pde = (uc_vaddr >> 21) & 0x1FF; constexpr uint64_t pde = (uc_vaddr >> 21) & 0x1FF;
constexpr uint64_t pte = (uc_vaddr >> 12) & 0x1FF;
uint64_t* pml4 = P2V(m_highest_paging_struct); uint64_t* pml4 = P2V(m_highest_paging_struct);
ASSERT(!(pml4[pml4e] & Flags::Present)); ASSERT(!(pml4[pml4e] & Flags::Present));
@@ -497,6 +498,10 @@ namespace Kernel
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask); uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
ASSERT(!(pd[pde] & Flags::Present)); ASSERT(!(pd[pde] & Flags::Present));
pd[pde] = allocate_zeroed_page_aligned_page() | Flags::ReadWrite | Flags::Present; pd[pde] = allocate_zeroed_page_aligned_page() | Flags::ReadWrite | Flags::Present;
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
ASSERT(pt[pte] == 0);
pt[pte] = Flags::Reserved;
} }
void PageTable::map_fast_page(paddr_t paddr) void PageTable::map_fast_page(paddr_t paddr)
@@ -521,7 +526,7 @@ namespace Kernel
ASSERT(!(pt[pte] & Flags::Present)); ASSERT(!(pt[pte] & Flags::Present));
pt[pte] = paddr | Flags::ReadWrite | Flags::Present; pt[pte] = paddr | Flags::ReadWrite | Flags::Present;
invalidate(fast_page(), false); asm volatile("invlpg (%0)" :: "r"(fast_page()) : "memory");
} }
void PageTable::unmap_fast_page() void PageTable::unmap_fast_page()
@@ -542,9 +547,9 @@ namespace Kernel
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask); uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
ASSERT(pt[pte] & Flags::Present); ASSERT(pt[pte] & Flags::Present);
pt[pte] = 0; pt[pte] = Flags::Reserved;
invalidate(fast_page(), false); asm volatile("invlpg (%0)" :: "r"(fast_page()) : "memory");
} }
BAN::ErrorOr<PageTable*> PageTable::create_userspace() BAN::ErrorOr<PageTable*> PageTable::create_userspace()
@@ -612,10 +617,39 @@ namespace Kernel
Processor::set_current_page_table(this); Processor::set_current_page_table(this);
} }
void PageTable::invalidate(vaddr_t vaddr, bool send_smp_message) void PageTable::invalidate_range(vaddr_t vaddr, size_t pages, bool send_smp_message)
{ {
ASSERT(vaddr % PAGE_SIZE == 0); ASSERT(vaddr % PAGE_SIZE == 0);
asm volatile("invlpg (%0)" :: "r"(vaddr) : "memory");
const bool is_userspace = (vaddr < KERNEL_OFFSET);
if (is_userspace && this != &PageTable::current())
;
else if (pages <= 32 || !s_is_post_heap_done)
{
for (size_t i = 0; i < pages; i++, vaddr += PAGE_SIZE)
asm volatile("invlpg (%0)" :: "r"(vaddr));
}
else if (is_userspace || !s_has_pge)
{
asm volatile("movq %0, %%cr3" :: "r"(m_highest_paging_struct));
}
else
{
asm volatile(
"movq %%cr4, %%rax;"
"andq $~0x80, %%rax;"
"movq %%rax, %%cr4;"
"movq %0, %%cr3;"
"orq $0x80, %%rax;"
"movq %%rax, %%cr4;"
:
: "r"(m_highest_paging_struct)
: "rax"
);
}
if (send_smp_message) if (send_smp_message)
{ {
@@ -623,13 +657,14 @@ namespace Kernel
.type = Processor::SMPMessage::Type::FlushTLB, .type = Processor::SMPMessage::Type::FlushTLB,
.flush_tlb = { .flush_tlb = {
.vaddr = vaddr, .vaddr = vaddr,
.page_count = 1 .page_count = pages,
.page_table = vaddr < KERNEL_OFFSET ? this : nullptr,
} }
}); });
} }
} }
void PageTable::unmap_page(vaddr_t vaddr, bool send_smp_message) void PageTable::unmap_page(vaddr_t vaddr, bool invalidate)
{ {
ASSERT(vaddr); ASSERT(vaddr);
ASSERT(vaddr != fast_page()); ASSERT(vaddr != fast_page());
@@ -658,30 +693,27 @@ namespace Kernel
uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask); uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask); uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
const paddr_t old_paddr = pt[pte] & PAGE_ADDR_MASK;
pt[pte] = 0; pt[pte] = 0;
invalidate(vaddr, send_smp_message);
if (invalidate && old_paddr != 0)
invalidate_page(vaddr, true);
} }
void PageTable::unmap_range(vaddr_t vaddr, size_t size) void PageTable::unmap_range(vaddr_t vaddr, size_t size)
{ {
ASSERT(vaddr % PAGE_SIZE == 0); ASSERT(vaddr % PAGE_SIZE == 0);
size_t page_count = range_page_count(vaddr, size); const size_t page_count = range_page_count(vaddr, size);
SpinLockGuard _(m_lock); SpinLockGuard _(m_lock);
for (vaddr_t page = 0; page < page_count; page++) for (vaddr_t page = 0; page < page_count; page++)
unmap_page(vaddr + page * PAGE_SIZE, false); unmap_page(vaddr + page * PAGE_SIZE, false);
invalidate_range(vaddr, page_count, true);
Processor::broadcast_smp_message({
.type = Processor::SMPMessage::Type::FlushTLB,
.flush_tlb = {
.vaddr = vaddr,
.page_count = page_count
}
});
} }
void PageTable::map_page_at(paddr_t paddr, vaddr_t vaddr, flags_t flags, MemoryType memory_type, bool send_smp_message) void PageTable::map_page_at(paddr_t paddr, vaddr_t vaddr, flags_t flags, MemoryType memory_type, bool invalidate)
{ {
ASSERT(vaddr); ASSERT(vaddr);
ASSERT(vaddr != fast_page()); ASSERT(vaddr != fast_page());
@@ -742,9 +774,12 @@ namespace Kernel
if (!(flags & Flags::Present)) if (!(flags & Flags::Present))
uwr_flags &= ~Flags::Present; uwr_flags &= ~Flags::Present;
const paddr_t old_paddr = pt[pte] & PAGE_ADDR_MASK;
pt[pte] = paddr | uwr_flags | extra_flags; pt[pte] = paddr | uwr_flags | extra_flags;
invalidate(vaddr, send_smp_message); if (invalidate && old_paddr != 0)
invalidate_page(vaddr, true);
} }
void PageTable::map_range_at(paddr_t paddr, vaddr_t vaddr, size_t size, flags_t flags, MemoryType memory_type) void PageTable::map_range_at(paddr_t paddr, vaddr_t vaddr, size_t size, flags_t flags, MemoryType memory_type)
@@ -760,14 +795,66 @@ namespace Kernel
SpinLockGuard _(m_lock); SpinLockGuard _(m_lock);
for (size_t page = 0; page < page_count; page++) for (size_t page = 0; page < page_count; page++)
map_page_at(paddr + page * PAGE_SIZE, vaddr + page * PAGE_SIZE, flags, memory_type, false); map_page_at(paddr + page * PAGE_SIZE, vaddr + page * PAGE_SIZE, flags, memory_type, false);
invalidate_range(vaddr, page_count, true);
}
Processor::broadcast_smp_message({ void PageTable::remove_writable_from_range(vaddr_t vaddr, size_t size)
.type = Processor::SMPMessage::Type::FlushTLB, {
.flush_tlb = { ASSERT(vaddr);
.vaddr = vaddr, ASSERT(vaddr % PAGE_SIZE == 0);
.page_count = page_count
ASSERT(is_canonical(vaddr));
ASSERT(is_canonical(vaddr + size - 1));
const vaddr_t uc_vaddr_start = uncanonicalize(vaddr);
const vaddr_t uc_vaddr_end = uncanonicalize(vaddr + size - 1);
uint16_t pml4e = (uc_vaddr_start >> 39) & 0x1FF;
uint16_t pdpte = (uc_vaddr_start >> 30) & 0x1FF;
uint16_t pde = (uc_vaddr_start >> 21) & 0x1FF;
uint16_t pte = (uc_vaddr_start >> 12) & 0x1FF;
const uint16_t e_pml4e = (uc_vaddr_end >> 39) & 0x1FF;
const uint16_t e_pdpte = (uc_vaddr_end >> 30) & 0x1FF;
const uint16_t e_pde = (uc_vaddr_end >> 21) & 0x1FF;
const uint16_t e_pte = (uc_vaddr_end >> 12) & 0x1FF;
SpinLockGuard _(m_lock);
const uint64_t* pml4 = P2V(m_highest_paging_struct);
for (; pml4e <= e_pml4e; pml4e++)
{
if (!(pml4[pml4e] & Flags::ReadWrite))
continue;
const uint64_t* pdpt = P2V(pml4[pml4e] & s_page_addr_mask);
for (; pdpte < 512; pdpte++)
{
if (pml4e == e_pml4e && pdpte > e_pdpte)
break;
if (!(pdpt[pdpte] & Flags::ReadWrite))
continue;
const uint64_t* pd = P2V(pdpt[pdpte] & s_page_addr_mask);
for (; pde < 512; pde++)
{
if (pml4e == e_pml4e && pdpte == e_pdpte && pde > e_pde)
break;
if (!(pd[pde] & Flags::ReadWrite))
continue;
uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
for (; pte < 512; pte++)
{
if (pml4e == e_pml4e && pdpte == e_pdpte && pde == e_pde && pte > e_pte)
break;
pt[pte] &= ~static_cast<uint64_t>(Flags::ReadWrite);
}
pte = 0;
}
pde = 0;
} }
}); pdpte = 0;
}
invalidate_range(vaddr, size / PAGE_SIZE, true);
} }
uint64_t PageTable::get_page_data(vaddr_t vaddr) const uint64_t PageTable::get_page_data(vaddr_t vaddr) const
@@ -814,13 +901,13 @@ namespace Kernel
return page_data & s_page_addr_mask; return page_data & s_page_addr_mask;
} }
bool PageTable::reserve_page(vaddr_t vaddr, bool only_free) bool PageTable::reserve_page(vaddr_t vaddr, bool only_free, bool invalidate)
{ {
SpinLockGuard _(m_lock); SpinLockGuard _(m_lock);
ASSERT(vaddr % PAGE_SIZE == 0); ASSERT(vaddr % PAGE_SIZE == 0);
if (only_free && !is_page_free(vaddr)) if (only_free && !is_page_free(vaddr))
return false; return false;
map_page_at(0, vaddr, Flags::Reserved); map_page_at(0, vaddr, Flags::Reserved, MemoryType::Normal, invalidate);
return true; return true;
} }
@@ -834,7 +921,8 @@ namespace Kernel
if (only_free && !is_range_free(vaddr, bytes)) if (only_free && !is_range_free(vaddr, bytes))
return false; return false;
for (size_t offset = 0; offset < bytes; offset += PAGE_SIZE) for (size_t offset = 0; offset < bytes; offset += PAGE_SIZE)
reserve_page(vaddr + offset); reserve_page(vaddr + offset, true, false);
invalidate_range(vaddr, bytes / PAGE_SIZE, true);
return true; return true;
} }
@@ -848,9 +936,9 @@ namespace Kernel
last_address -= rem; last_address -= rem;
ASSERT(is_canonical(first_address)); ASSERT(is_canonical(first_address));
ASSERT(is_canonical(last_address)); ASSERT(is_canonical(last_address - 1));
const vaddr_t uc_vaddr_start = uncanonicalize(first_address); const vaddr_t uc_vaddr_start = uncanonicalize(first_address);
const vaddr_t uc_vaddr_end = uncanonicalize(last_address); const vaddr_t uc_vaddr_end = uncanonicalize(last_address - 1);
uint16_t pml4e = (uc_vaddr_start >> 39) & 0x1FF; uint16_t pml4e = (uc_vaddr_start >> 39) & 0x1FF;
uint16_t pdpte = (uc_vaddr_start >> 30) & 0x1FF; uint16_t pdpte = (uc_vaddr_start >> 30) & 0x1FF;
@@ -867,10 +955,8 @@ namespace Kernel
// Try to find free page that can be mapped without // Try to find free page that can be mapped without
// allocations (page table with unused entries) // allocations (page table with unused entries)
const uint64_t* pml4 = P2V(m_highest_paging_struct); const uint64_t* pml4 = P2V(m_highest_paging_struct);
for (; pml4e < 512; pml4e++) for (; pml4e <= e_pml4e; pml4e++)
{ {
if (pml4e > e_pml4e)
break;
if (!(pml4[pml4e] & Flags::Present)) if (!(pml4[pml4e] & Flags::Present))
continue; continue;
const uint64_t* pdpt = P2V(pml4[pml4e] & s_page_addr_mask); const uint64_t* pdpt = P2V(pml4[pml4e] & s_page_addr_mask);
@@ -890,22 +976,24 @@ namespace Kernel
const uint64_t* pt = P2V(pd[pde] & s_page_addr_mask); const uint64_t* pt = P2V(pd[pde] & s_page_addr_mask);
for (; pte < 512; pte++) for (; pte < 512; pte++)
{ {
if (pml4e == e_pml4e && pdpte == e_pdpte && pde == e_pde && pte >= e_pte) if (pml4e == e_pml4e && pdpte == e_pdpte && pde == e_pde && pte > e_pte)
break; break;
if (!(pt[pte] & Flags::Used)) if (pt[pte] & Flags::Used)
{ continue;
vaddr_t vaddr = 0; vaddr_t vaddr = 0;
vaddr |= static_cast<uint64_t>(pml4e) << 39; vaddr |= static_cast<uint64_t>(pml4e) << 39;
vaddr |= static_cast<uint64_t>(pdpte) << 30; vaddr |= static_cast<uint64_t>(pdpte) << 30;
vaddr |= static_cast<uint64_t>(pde) << 21; vaddr |= static_cast<uint64_t>(pde) << 21;
vaddr |= static_cast<uint64_t>(pte) << 12; vaddr |= static_cast<uint64_t>(pte) << 12;
vaddr = canonicalize(vaddr); vaddr = canonicalize(vaddr);
ASSERT(reserve_page(vaddr)); ASSERT(reserve_page(vaddr));
return vaddr; return vaddr;
}
} }
pte = 0;
} }
pde = 0;
} }
pdpte = 0;
} }
for (vaddr_t uc_vaddr = uc_vaddr_start; uc_vaddr < uc_vaddr_end; uc_vaddr += PAGE_SIZE) for (vaddr_t uc_vaddr = uc_vaddr_start; uc_vaddr < uc_vaddr_end; uc_vaddr += PAGE_SIZE)
@@ -917,7 +1005,7 @@ namespace Kernel
} }
} }
ASSERT_NOT_REACHED(); return 0;
} }
vaddr_t PageTable::reserve_free_contiguous_pages(size_t page_count, vaddr_t first_address, vaddr_t last_address) vaddr_t PageTable::reserve_free_contiguous_pages(size_t page_count, vaddr_t first_address, vaddr_t last_address)
@@ -930,7 +1018,7 @@ namespace Kernel
last_address -= rem; last_address -= rem;
ASSERT(is_canonical(first_address)); ASSERT(is_canonical(first_address));
ASSERT(is_canonical(last_address)); ASSERT(is_canonical(last_address - 1));
SpinLockGuard _(m_lock); SpinLockGuard _(m_lock);
@@ -959,7 +1047,7 @@ namespace Kernel
} }
} }
ASSERT_NOT_REACHED(); return 0;
} }
bool PageTable::is_page_free(vaddr_t page) const bool PageTable::is_page_free(vaddr_t page) const

View File

@@ -1,30 +1,48 @@
.section .userspace, "ax" .section .userspace, "ax"
// stack contains // stack contains
// return address // (8 bytes) return address (on return stack)
// signal number // (8 bytes) return stack
// signal handler // (8 bytes) return rflags
// (8 bytes) restore sigmask
// (56 bytes) siginfo_t
// (8 bytes) signal number
// (8 bytes) signal handler
.global signal_trampoline .global signal_trampoline
signal_trampoline: signal_trampoline:
pushq %rax pushq %r15 // gregs
pushq %rbx
pushq %rcx
pushq %rdx
pushq %rbp
pushq %rdi
pushq %rsi
pushq %r8
pushq %r9
pushq %r10
pushq %r11
pushq %r12
pushq %r13
pushq %r14 pushq %r14
pushq %r15 pushq %r13
pushq %r12
pushq %r11
pushq %r10
pushq %r9
pushq %r8
pushq %rsi
pushq %rdi
pushq %rdx
pushq %rcx
pushq %rbx
pushq %rax
pushq %rbp
movq 128(%rsp), %rdi movq 208(%rsp), %rax
movq 120(%rsp), %rax pushq %rax; addq $(128 + 8), (%rsp)
pushq (%rax)
// FIXME: populate these
xorq %rax, %rax
pushq %rax // stack
pushq %rax
pushq %rax
pushq %rax // sigset
pushq %rax // link
movq %rsp, %rdx // ucontext
leaq 192(%rsp), %rsi // siginfo
movq 184(%rsp), %rdi // signal number
movq 176(%rsp), %rax // handler
// align stack to 16 bytes // align stack to 16 bytes
movq %rsp, %rbp movq %rsp, %rbp
@@ -40,24 +58,40 @@ signal_trampoline:
// restore stack // restore stack
movq %rbp, %rsp movq %rbp, %rsp
popq %r15 addq $40, %rsp
popq %r14
popq %r13
popq %r12
popq %r11
popq %r10
popq %r9
popq %r8
popq %rsi
popq %rdi
popq %rbp
popq %rdx
popq %rcx
popq %rbx
popq %rax
// restore sigmask
movq $83, %rdi // SYS_SIGPROCMASK
movq $3, %rsi // SIG_SETMASK
leaq 192(%rsp), %rdx // set
xorq %r10, %r10 // oset
syscall
// restore registers
addq $16, %rsp addq $16, %rsp
popq %rbp
popq %rax
popq %rbx
popq %rcx
popq %rdx
popq %rdi
popq %rsi
popq %r8
popq %r9
popq %r10
popq %r11
popq %r12
popq %r13
popq %r14
popq %r15
// skip handler, number, siginfo_t, sigmask
addq $80, %rsp
// restore flags
popfq popfq
movq (%rsp), %rsp
// return over red-zone // return over red-zone
ret $128 ret $128

View File

@@ -1,49 +1,26 @@
// arguments in RAX, RBX, RCX, RDX, RSI, RDI
// System V ABI: RDI, RSI, RDX, RCX, R8, R9
.global asm_syscall_handler .global asm_syscall_handler
asm_syscall_handler: asm_syscall_handler:
pushq %rbx swapgs
pushq %rcx
pushq %rdx movq %rsp, %rax
pushq %rdi movq %gs:8, %rsp
pushq %rsi
pushq %rbp pushq $(0x20 | 3)
pushq %r8 pushq %rax
pushq %r9
pushq %r10
pushq %r11 pushq %r11
pushq %r12 pushq $(0x28 | 3)
pushq %r13 pushq %rcx
pushq %r14 subq $8, %rsp
pushq %r15
cld
movq %rsi, %r8 movq %r10, %rcx
movq %rdi, %r9
movq %rax, %rdi
movq %rbx, %rsi
xchgq %rcx, %rdx
leaq 112(%rsp), %rbx
pushq %rbx
call cpp_syscall_handler call cpp_syscall_handler
addq $8, %rsp
popq %r15 movq 8(%rsp), %rcx
popq %r14 movq 24(%rsp), %r11
popq %r13 movq 32(%rsp), %rsp
popq %r12
popq %r11
popq %r10
popq %r9
popq %r8
popq %rbp
popq %rsi
popq %rdi
popq %rdx
popq %rcx
popq %rbx
iretq
swapgs
sysretq
.global sys_fork_trampoline .global sys_fork_trampoline
sys_fork_trampoline: sys_fork_trampoline:
@@ -56,7 +33,7 @@ sys_fork_trampoline:
call read_ip call read_ip
testq %rax, %rax testq %rax, %rax
je .reload_stack jz .done
movq %rax, %rsi movq %rax, %rsi
movq %rsp, %rdi movq %rsp, %rdi
@@ -70,9 +47,3 @@ sys_fork_trampoline:
popq %rbp popq %rbp
popq %rbx popq %rbx
ret ret
.reload_stack:
call get_thread_start_sp
movq %rax, %rsp
xorq %rax, %rax
jmp .done

View File

@@ -7,9 +7,6 @@ read_ip:
# void start_kernel_thread() # void start_kernel_thread()
.global start_kernel_thread .global start_kernel_thread
start_kernel_thread: start_kernel_thread:
call get_thread_start_sp
movq %rax, %rsp
# STACK LAYOUT # STACK LAYOUT
# on_exit arg # on_exit arg
# on_exit func # on_exit func
@@ -27,9 +24,5 @@ start_kernel_thread:
.global start_userspace_thread .global start_userspace_thread
start_userspace_thread: start_userspace_thread:
call load_thread_sse swapgs
call get_thread_start_sp
movq %rax, %rsp
iretq iretq

87
kernel/arch/x86_64/User.S Normal file
View File

@@ -0,0 +1,87 @@
# bool safe_user_memcpy(void*, const void*, size_t)
.global safe_user_memcpy
.global safe_user_memcpy_end
.global safe_user_memcpy_fault
safe_user_memcpy:
xorq %rax, %rax
movq %rdx, %rcx
rep movsb
incq %rax
safe_user_memcpy_fault:
ret
safe_user_memcpy_end:
# bool safe_user_strncpy(void*, const void*, size_t)
.global safe_user_strncpy
.global safe_user_strncpy_end
.global safe_user_strncpy_fault
safe_user_strncpy:
movq %rdx, %rcx
testq %rcx, %rcx
jz safe_user_strncpy_fault
.safe_user_strncpy_align_loop:
testb $0x7, %sil
jz .safe_user_strncpy_align_done
movb (%rsi), %al
movb %al, (%rdi)
testb %al, %al
jz .safe_user_strncpy_done
incq %rdi
incq %rsi
decq %rcx
jnz .safe_user_strncpy_align_loop
jmp safe_user_strncpy_fault
.safe_user_strncpy_align_done:
movq $0x0101010101010101, %r8
movq $0x8080808080808080, %r9
.safe_user_strncpy_qword_loop:
cmpq $8, %rcx
jb .safe_user_strncpy_qword_done
movq (%rsi), %rax
movq %rax, %r10
movq %rax, %r11
# https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
subq %r8, %r10
notq %r11
andq %r11, %r10
andq %r9, %r10
jnz .safe_user_strncpy_byte_loop
movq %rax, (%rdi)
addq $8, %rdi
addq $8, %rsi
subq $8, %rcx
jnz .safe_user_strncpy_qword_loop
jmp safe_user_strncpy_fault
.safe_user_strncpy_qword_done:
testq %rcx, %rcx
jz safe_user_strncpy_fault
.safe_user_strncpy_byte_loop:
movb (%rsi), %al
movb %al, (%rdi)
testb %al, %al
jz .safe_user_strncpy_done
incq %rdi
incq %rsi
decq %rcx
jnz .safe_user_strncpy_byte_loop
safe_user_strncpy_fault:
xorq %rax, %rax
ret
.safe_user_strncpy_done:
movb $1, %al
ret
safe_user_strncpy_end:

View File

@@ -0,0 +1,29 @@
.global asm_yield_trampoline
asm_yield_trampoline:
leaq 8(%rsp), %rcx
movq %rdi, %rsp
subq $8, %rsp
pushq -8(%rcx)
pushq %rcx
pushq %rax
pushq %rbx
pushq %rbp
pushq %r12
pushq %r13
pushq %r14
pushq %r15
movq %rsp, %rdi
call scheduler_on_yield
popq %r15
popq %r14
popq %r13
popq %r12
popq %rbp
popq %rbx
popq %rax
movq 8(%rsp), %rcx
movq 0(%rsp), %rsp
jmp *%rcx

View File

@@ -11,9 +11,28 @@
.code32 .code32
# multiboot2 header // custom addresses, video mode info, page align modules
.set multiboot_flags, (1 << 16) | (1 << 2) | (1 << 0)
.section .multiboot, "aw" .section .multiboot, "aw"
.align 8 multiboot_start:
.long 0x1BADB002
.long multiboot_flags
.long -(0x1BADB002 + multiboot_flags)
.long V2P(multiboot_start)
.long V2P(g_kernel_start)
.long V2P(g_kernel_bss_start)
.long V2P(g_kernel_end)
.long V2P(_start)
.long 0
.long FB_WIDTH
.long FB_HEIGHT
.long FB_BPP
multiboot_end:
.section .multiboot2, "aw"
multiboot2_start: multiboot2_start:
.long 0xE85250D6 .long 0xE85250D6
.long 0 .long 0
@@ -49,7 +68,6 @@ multiboot2_start:
multiboot2_end: multiboot2_end:
.section .bananboot, "aw" .section .bananboot, "aw"
.align 8
bananboot_start: bananboot_start:
.long 0xBABAB007 .long 0xBABAB007
.long -(0xBABAB007 + FB_WIDTH + FB_HEIGHT + FB_BPP) .long -(0xBABAB007 + FB_WIDTH + FB_HEIGHT + FB_BPP)
@@ -162,6 +180,13 @@ enable_sse:
movl %eax, %cr4 movl %eax, %cr4
ret ret
enable_tsc:
# allow userspace to use RDTSC
movl %cr4, %ecx
andl $0xFFFFFFFB, %ecx
movl %ecx, %cr4
ret
initialize_paging: initialize_paging:
# enable PAE # enable PAE
movl %cr4, %ecx movl %cr4, %ecx
@@ -198,6 +223,7 @@ _start:
call check_requirements call check_requirements
call enable_sse call enable_sse
call enable_tsc
call initialize_paging call initialize_paging
# flush gdt and jump to 64 bit # flush gdt and jump to 64 bit
@@ -284,6 +310,7 @@ ap_protected_mode:
movb $1, AP_V2P(ap_stack_loaded) movb $1, AP_V2P(ap_stack_loaded)
leal V2P(enable_sse), %ecx; call *%ecx leal V2P(enable_sse), %ecx; call *%ecx
leal V2P(enable_tsc), %ecx; call *%ecx
leal V2P(initialize_paging), %ecx; call *%ecx leal V2P(initialize_paging), %ecx; call *%ecx
# load boot gdt and enter long mode # load boot gdt and enter long mode

View File

@@ -1,4 +1,4 @@
.macro pushaq .macro intr_header, n
pushq %rax pushq %rax
pushq %rcx pushq %rcx
pushq %rdx pushq %rdx
@@ -14,10 +14,18 @@
pushq %r13 pushq %r13
pushq %r14 pushq %r14
pushq %r15 pushq %r15
testb $3, \n+15*8(%rsp)
jz 1f
swapgs
1: cld
.endm .endm
.macro popaq .macro intr_footer, n
popq %r15 testb $3, \n+15*8(%rsp)
jz 1f
call cpp_check_signal
swapgs
1: popq %r15
popq %r14 popq %r14
popq %r13 popq %r13
popq %r12 popq %r12
@@ -35,8 +43,7 @@
.endm .endm
isr_stub: isr_stub:
pushaq intr_header 24
cld
movq %cr0, %rax; pushq %rax movq %cr0, %rax; pushq %rax
movq %cr2, %rax; pushq %rax movq %cr2, %rax; pushq %rax
movq %cr3, %rax; pushq %rax movq %cr3, %rax; pushq %rax
@@ -49,43 +56,33 @@ isr_stub:
call cpp_isr_handler call cpp_isr_handler
addq $32, %rsp addq $32, %rsp
popaq intr_footer 24
addq $16, %rsp addq $16, %rsp
iretq iretq
irq_stub: irq_stub:
pushaq intr_header 24
cld xorq %rbp, %rbp
movq 120(%rsp), %rdi # irq number movq 120(%rsp), %rdi # irq number
call cpp_irq_handler call cpp_irq_handler
popaq intr_footer 24
addq $16, %rsp addq $16, %rsp
iretq iretq
.global asm_yield_handler
asm_yield_handler:
pushaq
cld
leaq 120(%rsp), %rdi # interrupt stack ptr
movq %rsp, %rsi # interrupt register ptr
call cpp_yield_handler
popaq
iretq
.global asm_ipi_handler .global asm_ipi_handler
asm_ipi_handler: asm_ipi_handler:
pushaq intr_header 8
cld xorq %rbp, %rbp
call cpp_ipi_handler call cpp_ipi_handler
popaq intr_footer 8
iretq iretq
.global asm_timer_handler .global asm_timer_handler
asm_timer_handler: asm_timer_handler:
pushaq intr_header 8
cld xorq %rbp, %rbp
call cpp_timer_handler call cpp_timer_handler
popaq intr_footer 8
iretq iretq
.macro isr n .macro isr n

View File

@@ -11,6 +11,7 @@ SECTIONS
{ {
g_kernel_execute_start = .; g_kernel_execute_start = .;
*(.multiboot) *(.multiboot)
*(.multiboot2)
*(.bananboot) *(.bananboot)
*(.text.*) *(.text.*)
} }
@@ -43,6 +44,7 @@ SECTIONS
} }
.bss ALIGN(4K) : AT(ADDR(.bss) - KERNEL_OFFSET) .bss ALIGN(4K) : AT(ADDR(.bss) - KERNEL_OFFSET)
{ {
g_kernel_bss_start = .;
*(COMMON) *(COMMON)
*(.bss) *(.bss)
g_kernel_writable_end = .; g_kernel_writable_end = .;

View File

@@ -2,6 +2,7 @@
#include <BAN/Vector.h> #include <BAN/Vector.h>
#include <kernel/ACPI/AML/Namespace.h> #include <kernel/ACPI/AML/Namespace.h>
#include <kernel/ACPI/EmbeddedController.h>
#include <kernel/ACPI/Headers.h> #include <kernel/ACPI/Headers.h>
#include <kernel/Memory/Types.h> #include <kernel/Memory/Types.h>
#include <kernel/ThreadBlocker.h> #include <kernel/ThreadBlocker.h>
@@ -35,8 +36,12 @@ namespace Kernel::ACPI
BAN::ErrorOr<void> poweroff(); BAN::ErrorOr<void> poweroff();
BAN::ErrorOr<void> reset(); BAN::ErrorOr<void> reset();
BAN::ErrorOr<void> register_gpe_handler(uint8_t gpe, void (*callback)(void*), void* argument);
void handle_irq() override; void handle_irq() override;
BAN::Span<BAN::UniqPtr<EmbeddedController>> embedded_controllers() { return m_embedded_controllers.span(); }
private: private:
ACPI() = default; ACPI() = default;
BAN::ErrorOr<void> initialize_impl(); BAN::ErrorOr<void> initialize_impl();
@@ -50,6 +55,12 @@ namespace Kernel::ACPI
BAN::ErrorOr<void> route_interrupt_link_device(const AML::Scope& device, uint64_t& routed_irq_mask); BAN::ErrorOr<void> route_interrupt_link_device(const AML::Scope& device, uint64_t& routed_irq_mask);
BAN::ErrorOr<void> initialize_embedded_controller(const AML::Scope& embedded_controller);
BAN::ErrorOr<void> initialize_embedded_controllers();
BAN::Optional<GAS> find_gpe_block(size_t index);
bool enable_gpe(uint8_t gpe);
private: private:
paddr_t m_header_table_paddr = 0; paddr_t m_header_table_paddr = 0;
vaddr_t m_header_table_vaddr = 0; vaddr_t m_header_table_vaddr = 0;
@@ -68,8 +79,23 @@ namespace Kernel::ACPI
ThreadBlocker m_event_thread_blocker; ThreadBlocker m_event_thread_blocker;
BAN::Vector<BAN::UniqPtr<EmbeddedController>> m_embedded_controllers;
struct GPEHandler
{
bool has_callback { false };
union {
AML::Reference* method;
struct
{
void (*callback)(void*);
void* argument;
};
};
};
bool m_has_any_gpes { false };
AML::Scope m_gpe_scope; AML::Scope m_gpe_scope;
BAN::Array<AML::Reference*, 0xFF> m_gpe_methods { nullptr }; BAN::Array<GPEHandler, 0xFF> m_gpe_methods;
bool m_hardware_reduced { false }; bool m_hardware_reduced { false };
AML::Namespace* m_namespace { nullptr }; AML::Namespace* m_namespace { nullptr };

View File

@@ -50,6 +50,7 @@ namespace Kernel::ACPI::AML
BAN::ErrorOr<void> for_each_child(const Scope&, const BAN::Function<BAN::Iteration(const Scope&, Reference*)>&); BAN::ErrorOr<void> for_each_child(const Scope&, const BAN::Function<BAN::Iteration(const Scope&, Reference*)>&);
BAN::ErrorOr<BAN::Vector<Scope>> find_device_with_eisa_id(BAN::StringView eisa_id); BAN::ErrorOr<BAN::Vector<Scope>> find_device_with_eisa_id(BAN::StringView eisa_id);
BAN::ErrorOr<BAN::Vector<Scope>> find_device_with_eisa_id(BAN::Span<BAN::StringView> eisa_ids);
private: private:
BAN::ErrorOr<Scope> resolve_path(const Scope& scope, const NameString& name_string); BAN::ErrorOr<Scope> resolve_path(const Scope& scope, const NameString& name_string);

View File

@@ -0,0 +1,69 @@
#pragma once
#include <BAN/Atomic.h>
#include <BAN/UniqPtr.h>
#include <kernel/ACPI/AML/Scope.h>
#include <kernel/Lock/Mutex.h>
#include <kernel/Thread.h>
namespace Kernel::ACPI
{
class EmbeddedController
{
public:
static BAN::ErrorOr<BAN::UniqPtr<EmbeddedController>> create(AML::Scope&& scope, uint16_t command_port, uint16_t data_port, BAN::Optional<uint8_t> gpe);
~EmbeddedController();
BAN::ErrorOr<uint8_t> read_byte(uint8_t offset);
BAN::ErrorOr<void> write_byte(uint8_t offset, uint8_t value);
const AML::Scope& scope() const { return m_scope; }
private:
EmbeddedController(AML::Scope&& scope, uint16_t command_port, uint16_t data_port, bool has_gpe)
: m_scope(BAN::move(scope))
, m_command_port(command_port)
, m_data_port(data_port)
, m_has_gpe(has_gpe)
{ }
private:
void wait_status_bit(uint8_t bit, uint8_t value);
uint8_t read_one(uint16_t port);
void write_one(uint16_t port, uint8_t value);
static void handle_gpe_wrapper(void*);
void handle_gpe();
BAN::ErrorOr<void> call_query_method(uint8_t notification);
void thread_task();
struct Command
{
uint8_t command;
BAN::Optional<uint8_t> data1;
BAN::Optional<uint8_t> data2;
uint8_t* response;
BAN::Atomic<bool> done;
};
BAN::ErrorOr<void> send_command(Command& command);
private:
const AML::Scope m_scope;
const uint16_t m_command_port;
const uint16_t m_data_port;
const bool m_has_gpe;
Mutex m_mutex;
ThreadBlocker m_thread_blocker;
BAN::Optional<Command*> m_queued_command;
Thread* m_thread { nullptr };
};
}

View File

@@ -0,0 +1,179 @@
#pragma once
#include <BAN/ByteSpan.h>
#include <BAN/Debug.h>
#include <BAN/Optional.h>
namespace Kernel::ACPI
{
struct ResourceData
{
enum class Type
{
IRQ,
DMA,
IOPort,
FixedIOPort,
FixedDMA,
// TODO: large stuff the stuff :)
};
union {
struct {
uint16_t irq_mask;
union {
struct {
uint8_t edge_triggered : 1;
uint8_t : 2;
uint8_t active_low : 1;
uint8_t shared : 1;
uint8_t wake_capable : 1;
uint8_t : 2;
};
uint8_t raw;
};
} irq;
struct {
uint8_t channel_mask;
union {
struct {
uint8_t type : 2; // 0: 8 bit, 1: 8 and 16 bit, 2: 16 bit only
uint8_t bus_master : 1;
uint8_t : 2;
uint8_t channel_speed : 2; // 0: compatibility, 1: type A, 2: type B, 3: type F
uint8_t : 1;
};
uint8_t raw;
};
} dma;
struct {
uint16_t range_min_base;
uint16_t range_max_base;
uint8_t base_alignment;
uint8_t range_length;
} io_port;
struct {
uint16_t range_base;
uint8_t range_length;
} fixed_io_port;
struct {
uint16_t request_line;
uint16_t channel;
uint8_t transfer_width; // 0: 8 bit, 1: 16 bit, 2: 32 bit, 3: 64 bit, 4: 128 bit
} fixed_dma;
} as;
Type type;
};
class ResourceParser
{
public:
ResourceParser(BAN::ConstByteSpan buffer)
: m_buffer(buffer)
{}
BAN::Optional<ResourceData> get_next()
{
for (;;)
{
if (m_buffer.empty())
return {};
if (m_buffer[0] & 0x80)
{
dprintln("Skipping large resource 0x{2H}", m_buffer[0] & 0x7F);
const uint16_t length = (m_buffer[2] << 8) | m_buffer[1];
if (m_buffer.size() < static_cast<size_t>(3 + length))
return {};
m_buffer = m_buffer.slice(3 + length);
continue;
}
const uint8_t length = m_buffer[0] & 0x07;
if (m_buffer.size() < static_cast<size_t>(1 + length))
return {};
BAN::Optional<ResourceData> result;
switch ((m_buffer[0] >> 3) & 0x0F)
{
case 0x04:
if (length < 2)
break;
result = ResourceData {
.as = { .irq = {
.irq_mask = static_cast<uint16_t>((m_buffer[2] << 8) | m_buffer[1]),
.raw = (length >= 3) ? m_buffer[3] : static_cast<uint8_t>(1),
}},
.type = ResourceData::Type::IRQ,
};
break;
case 0x05:
if (length < 2)
break;
result = ResourceData {
.as = { .dma = {
.channel_mask = m_buffer[1],
.raw = m_buffer[2],
}},
.type = ResourceData::Type::DMA,
};
break;
case 0x08:
if (length < 7)
break;
result = ResourceData {
.as = { .io_port = {
.range_min_base = static_cast<uint16_t>(((m_buffer[3] << 8) | m_buffer[2]) & ((m_buffer[1] & 1) ? 0xFFFF : 0x03FF)),
.range_max_base = static_cast<uint16_t>(((m_buffer[5] << 8) | m_buffer[4]) & ((m_buffer[1] & 1) ? 0xFFFF : 0x03FF)),
.base_alignment = m_buffer[6],
.range_length = m_buffer[7],
}},
.type = ResourceData::Type::IOPort,
};
break;
case 0x09:
if (length < 3)
break;
result = ResourceData {
.as = { .fixed_io_port = {
.range_base = static_cast<uint16_t>(((m_buffer[2] << 8) | m_buffer[1]) & 0x03FF),
.range_length = m_buffer[3],
}},
.type = ResourceData::Type::FixedIOPort,
};
break;
case 0x0A:
if (length < 5)
break;
result = ResourceData {
.as = { .fixed_dma = {
.request_line = static_cast<uint16_t>((m_buffer[2] << 8) | m_buffer[1]),
.channel = static_cast<uint16_t>((m_buffer[4] << 8) | m_buffer[3]),
.transfer_width = m_buffer[5],
}},
.type = ResourceData::Type::FixedDMA,
};
break;
case 0x0F:
// End tag
return {};
case 0x06:
case 0x07:
case 0x0E:
dprintln("Skipping short resource 0x{2H}", (m_buffer[0] >> 3) & 0x0F);
break;
}
m_buffer = m_buffer.slice(1 + length);
if (result.has_value())
return result.release_value();
}
}
private:
BAN::ConstByteSpan m_buffer;
};
}

View File

@@ -0,0 +1,37 @@
#pragma once
#include <stdint.h>
namespace Kernel::API
{
enum SharedPageFeature : uint32_t
{
SPF_GETTIME = 1 << 0,
};
struct SharedPage
{
uint8_t __sequence[0x100];
uint32_t features;
struct
{
uint8_t shift;
uint64_t mult;
uint64_t realtime_seconds;
} gettime_shared;
struct
{
struct
{
uint32_t seq;
uint64_t last_ns;
uint64_t last_tsc;
} gettime_local;
} cpus[];
};
}

View File

@@ -0,0 +1,34 @@
#pragma once
#include <BAN/MacroUtils.h>
#if defined(__x86_64__)
#define _kas_instruction "syscall"
#define _kas_result rax
#define _kas_arguments rdi, rsi, rdx, r10, r8, r9
#define _kas_globbers rcx, rdx, rdi, rsi, r8, r9, r10, r11
#elif defined(__i686__)
#define _kas_instruction "int $0xF0"
#define _kas_result eax
#define _kas_arguments eax, ebx, ecx, edx, esi, edi
#define _kas_globbers
#endif
#define _kas_argument_var(index, value) register long _kas_a##index asm(_ban_stringify(_ban_get(index, _kas_arguments))) = (long)value;
#define _kas_dummy_var(index, value) register long _kas_d##index asm(#value);
#define _kas_input(index, _) "r"(_kas_a##index)
#define _kas_output(index, _) , "=r"(_kas_d##index)
#define _kas_globber(_, value) #value
#define _kas_syscall(...) ({ \
register long _kas_ret asm(_ban_stringify(_kas_result)); \
_ban_for_each(_kas_argument_var, __VA_ARGS__) \
_ban_for_each(_kas_dummy_var, _kas_globbers) \
asm volatile( \
_kas_instruction \
: "=r"(_kas_ret) _ban_for_each(_kas_output, _kas_globbers) \
: _ban_for_each_comma(_kas_input, __VA_ARGS__) \
: "cc", "memory"); \
(void)_kas_a0; /* require 1 argument */ \
_kas_ret; \
})

View File

@@ -6,10 +6,10 @@
namespace Kernel namespace Kernel
{ {
class AC97AudioController : public AudioController, public Interruptable class AC97AudioController final : public AudioController, public Interruptable
{ {
public: public:
static BAN::ErrorOr<BAN::RefPtr<AC97AudioController>> create(PCI::Device& pci_device); static BAN::ErrorOr<void> create(PCI::Device& pci_device);
void handle_irq() override; void handle_irq() override;
@@ -19,16 +19,24 @@ namespace Kernel
uint32_t get_channels() const override { return 2; } uint32_t get_channels() const override { return 2; }
uint32_t get_sample_rate() const override { return 48000; } uint32_t get_sample_rate() const override { return 48000; }
uint32_t get_total_pins() const override { return 1; }
uint32_t get_current_pin() const override { return 0; }
BAN::ErrorOr<void> set_current_pin(uint32_t pin) override { if (pin != 0) return BAN::Error::from_errno(EINVAL); return {}; }
BAN::ErrorOr<void> set_volume_mdB(int32_t) override;
private: private:
AC97AudioController(PCI::Device& pci_device) AC97AudioController(PCI::Device& pci_device)
: m_pci_device(pci_device) : m_pci_device(pci_device)
{ } { }
uint32_t get_volume_data() const;
BAN::ErrorOr<void> initialize(); BAN::ErrorOr<void> initialize();
BAN::ErrorOr<void> initialize_bld(); BAN::ErrorOr<void> initialize_bld();
BAN::ErrorOr<void> initialize_interrupts(); BAN::ErrorOr<void> initialize_interrupts();
void queue_samples_to_bld(); bool queue_samples_to_bld();
private: private:
static constexpr size_t m_bdl_entries = 32; static constexpr size_t m_bdl_entries = 32;

View File

@@ -1,29 +1,39 @@
#pragma once #pragma once
#include <kernel/Device/Device.h> #include <kernel/Device/Device.h>
#include <kernel/Memory/ByteRingBuffer.h>
#include <kernel/PCI.h> #include <kernel/PCI.h>
#include <sys/ioctl.h>
namespace Kernel namespace Kernel
{ {
class AudioController : public CharacterDevice class AudioController : public CharacterDevice
{ {
public: public:
static BAN::ErrorOr<BAN::RefPtr<AudioController>> create(PCI::Device& pci_device); static BAN::ErrorOr<void> create(PCI::Device& pci_device);
dev_t rdev() const override { return m_rdev; } dev_t rdev() const override { return m_rdev; }
BAN::StringView name() const override { return m_name; } BAN::StringView name() const override { return m_name; }
protected: protected:
AudioController(); AudioController();
BAN::ErrorOr<void> initialize();
virtual void handle_new_data() = 0; virtual void handle_new_data() = 0;
virtual uint32_t get_channels() const = 0; virtual uint32_t get_channels() const = 0;
virtual uint32_t get_sample_rate() const = 0; virtual uint32_t get_sample_rate() const = 0;
virtual uint32_t get_total_pins() const = 0;
virtual uint32_t get_current_pin() const = 0;
virtual BAN::ErrorOr<void> set_current_pin(uint32_t) = 0;
virtual BAN::ErrorOr<void> set_volume_mdB(int32_t) = 0;
bool can_read_impl() const override { return false; } bool can_read_impl() const override { return false; }
bool can_write_impl() const override { SpinLockGuard _(m_spinlock); return m_sample_data_size < m_sample_data_capacity; } bool can_write_impl() const override { SpinLockGuard _(m_spinlock); return !m_sample_data->full(); }
bool has_error_impl() const override { return false; } bool has_error_impl() const override { return false; }
bool has_hungup_impl() const override { return false; } bool has_hungup_impl() const override { return false; }
@@ -36,9 +46,9 @@ namespace Kernel
mutable SpinLock m_spinlock; mutable SpinLock m_spinlock;
static constexpr size_t m_sample_data_capacity = 1 << 20; static constexpr size_t m_sample_data_capacity = 1 << 20;
uint8_t m_sample_data[m_sample_data_capacity]; BAN::UniqPtr<ByteRingBuffer> m_sample_data;
size_t m_sample_data_head { 0 };
size_t m_sample_data_size { 0 }; snd_volume_info m_volume_info {};
private: private:
const dev_t m_rdev; const dev_t m_rdev;

View File

@@ -0,0 +1,80 @@
#pragma once
#include <kernel/Audio/Controller.h>
#include <kernel/Audio/HDAudio/Controller.h>
namespace Kernel
{
class HDAudioController;
class HDAudioFunctionGroup final : public AudioController
{
public:
static BAN::ErrorOr<BAN::RefPtr<HDAudioFunctionGroup>> create(BAN::RefPtr<HDAudioController>, uint8_t cid, HDAudio::AFGNode&&);
void on_stream_interrupt(uint8_t stream_index);
protected:
// FIXME: allow setting these :D
uint32_t get_channels() const override { return 2; }
uint32_t get_sample_rate() const override { return 48000; }
uint32_t get_total_pins() const override;
uint32_t get_current_pin() const override;
BAN::ErrorOr<void> set_current_pin(uint32_t) override;
BAN::ErrorOr<void> set_volume_mdB(int32_t) override;
void handle_new_data() override;
private:
HDAudioFunctionGroup(BAN::RefPtr<HDAudioController> controller, uint8_t cid, HDAudio::AFGNode&& afg_node)
: m_controller(controller)
, m_afg_node(BAN::move(afg_node))
, m_cid(cid)
{ }
~HDAudioFunctionGroup();
BAN::ErrorOr<void> initialize();
BAN::ErrorOr<void> initialize_stream();
BAN::ErrorOr<void> initialize_output();
BAN::ErrorOr<void> enable_output_path(uint8_t index);
BAN::ErrorOr<void> disable_output_path(uint8_t index);
void reset_stream();
BAN::ErrorOr<void> recurse_output_paths(const HDAudio::AFGWidget& widget, BAN::Vector<const HDAudio::AFGWidget*>& path);
uint16_t get_format_data() const;
size_t bdl_offset() const;
void queue_bdl_data();
private:
// use 6 512 sample BDL entries
// each entry is ~10.7 ms at 48 kHz
// -> total buffered audio is 64 ms
static constexpr size_t m_bdl_entry_sample_frames = 512;
static constexpr size_t m_bdl_entry_count = 6;
BAN::RefPtr<HDAudioController> m_controller;
const HDAudio::AFGNode m_afg_node;
const uint8_t m_cid;
BAN::Vector<BAN::Vector<const HDAudio::AFGWidget*>> m_output_paths;
BAN::Vector<const HDAudio::AFGWidget*> m_output_pins;
size_t m_output_path_index { SIZE_MAX };
uint8_t m_stream_id { 0xFF };
uint8_t m_stream_index { 0xFF };
BAN::UniqPtr<DMARegion> m_bdl_region;
size_t m_bdl_head { 0 };
size_t m_bdl_tail { 0 };
bool m_stream_running { false };
};
}

View File

@@ -0,0 +1,77 @@
#pragma once
#include <kernel/Audio/Controller.h>
#include <kernel/Audio/HDAudio/Definitions.h>
#include <kernel/Memory/DMARegion.h>
namespace Kernel
{
class HDAudioController : public Interruptable, public BAN::RefCounted<HDAudioController>
{
public:
static BAN::ErrorOr<void> create(PCI::Device& pci_device);
BAN::ErrorOr<uint32_t> send_command(HDAudio::CORBEntry);
uint8_t get_stream_index(HDAudio::StreamType type, uint8_t index) const;
BAN::ErrorOr<uint8_t> allocate_stream_id();
void deallocate_stream_id(uint8_t id);
BAN::ErrorOr<uint8_t> allocate_stream(HDAudio::StreamType type, void* afg);
void deallocate_stream(uint8_t index);
PCI::BarRegion& bar0() { return *m_bar0; }
bool is_64bit() const { return m_is64bit; }
void handle_irq() override;
private:
HDAudioController(PCI::Device& pci_device)
: m_pci_device(pci_device)
{ }
BAN::ErrorOr<void> initialize();
BAN::ErrorOr<void> initialize_ring_buffers();
BAN::ErrorOr<void> reset_controller();
BAN::ErrorOr<HDAudio::Codec> initialize_codec(uint8_t codec);
BAN::ErrorOr<HDAudio::AFGNode> initialize_node(uint8_t codec, uint8_t node);
BAN::ErrorOr<HDAudio::AFGWidget> initialize_widget(uint8_t codec, uint8_t node);
private:
struct RingBuffer
{
vaddr_t vaddr;
uint32_t index;
uint32_t size;
};
private:
PCI::Device& m_pci_device;
BAN::UniqPtr<PCI::BarRegion> m_bar0;
bool m_is64bit { false };
bool m_use_immediate_command { false };
uint8_t m_output_streams { 0 };
uint8_t m_input_streams { 0 };
uint8_t m_bidir_streams { 0 };
void* m_allocated_streams[30] {};
// NOTE: stream ids are from 1 to 15
uint16_t m_allocated_stream_ids { 0 };
Mutex m_command_mutex;
SpinLock m_rb_lock;
ThreadBlocker m_rb_blocker;
RingBuffer m_corb;
RingBuffer m_rirb;
BAN::UniqPtr<DMARegion> m_ring_buffer_region;
};
}

View File

@@ -0,0 +1,90 @@
#pragma once
#include <BAN/Vector.h>
namespace Kernel::HDAudio
{
struct CORBEntry
{
union {
struct {
uint32_t data : 8;
uint32_t command : 12;
uint32_t node_index : 8;
uint32_t codec_address : 4;
};
uint32_t raw;
};
};
static_assert(sizeof(CORBEntry) == sizeof(uint32_t));
struct BDLEntry
{
paddr_t address;
uint32_t length;
uint32_t ioc;
};
static_assert(sizeof(BDLEntry) == 16);
struct AFGWidget
{
enum class Type
{
OutputConverter,
InputConverter,
Mixer,
Selector,
PinComplex,
Power,
VolumeKnob,
BeepGenerator,
};
Type type;
uint8_t id;
union
{
struct
{
bool input;
bool output;
bool display; // HDMI or DP
uint32_t config;
} pin_complex;
};
struct Amplifier
{
uint8_t offset;
uint8_t num_steps;
uint8_t step_size;
bool mute;
};
BAN::Optional<Amplifier> output_amplifier;
BAN::Vector<uint16_t> connections;
};
struct AFGNode
{
uint8_t id;
BAN::Vector<AFGWidget> widgets;
};
struct Codec
{
uint8_t id;
BAN::Vector<AFGNode> nodes;
};
enum class StreamType
{
Input,
Output,
Bidirectional,
};
}

View File

@@ -0,0 +1,50 @@
#pragma once
#include <stdint.h>
namespace Kernel::HDAudio
{
enum Regs : uint8_t
{
GCAP = 0x00,
VMIN = 0x02,
VMAJ = 0x03,
GCTL = 0x08,
STATESTS = 0x0E,
INTCTL = 0x20,
INTSTS = 0x24,
CORBLBASE = 0x40,
CORBUBASE = 0x44,
CORBWP = 0x48,
CORBRP = 0x4A,
CORBCTL = 0x4C,
CORBSTS = 0x4D,
CORBSIZE = 0x4E,
RIRBLBASE = 0x50,
RIRBUBASE = 0x54,
RIRBWP = 0x58,
RINTCNT = 0x5A,
RIRBCTL = 0x5C,
RIRBSTS = 0x5D,
RIRBSIZE = 0x5E,
ICOI = 0x60,
ICII = 0x64,
ICIS = 0x68,
SDCTL = 0x00,
SDSTS = 0x03,
SDLPIB = 0x04,
SDCBL = 0x08,
SDLVI = 0x0C,
SDFIFOD = 0x10,
SDFMT = 0x12,
SDBDPL = 0x18,
SDBDPU = 0x1C,
};
}

View File

@@ -44,7 +44,7 @@ namespace Kernel
struct BootModule struct BootModule
{ {
paddr_t start; paddr_t start;
size_t size; uint64_t size;
}; };
struct BootInfo struct BootInfo

View File

@@ -81,5 +81,6 @@ namespace CPUID
bool has_pge(); bool has_pge();
bool has_pat(); bool has_pat();
bool has_1gib_pages(); bool has_1gib_pages();
bool has_invariant_tsc();
} }

View File

@@ -35,10 +35,8 @@ namespace Kernel
bool has_egid(gid_t) const; bool has_egid(gid_t) const;
BAN::ErrorOr<void> initialize_supplementary_groups(); BAN::Span<const gid_t> groups() const { return m_supplementary.span(); }
BAN::ErrorOr<void> set_groups(BAN::Span<const gid_t> groups);
private:
BAN::ErrorOr<BAN::String> find_username() const;
private: private:
uid_t m_ruid, m_euid, m_suid; uid_t m_ruid, m_euid, m_suid;

View File

@@ -70,10 +70,15 @@
#define DEBUG_USB_MOUSE 0 #define DEBUG_USB_MOUSE 0
#define DEBUG_USB_MASS_STORAGE 0 #define DEBUG_USB_MASS_STORAGE 0
#define DEBUG_HDAUDIO 0
namespace Debug namespace Debug
{ {
void dump_stack_trace(); void dump_stack_trace();
void dump_stack_trace(uintptr_t ip, uintptr_t bp);
void dump_qr_code();
void putchar(char); void putchar(char);
void print_prefix(const char*, int); void print_prefix(const char*, int);

View File

@@ -16,7 +16,11 @@ namespace Kernel
virtual bool is_partition() const { return false; } virtual bool is_partition() const { return false; }
virtual bool is_storage_device() const { return false; } virtual bool is_storage_device() const { return false; }
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> mmap_region(PageTable&, off_t offset, size_t len, AddressRange, MemoryRegion::Type, PageTable::flags_t) { (void)offset; (void)len; return BAN::Error::from_errno(EINVAL); } virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> mmap_region(PageTable&, off_t offset, size_t len, AddressRange, MemoryRegion::Type, PageTable::flags_t, int status_flags)
{
(void)offset; (void)len; (void)status_flags;
return BAN::Error::from_errno(ENOTSUP);
}
virtual dev_t rdev() const override = 0; virtual dev_t rdev() const override = 0;

View File

@@ -16,6 +16,7 @@ namespace Kernel
Debug, Debug,
Keyboard, Keyboard,
Mouse, Mouse,
Joystick,
SCSI, SCSI,
NVMeController, NVMeController,
NVMeNamespace, NVMeNamespace,

View File

@@ -10,6 +10,7 @@ namespace Kernel
{ {
public: public:
static BAN::ErrorOr<BAN::RefPtr<FramebufferDevice>> create_from_boot_framebuffer(); static BAN::ErrorOr<BAN::RefPtr<FramebufferDevice>> create_from_boot_framebuffer();
static BAN::RefPtr<FramebufferDevice> boot_framebuffer();
~FramebufferDevice(); ~FramebufferDevice();
uint32_t width() const { return m_width; } uint32_t width() const { return m_width; }
@@ -27,7 +28,7 @@ namespace Kernel
void sync_pixels_linear(uint32_t first_pixel, uint32_t pixel_count); void sync_pixels_linear(uint32_t first_pixel, uint32_t pixel_count);
void sync_pixels_rectangle(uint32_t top_right_x, uint32_t top_right_y, uint32_t width, uint32_t height); void sync_pixels_rectangle(uint32_t top_right_x, uint32_t top_right_y, uint32_t width, uint32_t height);
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> mmap_region(PageTable&, off_t offset, size_t len, AddressRange, MemoryRegion::Type, PageTable::flags_t) override; virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> mmap_region(PageTable&, off_t offset, size_t len, AddressRange, MemoryRegion::Type, PageTable::flags_t, int status_flags) override;
virtual dev_t rdev() const override { return m_rdev; } virtual dev_t rdev() const override { return m_rdev; }
virtual BAN::StringView name() const override { return m_name.sv(); } virtual BAN::StringView name() const override { return m_name.sv(); }
@@ -36,6 +37,8 @@ namespace Kernel
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override; virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override; virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
BAN::ErrorOr<long> ioctl_impl(int cmd, void* arg) override;
virtual bool can_read_impl() const override { return true; } virtual bool can_read_impl() const override { return true; }
virtual bool can_write_impl() const override { return true; } virtual bool can_write_impl() const override { return true; }
virtual bool has_error_impl() const override { return false; } virtual bool has_error_impl() const override { return false; }

View File

@@ -20,6 +20,6 @@ namespace Kernel::ELF
BAN::Vector<BAN::UniqPtr<MemoryRegion>> regions; BAN::Vector<BAN::UniqPtr<MemoryRegion>> regions;
}; };
BAN::ErrorOr<LoadResult> load_from_inode(BAN::RefPtr<Inode>, const Credentials&, PageTable&); BAN::ErrorOr<LoadResult> load_from_inode(BAN::RefPtr<Inode> root, BAN::RefPtr<Inode> inode, const Credentials&, PageTable&);
} }

View File

@@ -22,6 +22,7 @@ namespace Kernel
void add_inode(BAN::StringView path, BAN::RefPtr<TmpInode>); void add_inode(BAN::StringView path, BAN::RefPtr<TmpInode>);
void initiate_disk_cache_drop();
void initiate_sync(bool should_block); void initiate_sync(bool should_block);
private: private:
@@ -37,6 +38,10 @@ namespace Kernel
ThreadBlocker m_sync_done; ThreadBlocker m_sync_done;
ThreadBlocker m_sync_thread_blocker; ThreadBlocker m_sync_thread_blocker;
volatile bool m_should_sync { false }; volatile bool m_should_sync { false };
SpinLock m_disk_cache_lock;
ThreadBlocker m_disk_cache_thread_blocker;
BAN::Atomic<bool> m_should_drop_disk_cache { false };
}; };
} }

View File

@@ -0,0 +1,52 @@
#pragma once
#include <kernel/FS/Inode.h>
namespace Kernel
{
class EventFD final : public Inode
{
public:
static BAN::ErrorOr<BAN::RefPtr<Inode>> create(uint64_t initval, bool semaphore);
ino_t ino() const override { return 0; }
Mode mode() const override { return { Mode::IFCHR | Mode::IRUSR | Mode::IWUSR }; }
nlink_t nlink() const override { return ref_count(); }
uid_t uid() const override { return 0; }
gid_t gid() const override { return 0; }
off_t size() const override { return 0; }
timespec atime() const override { return {}; }
timespec mtime() const override { return {}; }
timespec ctime() const override { return {}; }
blksize_t blksize() const override { return 8; }
blkcnt_t blocks() const override { return 0; }
dev_t dev() const override { return 0; }
dev_t rdev() const override { return 0; }
const FileSystem* filesystem() const override { return nullptr; }
protected:
BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
BAN::ErrorOr<void> fsync_impl() final override { return {}; }
bool can_read_impl() const override { return m_value > 0; }
bool can_write_impl() const override { return m_value < UINT64_MAX - 1; }
bool has_error_impl() const override { return false; }
bool has_hungup_impl() const override { return false; }
private:
EventFD(uint64_t initval, bool is_semaphore)
: m_is_semaphore(is_semaphore)
, m_value(initval)
{ }
private:
const bool m_is_semaphore;
uint64_t m_value;
ThreadBlocker m_thread_blocker;
};
}

View File

@@ -26,18 +26,32 @@ namespace Kernel
class BlockBufferWrapper class BlockBufferWrapper
{ {
BAN_NON_COPYABLE(BlockBufferWrapper); BAN_NON_COPYABLE(BlockBufferWrapper);
BAN_NON_MOVABLE(BlockBufferWrapper);
public: public:
BlockBufferWrapper(BAN::Span<uint8_t> buffer, bool& used) BlockBufferWrapper(BAN::Span<uint8_t> buffer, void (*callback)(void*, const uint8_t*), void* argument)
: m_buffer(buffer) : m_buffer(buffer)
, m_used(used) , m_callback(callback)
{ , m_argument(argument)
ASSERT(m_used); { }
} BlockBufferWrapper(BlockBufferWrapper&& other) { *this = BAN::move(other); }
~BlockBufferWrapper() ~BlockBufferWrapper()
{ {
m_used = false; if (m_callback == nullptr)
return;
m_callback(m_argument, m_buffer.data());
}
BlockBufferWrapper& operator=(BlockBufferWrapper&& other)
{
this->m_buffer = other.m_buffer;
this->m_callback = other.m_callback;
this->m_argument = other.m_argument;
other.m_buffer = {};
other.m_callback = nullptr;
other.m_argument = nullptr;
return *this;
} }
size_t size() const { return m_buffer.size(); } size_t size() const { return m_buffer.size(); }
@@ -53,7 +67,8 @@ namespace Kernel
private: private:
BAN::Span<uint8_t> m_buffer; BAN::Span<uint8_t> m_buffer;
bool& m_used; void (*m_callback)(void*, const uint8_t*);
void* m_argument;
}; };
public: public:
@@ -79,7 +94,7 @@ namespace Kernel
BAN::ErrorOr<void> sync_superblock(); BAN::ErrorOr<void> sync_superblock();
BAN::ErrorOr<void> sync_block(uint32_t block); BAN::ErrorOr<void> sync_block(uint32_t block);
BlockBufferWrapper get_block_buffer(); BAN::ErrorOr<BlockBufferWrapper> get_block_buffer();
BAN::ErrorOr<uint32_t> reserve_free_block(uint32_t primary_bgd); BAN::ErrorOr<uint32_t> reserve_free_block(uint32_t primary_bgd);
BAN::ErrorOr<void> release_block(uint32_t block); BAN::ErrorOr<void> release_block(uint32_t block);
@@ -102,10 +117,13 @@ namespace Kernel
{ {
public: public:
BlockBufferManager() = default; BlockBufferManager() = default;
BlockBufferWrapper get_buffer(); BAN::ErrorOr<BlockBufferWrapper> get_buffer();
BAN::ErrorOr<void> initialize(size_t block_size); BAN::ErrorOr<void> initialize(size_t block_size);
private:
void destroy_callback(const uint8_t* buffer_ptr);
private: private:
struct BlockBuffer struct BlockBuffer
{ {
@@ -113,8 +131,20 @@ namespace Kernel
bool used { false }; bool used { false };
}; };
struct ThreadInfo
{
pid_t tid { 0 };
size_t buffers { 0 };
};
private: private:
BAN::Array<BlockBuffer, 10> m_buffers; static constexpr size_t max_threads = 8;
static constexpr size_t max_buffers_per_thread = 6;
Mutex m_buffer_mutex;
ThreadBlocker m_buffer_blocker;
BAN::Array<BlockBuffer, max_threads * max_buffers_per_thread> m_buffers;
BAN::Array<ThreadInfo, max_threads> m_thread_infos;
}; };
private: private:

View File

@@ -37,6 +37,7 @@ namespace Kernel
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override; virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override;
virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override; virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override;
virtual BAN::ErrorOr<void> link_inode_impl(BAN::StringView, BAN::RefPtr<Inode>) override; virtual BAN::ErrorOr<void> link_inode_impl(BAN::StringView, BAN::RefPtr<Inode>) override;
virtual BAN::ErrorOr<void> rename_inode_impl(BAN::RefPtr<Inode>, BAN::StringView, BAN::StringView) override;
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override; virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override;
virtual BAN::ErrorOr<BAN::String> link_target_impl() override; virtual BAN::ErrorOr<BAN::String> link_target_impl() override;
@@ -60,18 +61,18 @@ namespace Kernel
// NOTE: the inode might have more blocks than what this suggests if it has been shrinked // NOTE: the inode might have more blocks than what this suggests if it has been shrinked
uint32_t max_used_data_block_count() const { return size() / blksize(); } uint32_t max_used_data_block_count() const { return size() / blksize(); }
BAN::ErrorOr<BAN::Optional<uint32_t>> block_from_indirect_block(uint32_t block, uint32_t index, uint32_t depth); BAN::ErrorOr<BAN::Optional<uint32_t>> block_from_indirect_block(uint32_t& block, uint32_t index, uint32_t depth, bool allocate);
BAN::ErrorOr<BAN::Optional<uint32_t>> fs_block_of_data_block_index(uint32_t data_block_index); BAN::ErrorOr<BAN::Optional<uint32_t>> fs_block_of_data_block_index(uint32_t data_block_index, bool allocate);
BAN::ErrorOr<void> link_inode_to_directory(Ext2Inode&, BAN::StringView name); BAN::ErrorOr<void> link_inode_to_directory(Ext2Inode&, BAN::StringView name);
BAN::ErrorOr<void> remove_inode_from_directory(BAN::StringView name, bool cleanup_directory);
BAN::ErrorOr<bool> is_directory_empty(); BAN::ErrorOr<bool> is_directory_empty();
BAN::ErrorOr<void> cleanup_indirect_block(uint32_t block, uint32_t depth); BAN::ErrorOr<void> cleanup_indirect_block(uint32_t block, uint32_t depth);
BAN::ErrorOr<void> cleanup_default_links(); BAN::ErrorOr<void> cleanup_default_links();
BAN::ErrorOr<void> cleanup_data_blocks();
BAN::ErrorOr<void> cleanup_from_fs(); BAN::ErrorOr<void> cleanup_from_fs();
BAN::ErrorOr<uint32_t> allocate_new_block_to_indirect_block(uint32_t& block, uint32_t index, uint32_t depth);
BAN::ErrorOr<uint32_t> allocate_new_block(uint32_t data_block_index);
BAN::ErrorOr<void> sync(); BAN::ErrorOr<void> sync();
uint32_t block_group() const; uint32_t block_group() const;
@@ -84,6 +85,26 @@ namespace Kernel
{} {}
static BAN::ErrorOr<BAN::RefPtr<Ext2Inode>> create(Ext2FS&, uint32_t); static BAN::ErrorOr<BAN::RefPtr<Ext2Inode>> create(Ext2FS&, uint32_t);
private:
struct ScopedSync
{
ScopedSync(Ext2Inode& inode)
: inode(inode)
, inode_info(inode.m_inode)
{ }
~ScopedSync()
{
if (memcmp(&inode.m_inode, &inode_info, sizeof(Ext2::Inode)) == 0)
return;
if (auto ret = inode.sync(); ret.is_error())
dwarnln("failed to sync inode: {}", ret.error());
}
Ext2Inode& inode;
Ext2::Inode inode_info;
};
private: private:
Ext2FS& m_fs; Ext2FS& m_fs;
Ext2::Inode m_inode; Ext2::Inode m_inode;

View File

@@ -22,7 +22,7 @@ namespace Kernel
class FileBackedRegion; class FileBackedRegion;
class FileSystem; class FileSystem;
class SharedFileData; struct SharedFileData;
class Inode : public BAN::RefCounted<Inode> class Inode : public BAN::RefCounted<Inode>
{ {
@@ -97,6 +97,7 @@ namespace Kernel
BAN::ErrorOr<void> create_file(BAN::StringView, mode_t, uid_t, gid_t); BAN::ErrorOr<void> create_file(BAN::StringView, mode_t, uid_t, gid_t);
BAN::ErrorOr<void> create_directory(BAN::StringView, mode_t, uid_t, gid_t); BAN::ErrorOr<void> create_directory(BAN::StringView, mode_t, uid_t, gid_t);
BAN::ErrorOr<void> link_inode(BAN::StringView, BAN::RefPtr<Inode>); BAN::ErrorOr<void> link_inode(BAN::StringView, BAN::RefPtr<Inode>);
BAN::ErrorOr<void> rename_inode(BAN::RefPtr<Inode>, BAN::StringView, BAN::StringView);
BAN::ErrorOr<void> unlink(BAN::StringView); BAN::ErrorOr<void> unlink(BAN::StringView);
// Link API // Link API
@@ -108,10 +109,12 @@ namespace Kernel
BAN::ErrorOr<void> bind(const sockaddr* address, socklen_t address_len); BAN::ErrorOr<void> bind(const sockaddr* address, socklen_t address_len);
BAN::ErrorOr<void> connect(const sockaddr* address, socklen_t address_len); BAN::ErrorOr<void> connect(const sockaddr* address, socklen_t address_len);
BAN::ErrorOr<void> listen(int backlog); BAN::ErrorOr<void> listen(int backlog);
BAN::ErrorOr<size_t> sendto(BAN::ConstByteSpan message, const sockaddr* address, socklen_t address_len); BAN::ErrorOr<size_t> sendmsg(const msghdr& message, int flags);
BAN::ErrorOr<size_t> recvfrom(BAN::ByteSpan buffer, sockaddr* address, socklen_t* address_len); BAN::ErrorOr<size_t> recvmsg(msghdr& message, int flags);
BAN::ErrorOr<void> getsockname(sockaddr* address, socklen_t* address_len); BAN::ErrorOr<void> getsockname(sockaddr* address, socklen_t* address_len);
BAN::ErrorOr<void> getpeername(sockaddr* address, socklen_t* address_len); BAN::ErrorOr<void> getpeername(sockaddr* address, socklen_t* address_len);
BAN::ErrorOr<void> getsockopt(int level, int option, void* value, socklen_t* value_len);
BAN::ErrorOr<void> setsockopt(int level, int option, const void* value, socklen_t value_len);
// General API // General API
BAN::ErrorOr<size_t> read(off_t, BAN::ByteSpan buffer); BAN::ErrorOr<size_t> read(off_t, BAN::ByteSpan buffer);
@@ -139,12 +142,13 @@ namespace Kernel
protected: protected:
// Directory API // Directory API
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<size_t> list_next_inodes_impl(off_t, struct dirent*, size_t) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr<size_t> list_next_inodes_impl(off_t, struct dirent*, size_t) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> link_inode_impl(BAN::StringView, BAN::RefPtr<Inode>) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr<void> link_inode_impl(BAN::StringView, BAN::RefPtr<Inode>) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr<void> rename_inode_impl(BAN::RefPtr<Inode>, BAN::StringView, BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); }
// Link API // Link API
virtual BAN::ErrorOr<BAN::String> link_target_impl() { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr<BAN::String> link_target_impl() { return BAN::Error::from_errno(ENOTSUP); }
@@ -155,10 +159,12 @@ namespace Kernel
virtual BAN::ErrorOr<void> connect_impl(const sockaddr*, socklen_t) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr<void> connect_impl(const sockaddr*, socklen_t) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> listen_impl(int) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr<void> listen_impl(int) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> bind_impl(const sockaddr*, socklen_t) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr<void> bind_impl(const sockaddr*, socklen_t) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<size_t> sendto_impl(BAN::ConstByteSpan, const sockaddr*, socklen_t) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr<size_t> recvmsg_impl(msghdr&, int) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<size_t> recvfrom_impl(BAN::ByteSpan, sockaddr*, socklen_t*) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr<size_t> sendmsg_impl(const msghdr&, int) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> getsockname_impl(sockaddr*, socklen_t*) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr<void> getsockname_impl(sockaddr*, socklen_t*) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> getsockopt_impl(int, int, void*, socklen_t*) { return BAN::Error::from_errno(ENOTSUP); }
virtual BAN::ErrorOr<void> setsockopt_impl(int, int, const void*, socklen_t) { return BAN::Error::from_errno(ENOTSUP); }
// General API // General API
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) { return BAN::Error::from_errno(ENOTSUP); } virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) { return BAN::Error::from_errno(ENOTSUP); }
@@ -187,7 +193,7 @@ namespace Kernel
friend class Epoll; friend class Epoll;
friend class FileBackedRegion; friend class FileBackedRegion;
friend class OpenFileDescriptorSet; friend class OpenFileDescriptorSet;
friend class SharedFileData; friend struct SharedFileData;
friend class TTY; friend class TTY;
}; };

View File

@@ -2,6 +2,7 @@
#include <BAN/Array.h> #include <BAN/Array.h>
#include <kernel/FS/Inode.h> #include <kernel/FS/Inode.h>
#include <kernel/Memory/ByteRingBuffer.h>
#include <kernel/ThreadBlocker.h> #include <kernel/ThreadBlocker.h>
namespace Kernel namespace Kernel
@@ -38,7 +39,7 @@ namespace Kernel
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override; virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
virtual BAN::ErrorOr<void> fsync_impl() final override { return {}; } virtual BAN::ErrorOr<void> fsync_impl() final override { return {}; }
virtual bool can_read_impl() const override { return m_buffer_size > 0; } virtual bool can_read_impl() const override { return !m_buffer->empty(); }
virtual bool can_write_impl() const override { return true; } virtual bool can_write_impl() const override { return true; }
virtual bool has_error_impl() const override { return m_reading_count == 0; } virtual bool has_error_impl() const override { return m_reading_count == 0; }
virtual bool has_hungup_impl() const override { return m_writing_count == 0; } virtual bool has_hungup_impl() const override { return m_writing_count == 0; }
@@ -54,9 +55,7 @@ namespace Kernel
timespec m_ctime {}; timespec m_ctime {};
ThreadBlocker m_thread_blocker; ThreadBlocker m_thread_blocker;
BAN::Array<uint8_t, PAGE_SIZE> m_buffer; BAN::UniqPtr<ByteRingBuffer> m_buffer;
BAN::Atomic<size_t> m_buffer_size { 0 };
size_t m_buffer_tail { 0 };
BAN::Atomic<uint32_t> m_writing_count { 1 }; BAN::Atomic<uint32_t> m_writing_count { 1 };
BAN::Atomic<uint32_t> m_reading_count { 1 }; BAN::Atomic<uint32_t> m_reading_count { 1 };

View File

@@ -57,6 +57,31 @@ namespace Kernel
size_t (Process::*m_callback)(off_t, BAN::ByteSpan) const; size_t (Process::*m_callback)(off_t, BAN::ByteSpan) const;
}; };
class ProcSymlinkProcessInode final : public TmpInode
{
public:
static BAN::ErrorOr<BAN::RefPtr<ProcSymlinkProcessInode>> create_new(Process& process, BAN::ErrorOr<BAN::String> (Process::*callback)() const, TmpFileSystem&, mode_t);
~ProcSymlinkProcessInode() = default;
virtual uid_t uid() const override { return m_process.credentials().ruid(); }
virtual gid_t gid() const override { return m_process.credentials().rgid(); }
protected:
virtual BAN::ErrorOr<BAN::String> link_target_impl() override;
virtual bool can_read_impl() const override { return false; }
virtual bool can_write_impl() const override { return false; }
virtual bool has_error_impl() const override { return false; }
virtual bool has_hungup_impl() const override { return false; }
private:
ProcSymlinkProcessInode(Process& process, BAN::ErrorOr<BAN::String> (Process::*)() const, TmpFileSystem&, const TmpInodeInfo&);
private:
Process& m_process;
BAN::ErrorOr<BAN::String> (Process::*m_callback)() const;
};
class ProcROInode final : public TmpInode class ProcROInode final : public TmpInode
{ {
public: public:
@@ -82,4 +107,57 @@ namespace Kernel
size_t (*m_callback)(off_t, BAN::ByteSpan); size_t (*m_callback)(off_t, BAN::ByteSpan);
}; };
class ProcSymlinkInode final : public TmpInode
{
public:
static BAN::ErrorOr<BAN::RefPtr<ProcSymlinkInode>> create_new(BAN::ErrorOr<BAN::String> (*)(void*), void (*)(void*), void* data, TmpFileSystem&, mode_t, uid_t, gid_t);
~ProcSymlinkInode();
protected:
virtual BAN::ErrorOr<BAN::String> link_target_impl() override;
virtual bool can_read_impl() const override { return false; }
virtual bool can_write_impl() const override { return false; }
virtual bool has_error_impl() const override { return false; }
virtual bool has_hungup_impl() const override { return false; }
private:
ProcSymlinkInode(BAN::ErrorOr<BAN::String> (*callback)(void*), void (*destructor)(void*), void* data, TmpFileSystem&, const TmpInodeInfo&);
private:
BAN::ErrorOr<BAN::String> (*m_callback)(void*);
void (*m_destructor)(void*);
void* m_data;
};
class ProcFDDirectoryInode final : public TmpInode
{
public:
static BAN::ErrorOr<BAN::RefPtr<ProcFDDirectoryInode>> create_new(Process&, TmpFileSystem&, mode_t);
~ProcFDDirectoryInode() = default;
virtual uid_t uid() const override { return m_process.credentials().ruid(); }
virtual gid_t gid() const override { return m_process.credentials().rgid(); }
protected:
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) override;
virtual BAN::ErrorOr<size_t> list_next_inodes_impl(off_t, struct dirent*, size_t) override;
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override { return BAN::Error::from_errno(EPERM); }
virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override { return BAN::Error::from_errno(EPERM); }
virtual BAN::ErrorOr<void> link_inode_impl(BAN::StringView, BAN::RefPtr<Inode>) override { return BAN::Error::from_errno(EPERM); }
virtual BAN::ErrorOr<void> rename_inode_impl(BAN::RefPtr<Inode>, BAN::StringView, BAN::StringView) override { return BAN::Error::from_errno(EPERM); }
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override { return BAN::Error::from_errno(EPERM); }
virtual bool can_read_impl() const override { return false; }
virtual bool can_write_impl() const override { return false; }
virtual bool has_error_impl() const override { return false; }
virtual bool has_hungup_impl() const override { return false; }
private:
ProcFDDirectoryInode(Process&, TmpFileSystem&, const TmpInodeInfo&);
private:
Process& m_process;
};
} }

View File

@@ -51,8 +51,6 @@ namespace Kernel
: m_info(info) : m_info(info)
{} {}
BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan buffer) override { return recvfrom_impl(buffer, nullptr, nullptr); }
BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan buffer) override { return sendto_impl(buffer, nullptr, 0); }
BAN::ErrorOr<void> fsync_impl() final override { return {}; } BAN::ErrorOr<void> fsync_impl() final override { return {}; }
private: private:

View File

@@ -156,6 +156,8 @@ namespace Kernel
virtual BAN::ErrorOr<size_t> list_next_inodes_impl(off_t, struct dirent*, size_t) override final; virtual BAN::ErrorOr<size_t> list_next_inodes_impl(off_t, struct dirent*, size_t) override final;
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override final; virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override final;
virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override final; virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override final;
virtual BAN::ErrorOr<void> link_inode_impl(BAN::StringView, BAN::RefPtr<Inode>) override final;
virtual BAN::ErrorOr<void> rename_inode_impl(BAN::RefPtr<Inode>, BAN::StringView, BAN::StringView) override final;
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override; virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override;
virtual bool can_read_impl() const override { return false; } virtual bool can_read_impl() const override { return false; }
@@ -167,6 +169,8 @@ namespace Kernel
template<TmpFuncs::for_each_valid_entry_callback F> template<TmpFuncs::for_each_valid_entry_callback F>
void for_each_valid_entry(F callback); void for_each_valid_entry(F callback);
BAN::ErrorOr<void> unlink_inode(BAN::StringView, bool cleanup);
friend class TmpInode; friend class TmpInode;
}; };

View File

@@ -1,12 +1,11 @@
#pragma once #pragma once
#include <kernel/BootInfo.h> #include <kernel/BootInfo.h>
#include <kernel/FS/FileSystem.h> #include <kernel/FS/Inode.h>
namespace Kernel namespace Kernel
{ {
bool is_ustar_boot_module(const BootModule&); BAN::ErrorOr<bool> unpack_boot_module_into_directory(BAN::RefPtr<Inode>, const BootModule&);
BAN::ErrorOr<void> unpack_boot_module_into_filesystem(BAN::RefPtr<FileSystem>, const BootModule&);
} }

View File

@@ -71,13 +71,13 @@ namespace Kernel
File root_file() File root_file()
{ {
return File(root_inode(), "/"_sv); return File { root_inode(), "/"_sv };
} }
BAN::ErrorOr<File> file_from_relative_path(const File& parent, const Credentials&, BAN::StringView, int); BAN::ErrorOr<File> file_from_relative_path(BAN::RefPtr<Inode> root_inode, const File& parent, const Credentials&, BAN::StringView, int);
BAN::ErrorOr<File> file_from_absolute_path(const Credentials& credentials, BAN::StringView path, int flags) BAN::ErrorOr<File> file_from_absolute_path(BAN::RefPtr<Inode> root_inode, const Credentials& credentials, BAN::StringView path, int flags)
{ {
return file_from_relative_path(root_file(), credentials, path, flags); return file_from_relative_path(root_inode, File { root_inode, "/"_sv }, credentials, path, flags);
} }
private: private:

View File

@@ -129,7 +129,8 @@ namespace Kernel
} }
#if ARCH(i686) #if ARCH(i686)
void set_tls(uintptr_t addr); void set_fsbase(uintptr_t addr);
void set_gsbase(uintptr_t addr);
#endif #endif
private: private:
@@ -150,11 +151,11 @@ namespace Kernel
private: private:
#if ARCH(x86_64) #if ARCH(x86_64)
BAN::Array<SegmentDescriptor, 7> m_gdt; // null, kernel code, kernel data, user code, user data, tss low, tss high BAN::Array<SegmentDescriptor, 8> m_gdt; // null, kernel code, kernel data, user code (32 bit), user data, user code (64 bit), tss low, tss high
static constexpr uint16_t m_tss_offset = 0x28; static constexpr uint16_t m_tss_offset = 0x30;
#elif ARCH(i686) #elif ARCH(i686)
BAN::Array<SegmentDescriptor, 8> m_gdt; // null, kernel code, kernel data, user code, user data, processor data, tls, tss BAN::Array<SegmentDescriptor, 9> m_gdt; // null, kernel code, kernel data, user code, user data, processor data, fsbase, gsbase, tss
static constexpr uint16_t m_tss_offset = 0x38; static constexpr uint16_t m_tss_offset = 0x40;
#endif #endif
TaskStateSegment m_tss; TaskStateSegment m_tss;
const GDTR m_gdtr { const GDTR m_gdtr {

View File

@@ -18,10 +18,12 @@ namespace Kernel
constexpr uint8_t IRQ_VECTOR_BASE = 0x20; constexpr uint8_t IRQ_VECTOR_BASE = 0x20;
constexpr uint8_t IRQ_MSI_BASE = 0x80; constexpr uint8_t IRQ_MSI_BASE = 0x80;
constexpr uint8_t IRQ_SYSCALL = 0xF0; constexpr uint8_t IRQ_MSI_END = 0xF0;
constexpr uint8_t IRQ_YIELD = 0xF1; #if ARCH(i686)
constexpr uint8_t IRQ_IPI = 0xF2; constexpr uint8_t IRQ_SYSCALL = 0xF0; // hard coded in kernel/API/Syscall.h
constexpr uint8_t IRQ_TIMER = 0xF3; #endif
constexpr uint8_t IRQ_IPI = 0xF1;
constexpr uint8_t IRQ_TIMER = 0xF2;
#if ARCH(x86_64) #if ARCH(x86_64)
struct GateDescriptor struct GateDescriptor

View File

@@ -15,6 +15,7 @@ namespace Kernel
{ {
Mouse, Mouse,
Keyboard, Keyboard,
Joystick,
}; };
public: public:

View File

@@ -14,6 +14,15 @@ namespace Kernel::Input
class PS2Controller class PS2Controller
{ {
public:
enum class DeviceType
{
None,
Unknown,
Keyboard,
Mouse,
};
public: public:
static BAN::ErrorOr<void> initialize(uint8_t scancode_set); static BAN::ErrorOr<void> initialize(uint8_t scancode_set);
static PS2Controller& get(); static PS2Controller& get();
@@ -24,10 +33,12 @@ namespace Kernel::Input
// Returns true, if byte is used as command, if returns false, byte is meant to device // Returns true, if byte is used as command, if returns false, byte is meant to device
bool handle_command_byte(PS2Device*, uint8_t); bool handle_command_byte(PS2Device*, uint8_t);
uint8_t data_port() const { return m_data_port; }
private: private:
PS2Controller() = default; PS2Controller() = default;
BAN::ErrorOr<void> initialize_impl(uint8_t scancode_set); BAN::ErrorOr<void> initialize_impl(uint8_t scancode_set);
BAN::ErrorOr<void> identify_device(uint8_t, uint8_t scancode_set); BAN::ErrorOr<DeviceType> identify_device(uint8_t);
void device_initialize_task(void*); void device_initialize_task(void*);
@@ -61,6 +72,9 @@ namespace Kernel::Input
}; };
private: private:
uint16_t m_command_port { PS2::IOPort::COMMAND };
uint16_t m_data_port { PS2::IOPort::DATA };
BAN::RefPtr<PS2Device> m_devices[2]; BAN::RefPtr<PS2Device> m_devices[2];
Mutex m_mutex; Mutex m_mutex;

View File

@@ -27,7 +27,6 @@ namespace Kernel
uintptr_t r10; uintptr_t r10;
uintptr_t r9; uintptr_t r9;
uintptr_t r8; uintptr_t r8;
uintptr_t rdi; uintptr_t rdi;
uintptr_t rsi; uintptr_t rsi;
uintptr_t rbp; uintptr_t rbp;
@@ -36,6 +35,18 @@ namespace Kernel
uintptr_t rcx; uintptr_t rcx;
uintptr_t rax; uintptr_t rax;
}; };
struct YieldRegisters
{
uintptr_t r15;
uintptr_t r14;
uintptr_t r13;
uintptr_t r12;
uintptr_t rbp;
uintptr_t rbx;
uintptr_t ret;
uintptr_t sp;
uintptr_t ip;
};
#elif ARCH(i686) #elif ARCH(i686)
struct InterruptRegisters struct InterruptRegisters
{ {
@@ -48,6 +59,16 @@ namespace Kernel
uintptr_t ecx; uintptr_t ecx;
uintptr_t eax; uintptr_t eax;
}; };
struct YieldRegisters
{
uintptr_t ebp;
uintptr_t edi;
uintptr_t esi;
uintptr_t ebx;
uintptr_t ret;
uintptr_t sp;
uintptr_t ip;
};
#endif #endif
} }

View File

@@ -0,0 +1,97 @@
#pragma once
#include <kernel/Lock/Mutex.h>
#include <kernel/Lock/LockGuard.h>
namespace Kernel
{
class RWLock
{
BAN_NON_COPYABLE(RWLock);
BAN_NON_MOVABLE(RWLock);
public:
RWLock() = default;
void rd_lock()
{
LockGuard _(m_mutex);
while (m_writers_waiting > 0 || m_writer_active)
m_thread_blocker.block_indefinite(&m_mutex);
m_readers_active++;
}
void rd_unlock()
{
LockGuard _(m_mutex);
if (--m_readers_active == 0)
m_thread_blocker.unblock();
}
void wr_lock()
{
LockGuard _(m_mutex);
m_writers_waiting++;
while (m_readers_active > 0 || m_writer_active)
m_thread_blocker.block_indefinite(&m_mutex);
m_writers_waiting--;
m_writer_active = true;
}
void wr_unlock()
{
LockGuard _(m_mutex);
m_writer_active = false;
m_thread_blocker.unblock();
}
private:
Mutex m_mutex;
ThreadBlocker m_thread_blocker;
uint32_t m_readers_active { 0 };
uint32_t m_writers_waiting { 0 };
bool m_writer_active { false };
};
class RWLockRDGuard
{
BAN_NON_COPYABLE(RWLockRDGuard);
BAN_NON_MOVABLE(RWLockRDGuard);
public:
RWLockRDGuard(RWLock& lock)
: m_lock(lock)
{
m_lock.rd_lock();
}
~RWLockRDGuard()
{
m_lock.rd_unlock();
}
private:
RWLock& m_lock;
};
class RWLockWRGuard
{
BAN_NON_COPYABLE(RWLockWRGuard);
BAN_NON_MOVABLE(RWLockWRGuard);
public:
RWLockWRGuard(RWLock& lock)
: m_lock(lock)
{
m_lock.wr_lock();
}
~RWLockWRGuard()
{
m_lock.wr_unlock();
}
private:
RWLock& m_lock;
};
}

View File

@@ -0,0 +1,76 @@
#pragma once
#include <BAN/ByteSpan.h>
#include <BAN/UniqPtr.h>
#include <BAN/Vector.h>
#include <kernel/Memory/Types.h>
namespace Kernel
{
class ByteRingBuffer
{
public:
static BAN::ErrorOr<BAN::UniqPtr<ByteRingBuffer>> create(size_t size);
~ByteRingBuffer();
void push(BAN::ConstByteSpan data)
{
ASSERT(data.size() + m_size <= m_capacity);
uint8_t* buffer_head = reinterpret_cast<uint8_t*>(m_vaddr) + (m_tail + m_size) % m_capacity;
memcpy(buffer_head, data.data(), data.size());
m_size += data.size();
}
void pop(size_t size)
{
ASSERT(size <= m_size);
m_tail = (m_tail + size) % m_capacity;
m_size -= size;
}
void pop_back(size_t size)
{
ASSERT(size <= m_size);
m_size -= size;
}
BAN::ConstByteSpan get_data() const
{
const uint8_t* base = reinterpret_cast<const uint8_t*>(m_vaddr);
return { base + m_tail, m_size };
}
uint8_t front() const
{
ASSERT(!empty());
return reinterpret_cast<const uint8_t*>(m_vaddr)[m_tail];
}
uint8_t back() const
{
ASSERT(!empty());
return reinterpret_cast<const uint8_t*>(m_vaddr)[m_tail + m_size];
}
bool empty() const { return m_size == 0; }
bool full() const { return m_size == m_capacity; }
size_t free() const { return m_capacity - m_size; }
size_t size() const { return m_size; }
size_t capacity() const { return m_capacity; }
private:
ByteRingBuffer(size_t capacity)
: m_capacity(capacity)
{ }
private:
size_t m_size { 0 };
size_t m_tail { 0 };
const size_t m_capacity;
vaddr_t m_vaddr { 0 };
};
}

View File

@@ -27,18 +27,19 @@ namespace Kernel
BAN_NON_MOVABLE(FileBackedRegion); BAN_NON_MOVABLE(FileBackedRegion);
public: public:
static BAN::ErrorOr<BAN::UniqPtr<FileBackedRegion>> create(BAN::RefPtr<Inode>, PageTable&, off_t offset, size_t size, AddressRange address_range, Type, PageTable::flags_t); static BAN::ErrorOr<BAN::UniqPtr<FileBackedRegion>> create(BAN::RefPtr<Inode>, PageTable&, off_t offset, size_t size, AddressRange address_range, Type, PageTable::flags_t, int status_flags);
~FileBackedRegion(); ~FileBackedRegion();
virtual BAN::ErrorOr<void> msync(vaddr_t, size_t, int) override; BAN::ErrorOr<void> msync(vaddr_t, size_t, int) override;
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override; BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override;
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> split(size_t offset) override;
protected: protected:
virtual BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override; BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override;
private: private:
FileBackedRegion(BAN::RefPtr<Inode>, PageTable&, off_t offset, ssize_t size, Type flags, PageTable::flags_t page_flags); FileBackedRegion(BAN::RefPtr<Inode>, PageTable&, off_t offset, ssize_t size, Type type, PageTable::flags_t flags, int status_flags);
private: private:
BAN::RefPtr<Inode> m_inode; BAN::RefPtr<Inode> m_inode;

View File

@@ -18,6 +18,8 @@ namespace Kernel
static void initialize(); static void initialize();
static Heap& get(); static Heap& get();
void release_boot_modules();
paddr_t take_free_page(); paddr_t take_free_page();
void release_page(paddr_t); void release_page(paddr_t);

View File

@@ -11,22 +11,37 @@ namespace Kernel
BAN_NON_MOVABLE(MemoryBackedRegion); BAN_NON_MOVABLE(MemoryBackedRegion);
public: public:
static BAN::ErrorOr<BAN::UniqPtr<MemoryBackedRegion>> create(PageTable&, size_t size, AddressRange, Type, PageTable::flags_t); static BAN::ErrorOr<BAN::UniqPtr<MemoryBackedRegion>> create(PageTable&, size_t size, AddressRange, Type, PageTable::flags_t, int status_flags);
~MemoryBackedRegion(); ~MemoryBackedRegion();
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override; BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override;
BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> split(size_t offset) override;
virtual BAN::ErrorOr<void> msync(vaddr_t, size_t, int) override { return {}; } BAN::ErrorOr<void> msync(vaddr_t, size_t, int) override { return {}; }
// Copy data from buffer into this region // Copy data from buffer into this region
// This can fail if no memory is mapped and no free memory was available // This can fail if no memory is mapped and no free memory was available
BAN::ErrorOr<void> copy_data_to_region(size_t offset_into_region, const uint8_t* buffer, size_t buffer_size); BAN::ErrorOr<void> copy_data_to_region(size_t offset_into_region, const uint8_t* buffer, size_t buffer_size);
protected: protected:
virtual BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override; BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override;
private: private:
MemoryBackedRegion(PageTable&, size_t size, Type, PageTable::flags_t); MemoryBackedRegion(PageTable&, size_t size, Type, PageTable::flags_t, int status_flags);
private:
struct PhysicalPage
{
PhysicalPage(paddr_t paddr)
: paddr(paddr)
{ }
~PhysicalPage();
BAN::Atomic<uint32_t> ref_count { 1 };
const paddr_t paddr;
};
BAN::Vector<PhysicalPage*> m_physical_pages;
Mutex m_mutex;
}; };
} }

View File

@@ -33,12 +33,17 @@ namespace Kernel
bool contains(vaddr_t address) const; bool contains(vaddr_t address) const;
bool contains_fully(vaddr_t address, size_t size) const; bool contains_fully(vaddr_t address, size_t size) const;
bool overlaps(vaddr_t address, size_t size) const; bool overlaps(vaddr_t address, size_t size) const;
bool is_contained_by(vaddr_t address, size_t size) const;
bool writable() const { return m_flags & PageTable::Flags::ReadWrite; } bool writable() const { return m_flags & PageTable::Flags::ReadWrite; }
size_t size() const { return m_size; } size_t size() const { return m_size; }
vaddr_t vaddr() const { return m_vaddr; } vaddr_t vaddr() const { return m_vaddr; }
int status_flags() const { return m_status_flags; }
Type type() const { return m_type; }
PageTable::flags_t flags() const { return m_flags; }
size_t virtual_page_count() const { return BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE); } size_t virtual_page_count() const { return BAN::Math::div_round_up<size_t>(m_size, PAGE_SIZE); }
size_t physical_page_count() const { return m_physical_page_count; } size_t physical_page_count() const { return m_physical_page_count; }
@@ -46,6 +51,7 @@ namespace Kernel
void unpin(); void unpin();
void wait_not_pinned(); void wait_not_pinned();
BAN::ErrorOr<void> mprotect(PageTable::flags_t);
virtual BAN::ErrorOr<void> msync(vaddr_t, size_t, int) = 0; virtual BAN::ErrorOr<void> msync(vaddr_t, size_t, int) = 0;
// Returns error if no memory was available // Returns error if no memory was available
@@ -54,18 +60,20 @@ namespace Kernel
BAN::ErrorOr<bool> allocate_page_containing(vaddr_t address, bool wants_write); BAN::ErrorOr<bool> allocate_page_containing(vaddr_t address, bool wants_write);
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) = 0; virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) = 0;
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> split(size_t offset) = 0;
protected: protected:
MemoryRegion(PageTable&, size_t size, Type type, PageTable::flags_t flags); MemoryRegion(PageTable&, size_t size, Type type, PageTable::flags_t flags, int status_flags);
BAN::ErrorOr<void> initialize(AddressRange); BAN::ErrorOr<void> initialize(AddressRange);
virtual BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t address, bool wants_write) = 0; virtual BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t address, bool wants_write) = 0;
protected: protected:
PageTable& m_page_table; PageTable& m_page_table;
const size_t m_size; size_t m_size { 0 };
const Type m_type; const Type m_type;
const PageTable::flags_t m_flags; PageTable::flags_t m_flags;
const int m_status_flags;
vaddr_t m_vaddr { 0 }; vaddr_t m_vaddr { 0 };
size_t m_physical_page_count { 0 }; size_t m_physical_page_count { 0 };

View File

@@ -100,19 +100,21 @@ namespace Kernel
static BAN::ErrorOr<PageTable*> create_userspace(); static BAN::ErrorOr<PageTable*> create_userspace();
~PageTable(); ~PageTable();
void unmap_page(vaddr_t, bool send_smp_message = true); void unmap_page(vaddr_t, bool invalidate = true);
void unmap_range(vaddr_t, size_t bytes); void unmap_range(vaddr_t, size_t bytes);
void map_page_at(paddr_t, vaddr_t, flags_t, MemoryType = MemoryType::Normal, bool send_smp_message = true); void map_page_at(paddr_t, vaddr_t, flags_t, MemoryType = MemoryType::Normal, bool invalidate = true);
void map_range_at(paddr_t, vaddr_t, size_t bytes, flags_t, MemoryType = MemoryType::Normal); void map_range_at(paddr_t, vaddr_t, size_t bytes, flags_t, MemoryType = MemoryType::Normal);
void remove_writable_from_range(vaddr_t, size_t);
paddr_t physical_address_of(vaddr_t) const; paddr_t physical_address_of(vaddr_t) const;
flags_t get_page_flags(vaddr_t) const; flags_t get_page_flags(vaddr_t) const;
bool is_page_free(vaddr_t) const; bool is_page_free(vaddr_t) const;
bool is_range_free(vaddr_t, size_t bytes) const; bool is_range_free(vaddr_t, size_t bytes) const;
bool reserve_page(vaddr_t, bool only_free = true); bool reserve_page(vaddr_t, bool only_free = true, bool invalidate = true);
bool reserve_range(vaddr_t, size_t bytes, bool only_free = true); bool reserve_range(vaddr_t, size_t bytes, bool only_free = true);
vaddr_t reserve_free_page(vaddr_t first_address, vaddr_t last_address = UINTPTR_MAX); vaddr_t reserve_free_page(vaddr_t first_address, vaddr_t last_address = UINTPTR_MAX);
@@ -121,6 +123,9 @@ namespace Kernel
void load(); void load();
void initial_load(); void initial_load();
void invalidate_page(vaddr_t addr, bool send_smp_message) { invalidate_range(addr, 1, send_smp_message); }
void invalidate_range(vaddr_t addr, size_t pages, bool send_smp_message);
InterruptState lock() const { return m_lock.lock(); } InterruptState lock() const { return m_lock.lock(); }
void unlock(InterruptState state) const { m_lock.unlock(state); } void unlock(InterruptState state) const { m_lock.unlock(state); }
@@ -133,8 +138,6 @@ namespace Kernel
void map_kernel_memory(); void map_kernel_memory();
void prepare_fast_page(); void prepare_fast_page();
static void invalidate(vaddr_t, bool send_smp_message);
static void map_fast_page(paddr_t); static void map_fast_page(paddr_t);
static void unmap_fast_page(); static void unmap_fast_page();

View File

@@ -10,7 +10,7 @@ namespace Kernel
class PhysicalRange class PhysicalRange
{ {
public: public:
PhysicalRange(paddr_t, size_t); PhysicalRange(paddr_t, uint64_t);
paddr_t reserve_page(); paddr_t reserve_page();
void release_page(paddr_t); void release_page(paddr_t);

View File

@@ -6,6 +6,8 @@
#include <kernel/Lock/SpinLock.h> #include <kernel/Lock/SpinLock.h>
#include <kernel/Memory/MemoryRegion.h> #include <kernel/Memory/MemoryRegion.h>
#include <fcntl.h>
namespace Kernel namespace Kernel
{ {
@@ -55,15 +57,17 @@ namespace Kernel
public: public:
static BAN::ErrorOr<BAN::UniqPtr<SharedMemoryObject>> create(BAN::RefPtr<SharedMemoryObjectManager::Object>, PageTable&, AddressRange); static BAN::ErrorOr<BAN::UniqPtr<SharedMemoryObject>> create(BAN::RefPtr<SharedMemoryObjectManager::Object>, PageTable&, AddressRange);
virtual BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override; BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> clone(PageTable& new_page_table) override;
virtual BAN::ErrorOr<void> msync(vaddr_t, size_t, int) override { return {}; } BAN::ErrorOr<BAN::UniqPtr<MemoryRegion>> split(size_t offset) override;
BAN::ErrorOr<void> msync(vaddr_t, size_t, int) override { return {}; }
protected: protected:
virtual BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override; BAN::ErrorOr<bool> allocate_page_containing_impl(vaddr_t vaddr, bool wants_write) override;
private: private:
SharedMemoryObject(BAN::RefPtr<SharedMemoryObjectManager::Object> object, PageTable& page_table) SharedMemoryObject(BAN::RefPtr<SharedMemoryObjectManager::Object> object, PageTable& page_table)
: MemoryRegion(page_table, object->size, MemoryRegion::Type::SHARED, object->flags) : MemoryRegion(page_table, object->size, MemoryRegion::Type::SHARED, object->flags, O_EXEC | O_RDWR)
, m_object(object) , m_object(object)
{ } { }

View File

@@ -4,7 +4,7 @@
#if ARCH(x86_64) #if ARCH(x86_64)
#define KERNEL_OFFSET 0xFFFFFFFF80000000 #define KERNEL_OFFSET 0xFFFFFFFF80000000
#define USERSPACE_END 0xFFFF800000000000 #define USERSPACE_END 0x800000000000
#elif ARCH(i686) #elif ARCH(i686)
#define KERNEL_OFFSET 0xC0000000 #define KERNEL_OFFSET 0xC0000000
#define USERSPACE_END 0xC0000000 #define USERSPACE_END 0xC0000000

View File

@@ -20,8 +20,6 @@ namespace Kernel
static BAN::ErrorOr<BAN::UniqPtr<VirtualRange>> create_to_vaddr_range(PageTable&, vaddr_t vaddr_start, vaddr_t vaddr_end, size_t, PageTable::flags_t flags, bool preallocate_pages, bool add_guard_pages); static BAN::ErrorOr<BAN::UniqPtr<VirtualRange>> create_to_vaddr_range(PageTable&, vaddr_t vaddr_start, vaddr_t vaddr_end, size_t, PageTable::flags_t flags, bool preallocate_pages, bool add_guard_pages);
~VirtualRange(); ~VirtualRange();
BAN::ErrorOr<BAN::UniqPtr<VirtualRange>> clone(PageTable&);
vaddr_t vaddr() const { return m_vaddr + (m_has_guard_pages ? PAGE_SIZE : 0); } vaddr_t vaddr() const { return m_vaddr + (m_has_guard_pages ? PAGE_SIZE : 0); }
size_t size() const { return m_size - (m_has_guard_pages ? 2 * PAGE_SIZE : 0); } size_t size() const { return m_size - (m_has_guard_pages ? 2 * PAGE_SIZE : 0); }
PageTable::flags_t flags() const { return m_flags; } PageTable::flags_t flags() const { return m_flags; }
@@ -38,7 +36,7 @@ namespace Kernel
bool contains(vaddr_t address) const { return vaddr() <= address && address < vaddr() + size(); } bool contains(vaddr_t address) const { return vaddr() <= address && address < vaddr() + size(); }
BAN::ErrorOr<void> allocate_page_for_demand_paging(vaddr_t address); BAN::ErrorOr<bool> allocate_page_for_demand_paging(vaddr_t address);
private: private:
VirtualRange(PageTable&, bool preallocated, bool has_guard_pages, vaddr_t, size_t, PageTable::flags_t); VirtualRange(PageTable&, bool preallocated, bool has_guard_pages, vaddr_t, size_t, PageTable::flags_t);

View File

@@ -31,35 +31,18 @@ namespace Kernel
public: public:
static BAN::ErrorOr<BAN::UniqPtr<ARPTable>> create(); static BAN::ErrorOr<BAN::UniqPtr<ARPTable>> create();
~ARPTable();
BAN::ErrorOr<BAN::MACAddress> get_mac_from_ipv4(NetworkInterface&, BAN::IPv4Address); BAN::ErrorOr<BAN::MACAddress> get_mac_from_ipv4(NetworkInterface&, BAN::IPv4Address);
void add_arp_packet(NetworkInterface&, BAN::ConstByteSpan); BAN::ErrorOr<void> handle_arp_packet(NetworkInterface&, BAN::ConstByteSpan);
private: private:
ARPTable(); ARPTable() = default;
void packet_handle_task();
BAN::ErrorOr<void> handle_arp_packet(NetworkInterface&, const ARPPacket&);
private: private:
struct PendingArpPacket SpinLock m_arp_table_lock;
{
NetworkInterface& interface;
ARPPacket packet;
};
private:
SpinLock m_table_lock;
SpinLock m_pending_lock;
BAN::HashMap<BAN::IPv4Address, BAN::MACAddress> m_arp_table; BAN::HashMap<BAN::IPv4Address, BAN::MACAddress> m_arp_table;
Thread* m_thread { nullptr };
BAN::CircularQueue<PendingArpPacket, 128> m_pending_packets;
ThreadBlocker m_pending_thread_blocker;
friend class BAN::UniqPtr<ARPTable>; friend class BAN::UniqPtr<ARPTable>;
}; };

View File

@@ -23,14 +23,14 @@ namespace Kernel
static BAN::ErrorOr<BAN::RefPtr<E1000>> create(PCI::Device&); static BAN::ErrorOr<BAN::RefPtr<E1000>> create(PCI::Device&);
~E1000(); ~E1000();
virtual BAN::MACAddress get_mac_address() const override { return m_mac_address; } BAN::MACAddress get_mac_address() const override { return m_mac_address; }
virtual bool link_up() override { return m_link_up; } bool link_up() override { return m_link_up; }
virtual int link_speed() override; int link_speed() override;
virtual size_t payload_mtu() const override { return E1000_RX_BUFFER_SIZE - sizeof(EthernetHeader); } size_t payload_mtu() const override { return E1000_RX_BUFFER_SIZE - sizeof(EthernetHeader); }
virtual void handle_irq() final override; void handle_irq() final override;
protected: protected:
E1000(PCI::Device& pci_device) E1000(PCI::Device& pci_device)
@@ -45,12 +45,12 @@ namespace Kernel
uint32_t read32(uint16_t reg); uint32_t read32(uint16_t reg);
void write32(uint16_t reg, uint32_t value); void write32(uint16_t reg, uint32_t value);
virtual BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan) override; BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::Span<const BAN::ConstByteSpan> payload) override;
virtual bool can_read_impl() const override { return false; } bool can_read_impl() const override { return false; }
virtual bool can_write_impl() const override { return false; } bool can_write_impl() const override { return false; }
virtual bool has_error_impl() const override { return false; } bool has_error_impl() const override { return false; }
virtual bool has_hungup_impl() const override { return false; } bool has_hungup_impl() const override { return false; }
private: private:
BAN::ErrorOr<void> read_mac_address(); BAN::ErrorOr<void> read_mac_address();
@@ -61,7 +61,7 @@ namespace Kernel
void enable_link(); void enable_link();
BAN::ErrorOr<void> enable_interrupt(); BAN::ErrorOr<void> enable_interrupt();
void handle_receive(); void receive_thread();
protected: protected:
PCI::Device& m_pci_device; PCI::Device& m_pci_device;
@@ -75,6 +75,10 @@ namespace Kernel
BAN::UniqPtr<DMARegion> m_tx_descriptor_region; BAN::UniqPtr<DMARegion> m_tx_descriptor_region;
SpinLock m_lock; SpinLock m_lock;
bool m_thread_should_die { false };
BAN::Atomic<bool> m_thread_is_dead { true };
ThreadBlocker m_thread_blocker;
BAN::MACAddress m_mac_address {}; BAN::MACAddress m_mac_address {};
bool m_link_up { false }; bool m_link_up { false };

View File

@@ -12,8 +12,8 @@ namespace Kernel
static BAN::ErrorOr<BAN::RefPtr<E1000E>> create(PCI::Device&); static BAN::ErrorOr<BAN::RefPtr<E1000E>> create(PCI::Device&);
protected: protected:
virtual void detect_eeprom() override; void detect_eeprom() override;
virtual uint32_t eeprom_read(uint8_t addr) override; uint32_t eeprom_read(uint8_t addr) override;
private: private:
E1000E(PCI::Device& pci_device) E1000E(PCI::Device& pci_device)

View File

@@ -38,14 +38,13 @@ namespace Kernel
public: public:
static BAN::ErrorOr<BAN::UniqPtr<IPv4Layer>> create(); static BAN::ErrorOr<BAN::UniqPtr<IPv4Layer>> create();
~IPv4Layer();
ARPTable& arp_table() { return *m_arp_table; } ARPTable& arp_table() { return *m_arp_table; }
void add_ipv4_packet(NetworkInterface&, BAN::ConstByteSpan); BAN::ErrorOr<void> handle_ipv4_packet(NetworkInterface&, BAN::ConstByteSpan);
virtual void unbind_socket(uint16_t port) override; virtual void unbind_socket(uint16_t port) override;
virtual BAN::ErrorOr<void> bind_socket_to_unused(BAN::RefPtr<NetworkSocket>, const sockaddr* send_address, socklen_t send_address_len) override; virtual BAN::ErrorOr<void> bind_socket_with_target(BAN::RefPtr<NetworkSocket>, const sockaddr* target_address, socklen_t target_address_len) override;
virtual BAN::ErrorOr<void> bind_socket_to_address(BAN::RefPtr<NetworkSocket>, const sockaddr* address, socklen_t address_len) override; virtual BAN::ErrorOr<void> bind_socket_to_address(BAN::RefPtr<NetworkSocket>, const sockaddr* address, socklen_t address_len) override;
virtual BAN::ErrorOr<void> get_socket_address(BAN::RefPtr<NetworkSocket>, sockaddr* address, socklen_t* address_len) override; virtual BAN::ErrorOr<void> get_socket_address(BAN::RefPtr<NetworkSocket>, sockaddr* address, socklen_t* address_len) override;
@@ -55,33 +54,15 @@ namespace Kernel
virtual size_t header_size() const override { return sizeof(IPv4Header); } virtual size_t header_size() const override { return sizeof(IPv4Header); }
private: private:
IPv4Layer(); IPv4Layer() = default;
void add_ipv4_header(BAN::ByteSpan packet, BAN::IPv4Address src_ipv4, BAN::IPv4Address dst_ipv4, uint8_t protocol) const; BAN::ErrorOr<in_port_t> find_free_port();
void packet_handle_task();
BAN::ErrorOr<void> handle_ipv4_packet(NetworkInterface&, BAN::ByteSpan);
private: private:
struct PendingIPv4Packet BAN::UniqPtr<ARPTable> m_arp_table;
{
NetworkInterface& interface;
};
private: RecursiveSpinLock m_bound_socket_lock;
RecursiveSpinLock m_bound_socket_lock; BAN::HashMap<int, BAN::WeakPtr<NetworkSocket>> m_bound_sockets;
BAN::UniqPtr<ARPTable> m_arp_table;
Thread* m_thread { nullptr };
static constexpr size_t pending_packet_buffer_size = 128 * PAGE_SIZE;
BAN::UniqPtr<VirtualRange> m_pending_packet_buffer;
BAN::CircularQueue<PendingIPv4Packet, 128> m_pending_packets;
ThreadBlocker m_pending_thread_blocker;
SpinLock m_pending_lock;
size_t m_pending_total_size { 0 };
BAN::HashMap<int, BAN::WeakPtr<NetworkSocket>> m_bound_sockets;
friend class BAN::UniqPtr<IPv4Layer>; friend class BAN::UniqPtr<IPv4Layer>;
}; };

View File

@@ -9,6 +9,7 @@ namespace Kernel
{ {
public: public:
static constexpr size_t buffer_size = BAN::numeric_limits<uint16_t>::max() + 1; static constexpr size_t buffer_size = BAN::numeric_limits<uint16_t>::max() + 1;
static constexpr size_t buffer_count = 32;
public: public:
static BAN::ErrorOr<BAN::RefPtr<LoopbackInterface>> create(); static BAN::ErrorOr<BAN::RefPtr<LoopbackInterface>> create();
@@ -24,8 +25,9 @@ namespace Kernel
LoopbackInterface() LoopbackInterface()
: NetworkInterface(Type::Loopback) : NetworkInterface(Type::Loopback)
{} {}
~LoopbackInterface();
BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan) override; BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::Span<const BAN::ConstByteSpan> payload) override;
bool can_read_impl() const override { return false; } bool can_read_impl() const override { return false; }
bool can_write_impl() const override { return false; } bool can_write_impl() const override { return false; }
@@ -33,8 +35,27 @@ namespace Kernel
bool has_hungup_impl() const override { return false; } bool has_hungup_impl() const override { return false; }
private: private:
SpinLock m_buffer_lock; void receive_thread();
private:
struct Descriptor
{
uint8_t* addr;
uint32_t size;
uint8_t state;
};
private:
Mutex m_buffer_lock;
BAN::UniqPtr<VirtualRange> m_buffer; BAN::UniqPtr<VirtualRange> m_buffer;
uint32_t m_buffer_tail { 0 };
uint32_t m_buffer_head { 0 };
Descriptor m_descriptors[buffer_count] {};
bool m_thread_should_die { false };
BAN::Atomic<bool> m_thread_is_dead { true };
ThreadBlocker m_thread_blocker;
}; };
} }

View File

@@ -60,7 +60,11 @@ namespace Kernel
virtual dev_t rdev() const override { return m_rdev; } virtual dev_t rdev() const override { return m_rdev; }
virtual BAN::StringView name() const override { return m_name; } virtual BAN::StringView name() const override { return m_name; }
virtual BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan) = 0; BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan payload)
{
return send_bytes(destination, protocol, { &payload, 1 });
}
virtual BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::Span<const BAN::ConstByteSpan> payload) = 0;
private: private:
const Type m_type; const Type m_type;

View File

@@ -11,7 +11,7 @@ namespace Kernel
BAN::IPv4Address src_ipv4 { 0 }; BAN::IPv4Address src_ipv4 { 0 };
BAN::IPv4Address dst_ipv4 { 0 }; BAN::IPv4Address dst_ipv4 { 0 };
BAN::NetworkEndian<uint16_t> protocol { 0 }; BAN::NetworkEndian<uint16_t> protocol { 0 };
BAN::NetworkEndian<uint16_t> extra { 0 }; BAN::NetworkEndian<uint16_t> length { 0 };
}; };
static_assert(sizeof(PseudoHeader) == 12); static_assert(sizeof(PseudoHeader) == 12);
@@ -23,7 +23,7 @@ namespace Kernel
virtual ~NetworkLayer() {} virtual ~NetworkLayer() {}
virtual void unbind_socket(uint16_t port) = 0; virtual void unbind_socket(uint16_t port) = 0;
virtual BAN::ErrorOr<void> bind_socket_to_unused(BAN::RefPtr<NetworkSocket>, const sockaddr* send_address, socklen_t send_address_len) = 0; virtual BAN::ErrorOr<void> bind_socket_with_target(BAN::RefPtr<NetworkSocket>, const sockaddr* target_address, socklen_t target_address_len) = 0;
virtual BAN::ErrorOr<void> bind_socket_to_address(BAN::RefPtr<NetworkSocket>, const sockaddr* address, socklen_t address_len) = 0; virtual BAN::ErrorOr<void> bind_socket_to_address(BAN::RefPtr<NetworkSocket>, const sockaddr* address, socklen_t address_len) = 0;
virtual BAN::ErrorOr<void> get_socket_address(BAN::RefPtr<NetworkSocket>, sockaddr* address, socklen_t* address_len) = 0; virtual BAN::ErrorOr<void> get_socket_address(BAN::RefPtr<NetworkSocket>, sockaddr* address, socklen_t* address_len) = 0;
@@ -36,6 +36,7 @@ namespace Kernel
NetworkLayer() = default; NetworkLayer() = default;
}; };
uint16_t calculate_internet_checksum(BAN::ConstByteSpan packet, const PseudoHeader& pseudo_header); uint16_t calculate_internet_checksum(BAN::ConstByteSpan buffer);
uint16_t calculate_internet_checksum(BAN::Span<const BAN::ConstByteSpan> buffers);
} }

View File

@@ -5,6 +5,8 @@
#include <kernel/Networking/NetworkInterface.h> #include <kernel/Networking/NetworkInterface.h>
#include <kernel/Networking/NetworkLayer.h> #include <kernel/Networking/NetworkLayer.h>
#include <netinet/in.h>
namespace Kernel namespace Kernel
{ {
@@ -24,18 +26,30 @@ namespace Kernel
static constexpr uint16_t PORT_NONE = 0; static constexpr uint16_t PORT_NONE = 0;
public: public:
void bind_interface_and_port(NetworkInterface*, uint16_t port); void bind_address_and_port(const sockaddr*, socklen_t);
~NetworkSocket(); ~NetworkSocket();
NetworkInterface& interface() { ASSERT(m_interface); return *m_interface; } BAN::ErrorOr<BAN::RefPtr<NetworkInterface>> interface(const sockaddr* target, socklen_t target_len);
virtual size_t protocol_header_size() const = 0; virtual size_t protocol_header_size() const = 0;
virtual void add_protocol_header(BAN::ByteSpan packet, uint16_t dst_port, PseudoHeader) = 0; virtual void get_protocol_header(BAN::ByteSpan header, BAN::ConstByteSpan payload, uint16_t dst_port, PseudoHeader) = 0;
virtual NetworkProtocol protocol() const = 0; virtual NetworkProtocol protocol() const = 0;
virtual void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) = 0; virtual void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) = 0;
bool is_bound() const { return m_interface != nullptr; } bool is_bound() const { return m_address_len >= static_cast<socklen_t>(sizeof(sa_family_t)) && m_address.ss_family != AF_UNSPEC; }
in_port_t bound_port() const
{
ASSERT(is_bound());
ASSERT(m_address.ss_family == AF_INET && m_address_len >= static_cast<socklen_t>(sizeof(sockaddr_in)));
return BAN::network_endian_to_host(reinterpret_cast<const sockaddr_in*>(&m_address)->sin_port);
}
const sockaddr* address() const { return reinterpret_cast<const sockaddr*>(&m_address); }
socklen_t address_len() const { return m_address_len; }
private:
bool can_interface_send_to(const NetworkInterface&, const sockaddr*, socklen_t) const;
protected: protected:
NetworkSocket(NetworkLayer&, const Socket::Info&); NetworkSocket(NetworkLayer&, const Socket::Info&);
@@ -45,9 +59,9 @@ namespace Kernel
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override = 0; virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override = 0;
protected: protected:
NetworkLayer& m_network_layer; NetworkLayer& m_network_layer;
NetworkInterface* m_interface = nullptr; sockaddr_storage m_address { .ss_family = AF_UNSPEC, .ss_storage = {} };
uint16_t m_port { PORT_NONE }; socklen_t m_address_len { 0 };
}; };
} }

View File

@@ -29,9 +29,11 @@ namespace Kernel
: NetworkInterface(Type::Ethernet) : NetworkInterface(Type::Ethernet)
, m_pci_device(pci_device) , m_pci_device(pci_device)
{ } { }
~RTL8169();
BAN::ErrorOr<void> initialize(); BAN::ErrorOr<void> initialize();
virtual BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::ConstByteSpan) override; virtual BAN::ErrorOr<void> send_bytes(BAN::MACAddress destination, EtherType protocol, BAN::Span<const BAN::ConstByteSpan>) override;
virtual bool can_read_impl() const override { return false; } virtual bool can_read_impl() const override { return false; }
virtual bool can_write_impl() const override { return false; } virtual bool can_write_impl() const override { return false; }
@@ -47,7 +49,7 @@ namespace Kernel
void enable_link(); void enable_link();
BAN::ErrorOr<void> enable_interrupt(); BAN::ErrorOr<void> enable_interrupt();
void handle_receive(); void receive_thread();
protected: protected:
PCI::Device& m_pci_device; PCI::Device& m_pci_device;
@@ -63,6 +65,9 @@ namespace Kernel
BAN::UniqPtr<DMARegion> m_tx_descriptor_region; BAN::UniqPtr<DMARegion> m_tx_descriptor_region;
SpinLock m_lock; SpinLock m_lock;
bool m_thread_should_die { false };
BAN::Atomic<bool> m_thread_is_dead { true };
ThreadBlocker m_thread_blocker; ThreadBlocker m_thread_blocker;
uint32_t m_rx_current { 0 }; uint32_t m_rx_current { 0 };

View File

@@ -1,9 +1,10 @@
#pragma once #pragma once
#include <BAN/HashMap.h>
#include <BAN/Endianness.h> #include <BAN/Endianness.h>
#include <BAN/Queue.h> #include <BAN/Queue.h>
#include <kernel/Lock/Mutex.h> #include <kernel/Lock/Mutex.h>
#include <kernel/Memory/VirtualRange.h> #include <kernel/Memory/ByteRingBuffer.h>
#include <kernel/Networking/NetworkInterface.h> #include <kernel/Networking/NetworkInterface.h>
#include <kernel/Networking/NetworkSocket.h> #include <kernel/Networking/NetworkSocket.h>
#include <kernel/Thread.h> #include <kernel/Thread.h>
@@ -49,26 +50,30 @@ namespace Kernel
static BAN::ErrorOr<BAN::RefPtr<TCPSocket>> create(NetworkLayer&, const Info&); static BAN::ErrorOr<BAN::RefPtr<TCPSocket>> create(NetworkLayer&, const Info&);
~TCPSocket(); ~TCPSocket();
virtual NetworkProtocol protocol() const override { return NetworkProtocol::TCP; } NetworkProtocol protocol() const override { return NetworkProtocol::TCP; }
virtual size_t protocol_header_size() const override { return sizeof(TCPHeader) + m_tcp_options_bytes; } size_t protocol_header_size() const override { return sizeof(TCPHeader) + m_tcp_options_bytes; }
virtual void add_protocol_header(BAN::ByteSpan packet, uint16_t dst_port, PseudoHeader) override; void get_protocol_header(BAN::ByteSpan header, BAN::ConstByteSpan payload, uint16_t dst_port, PseudoHeader) override;
protected: protected:
virtual BAN::ErrorOr<long> accept_impl(sockaddr*, socklen_t*, int) override; BAN::ErrorOr<long> accept_impl(sockaddr*, socklen_t*, int) override;
virtual BAN::ErrorOr<void> connect_impl(const sockaddr*, socklen_t) override; BAN::ErrorOr<void> connect_impl(const sockaddr*, socklen_t) override;
virtual BAN::ErrorOr<void> listen_impl(int) override; BAN::ErrorOr<void> listen_impl(int) override;
virtual BAN::ErrorOr<void> bind_impl(const sockaddr*, socklen_t) override; BAN::ErrorOr<void> bind_impl(const sockaddr*, socklen_t) override;
virtual BAN::ErrorOr<size_t> sendto_impl(BAN::ConstByteSpan, const sockaddr*, socklen_t) override; BAN::ErrorOr<size_t> recvmsg_impl(msghdr& message, int flags) override;
virtual BAN::ErrorOr<size_t> recvfrom_impl(BAN::ByteSpan, sockaddr*, socklen_t*) override; BAN::ErrorOr<size_t> sendmsg_impl(const msghdr& message, int flags) override;
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override; BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override;
BAN::ErrorOr<void> getsockopt_impl(int, int, void*, socklen_t*) override;
BAN::ErrorOr<void> setsockopt_impl(int, int, const void*, socklen_t) override;
virtual void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) override; BAN::ErrorOr<long> ioctl_impl(int, void*) override;
virtual bool can_read_impl() const override; void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) override;
virtual bool can_write_impl() const override;
virtual bool has_error_impl() const override { return false; } bool can_read_impl() const override;
virtual bool has_hungup_impl() const override; bool can_write_impl() const override;
bool has_error_impl() const override { return false; }
bool has_hungup_impl() const override;
private: private:
enum class State enum class State
@@ -88,33 +93,32 @@ namespace Kernel
struct RecvWindowInfo struct RecvWindowInfo
{ {
uint32_t start_seq { 0 }; // sequence number of first byte in buffer uint32_t start_seq { 0 }; // sequence number of first byte in buffer
bool has_ghost_byte { false }; bool has_ghost_byte { false };
uint32_t data_size { 0 }; // number of bytes in this buffer uint8_t scale_shift { 0 }; // window scale
uint8_t scale_shift { 0 }; // window scale BAN::UniqPtr<ByteRingBuffer> buffer;
BAN::UniqPtr<VirtualRange> buffer;
}; };
struct SendWindowInfo struct SendWindowInfo
{ {
uint32_t mss { 0 }; // maximum segment size uint32_t mss { 0 }; // maximum segment size
uint16_t non_scaled_size { 0 }; // window size without scaling uint16_t non_scaled_size { 0 }; // window size without scaling
uint8_t scale_shift { 0 }; // window scale uint8_t scale_shift { 0 }; // window scale
uint32_t scaled_size() const { return (uint32_t)non_scaled_size << scale_shift; } uint32_t scaled_size() const { return (uint32_t)non_scaled_size << scale_shift; }
uint32_t start_seq { 0 }; // sequence number of first byte in buffer uint32_t start_seq { 0 }; // sequence number of first byte in buffer
uint32_t current_seq { 0 }; // sequence number of next send uint32_t current_seq { 0 }; // sequence number of next send
uint32_t current_ack { 0 }; // sequence number aknowledged by connection uint32_t current_ack { 0 }; // sequence number aknowledged by connection
uint64_t last_send_ms { 0 }; // last send time, used for retransmission timeout uint64_t last_send_ms { 0 }; // last send time, used for retransmission timeout
bool has_ghost_byte { false }; bool has_ghost_byte { false };
bool had_zero_window { false };
uint32_t data_size { 0 }; // number of bytes in this buffer uint32_t sent_size { 0 }; // number of bytes in this buffer that have been sent
uint32_t sent_size { 0 }; // number of bytes in this buffer that have been sent BAN::UniqPtr<ByteRingBuffer> buffer;
BAN::UniqPtr<VirtualRange> buffer;
}; };
struct ConnectionInfo struct ConnectionInfo
@@ -128,6 +132,8 @@ namespace Kernel
{ {
ConnectionInfo target; ConnectionInfo target;
uint32_t target_start_seq; uint32_t target_start_seq;
uint16_t maximum_seqment_size;
uint8_t window_scale;
}; };
struct ListenKey struct ListenKey
@@ -162,8 +168,17 @@ namespace Kernel
State m_next_state { State::Closed }; State m_next_state { State::Closed };
uint8_t m_next_flags { 0 }; uint8_t m_next_flags { 0 };
size_t m_last_sent_window_size { 0 };
Thread* m_thread { nullptr }; Thread* m_thread { nullptr };
// TODO: actually support these
bool m_keep_alive { false };
bool m_no_delay { false };
bool m_should_send_zero_window { false };
bool m_should_send_window_update { false };
uint64_t m_time_wait_start_ms { 0 }; uint64_t m_time_wait_start_ms { 0 };
ThreadBlocker m_thread_blocker; ThreadBlocker m_thread_blocker;

View File

@@ -25,23 +25,28 @@ namespace Kernel
public: public:
static BAN::ErrorOr<BAN::RefPtr<UDPSocket>> create(NetworkLayer&, const Socket::Info&); static BAN::ErrorOr<BAN::RefPtr<UDPSocket>> create(NetworkLayer&, const Socket::Info&);
virtual NetworkProtocol protocol() const override { return NetworkProtocol::UDP; } NetworkProtocol protocol() const override { return NetworkProtocol::UDP; }
virtual size_t protocol_header_size() const override { return sizeof(UDPHeader); } size_t protocol_header_size() const override { return sizeof(UDPHeader); }
virtual void add_protocol_header(BAN::ByteSpan packet, uint16_t dst_port, PseudoHeader) override; void get_protocol_header(BAN::ByteSpan header, BAN::ConstByteSpan payload, uint16_t dst_port, PseudoHeader) override;
protected: protected:
virtual void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) override; void receive_packet(BAN::ConstByteSpan, const sockaddr* sender, socklen_t sender_len) override;
virtual BAN::ErrorOr<void> bind_impl(const sockaddr* address, socklen_t address_len) override; BAN::ErrorOr<void> connect_impl(const sockaddr*, socklen_t) override;
virtual BAN::ErrorOr<size_t> sendto_impl(BAN::ConstByteSpan message, const sockaddr* address, socklen_t address_len) override; BAN::ErrorOr<void> bind_impl(const sockaddr* address, socklen_t address_len) override;
virtual BAN::ErrorOr<size_t> recvfrom_impl(BAN::ByteSpan buffer, sockaddr* address, socklen_t* address_len) override; BAN::ErrorOr<size_t> recvmsg_impl(msghdr& message, int flags) override;
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override { return BAN::Error::from_errno(ENOTCONN); } BAN::ErrorOr<size_t> sendmsg_impl(const msghdr& message, int flags) override;
BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override { return BAN::Error::from_errno(ENOTCONN); }
BAN::ErrorOr<void> getsockopt_impl(int, int, void*, socklen_t*) override;
BAN::ErrorOr<void> setsockopt_impl(int, int, const void*, socklen_t) override;
virtual bool can_read_impl() const override { return !m_packets.empty(); } BAN::ErrorOr<long> ioctl_impl(int, void*) override;
virtual bool can_write_impl() const override { return true; }
virtual bool has_error_impl() const override { return false; } bool can_read_impl() const override { return !m_packets.empty(); }
virtual bool has_hungup_impl() const override { return false; } bool can_write_impl() const override { return true; }
bool has_error_impl() const override { return false; }
bool has_hungup_impl() const override { return false; }
private: private:
UDPSocket(NetworkLayer&, const Socket::Info&); UDPSocket(NetworkLayer&, const Socket::Info&);
@@ -59,7 +64,10 @@ namespace Kernel
BAN::CircularQueue<PacketInfo, 32> m_packets; BAN::CircularQueue<PacketInfo, 32> m_packets;
size_t m_packet_total_size { 0 }; size_t m_packet_total_size { 0 };
SpinLock m_packet_lock; SpinLock m_packet_lock;
ThreadBlocker m_packet_thread_blocker; ThreadBlocker m_packet_thread_blocker;
sockaddr_storage m_peer_address {};
socklen_t m_peer_address_len { 0 };
friend class BAN::RefPtr<UDPSocket>; friend class BAN::RefPtr<UDPSocket>;
}; };

View File

@@ -5,7 +5,8 @@
#include <BAN/WeakPtr.h> #include <BAN/WeakPtr.h>
#include <kernel/FS/Socket.h> #include <kernel/FS/Socket.h>
#include <kernel/FS/TmpFS/Inode.h> #include <kernel/FS/TmpFS/Inode.h>
#include <kernel/Lock/SpinLock.h> #include <kernel/FS/VirtualFileSystem.h>
#include <kernel/OpenFileDescriptorSet.h>
namespace Kernel namespace Kernel
{ {
@@ -15,6 +16,9 @@ namespace Kernel
BAN_NON_COPYABLE(UnixDomainSocket); BAN_NON_COPYABLE(UnixDomainSocket);
BAN_NON_MOVABLE(UnixDomainSocket); BAN_NON_MOVABLE(UnixDomainSocket);
public:
using FDWrapper = OpenFileDescriptorSet::FDWrapper;
public: public:
static BAN::ErrorOr<BAN::RefPtr<UnixDomainSocket>> create(Socket::Type, const Socket::Info&); static BAN::ErrorOr<BAN::RefPtr<UnixDomainSocket>> create(Socket::Type, const Socket::Info&);
BAN::ErrorOr<void> make_socket_pair(UnixDomainSocket&); BAN::ErrorOr<void> make_socket_pair(UnixDomainSocket&);
@@ -24,9 +28,11 @@ namespace Kernel
virtual BAN::ErrorOr<void> connect_impl(const sockaddr*, socklen_t) override; virtual BAN::ErrorOr<void> connect_impl(const sockaddr*, socklen_t) override;
virtual BAN::ErrorOr<void> listen_impl(int) override; virtual BAN::ErrorOr<void> listen_impl(int) override;
virtual BAN::ErrorOr<void> bind_impl(const sockaddr*, socklen_t) override; virtual BAN::ErrorOr<void> bind_impl(const sockaddr*, socklen_t) override;
virtual BAN::ErrorOr<size_t> sendto_impl(BAN::ConstByteSpan, const sockaddr*, socklen_t) override; virtual BAN::ErrorOr<size_t> recvmsg_impl(msghdr& message, int flags) override;
virtual BAN::ErrorOr<size_t> recvfrom_impl(BAN::ByteSpan, sockaddr*, socklen_t*) override; virtual BAN::ErrorOr<size_t> sendmsg_impl(const msghdr& message, int flags) override;
virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override; virtual BAN::ErrorOr<void> getpeername_impl(sockaddr*, socklen_t*) override;
virtual BAN::ErrorOr<void> getsockopt_impl(int, int, void*, socklen_t*) override;
virtual BAN::ErrorOr<void> setsockopt_impl(int, int, const void*, socklen_t) override;
virtual bool can_read_impl() const override; virtual bool can_read_impl() const override;
virtual bool can_write_impl() const override; virtual bool can_write_impl() const override;
@@ -37,10 +43,8 @@ namespace Kernel
UnixDomainSocket(Socket::Type, const Socket::Info&); UnixDomainSocket(Socket::Type, const Socket::Info&);
~UnixDomainSocket(); ~UnixDomainSocket();
BAN::ErrorOr<void> add_packet(BAN::ConstByteSpan); bool is_bound() const { return !m_bound_file.canonical_path.empty(); }
bool is_bound_to_unused() const { return !m_bound_file.inode; }
bool is_bound() const { return !m_bound_path.empty(); }
bool is_bound_to_unused() const { return m_bound_path == "X"_sv; }
bool is_streaming() const; bool is_streaming() const;
@@ -53,7 +57,7 @@ namespace Kernel
BAN::WeakPtr<UnixDomainSocket> connection; BAN::WeakPtr<UnixDomainSocket> connection;
BAN::Queue<BAN::RefPtr<UnixDomainSocket>> pending_connections; BAN::Queue<BAN::RefPtr<UnixDomainSocket>> pending_connections;
ThreadBlocker pending_thread_blocker; ThreadBlocker pending_thread_blocker;
SpinLock pending_lock; Mutex pending_lock;
}; };
struct ConnectionlessInfo struct ConnectionlessInfo
@@ -61,17 +65,31 @@ namespace Kernel
BAN::String peer_address; BAN::String peer_address;
}; };
struct PacketInfo
{
size_t size;
BAN::Vector<FDWrapper> fds;
BAN::Optional<struct ucred> ucred;
BAN::WeakPtr<UnixDomainSocket> sender;
};
BAN::ErrorOr<size_t> add_packet(const msghdr&, PacketInfo&&, bool dont_block);
private: private:
const Socket::Type m_socket_type; const Socket::Type m_socket_type;
BAN::String m_bound_path; VirtualFileSystem::File m_bound_file;
BAN::Variant<ConnectionInfo, ConnectionlessInfo> m_info; BAN::Variant<ConnectionInfo, ConnectionlessInfo> m_info;
BAN::CircularQueue<size_t, 128> m_packet_sizes; BAN::CircularQueue<PacketInfo, 512> m_packet_infos;
size_t m_packet_size_total { 0 }; size_t m_packet_size_total { 0 };
BAN::UniqPtr<VirtualRange> m_packet_buffer; size_t m_packet_buffer_tail { 0 };
SpinLock m_packet_lock; BAN::UniqPtr<VirtualRange> m_packet_buffer;
ThreadBlocker m_packet_thread_blocker; mutable Mutex m_packet_lock;
ThreadBlocker m_packet_thread_blocker;
BAN::Atomic<size_t> m_sndbuf { 0 };
BAN::Atomic<size_t> m_bytes_sent { 0 };
friend class BAN::RefPtr<UnixDomainSocket>; friend class BAN::RefPtr<UnixDomainSocket>;
}; };

View File

@@ -33,7 +33,7 @@ namespace Kernel
BAN::ErrorOr<int> dup2(int, int); BAN::ErrorOr<int> dup2(int, int);
BAN::ErrorOr<int> fcntl(int fd, int cmd, int extra); BAN::ErrorOr<int> fcntl(int fd, int cmd, uintptr_t extra);
BAN::ErrorOr<off_t> seek(int fd, off_t offset, int whence); BAN::ErrorOr<off_t> seek(int fd, off_t offset, int whence);
BAN::ErrorOr<off_t> tell(int) const; BAN::ErrorOr<off_t> tell(int) const;
@@ -44,6 +44,10 @@ namespace Kernel
void close_all(); void close_all();
void close_cloexec(); void close_cloexec();
bool is_cloexec(int fd);
void add_cloexec(int fd);
void remove_cloexec(int fd);
BAN::ErrorOr<void> flock(int fd, int op); BAN::ErrorOr<void> flock(int fd, int op);
BAN::ErrorOr<size_t> read(int fd, BAN::ByteSpan); BAN::ErrorOr<size_t> read(int fd, BAN::ByteSpan);
@@ -51,8 +55,8 @@ namespace Kernel
BAN::ErrorOr<size_t> read_dir_entries(int fd, struct dirent* list, size_t list_len); BAN::ErrorOr<size_t> read_dir_entries(int fd, struct dirent* list, size_t list_len);
BAN::ErrorOr<size_t> recvfrom(int fd, BAN::ByteSpan buffer, sockaddr* address, socklen_t* address_len); BAN::ErrorOr<size_t> recvmsg(int socket, msghdr& message, int flags);
BAN::ErrorOr<size_t> sendto(int fd, BAN::ConstByteSpan buffer, const sockaddr* address, socklen_t address_len); BAN::ErrorOr<size_t> sendmsg(int socket, const msghdr& message, int flags);
BAN::ErrorOr<VirtualFileSystem::File> file_of(int) const; BAN::ErrorOr<VirtualFileSystem::File> file_of(int) const;
BAN::ErrorOr<BAN::String> path_of(int) const; BAN::ErrorOr<BAN::String> path_of(int) const;
@@ -74,8 +78,8 @@ namespace Kernel
struct flock_t struct flock_t
{ {
bool locked; bool locked { false };
bool shared; bool shared { false };
ThreadBlocker thread_blocker; ThreadBlocker thread_blocker;
BAN::HashSet<pid_t> lockers; BAN::HashSet<pid_t> lockers;
}; };
@@ -84,36 +88,42 @@ namespace Kernel
friend class BAN::RefPtr<OpenFileDescription>; friend class BAN::RefPtr<OpenFileDescription>;
}; };
struct OpenFile
{
OpenFile() = default;
OpenFile(BAN::RefPtr<OpenFileDescription> description, int descriptor_flags)
: description(BAN::move(description))
, descriptor_flags(descriptor_flags)
{ }
BAN::RefPtr<Inode> inode() const { ASSERT(description); return description->file.inode; }
BAN::StringView path() const { ASSERT(description); return description->file.canonical_path.sv(); }
int& status_flags() { ASSERT(description); return description->status_flags; }
const int& status_flags() const { ASSERT(description); return description->status_flags; }
off_t& offset() { ASSERT(description); return description->offset; }
const off_t& offset() const { ASSERT(description); return description->offset; }
BAN::RefPtr<OpenFileDescription> description;
int descriptor_flags { 0 };
};
BAN::ErrorOr<void> validate_fd(int) const; BAN::ErrorOr<void> validate_fd(int) const;
BAN::ErrorOr<int> get_free_fd() const; BAN::ErrorOr<int> get_free_fd() const;
BAN::ErrorOr<void> get_free_fd_pair(int fds[2]) const; BAN::ErrorOr<void> get_free_fd_pair(int fds[2]) const;
public:
class FDWrapper
{
public:
FDWrapper(BAN::RefPtr<OpenFileDescription>);
FDWrapper(const FDWrapper& other) { *this = other; }
FDWrapper(FDWrapper&& other) { *this = BAN::move(other); }
~FDWrapper();
FDWrapper& operator=(const FDWrapper&);
FDWrapper& operator=(FDWrapper&&);
int fd() const { return m_fd; }
void clear();
private:
BAN::RefPtr<OpenFileDescription> m_description;
int m_fd { -1 };
friend class OpenFileDescriptorSet;
};
BAN::ErrorOr<FDWrapper> get_fd_wrapper(int fd);
size_t open_all_fd_wrappers(BAN::Span<FDWrapper> fd_wrappers);
private: private:
const Credentials& m_credentials; const Credentials& m_credentials;
mutable Mutex m_mutex; mutable Mutex m_mutex;
BAN::Array<OpenFile, OPEN_MAX> m_open_files; BAN::Array<BAN::RefPtr<OpenFileDescription>, OPEN_MAX> m_open_files;
BAN::Array<uint32_t, (OPEN_MAX + 31) / 32> m_cloexec_files {};
}; };
} }

View File

@@ -187,7 +187,7 @@ namespace Kernel::PCI
void initialize_impl(); void initialize_impl();
private: private:
static constexpr uint8_t m_msi_count = IRQ_SYSCALL - IRQ_MSI_BASE; static constexpr uint8_t m_msi_count = IRQ_MSI_END - IRQ_MSI_BASE;
using PCIBus = BAN::Array<BAN::Array<Device, 8>, 32>; using PCIBus = BAN::Array<BAN::Array<Device, 8>, 32>;
BAN::Array<PCIBus, 256> m_buses; BAN::Array<PCIBus, 256> m_buses;
BAN::Array<paddr_t, 256> m_bus_pcie_paddr; BAN::Array<paddr_t, 256> m_bus_pcie_paddr;

View File

@@ -19,15 +19,26 @@ namespace Kernel
asm volatile("cli"); asm volatile("cli");
const bool had_debug_lock = Debug::s_debug_lock.current_processor_has_lock(); const bool had_debug_lock = Debug::s_debug_lock.current_processor_has_lock();
derrorln("Kernel panic at {}", location);
if (had_debug_lock) bool first_panic = false;
derrorln(" while having debug lock...");
derrorln(message, BAN::forward<Args>(args)...);
if (!g_paniced)
{ {
g_paniced = true; SpinLockGuard _(Debug::s_debug_lock);
Debug::dump_stack_trace(); derrorln("Kernel panic at {}", location);
if (had_debug_lock)
derrorln(" while having debug lock...");
derrorln(message, BAN::forward<Args>(args)...);
if (!g_paniced)
{
Debug::dump_stack_trace();
g_paniced = true;
first_panic = true;
}
} }
if (first_panic)
Debug::dump_qr_code();
asm volatile("ud2"); asm volatile("ud2");
__builtin_unreachable(); __builtin_unreachable();
} }

View File

@@ -9,6 +9,7 @@
#include <kernel/ELF.h> #include <kernel/ELF.h>
#include <kernel/FS/Inode.h> #include <kernel/FS/Inode.h>
#include <kernel/Lock/Mutex.h> #include <kernel/Lock/Mutex.h>
#include <kernel/Lock/RWLock.h>
#include <kernel/Memory/Heap.h> #include <kernel/Memory/Heap.h>
#include <kernel/Memory/MemoryRegion.h> #include <kernel/Memory/MemoryRegion.h>
#include <kernel/Memory/SharedMemoryObject.h> #include <kernel/Memory/SharedMemoryObject.h>
@@ -76,6 +77,7 @@ namespace Kernel
BAN::ErrorOr<long> sys_getcwd(char* buffer, size_t size); BAN::ErrorOr<long> sys_getcwd(char* buffer, size_t size);
BAN::ErrorOr<long> sys_chdir(const char* path); BAN::ErrorOr<long> sys_chdir(const char* path);
BAN::ErrorOr<long> sys_fchdir(int fildes); BAN::ErrorOr<long> sys_fchdir(int fildes);
BAN::ErrorOr<long> sys_chroot(const char* path);
BAN::ErrorOr<long> sys_setuid(uid_t); BAN::ErrorOr<long> sys_setuid(uid_t);
BAN::ErrorOr<long> sys_setgid(gid_t); BAN::ErrorOr<long> sys_setgid(gid_t);
@@ -95,6 +97,9 @@ namespace Kernel
BAN::ErrorOr<long> sys_getppid() const { return m_parent; } BAN::ErrorOr<long> sys_getppid() const { return m_parent; }
BAN::ErrorOr<long> sys_getpid() const { return pid(); } BAN::ErrorOr<long> sys_getpid() const { return pid(); }
BAN::ErrorOr<long> sys_getgroups(gid_t groups[], size_t count);
BAN::ErrorOr<long> sys_setgroups(const gid_t groups[], size_t count);
BAN::ErrorOr<long> open_inode(VirtualFileSystem::File&&, int flags); BAN::ErrorOr<long> open_inode(VirtualFileSystem::File&&, int flags);
BAN::ErrorOr<void> create_file_or_dir(int fd, const char* path, mode_t mode) const; BAN::ErrorOr<void> create_file_or_dir(int fd, const char* path, mode_t mode) const;
@@ -105,9 +110,9 @@ namespace Kernel
BAN::ErrorOr<long> sys_access(const char* path, int amode); BAN::ErrorOr<long> sys_access(const char* path, int amode);
BAN::ErrorOr<long> sys_create_dir(const char*, mode_t); BAN::ErrorOr<long> sys_create_dir(const char*, mode_t);
BAN::ErrorOr<long> sys_hardlinkat(int fd1, const char* path1, int fd2, const char* path2, int flag); BAN::ErrorOr<long> sys_hardlinkat(int fd1, const char* path1, int fd2, const char* path2, int flag);
BAN::ErrorOr<long> sys_renameat(int oldfd, const char* old, int newfd, const char* _new);
BAN::ErrorOr<long> sys_unlinkat(int fd, const char* path, int flag); BAN::ErrorOr<long> sys_unlinkat(int fd, const char* path, int flag);
BAN::ErrorOr<long> sys_readlinkat(int fd, const char* path, char* buffer, size_t bufsize); BAN::ErrorOr<long> sys_readlinkat(int fd, const char* path, char* buffer, size_t bufsize);
BAN::ErrorOr<long> sys_symlinkat(const char* path1, int fd, const char* path2); BAN::ErrorOr<long> sys_symlinkat(const char* path1, int fd, const char* path2);
BAN::ErrorOr<long> sys_flock(int fd, int op); BAN::ErrorOr<long> sys_flock(int fd, int op);
@@ -130,8 +135,8 @@ namespace Kernel
BAN::ErrorOr<long> sys_bind(int socket, const sockaddr* address, socklen_t address_len); BAN::ErrorOr<long> sys_bind(int socket, const sockaddr* address, socklen_t address_len);
BAN::ErrorOr<long> sys_connect(int socket, const sockaddr* address, socklen_t address_len); BAN::ErrorOr<long> sys_connect(int socket, const sockaddr* address, socklen_t address_len);
BAN::ErrorOr<long> sys_listen(int socket, int backlog); BAN::ErrorOr<long> sys_listen(int socket, int backlog);
BAN::ErrorOr<long> sys_sendto(const sys_sendto_t*); BAN::ErrorOr<long> sys_recvmsg(int socket, msghdr* message, int flags);
BAN::ErrorOr<long> sys_recvfrom(sys_recvfrom_t*); BAN::ErrorOr<long> sys_sendmsg(int socket, const msghdr* message, int flags);
BAN::ErrorOr<long> sys_ioctl(int fildes, int request, void* arg); BAN::ErrorOr<long> sys_ioctl(int fildes, int request, void* arg);
@@ -142,10 +147,12 @@ namespace Kernel
BAN::ErrorOr<long> sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event* event); BAN::ErrorOr<long> sys_epoll_ctl(int epfd, int op, int fd, struct epoll_event* event);
BAN::ErrorOr<long> sys_epoll_pwait2(int epfd, struct epoll_event* events, int maxevents, const struct timespec* timeout, const sigset_t* sigmask); BAN::ErrorOr<long> sys_epoll_pwait2(int epfd, struct epoll_event* events, int maxevents, const struct timespec* timeout, const sigset_t* sigmask);
BAN::ErrorOr<long> sys_eventfd(unsigned int initval_hi, int flags);
BAN::ErrorOr<long> sys_pipe(int fildes[2]); BAN::ErrorOr<long> sys_pipe(int fildes[2]);
BAN::ErrorOr<long> sys_dup2(int fildes, int fildes2); BAN::ErrorOr<long> sys_dup2(int fildes, int fildes2);
BAN::ErrorOr<long> sys_fcntl(int fildes, int cmd, int extra); BAN::ErrorOr<long> sys_fcntl(int fildes, int cmd, uintptr_t extra);
BAN::ErrorOr<long> sys_seek(int fd, off_t offset, int whence); BAN::ErrorOr<long> sys_seek(int fd, off_t offset, int whence);
BAN::ErrorOr<long> sys_tell(int fd); BAN::ErrorOr<long> sys_tell(int fd);
@@ -161,35 +168,50 @@ namespace Kernel
BAN::ErrorOr<long> sys_sync(bool should_block); BAN::ErrorOr<long> sys_sync(bool should_block);
BAN::ErrorOr<long> sys_get_nprocessor();
static BAN::ErrorOr<long> clean_poweroff(int command); static BAN::ErrorOr<long> clean_poweroff(int command);
BAN::ErrorOr<long> sys_poweroff(int command); BAN::ErrorOr<long> sys_poweroff(int command);
BAN::ErrorOr<long> sys_readdir(int fd, struct dirent* list, size_t list_len); BAN::ErrorOr<long> sys_readdir(int fd, struct dirent* list, size_t list_len);
BAN::ErrorOr<BAN::Vector<BAN::UniqPtr<MemoryRegion>>> split_memory_region(BAN::UniqPtr<MemoryRegion>&& region, vaddr_t base, size_t length);
BAN::ErrorOr<long> sys_mmap(const sys_mmap_t*); BAN::ErrorOr<long> sys_mmap(const sys_mmap_t*);
BAN::ErrorOr<long> sys_munmap(void* addr, size_t len); BAN::ErrorOr<long> sys_munmap(void* addr, size_t len);
BAN::ErrorOr<long> sys_mprotect(void* addr, size_t len, int prot);
BAN::ErrorOr<long> sys_msync(void* addr, size_t len, int flags); BAN::ErrorOr<long> sys_msync(void* addr, size_t len, int flags);
BAN::ErrorOr<long> sys_smo_create(size_t len, int prot); BAN::ErrorOr<long> sys_smo_create(size_t len, int prot);
BAN::ErrorOr<long> sys_smo_delete(SharedMemoryObjectManager::Key); BAN::ErrorOr<long> sys_smo_delete(SharedMemoryObjectManager::Key);
BAN::ErrorOr<long> sys_smo_map(SharedMemoryObjectManager::Key); BAN::ErrorOr<long> sys_smo_map(SharedMemoryObjectManager::Key);
BAN::ErrorOr<long> sys_ttyname(int fildes, char* storage); BAN::ErrorOr<long> sys_ttyname(int fildes, char* name, size_t namesize);
BAN::ErrorOr<long> sys_isatty(int fildes); BAN::ErrorOr<long> sys_isatty(int fildes);
BAN::ErrorOr<long> sys_posix_openpt(int flags); BAN::ErrorOr<long> sys_posix_openpt(int flags);
BAN::ErrorOr<long> sys_ptsname(int fildes, char* buffer, size_t buffer_len); BAN::ErrorOr<long> sys_ptsname(int fildes, char* buffer, size_t buffer_len);
BAN::ErrorOr<long> sys_tty_ctrl(int fildes, int command, int flags); BAN::ErrorOr<long> sys_tty_ctrl(int fildes, int command, int flags);
static BAN::ErrorOr<void> kill(pid_t pid, int signal); void set_stopped(bool stopped, int signal);
void wait_while_stopped();
static BAN::ErrorOr<void> kill(pid_t pid, int signal, const siginfo_t& = {});
BAN::ErrorOr<long> sys_kill(pid_t pid, int signal); BAN::ErrorOr<long> sys_kill(pid_t pid, int signal);
BAN::ErrorOr<long> sys_sigaction(int signal, const struct sigaction* act, struct sigaction* oact); BAN::ErrorOr<long> sys_sigaction(int signal, const struct sigaction* act, struct sigaction* oact);
BAN::ErrorOr<long> sys_sigpending(sigset_t* set); BAN::ErrorOr<long> sys_sigpending(sigset_t* set);
BAN::ErrorOr<long> sys_sigprocmask(int how, const sigset_t* set, sigset_t* oset); BAN::ErrorOr<long> sys_sigprocmask(int how, const sigset_t* set, sigset_t* oset);
BAN::ErrorOr<long> sys_sigsuspend(const sigset_t* set);
BAN::ErrorOr<long> sys_sigwait(const sigset_t* set, int* sig);
BAN::ErrorOr<long> sys_sigaltstack(const stack_t* ss, stack_t* oss);
BAN::ErrorOr<long> sys_futex(int op, const uint32_t* addr, uint32_t val, const timespec* abstime);
BAN::ErrorOr<long> sys_yield(); BAN::ErrorOr<long> sys_yield();
BAN::ErrorOr<long> sys_set_tls(void*);
BAN::ErrorOr<long> sys_get_tls(); BAN::ErrorOr<long> sys_set_fsbase(void*);
BAN::ErrorOr<long> sys_get_fsbase();
BAN::ErrorOr<long> sys_set_gsbase(void*);
BAN::ErrorOr<long> sys_get_gsbase();
BAN::ErrorOr<long> sys_pthread_create(const pthread_attr_t* attr, void (*entry)(void*), void* arg); BAN::ErrorOr<long> sys_pthread_create(const pthread_attr_t* attr, void (*entry)(void*), void* arg);
BAN::ErrorOr<long> sys_pthread_exit(void* value); BAN::ErrorOr<long> sys_pthread_exit(void* value);
BAN::ErrorOr<long> sys_pthread_join(pthread_t thread, void** value); BAN::ErrorOr<long> sys_pthread_join(pthread_t thread, void** value);
@@ -199,8 +221,6 @@ namespace Kernel
BAN::ErrorOr<long> sys_tcgetpgrp(int fd); BAN::ErrorOr<long> sys_tcgetpgrp(int fd);
BAN::ErrorOr<long> sys_tcsetpgrp(int fd, pid_t pgid); BAN::ErrorOr<long> sys_tcsetpgrp(int fd, pid_t pgid);
BAN::ErrorOr<long> sys_termid(char*);
BAN::ErrorOr<long> sys_clock_gettime(clockid_t, timespec*); BAN::ErrorOr<long> sys_clock_gettime(clockid_t, timespec*);
BAN::ErrorOr<long> sys_load_keymap(const char* path); BAN::ErrorOr<long> sys_load_keymap(const char* path);
@@ -209,24 +229,33 @@ namespace Kernel
static Process& current() { return Thread::current().process(); } static Process& current() { return Thread::current().process(); }
vaddr_t shared_page_vaddr() const { return m_shared_page_vaddr; }
PageTable& page_table() { return m_page_table ? *m_page_table : PageTable::kernel(); } PageTable& page_table() { return m_page_table ? *m_page_table : PageTable::kernel(); }
size_t proc_meminfo(off_t offset, BAN::ByteSpan) const; size_t proc_meminfo(off_t offset, BAN::ByteSpan) const;
size_t proc_cmdline(off_t offset, BAN::ByteSpan) const; size_t proc_cmdline(off_t offset, BAN::ByteSpan) const;
size_t proc_environ(off_t offset, BAN::ByteSpan) const; size_t proc_environ(off_t offset, BAN::ByteSpan) const;
BAN::ErrorOr<BAN::String> proc_cwd() const;
BAN::ErrorOr<BAN::String> proc_exe() const;
BAN::StringView executable() const { return m_executable; }
// Returns error if page could not be allocated // Returns error if page could not be allocated
// Returns true if the page was allocated successfully // Returns true if the page was allocated successfully
// Return false if access was page violation (segfault) // Return false if access was page violation (segfault)
BAN::ErrorOr<bool> allocate_page_for_demand_paging(vaddr_t addr, bool wants_write); BAN::ErrorOr<bool> allocate_page_for_demand_paging(vaddr_t addr, bool wants_write, bool wants_exec);
// FIXME: remove this API // FIXME: remove this API
BAN::ErrorOr<BAN::String> absolute_path_of(BAN::StringView) const; BAN::ErrorOr<BAN::String> absolute_path_of(BAN::StringView) const;
OpenFileDescriptorSet& open_file_descriptor_set() { return m_open_file_descriptors; }
// ONLY CALLED BY TIMER INTERRUPT // ONLY CALLED BY TIMER INTERRUPT
static void update_alarm_queue(); static void update_alarm_queue();
const VirtualFileSystem::File& working_directory() const { return m_working_directory; } const VirtualFileSystem::File& working_directory() const { return m_working_directory; }
const VirtualFileSystem::File& root_file() const { return m_root_file; }
private: private:
Process(const Credentials&, pid_t pid, pid_t parent, pid_t sid, pid_t pgrp); Process(const Credentials&, pid_t pid, pid_t parent, pid_t sid, pid_t pgrp);
@@ -245,13 +274,21 @@ namespace Kernel
BAN::StringView file_name; BAN::StringView file_name;
}; };
// Adds new region to the sorted array of mapped regions
// You must hold writer end of m_mapped_region_lock when calling this.
BAN::ErrorOr<void> add_mapped_region(BAN::UniqPtr<MemoryRegion>&&);
// If address is contained by a region, returns the index of that.
// Otherwise returns the address of the first region after this address.
// You must hold reader end of m_mapped_region_lock when calling this.
size_t find_mapped_region(vaddr_t) const;
BAN::ErrorOr<VirtualFileSystem::File> find_file(int fd, const char* path, int flags) const; BAN::ErrorOr<VirtualFileSystem::File> find_file(int fd, const char* path, int flags) const;
BAN::ErrorOr<FileParent> find_parent_file(int fd, const char* path, int flags) const; BAN::ErrorOr<FileParent> find_parent_file(int fd, const char* path, int flags) const;
BAN::ErrorOr<VirtualFileSystem::File> find_relative_parent(int fd, const char* path) const; BAN::ErrorOr<VirtualFileSystem::File> find_relative_parent(int fd, const char* path) const;
BAN::ErrorOr<void> validate_string_access(const char*); BAN::ErrorOr<void> read_from_user(const void* user_addr, void* out, size_t size);
BAN::ErrorOr<void> validate_pointer_access_check(const void*, size_t, bool needs_write); BAN::ErrorOr<void> read_string_from_user(const char* user_addr, char* out, size_t max_size);
BAN::ErrorOr<void> validate_pointer_access(const void*, size_t, bool needs_write); BAN::ErrorOr<void> write_to_user(void* user_addr, const void* in, size_t size);
BAN::ErrorOr<MemoryRegion*> validate_and_pin_pointer_access(const void*, size_t, bool needs_write); BAN::ErrorOr<MemoryRegion*> validate_and_pin_pointer_access(const void*, size_t, bool needs_write);
uint64_t signal_pending_mask() const uint64_t signal_pending_mask() const
@@ -260,7 +297,7 @@ namespace Kernel
return m_signal_pending_mask; return m_signal_pending_mask;
} }
void add_pending_signal(uint8_t signal) void add_pending_signal(uint8_t signal, const siginfo_t& info)
{ {
ASSERT(signal >= _SIGMIN); ASSERT(signal >= _SIGMIN);
ASSERT(signal <= _SIGMAX); ASSERT(signal <= _SIGMAX);
@@ -272,6 +309,7 @@ namespace Kernel
if (handler == SIG_DFL && (signal == SIGCHLD || signal == SIGURG)) if (handler == SIG_DFL && (signal == SIGCHLD || signal == SIGURG))
return; return;
m_signal_pending_mask |= 1ull << signal; m_signal_pending_mask |= 1ull << signal;
m_signal_infos[signal] = info;
} }
void remove_pending_signal(uint8_t signal) void remove_pending_signal(uint8_t signal)
@@ -284,18 +322,18 @@ namespace Kernel
} }
private: private:
struct ChildExitStatus struct ChildWaitStatus
{ {
pid_t pid { 0 }; pid_t pid { 0 };
pid_t pgrp { 0 }; pid_t pgrp { 0 };
int exit_code { 0 }; BAN::Optional<int> status;
bool exited { false };
}; };
Credentials m_credentials; Credentials m_credentials;
OpenFileDescriptorSet m_open_file_descriptors; OpenFileDescriptorSet m_open_file_descriptors;
mutable RWLock m_memory_region_lock;
BAN::Vector<BAN::UniqPtr<MemoryRegion>> m_mapped_regions; BAN::Vector<BAN::UniqPtr<MemoryRegion>> m_mapped_regions;
pid_t m_sid; pid_t m_sid;
@@ -305,7 +343,27 @@ namespace Kernel
mutable Mutex m_process_lock; mutable Mutex m_process_lock;
BAN::Atomic<bool> m_stopped { false };
ThreadBlocker m_stop_blocker;
VirtualFileSystem::File m_working_directory; VirtualFileSystem::File m_working_directory;
VirtualFileSystem::File m_root_file;
vaddr_t m_shared_page_vaddr { 0 };
struct futex_t
{
Mutex mutex;
ThreadBlocker blocker;
uint32_t waiters { 0 };
uint32_t to_wakeup { 0 };
};
static BAN::HashMap<paddr_t, BAN::UniqPtr<futex_t>> s_futexes;
static Mutex s_futex_lock;
BAN::HashMap<paddr_t, BAN::UniqPtr<futex_t>> m_futexes;
Mutex m_futex_lock;
BAN::Vector<Thread*> m_threads; BAN::Vector<Thread*> m_threads;
@@ -321,20 +379,26 @@ namespace Kernel
uint64_t m_alarm_wake_time_ns { 0 }; uint64_t m_alarm_wake_time_ns { 0 };
mutable SpinLock m_signal_lock; mutable SpinLock m_signal_lock;
siginfo_t m_signal_infos[_SIGMAX + 1] { };
struct sigaction m_signal_handlers[_SIGMAX + 1] { }; struct sigaction m_signal_handlers[_SIGMAX + 1] { };
uint64_t m_signal_pending_mask { 0 }; uint64_t m_signal_pending_mask { 0 };
BAN::Vector<BAN::String> m_cmdline; BAN::Vector<BAN::String> m_cmdline;
BAN::Vector<BAN::String> m_environ; BAN::Vector<BAN::String> m_environ;
BAN::String m_executable;
BAN::Vector<ChildExitStatus> m_child_exit_statuses; BAN::Vector<ChildWaitStatus> m_child_wait_statuses;
ThreadBlocker m_child_exit_blocker; SpinLock m_child_wait_lock;
ThreadBlocker m_child_wait_blocker;
BAN::Atomic<bool> m_is_exiting { false };
bool m_has_called_exec { false }; bool m_has_called_exec { false };
BAN::UniqPtr<PageTable> m_page_table; BAN::UniqPtr<PageTable> m_page_table;
BAN::RefPtr<TTY> m_controlling_terminal; BAN::RefPtr<TTY> m_controlling_terminal;
friend class OpenFileDescriptorSet;
friend class Thread; friend class Thread;
}; };

View File

@@ -3,10 +3,12 @@
#include <BAN/Atomic.h> #include <BAN/Atomic.h>
#include <BAN/ForwardList.h> #include <BAN/ForwardList.h>
#include <kernel/API/SharedPage.h>
#include <kernel/Arch.h> #include <kernel/Arch.h>
#include <kernel/GDT.h> #include <kernel/GDT.h>
#include <kernel/IDT.h> #include <kernel/IDT.h>
#include <kernel/InterruptStack.h> #include <kernel/InterruptStack.h>
#include <kernel/Memory/Types.h>
#include <kernel/ProcessorID.h> #include <kernel/ProcessorID.h>
#include <kernel/Scheduler.h> #include <kernel/Scheduler.h>
@@ -33,6 +35,7 @@ namespace Kernel
FlushTLB, FlushTLB,
NewThread, NewThread,
UnblockThread, UnblockThread,
UpdateTSC,
StackTrace, StackTrace,
}; };
SMPMessage* next { nullptr }; SMPMessage* next { nullptr };
@@ -43,6 +46,7 @@ namespace Kernel
{ {
uintptr_t vaddr; uintptr_t vaddr;
size_t page_count; size_t page_count;
void* page_table;
} flush_tlb; } flush_tlb;
SchedulerQueue::Node* new_thread; SchedulerQueue::Node* new_thread;
SchedulerQueue::Node* unblock_thread; SchedulerQueue::Node* unblock_thread;
@@ -55,17 +59,19 @@ namespace Kernel
static Processor& initialize(); static Processor& initialize();
static ProcessorID current_id() { return read_gs_sized<ProcessorID>(offsetof(Processor, m_id)); } static ProcessorID current_id() { return read_gs_sized<ProcessorID>(offsetof(Processor, m_id)); }
static uint8_t current_index() { return read_gs_sized<uint8_t>(offsetof(Processor, m_index)); }
static ProcessorID id_from_index(size_t index); static ProcessorID id_from_index(size_t index);
static uint8_t count() { return s_processor_count; } static uint8_t count() { return s_processor_count; }
static bool is_smp_enabled() { return s_is_smp_enabled; } static bool is_smp_enabled() { return s_is_smp_enabled; }
static void set_smp_enabled() { s_is_smp_enabled = true; }
static void wait_until_processors_ready(); static void wait_until_processors_ready();
static void toggle_should_print_cpu_load() { s_should_print_cpu_load = !s_should_print_cpu_load; } static void toggle_should_print_cpu_load() { s_should_print_cpu_load = !s_should_print_cpu_load; }
static bool get_should_print_cpu_load() { return s_should_print_cpu_load; } static bool get_should_print_cpu_load() { return s_should_print_cpu_load; }
static ProcessorID bsb_id() { return s_bsb_id; } static ProcessorID bsp_id() { return s_bsp_id; }
static bool current_is_bsb() { return current_id() == bsb_id(); } static bool current_is_bsp() { return current_id() == bsp_id(); }
static void set_interrupt_state(InterruptState state) static void set_interrupt_state(InterruptState state)
{ {
@@ -77,8 +83,11 @@ namespace Kernel
static InterruptState get_interrupt_state() static InterruptState get_interrupt_state()
{ {
uintptr_t flags; #if ARCH(x86_64)
asm volatile("pushf; pop %0" : "=rm"(flags)); const auto flags = __builtin_ia32_readeflags_u64();
#elif ARCH(i686)
const auto flags = __builtin_ia32_readeflags_u32();
#endif
if (flags & (1 << 9)) if (flags & (1 << 9))
return InterruptState::Enabled; return InterruptState::Enabled;
return InterruptState::Disabled; return InterruptState::Disabled;
@@ -97,6 +106,8 @@ namespace Kernel
uintptr_t stack_bottom() const { return reinterpret_cast<uintptr_t>(m_stack); } uintptr_t stack_bottom() const { return reinterpret_cast<uintptr_t>(m_stack); }
uintptr_t stack_top() const { return stack_bottom() + s_stack_size; } uintptr_t stack_top() const { return stack_bottom() + s_stack_size; }
static void set_thread_syscall_stack(vaddr_t vaddr) { write_gs_sized<vaddr_t>(offsetof(Processor, m_thread_syscall_stack), vaddr); }
static GDT& gdt() { return *read_gs_sized<GDT*>(offsetof(Processor, m_gdt)); } static GDT& gdt() { return *read_gs_sized<GDT*>(offsetof(Processor, m_gdt)); }
static IDT& idt() { return *read_gs_sized<IDT*>(offsetof(Processor, m_idt)); } static IDT& idt() { return *read_gs_sized<IDT*>(offsetof(Processor, m_idt)); }
@@ -106,13 +117,40 @@ namespace Kernel
static void yield(); static void yield();
static Scheduler& scheduler() { return *read_gs_sized<Scheduler*>(offsetof(Processor, m_scheduler)); } static Scheduler& scheduler() { return *read_gs_sized<Scheduler*>(offsetof(Processor, m_scheduler)); }
static void initialize_tsc(uint8_t shift, uint64_t mult, uint64_t realtime_seconds);
static void update_tsc();
static uint64_t ns_since_boot_tsc();
static Thread* get_current_sse_thread() { return read_gs_sized<Thread*>(offsetof(Processor, m_sse_thread)); };
static void set_current_sse_thread(Thread* thread) { write_gs_sized<Thread*>(offsetof(Processor, m_sse_thread), thread); };
static paddr_t shared_page_paddr() { return s_shared_page_paddr; }
static volatile API::SharedPage& shared_page() { return *reinterpret_cast<API::SharedPage*>(s_shared_page_vaddr); }
static void handle_ipi(); static void handle_ipi();
static void handle_smp_messages(); static void handle_smp_messages();
static void send_smp_message(ProcessorID, const SMPMessage&, bool send_ipi = true); static void send_smp_message(ProcessorID, const SMPMessage&, bool send_ipi = true);
static void broadcast_smp_message(const SMPMessage&); static void broadcast_smp_message(const SMPMessage&);
static void load_tls(); static void load_segments();
static void load_fsbase();
static void load_gsbase();
static void disable_sse()
{
uintptr_t dummy;
#if ARCH(x86_64)
asm volatile("movq %%cr0, %0; orq $0x08, %0; movq %0, %%cr0" : "=r"(dummy));
#elif ARCH(i686)
asm volatile("movl %%cr0, %0; orl $0x08, %0; movl %0, %%cr0" : "=r"(dummy));
#endif
}
static void enable_sse()
{
asm volatile("clts");
}
private: private:
Processor() = default; Processor() = default;
@@ -120,6 +158,16 @@ namespace Kernel
static ProcessorID read_processor_id(); static ProcessorID read_processor_id();
static void initialize_smp();
static void initialize_shared_page();
static void dummy()
{
#if ARCH(x86_64)
static_assert(offsetof(Processor, m_thread_syscall_stack) == 8, "This is hardcoded in Syscall.S");
#endif
}
template<typename T> template<typename T>
static T read_gs_sized(uintptr_t offset) requires(sizeof(T) <= 8) static T read_gs_sized(uintptr_t offset) requires(sizeof(T) <= 8)
{ {
@@ -153,12 +201,19 @@ namespace Kernel
} }
private: private:
static ProcessorID s_bsb_id; static ProcessorID s_bsp_id;
static BAN::Atomic<uint8_t> s_processor_count; static BAN::Atomic<uint8_t> s_processor_count;
static BAN::Atomic<bool> s_is_smp_enabled; static BAN::Atomic<bool> s_is_smp_enabled;
static BAN::Atomic<bool> s_should_print_cpu_load; static BAN::Atomic<bool> s_should_print_cpu_load;
static paddr_t s_shared_page_paddr;
static vaddr_t s_shared_page_vaddr;
ProcessorID m_id { PROCESSOR_NONE }; ProcessorID m_id { 0 };
uint8_t m_index { 0 };
vaddr_t m_thread_syscall_stack;
Thread* m_sse_thread { nullptr };
static constexpr size_t s_stack_size { 4096 }; static constexpr size_t s_stack_size { 4096 };
void* m_stack { nullptr }; void* m_stack { nullptr };
@@ -173,12 +228,8 @@ namespace Kernel
uint64_t m_last_update_ns { 0 }; uint64_t m_last_update_ns { 0 };
uint64_t m_next_update_ns { 0 }; uint64_t m_next_update_ns { 0 };
BAN::Atomic<bool> m_smp_pending_lock { false }; BAN::Atomic<SMPMessage*> m_smp_pending { nullptr };
SMPMessage* m_smp_pending { nullptr }; BAN::Atomic<SMPMessage*> m_smp_free { nullptr };
BAN::Atomic<bool> m_smp_free_lock { false };
SMPMessage* m_smp_free { nullptr };
SMPMessage* m_smp_message_storage { nullptr }; SMPMessage* m_smp_message_storage { nullptr };
void* m_current_page_table { nullptr }; void* m_current_page_table { nullptr };

Some files were not shown because too many files have changed in this diff Show More