Compare commits

...

715 Commits

Author SHA1 Message Date
Bananymous
f0b6844feb meminfo: Add process command line to the output 2023-09-30 23:17:31 +03:00
Bananymous
b712c70c75 Kernel: Expose command line and environment to /proc 2023-09-30 23:01:33 +03:00
Bananymous
797ca65c66 Kernel: Add physical memory info to /proc/{pid}/meminfo 2023-09-30 22:11:45 +03:00
Bananymous
762b7a4276 Userspace: Add meminfo command that parses /proc/{pid}/meminfo 2023-09-30 21:20:53 +03:00
Bananymous
a511441f7e Kernel: /proc/{pid}/meminfo now reports per process memory usage 2023-09-30 21:20:18 +03:00
Bananymous
cd61d710df Kernel: Add procfs that contains only pids 2023-09-30 21:19:36 +03:00
Bananymous
f88ad7efcd Kernel: All process' memory areas can report their virtual mem usage 2023-09-30 21:15:46 +03:00
Bananymous
38320018dc LibC: Implement stpcpy since gcc seems to need it
gcc seems to optimize some calls to strcpy to stpcpy
2023-09-30 20:58:19 +03:00
Bananymous
d883d212b1 Kernel/LibC: dirent now contains file type 2023-09-30 20:46:57 +03:00
Bananymous
dedb2a2399 Kernel: RamInode verifies that you have not specified mode type
This is kinda weird behaviour, but it ensures the user cannot
create e.g. CharacterDevice with mode having IFLNK.

The Inode overrider is the only one setting the mode.
2023-09-30 20:46:57 +03:00
Bananymous
8604c55de8 Kernel: Add API for RamDirectoryInodes to delete containing inodes 2023-09-30 19:22:30 +03:00
Bananymous
e949e8550c Kernel: Rework RamInode API
RamInode is now a general RamInode with no data. RamFileInode is now
a inode for regular files. This is much cleaner and more intuitive
since there is no reason for most non-regular inodes to hold data
Vector.
2023-09-30 19:22:30 +03:00
Bananymous
eb5c6cf736 BAN: Remove endianness functions from Math
There is now a Endianness.h for these. The functions were super slow.
2023-09-29 19:38:07 +03:00
Bananymous
94ce2c97be Shell: Quick fix to not freeze for multiple seconds
When sync is writing to disk, it reserves whole disk to itself.
This commit makes Shell to read username only once from getpwuid().
We used to get username every time prompt was printed.
2023-09-29 19:20:48 +03:00
Bananymous
3f164c6b82 Userspace: Implement basic test for MAP_SHARED 2023-09-29 18:59:37 +03:00
Bananymous
f953f3d3ff Kernel: Implement MAP_SHARED for regular files
Every inode holds a weak pointer to shared file data. This contains
physical addresses of pages for inode file data. Physical addresses
are allocated and read on demand.

When last shared mapping is unmapped. The inodes shared data is freed
and written to the inode.
2023-09-29 18:59:20 +03:00
Bananymous
9fc75fe445 Kernel: Don't write to stat_loc on SYS_WAIT if it is null 2023-09-29 18:31:44 +03:00
Bananymous
7a5bb6a56b Userspace: Implement cat-mmap
This behaves exactly as cat, but uses mmap to read the file.
2023-09-29 17:24:55 +03:00
Bananymous
d54c6b7f6b LibC: Fix mmap()
mmap() did not pass fildes to the syscall structure.
2023-09-29 17:24:21 +03:00
Bananymous
db5d6a7f80 Kernel: Implement MAP_PRIVATE file mappings
mmap() now supports mapping files with MAP_PRIVATE.
2023-09-29 17:23:42 +03:00
Bananymous
4a92f44cf6 Kernel: Implement new abstract MemoryRegion
MemoryBackedRegion now inherits from this and is used for private
anonymous mappigs. This will make shared mappings and file backed
mappings much easier to implement.
2023-09-29 16:18:23 +03:00
Bananymous
376b9f7272 LibC: mmap returns MAP_FAILED instead of NULL 2023-09-29 10:38:08 +03:00
Bananymous
7e9e4c47ae LibELF: Optimize LoadableELF::clone() memory usage
We only clone mapped pages that have been marked as writeble.
Read/execute only pages will be exactly as in the file itself and
can be demand paged also :D
2023-09-29 02:05:12 +03:00
Bananymous
603fc200e6 Kernel: Add some sanity assertions/functions 2023-09-29 02:03:19 +03:00
Bananymous
c11e84b248 Kernel: Use the new on demand ELF structure
All executable files are now read from disk and paged on demand.
This was a big rewrite of the old ELF library but in the end
everything seems much cleaner, since all the old functionality was
not actually needed for execution.

I have to do some measurements, but I feel like memory usage dropped
quite a bit after this change.
2023-09-29 02:00:10 +03:00
Bananymous
be13120554 LibELF: Implement new ELF structure
This structure is used for demand pagable execution. It handles all
memory allocation and file reading.
2023-09-29 01:58:03 +03:00
Bananymous
9943edad5a LibELF: Add types for native executable 2023-09-29 01:56:57 +03:00
Bananymous
f4049be975 Kernel: Fix off by one error when calculating pages in range 2023-09-29 01:56:15 +03:00
Bananymous
6cf7e01fe9 Kernel: Don't map interrupt stack as userspace accessable 2023-09-28 21:58:24 +03:00
Bananymous
b51d2f5295 Kernel: mmap regions are now demand paged
mmap will not actually take any memory unless you use the given
memory.
2023-09-28 21:07:14 +03:00
Bananymous
49d941ad65 LibC: Fix a bug in malloc
You could not allocate with size equal to one of the pool sizes.
2023-09-28 21:05:27 +03:00
Bananymous
a66c3bdae5 Kernel: Remove duplicate code in VirtualRange::create_to_vaddr_range 2023-09-28 13:59:49 +03:00
Bananymous
547eabb403 Kernel: Reboot will now always succeed
If acpi reset fails, we forcefully trigger a triple fault to restart
the system.
2023-09-28 13:53:03 +03:00
Bananymous
79851394b3 Kernel/LibC/Userspace: Add SYS_POWEROFF + cli tool
You can now shutdown/reboot banan-os with the poweroff cli tool.

Reboot doesn't seem to work on qemu.
2023-09-28 12:36:47 +03:00
Bananymous
fcdc922343 Kernel: Enter ACPI mode with lai 2023-09-28 12:30:27 +03:00
Bananymous
0b11d76576 LibC: Add errno for unknown error 2023-09-28 12:06:17 +03:00
Bananymous
f7097398ca Kernel: Make tty overload correct has_data() function
This allows snake game to work again :)
2023-09-28 11:54:12 +03:00
Bananymous
85b1252b9e Userspace: Use printf length modifiers when printing 2023-09-28 11:49:31 +03:00
Bananymous
1cd12b5f16 LibC: Implement length modifiers to printf 2023-09-28 11:42:57 +03:00
Bananymous
c84b66d078 Shell: String leading and trailing whitespace from commands
This fixes a bug of inserting empty argument if command had trailing
whitespace
2023-09-28 10:28:49 +03:00
Bananymous
27adb9486b BAN: Update Endiannes API
Add functions to swap endiannes or convert host to big/little endian

This code should be very compiler friendly and should be optimized to
single bswap instruction on x86.
2023-09-28 01:22:14 +03:00
Bananymous
8d5369fafe Kernel: Add some functionality to disable TTY input/output
Userspace programs can call tty_ctrl() to disable/enable tty from
handling input and displaying output.

This API is probably going to change in the future to ioctl calls
but I'm not sure how ioctl is used and what functionality should it
have. I decided to create whole new function and syscall for now.

Next I will expose framebuffer in /dev/fb0 and then I can start work
on graphical environment! :D
2023-09-27 15:44:05 +03:00
Bananymous
feafc57b63 Kernel: Disable DiskCache sync messages 2023-09-27 14:12:21 +03:00
Bananymous
f9b347f9d9 BuildSystem: Rework calling qemu
I change always manually the serial/graphical. When running cmake
you can define variable QEMU_ACCEL that will be used as accelerator.

Also ninja has the following targets for running qemu
  1. qemu:            Run graphical qemu environment
  2. qemu-nographic:  Run qemu without graphical screen. You should
                      select 'serial only' from grub menu.
  3. qemu-debug:      Run qemu without accelerator and interrupt
                      debugger.
2023-09-27 13:49:01 +03:00
Bananymous
6e1825d6b4 Kernel: Add missing TRY() to font loading 2023-09-27 00:49:53 +03:00
Bananymous
ec2baeb276 Sync: Add some argument parsing to sync(1)
You can specify --block to make the program wait until sync is
complete.
2023-09-27 00:37:23 +03:00
Bananymous
6cb8bda6e1 LibC: add syncsync() to unistd.h
This is my own WELL NAMED (:D) function that takes a paramemeter
to make the sync operation synchronous.
2023-09-27 00:35:36 +03:00
Bananymous
05e57801e7 Kernel: SYS_SYNC now schedules sync to happen soon
You can pass non-zero argument to the syscall to block until the
sync has finished.
2023-09-27 00:34:00 +03:00
Bananymous
b924c85669 Kernel: DiskCache now requires sync to be called from kernel thread
This disables the scenario where user interrupts sync operation
possibly leaving the syncing in invalid state.
2023-09-27 00:32:13 +03:00
Bananymous
09c1aa44d8 Kernel: Allow creationg of empty processes and manual registration
You can now create kernel processes without any threads, add the
needed threads and only then register the process and its threads
to the scheduler.
2023-09-27 00:29:45 +03:00
Bananymous
1d470fb5ba Kernel: All syscalls now validate users pointers
We now validate pointers passed by the user, to forbid arbitary
memory read/write. Now the user is only allowed to pass in pointers
in their own mapped memory space (or null).
2023-09-25 22:07:12 +03:00
Bananymous
b4e4f7a6cc Kernel: Print more detailed output on ISR 2023-09-25 20:33:07 +03:00
Bananymous
55d30a7cc3 Kernel: Ext2 inodes are now stored in cache
This allows faster inode access and ensures working inodes when
opened in multiple places.
2023-09-25 20:31:40 +03:00
Bananymous
b62186441b BAN: Implement basic WeakPtr
This can be constructed from classes that inherit from Weakable
2023-09-25 19:43:10 +03:00
Bananymous
8caba1e774 Kernel: Ext2 filesystem now holds 10 preallocated block buffers
Inodes can query blocks from this buffer. This allows allocation of
blocks to not fail during normal operations. Also less stress on
kmalloc.
2023-09-25 14:32:25 +03:00
Bananymous
7bdb428938 Kernel: Fix ext2 block allocation
Redo ext2 block allocation. This is now much "cleaner" although
I'm not too fond of the macros.
2023-09-25 13:17:44 +03:00
Bananymous
3ea707c0e7 BuildSystem: Optimize image creation
We now use truncate to create disk image, since it doesn't require
writing zeroes to full disk. I also removed creation of third
partition as this was not currently used.
2023-09-25 13:15:55 +03:00
Bananymous
18d582c6ce Kernel: Hacky kmalloc quick fix
Remove GeneralAllocator from kmalloc as it is not CriticalScope safe.
This requires increasing kmalloc memory.
2023-09-25 13:13:57 +03:00
Bananymous
8b2bb95b81 Kernel: VirtualRange doesn't store physical addresses of pages
This was unnecessarry allocation, since the page table allready
contains virtual address -> physical address mappings.
2023-09-24 01:29:34 +03:00
Bananymous
2ef496a24a Kernel: all mapped ranges are now stored in one container
We just now have a flag if a mapping is unmappable
2023-09-23 23:45:26 +03:00
Bananymous
c0a89e8951 Kernel: Fully remove sys_alloc and sys_free
I could delete the whole FixedWidthAllocator as it was now obsolete.
GeneralAllocator is still used by kmalloc. Kmalloc cannot actually
use it since, GeneralAllocator depends on SpinLock and kmalloc runs
without interrupts.
2023-09-23 03:53:30 +03:00
Bananymous
fc953df281 Kernel/LibC: remove PATH resoltion from kernel
I have no idea why I had made PATH environment variable parsing
to be part of the kernel. Now the shell does the parsing and
environment syscall is no longer needed.
2023-09-23 03:08:14 +03:00
Bananymous
fe2dca16f0 Kernel/LibC: add flag to enable/disable sse support
SSE support is very experimental and causes GP. I decided to make
SSE not default until I get to fixing it :)
2023-09-23 02:28:25 +03:00
Bananymous
f662aa6da2 Kernel/LibC: userspace malloc now uses mmap to get memory
We could remove syscalls to allocate more memory. This was not
something the kernel should have done.
2023-09-23 02:26:23 +03:00
Bananymous
fee3677fb9 Kernel/LibC: add mmap for private anonymous mappings
This will be used by the userspace to get more memory. Currently
kernel handles all allocations, which is not preferable.
2023-09-22 23:01:14 +03:00
Bananymous
4818c6e3dd BuildSystem: Add cmake target for debugging qemu 2023-09-22 17:20:35 +03:00
Bananymous
971eb737c1 BAN: Fix LinkedList::pop_back() 2023-09-22 17:20:35 +03:00
Bananymous
9a3286ad57 Kernel: Add constexpr conditional debug prints 2023-09-22 17:20:35 +03:00
Bananymous
c9e09b840e Kernel: Add LAI as a dependency
I did not feel like implementing AML interpreter now, and wanted
everything AML has to offer. I will be writing my own AML interperter
at some point.
2023-09-22 17:20:35 +03:00
Bananymous
8136248a67 Kernel: Fix timer includes 2023-09-22 17:20:35 +03:00
Bananymous
0d67e46041 Kernel: Add config read/write api to PCI 2023-09-22 17:20:35 +03:00
Bananymous
bc1087f5a7 Kernel: Add pointer validation API to page table 2023-09-22 17:20:35 +03:00
Bananymous
3a9c6fc51a General: remove linecount.sh 2023-09-22 17:20:35 +03:00
Bananymous
7774f56ab6 Kernel: PCI devices can now create region for BAR
This creates either MEM or IO region for read/write access to PCI
device.
2023-09-22 17:20:35 +03:00
Bananymous
14a608effd 1000th COMMIT: Kernel: Add basic E1000 driver
This driver is only capable to read mac address and enable and read
link status
2023-09-22 17:20:28 +03:00
Bananymous
5fae3cec2a Kernel: Implement SYS_SYNC and add sync executable to userspace
You can (and have to) manually sync disk after writes to it.
2023-09-11 01:26:27 +03:00
Bananymous
b0c22b61ec Kernel: Writes to disk are not synchronous anymore
Implement "proper" DiskCache syncing
2023-09-11 01:25:16 +03:00
Bananymous
82b049204d Kernel: Print stack trace on isr 2023-09-11 01:20:55 +03:00
Bananymous
aa59142bfa Kernel: Fix ext2 file write 2023-09-11 01:20:39 +03:00
Bananymous
c55bb77ff5 BuildSystem: remove install-usb.sh since it is not used
This was dangerous script since it rewrote /dev/sda
2023-09-10 01:20:44 +03:00
Bananymous
9b4e2e1e21 Kernel: Add basic dd command
This only supports if, of, bs, count and status=progress
2023-09-10 01:19:47 +03:00
Bananymous
202c38a65a Kernel: Improve open() POSIX compatability
Also rename Process::sys_creat -> create_file since it is not
actually a syscall and only used by open as a healper.
2023-09-10 00:31:42 +03:00
Bananymous
720bc418a6 All: Clear lines with only whitspace in them 2023-09-10 00:31:42 +03:00
Bananymous
d77f455065 Kernel: Add basic ZeroDevice to /dev/zero 2023-09-10 00:31:42 +03:00
Bananymous
7e08f0fb66 Kernel: Start work on making inodes more thread safe
All inode operations are now locked and thread blocked
2023-09-10 00:31:42 +03:00
Bananymous
9e4a87021c Kernel: Fix directory permissions
We did not care about X bit in directories and instead used only the
R bit for search/read.
2023-09-08 11:46:53 +03:00
Bananymous
5887f6bcaa Kernel: Ext2 directories can allocate new blocks if needed 2023-09-08 10:29:26 +03:00
Bananymous
5d67559e33 Kernel: Fix bug in disk writing
I have used two weeks in locating a bug in my ext2 implementation
while the bug was actually in disk write. If you called write_sectors
on disk it would write the first sector_size bytes repeatedly to all
asked sectors and this corrupted the disk...
2023-09-08 02:43:08 +03:00
Bananymous
e631eb7a7a Kernel: Fix possible out-of-bounds disk access in ext2 2023-09-08 02:42:53 +03:00
Bananymous
64ff4c232a BuildSystem: Cleanup disk image creation 2023-09-08 02:41:39 +03:00
Bananymous
0ec4f970f7 LibC: fix fread implementation
fread() should read until either size*nitems bytes are read or eof
is reached.
2023-09-07 16:00:47 +03:00
Bananymous
afe95be42f Shell: Clean exit on ^D and use getchar()
Use getchar() instead of fread(&ch, 1, sizeof(char), stdin). This
is much cleaner.
2023-09-07 15:51:05 +03:00
Bananymous
14ac1c9904 Init: use read instead of fread()
This allows actually correct behaviour. My fread implementation is
flawed. It should not return on '\n'
2023-09-07 15:47:59 +03:00
Bananymous
7c11ea3694 Kernel: Cleanup TTY::read() 2023-09-07 15:27:21 +03:00
Bananymous
c1fd341698 Kernel: TTY now reads input byte by byte
This allows correct behaviour for character streams / keyboard
handling. Serial input can now send working ^C :D
2023-09-07 15:06:27 +03:00
Bananymous
0deab1be51 Kernel: Remove bitmap debug printing from ext2 inode allocation 2023-09-06 01:25:09 +03:00
Bananymous
5a623adaa6 Kernel: Correct inode links count 2023-09-05 14:46:56 +03:00
Bananymous
4363118d9d Snake render grid lines without extra space after last '#' 2023-09-05 14:35:53 +03:00
Bananymous
d613da4b6c BuildSystem: Don't set permissions on image creation
This is already handled by *new* tar ball sysroot
2023-09-05 14:35:53 +03:00
Bananymous
f46f5b2050 Snake: Reorder apple generation/snake body update
If new apple was generated to heads previous position after update,
it would not render.
2023-09-05 14:30:30 +03:00
Bananymous
d9c4114b5f Base: Add grub entries for serial-only boot
We can now fully boot with serial input and output :)
Qemu can be run with -nographic flag
2023-09-05 01:07:52 +03:00
Bananymous
ddd36af0f1 Kernel: Add /dev/tty symlink that targets the current tty 2023-09-05 01:07:52 +03:00
Bananymous
35fd30ee29 Kernel: Implement basic RamSymlinkInode 2023-09-05 01:07:52 +03:00
Bananymous
4a0652684c Kernel: You can now read serial output from the /dev/ttyS* 2023-09-05 01:07:52 +03:00
Bananymous
33c81f00b7 Kernel: Receive interrupts for COM1 and COM2 input
The input has to still be attached to terminal
2023-09-04 22:07:40 +03:00
Bananymous
55714b90cd Kernel: Rework whole Terminal structure
Serial monitors can now be used as a output. This requires editing
init code for the stdio opening. Serial input is not supported, so qemu
still needs graphical window for ps/2 keyboard.
2023-09-04 19:34:18 +03:00
Bananymous
9b47603a1d Kernel: Make serial devices to their own class 2023-09-04 14:57:05 +03:00
Bananymous
2e2a913412 Userspace: Implement basic snake game :) 2023-09-04 14:30:45 +03:00
Bananymous
42b85dc33b Kernel: Add ANSI support for hiding/showing cursor to TTY 2023-09-04 14:30:09 +03:00
Bananymous
a15ffcb071 LibC: add time() implementation 2023-09-04 13:52:58 +03:00
Bananymous
692b77fb8e LibC: Add rand() and srand() implementation
This code is from the wikipedia page for Permuted congruential generator
2023-09-04 13:52:13 +03:00
Bananymous
044378cfa3 Kernel: Add basic nanosleep, only millisecond percision 2023-09-04 12:59:50 +03:00
Bananymous
f1d4d5f995 Kernel: Add basic support for O_NONBLOCK (only for tty) 2023-09-04 12:57:52 +03:00
Bananymous
19d0fb6fcd Kernel: add basic fcntl() with couple of commands and no validation 2023-09-04 12:57:09 +03:00
Bananymous
7933265095 Kernel: Split ext2 implementation to multiple files 2023-09-01 15:10:23 +03:00
Bananymous
d810644018 Kernel: Start work on writable ext2 filesystem 2023-08-31 23:40:31 +03:00
Bananymous
a7bfc1c2ec Kernel: Add missing ififo() to Inode::Mode 2023-08-31 21:38:31 +03:00
Bananymous
104b2740bc BuildSystem: Add cmake target to validate main partition 2023-08-31 21:37:30 +03:00
Bananymous
65501837b7 Kernel: Stack trace dumping validates pointers before using them 2023-08-31 21:36:23 +03:00
Bananymous
3ed0a54847 Update README.md 2023-08-31 17:54:12 +03:00
Bananymous
cbd2519b9a Kernel: better handle kernel errors 2023-08-29 00:13:21 +03:00
Bananymous
e8a73f9696 BuildSystem: use -a with rsync
This allows cmake to not rebuild whole project every time
2023-08-28 11:38:17 +03:00
Bananymous
1a0d114861 LibC: Don't undef needed values in inttypes.h 2023-08-24 15:48:14 +03:00
Bananymous
5c3497681e BuildSystem: Add USES_TERMINAL when preparing sysroot
You were not able to enter sudo password on sysroot unpacking,
which caused ninja to hang
2023-08-23 20:48:40 +03:00
Bananymous
b05cf9ef09 BuildSystem: Base sysroot is now distributed as a tar ball
This allows file and directory permissions work as intended.

cmake is now filled with 'sudo' but with sudo timeout this should be
fine.
2023-08-23 10:38:21 +03:00
Bananymous
a74eb357a1 Shell: hostname is not parsed from /etc/hostname 2023-08-23 10:38:21 +03:00
Bananymous
8eb71084f0 Shell: use process groups more properly 2023-08-22 14:54:50 +03:00
Bananymous
ef1077fd7b Kernel: kill() with negative pid actually matches pgid 2023-08-22 14:54:15 +03:00
Bananymous
f1ba5c7e0f Kernel: Process keeps track if forked process has called exec*() 2023-08-22 14:53:46 +03:00
Bananymous
97ea4986af Kernel/LibC: implement proper getpgid and setpgid 2023-08-22 14:53:12 +03:00
Bananymous
25c021c15b Kernel: Add function to enumerate processes in session 2023-08-22 14:52:28 +03:00
Bananymous
2bf12a52d1 BAN: increase function size to 5 * sizeof(void*) 2023-08-22 14:52:03 +03:00
Bananymous
6ada36d3cb Shell/init: We now use pgrp instead of pid and init open terminal 2023-08-22 11:37:04 +03:00
Bananymous
42b90ae76c Kernel/LibC: Add {get,set}pgrp() 2023-08-22 11:36:33 +03:00
Bananymous
ccc61cb10c Kernel: Barebones implementation sessions and process groups 2023-08-22 11:35:40 +03:00
Bananymous
be5b81740e BAN: Add enum class Iteration for for_each loops 2023-08-22 11:30:53 +03:00
Bananymous
e7458ca10a BAN: Function call is now const 2023-08-22 11:30:40 +03:00
Bananymous
b10168eb1c LibC: make printf buffer only 128 bytes
Only reason for it to be big is if you want super large zero padding
for your number. This will eventually be handled without the buffer.
2023-08-18 16:49:27 +03:00
Bananymous
30463c9082 Id: Print username corresponding to uid/euid
Also print euid and egid if they differ from uid or gid.
2023-08-18 15:36:51 +03:00
Bananymous
dc7391dc89 BuildSystem: only apply stack usage warning to libc 2023-08-17 20:49:52 +03:00
Bananymous
eb98d70a0b Shell: command execution and parsing support piped commands
There is still problems with "blocking" builtin commands (time),
return value, ...
2023-08-17 12:05:38 +03:00
Bananymous
dcd8374b89 LibC: add fileno() and fdopen()
fdopen() doesn't currently care about mode and will have same mode
as the underlying file descriptor.
2023-08-17 12:03:59 +03:00
Bananymous
8e4216215e Kernel/LibC: add dup() syscall and function 2023-08-17 12:03:29 +03:00
Bananymous
5bd7099b96 Shell: add basic printf test 2023-08-16 10:49:34 +03:00
Bananymous
9a63d3b2da LibC: printf handles nan and inf 2023-08-16 10:49:34 +03:00
Bananymous
bf02330db9 LibC: math.h defines is*() macros and uses builtins for values 2023-08-16 10:41:55 +03:00
Bananymous
5806a6484f cat: use 1025 buffer. this allows reads to be 1024 byte
reading from disk currently returns ENOTSUP if buffer size is not
multiple of sector size.
2023-08-16 09:33:14 +03:00
Bananymous
0fa5401800 Shell: $? returns last return value 2023-08-15 09:17:46 +03:00
Bananymous
b30f4cbfb5 Userspace: Add basic whoami command 2023-08-15 09:03:51 +03:00
Bananymous
ba37183c9c Shell: '\u' in PS1 is replaced with username corresponding to euid 2023-08-14 14:55:23 +03:00
Bananymous
2f298a1979 Shell: ^A moves cursor to the beginning of line 2023-08-14 12:26:22 +03:00
Bananymous
8c282a5d83 Kernel: O_SEARCH doesn't require any permissions
Except read permissions for all directories in the path

This allows us to stat e.g. device files for which we don't have
the permissions.
2023-08-11 12:26:07 +03:00
Bananymous
d34c0a5abe LibC: cleanup fstatat 2023-08-11 12:25:15 +03:00
Bananymous
8f3348cf2b Kernel: open() now validates file access mode 2023-08-11 11:53:38 +03:00
Bananymous
38c0bc7bae Kernel: Remove unused syscall 2023-08-11 11:43:48 +03:00
Bananymous
313b00b11f Userspace: implement basic stat
I tried to format the output pretty much how linux does, except for
uid and git -> name resolution which is not implemented
2023-08-11 10:30:50 +03:00
Bananymous
165a379c73 LibC: Fix S_IF* macros and add macros for access/type masks 2023-08-11 10:30:50 +03:00
Bananymous
a7f37236bf Kernel: Zero initialize threads sse_storage 2023-08-11 00:26:43 +03:00
Bananymous
51532336b0 Kernel: Move structures in boot.S to .data section 2023-08-11 00:26:12 +03:00
Bananymous
03d4b47f63 Kernel: HPET is now used in legacy mode when PIC is forced 2023-08-10 22:01:30 +03:00
Bananymous
8b57edde6b Kernel: Fix slave PIC
we dont mask interrupt 2 in PIC since it corresponds to the
slave PIC. Also cleanup PIC code :)
2023-08-10 21:52:31 +03:00
Bananymous
778778fede Kernel: HPET doesn't use the legacy mapping anymore 2023-08-10 21:08:32 +03:00
Bananymous
f7449c4ab9 Kernel: APIC now uses MMIO namespace functions for mmio 2023-08-10 21:07:23 +03:00
Bananymous
fd2bcc9156 Kernel: IDT now sends EOI for every interrupt
EOI is sent before calling the interrupt handler. This should be fine
since all interrupts are processed with interrupts disabled
2023-08-09 09:57:02 +03:00
Bananymous
a5b1555725 Kernel: Validate HPET tick period 2023-08-09 09:50:38 +03:00
Bananymous
e74fdbc55b Kernel: Remove get_unix_timestamp from SystemTimer
Kernel now uses the percise real_time() and time_since_boot()
2023-08-09 08:57:50 +03:00
Bananymous
008c777a9f Kernel: Add PageTable::Flags::CacheDisable
Also fix multiple places where we were using uint8_t as page table
flags instead of PageTable::flags_t which we promoted to uint16_t
while back.
2023-08-06 23:59:30 +03:00
Bananymous
d8a9d4a24e Kerne: SystemTimer can now output the current real time 2023-08-04 16:06:47 +03:00
Bananymous
bc0e1fa898 Kernel: Rename TimerHandler to SystemTimer
I changed SystemTimer to only handle the "best" supported timer
it can initialize.
2023-08-04 16:06:47 +03:00
Bananymous
17f1737c9a Kernel: Add function to retrieve boot time as timespec 2023-08-04 16:06:47 +03:00
Bananymous
868444f043 Kernel: F11 now prints current time to debug output
This allows better timer percision and system freeze checks
2023-08-04 15:22:51 +03:00
Bananymous
fdae253695 Kernel: Add basic HPET support to replace PIT if exists
This works same way as the PIT implementation; calls Scheduler every
milli second.
2023-08-04 15:22:51 +03:00
Bananymous
d4adcff958 Kernel: Move sleep() implementation to TimerHandler 2023-08-04 15:15:00 +03:00
Bananymous
2c59c9a3cc Kernel: Add more structures to ACPI 2023-08-04 15:13:47 +03:00
Bananymous
3a59a64355 Kernel: Implement basic MMIO functions
This is equivalent to IO.h except for memory mapped io instead of
IO ports
2023-08-04 15:12:29 +03:00
Bananymous
9363c1cdaf Kernel: Move RTC to Timer directory
PIT ms counter seems to be off by multiple seconds/minute. I will
be probably changing to HPET for system time
2023-08-04 11:12:16 +03:00
Bananymous
198e6d7cf6 Kernel: Start work on abstracting Timers 2023-08-04 10:29:42 +03:00
Bananymous
07ee898f4f Kernel: Remove unnecessary timer check from Scheduler 2023-08-04 10:29:42 +03:00
Bananymous
6feb8a99d2 BAN: UniqPtr can now be constructed from other convertible UniqPtr 2023-08-04 10:29:42 +03:00
Bananymous
e57c1fc9fc Kernel: Threads are deleted sooner and cleaner
We now delete threads when
    1. it is marked as Terminated and is the current thread
    2. it tries to start execution in Terminated state

This allows us to never have thread executing in Terminated state
2023-08-04 10:29:42 +03:00
Bananymous
a11b5ae41f Kernel: align userspace stacks
I was getting #GP on sse instructions
2023-08-03 18:09:48 +03:00
Bananymous
c67a7cec5b LibC: fix typo 2023-08-02 22:10:12 +03:00
Bananymous
91f04ce250 Kernel: Change PageTable API
Getting free pages not reserves them, so you don't have to hold
the page table lock :)
2023-08-02 22:09:14 +03:00
Bananymous
926df2b276 Kernel: PageTable now supports reserved pages
You can now map pages as reserved, so that they will not be given
from get_free_page() or get_free_contiguous_pages().
2023-08-01 16:35:54 +03:00
Bananymous
9fe878bbec Shell: Print if the process exited because of a signal 2023-08-01 14:24:36 +03:00
Bananymous
217dbca7b7 Kernel: Cleanup returns from any kind on interrupts 2023-08-01 14:23:50 +03:00
Bananymous
13852e865c LibC: sys/wait.h now has proper exit status macros
We use the same format as basically every implementation
2023-08-01 10:32:04 +03:00
Bananymous
679d47131d BuildSystem: Edit build flags regarding sse and warnings 2023-07-31 22:31:17 +03:00
Bananymous
8b1bccb79b Kernel: store/load sse/mmx/fpu state on isr/irq/syscall
I haven't tested this yet but should be fine. This will be optimized
to only save state from threads that are using it
2023-07-31 22:28:57 +03:00
Bananymous
e86e755c51 Kernel: Generally improve signals 2023-07-31 22:28:18 +03:00
Bananymous
8ec6d4c9fc LibC: we don't parse syscall arguments in unistd
We just call Kernel::syscall() with 5 arguments from the variadic function.

This was a necessary addition since the syscall() function
used over 2 KiB of stack space.
2023-07-31 22:24:11 +03:00
Bananymous
08cdf88586 Kernel: Cleanup signal trampoline 2023-07-30 15:58:35 +03:00
Bananymous
6f7d97cf94 Kernel: Remove is_in_syscall from Thread 2023-07-30 14:49:51 +03:00
Bananymous
5e434f5131 Kernel: Hardware exceptions now sends signals to userspace 2023-07-30 14:34:15 +03:00
Bananymous
a152d0aac5 Kernel: raise() now force sends signal 2023-07-30 14:17:07 +03:00
Bananymous
879706e6e9 Kernel: Signals are not queued anymore
Posix doesn't require signal queing if you don't use sigqueue() which
we don't support. Process also has its own pending signal mask.
2023-07-29 16:54:31 +03:00
Bananymous
00f1f30a08 Kernel: Userspace sets the foreground process and Shell handles ^C 2023-07-28 18:10:36 +03:00
Bananymous
a5813f9ba5 Kernel: TTY now sends SIGINT on ^C to foreground process 2023-07-28 18:10:09 +03:00
Bananymous
5652af3384 Kernel: Mark reading section from StorageDevice as terminate critical 2023-07-28 18:09:35 +03:00
Bananymous
22cd9af8cc Kernel: Restructure process and thread termination
When we want to kill a process, we mark its threads as Terminating
or Terminated. If the thread is in critical section that has to be
finished, it will be in Terminating state until done. Once Scheduler
is trying to execute Terminated thread it will instead delete it.

Once processes last thread is marked Terminated, the processes will
turn it into a cleanup thread, that will allow blocks and memory
cleanup to be done.
2023-07-28 18:06:20 +03:00
Bananymous
a9cf9bceef Kernel: Rewrite DiskCache
We now cache only clean pages since I don't want to think about
syncing the disk later.
2023-07-27 22:22:39 +03:00
Bananymous
6c0f864a6e Kernel: Locks allow locking after locker is invalid
SpinLock and RecursiveSpinLock will now allow locking after the initial
locker is invalid. This allows us to kill threads even if they are holding
internal locks
2023-07-27 18:52:51 +03:00
Bananymous
e4509d9482 Kernel: DiskCache uses are now done without interrupts
This allows disk cache to not be invalid state after partial read/write
2023-07-27 18:52:51 +03:00
Bananymous
0f23e1f0f4 Kernel: Scheduler can now check if tid is valid
Tid can become invalid if the thread is already terminated
2023-07-27 18:34:06 +03:00
Bananymous
642a6aa4ad Kernel: Process::exit() unblocks the whole lock before blocking 2023-07-24 22:29:59 +03:00
Bananymous
432c296b7b Kernel: Implement SYS_GET_PID and SYS_TCSETPGID
we don't have consept of process groups yet
2023-07-24 22:29:59 +03:00
Bananymous
b576d373c4 Kernel: TTY now stores foreground process pid
this will be process pgid when we have process groups
2023-07-24 22:29:59 +03:00
Bananymous
522aa8e762 Kernel: add Thread::queue_signal() 2023-07-24 22:26:10 +03:00
Bananymous
146802fa4c Kernel: Scheduler can now block threads based on tid 2023-07-24 22:24:21 +03:00
Bananymous
cc8af25d73 Kernel: remove Semaphore::is_blocked
this will not mean anything after semaphores can spuriously wake up
2023-07-24 22:23:13 +03:00
Bananymous
f5f4bf58ad Kernel: add is_tty() to inode 2023-07-24 22:19:59 +03:00
Bananymous
3784da0d18 Kernel: you can now ask process if it is userspace process 2023-07-23 18:54:10 +03:00
Bananymous
9eb72f4392 Kernel: OpenFileDesctiptor can now return inode of fd 2023-07-23 18:52:33 +03:00
Bananymous
f7bf6d5e62 Kernel: Change signal kernel API
return rsp and rip are now stored per thread
2023-07-23 18:33:10 +03:00
Bananymous
adb14ba373 Kernel: Userspace signal handlers are now called one at a time
I added a syscall for telling the kernel when signal execution has
finished. We should send a random hash or id to the signal trampoline
that we would include in the syscall, so validity of signal exit can
be confirmed.
2023-07-23 13:34:53 +03:00
Bananymous
7391d91317 Kernel/LibC: add SYS_SIGNAL/signal() 2023-07-21 20:08:13 +03:00
Bananymous
2149cec29f Kernel: Make signals more POSIX 2023-07-21 20:01:12 +03:00
Bananymous
ad756c36fc Kernel/LibC: Add SYS_KILL/kill() 2023-07-21 19:27:38 +03:00
Bananymous
b56316e9da Kernel: Scheduler now sends queued signals 2023-07-21 19:27:10 +03:00
Bananymous
a989c44211 Kernel: Make signals thread specific 2023-07-21 19:00:59 +03:00
Bananymous
217e5f81cc Kernel: add default signal actions 2023-07-21 18:02:35 +03:00
Bananymous
5f2549b198 BuildSystem: Strip kernel. We will add the map once we use it 2023-07-21 15:47:31 +03:00
Bananymous
dcd4d0daeb Kernel/LibC: Add bareboness signals
You can now call raise() to raise a signal. Signal handlers are
not yet supported, but the handling works :)
2023-07-21 15:45:02 +03:00
Bananymous
faf4220b38 Kernel: kernel memory takes now full pml4e
This allows flags to work properly
2023-07-21 13:47:05 +03:00
Bananymous
193ddaa2f6 Kernel: remove PAGE_FLAGS_MASK as that was not correct anymore
After I added NXE bit, the flags mask is no longer valid
2023-07-21 12:01:50 +03:00
Bananymous
46eb27883a Kernel: Don't map kernel executable memory as writable 2023-07-21 11:17:39 +03:00
Bananymous
2db7cdb71e Kernel: Syscalls now get the interrupt stack 2023-07-21 11:04:16 +03:00
Bananymous
5411c5aa4a BAN: Fix function call in Optional 2023-07-21 10:57:46 +03:00
Bananymous
f8a1a10897 Kernel: add NullDevice to /dev/null 2023-07-20 00:06:22 +03:00
Bananymous
adbe13938e Kernel: move Device.h to its own directory 2023-07-19 23:55:38 +03:00
Bananymous
4d5b14753d Kernel: cleanup sys_exec()
We now scope everyting so desctructors get called
2023-07-19 23:20:39 +03:00
Bananymous
ba9fa00947 Kernel: fix memory leak in PageTable
PageTable used to leak 2 pages on creation and other two on deletion
2023-07-19 23:17:39 +03:00
Bananymous
98cedf155c Kernel: FixedWidthAllocator creation can now fail 2023-07-19 18:07:24 +03:00
Bananymous
88e3998664 Kernel: VirtualRange creation can fail 2023-07-19 17:56:26 +03:00
Bananymous
c0c0bbc1bf Kernel: SYS_FORK can now fail instead of panicing on error 2023-07-19 17:47:12 +03:00
Bananymous
650e1b4fc5 Kernel: Fix bug which made bochs unbootable
We could not boot if ATABus did not have valid primary device.
2023-07-13 15:53:09 +03:00
Bananymous
6c1ada8d0a Kernel: Enable global bit on kernel pages 2023-07-13 15:23:25 +03:00
Bananymous
7d00c2670f Kernel: Support execute disable bit
We will now map executable memory explicitly as executable.
2023-07-13 14:28:53 +03:00
Bananymous
bca7e9a1e8 Kernel: CPUID can detect wether cpu supports nxe bit 2023-07-13 14:24:58 +03:00
Bananymous
3748f0304f Kernel: Fix multiple bugs with terminal 2023-07-13 13:09:52 +03:00
Bananymous
2576bdbd14 Kernel: Fix ATA disk and partition numbering 2023-07-13 12:12:47 +03:00
Bananymous
e341a36287 Init: Use the new pwd.h api for user parsing 2023-07-13 12:01:41 +03:00
Bananymous
bba09a3cd0 LibC: add getpwname() and getpwuid() 2023-07-13 12:01:16 +03:00
Bananymous
985df3532b LibC: implement endpwent(), getpwent() and setpwent() 2023-07-13 11:22:09 +03:00
Bananymous
72041a52e8 Kernel: Ext2Inode::create_file actually sets the inode data
We used to just create inode without touching its memory.
2023-07-13 10:20:56 +03:00
Bananymous
891144dac1 BAN: Iterators are now single general type with CONST template
This allows us to use the same base class for iterator and
const_iterator which were practically the same code.
2023-07-12 13:35:21 +03:00
Bananymous
41e7b53903 BAN: add either_or and either_or_t
This allows you to select type depending on constexpr evaluatable
boolean
2023-07-12 13:34:31 +03:00
Bananymous
6b0920e8c0 BAN: Implement ConstIteratorDouble and add it to HashMap
This is same as IteratorDouble except it uses const_iterator and does
not return non-const references.
2023-07-12 11:41:05 +03:00
Bananymous
4285729d5c BAN: Generalize HashMapIterator to IteratorDouble
This iterator should be able to iterate any container within container
with type iterator defined.

This also fixed bug if first entry in outer container is empty container.
2023-07-12 09:29:05 +03:00
Bananymous
a9c10d0751 Base: add empty directories with .gitkeep to base/ 2023-07-11 08:02:28 +03:00
Bananymous
74c79c7eff Kernel: Rewrite whole device structure
We now have DevFileSystem which is derived from RamFileSystem. All
devices are RamInodes. We don't have separate DeviceManager anymore.
To iterate over devices, you can loop througn every inode in devfs.
2023-07-10 23:17:14 +03:00
Bananymous
9174a89971 BAN: Add iterators to HashMap 2023-07-10 23:16:41 +03:00
Bananymous
5c94a583bc Userspace: add basic 'touch' command 2023-07-10 16:38:15 +03:00
Bananymous
6e1fc2766f tee: indent with tabs 2023-07-10 16:18:08 +03:00
Bananymous
d3bb00cb55 Userspace: Add basic tee command 2023-07-10 16:07:53 +03:00
Bananymous
5a5656b2d3 Kenrel: RamInode now implements truncate() 2023-07-10 16:07:09 +03:00
Bananymous
1a1e584cba Kernel: OpenFileDescriptors can now store more than 8 bits of flags 2023-07-10 16:06:36 +03:00
Bananymous
65fa05f998 Kernel: add O_TRUNC
this is not supported by anything yet
2023-07-10 15:48:18 +03:00
Bananymous
2276fc95b8 Kernel: creat() mode now has to be access mode
We provide the S_IFREG in creat
2023-07-10 15:34:41 +03:00
Bananymous
1e173c178d Kernel: Ext2 fill now return ENOTSUP on write
We used to crash the kernel
2023-07-10 15:34:25 +03:00
Bananymous
773747cf9c Kernel: O_APPEND is now supported 2023-07-10 15:11:27 +03:00
Bananymous
4972284dde Kernel: open() and openat() now take mode as parameter
O_CREAT now tries to create file if O_CREAT is specified
2023-07-10 15:08:54 +03:00
Bananymous
45789fda08 Kernel: You can now read/write to RamInodes
RamFS should be stored on physical pages and not in kmalloc, but
that will be implemented later :)
2023-07-10 14:09:35 +03:00
Bananymous
3b5bc63d1b Kernel: Inode::create_file() now takes uid and gid as parameters 2023-07-10 13:32:10 +03:00
Bananymous
f1089e2b8a Kernel: start work on ram file system 2023-07-10 13:26:14 +03:00
Bananymous
6d93c1eb92 LibC: add NAME_MAX to limits.h
This is defined to 255 which is _XOPEN_NAME_MAX, smallest value
for XOPEN compliance
2023-07-10 11:48:11 +03:00
Bananymous
363c325c79 Kenrel: Fix inode comparison
We should not compare rdevs
2023-07-10 11:48:11 +03:00
Bananymous
583504ebe0 Kernel: Inode rename directory functions 2023-07-10 11:48:11 +03:00
Bananymous
b354b77f8b Kernel: Mark Ext2 classes final 2023-07-10 11:48:11 +03:00
Bananymous
74af46cb4a BAN: RefPtr can be constructed from other types 2023-07-10 11:48:11 +03:00
Bananymous
19dab08275 Kernel: add more functionality to PCI 2023-07-09 23:04:11 +03:00
Bananymous
3840fbf957 Kernel: Edit lock scopes and make string copy able to fail 2023-07-07 23:12:19 +03:00
Bananymous
78c091f7f8 Kernel: Move open file descriptors to their own class
This simplifies code a lot :)
2023-07-07 23:11:37 +03:00
Bananymous
274ecbba78 LibC: limits.h now defined OPEN_MAX 2023-07-07 23:08:49 +03:00
Bananymous
683c2a68cd Shell: $(...) expansion works now :) 2023-07-06 23:22:57 +03:00
Bananymous
ad98181069 Shell: you can call Shell -c ... to invoke the shell as interpreter 2023-07-06 23:22:49 +03:00
Bananymous
a549336530 Kernel/LibC: add basic dup2 2023-07-06 23:17:54 +03:00
Bananymous
4eb95c963d Kernel/LibC: Add basic pipe() syscall and command
You can now create pipes :)
2023-07-06 22:16:26 +03:00
Bananymous
22caacd2a9 LibC: add read() and write() to unistd 2023-07-06 22:15:55 +03:00
Bananymous
af30d537da Kernel: TTY now unblocks semaphore after read
This allows concurrent reads not fully reading the buffer not block
indefinately.
2023-07-06 21:32:34 +03:00
Bananymous
f1bd26fb92 Kernel: Add O_CLOEXEC 2023-07-06 20:00:33 +03:00
Bananymous
5c6bbcb62f Kernel: Remove spammy process/thread exit printing 2023-07-06 10:34:46 +03:00
Bananymous
21bd87bb07 Userspace: Shell now has 'env' for printing environment 2023-07-06 10:32:43 +03:00
Bananymous
79450df04c Userspace: Shell imporove 'time' command 2023-07-06 09:45:04 +03:00
Bananymous
7f8b7b811e Userspace: Shell now has time builtin 2023-07-06 00:39:04 +03:00
Bananymous
3c068aa0ae Kernel/LibC: add clock_gettime() for CLOCK_MONOTONIC
This gets the number of milliseconds since boot
2023-07-06 00:38:29 +03:00
Bananymous
86df258365 Kernel: rework the whole PageTable structure
We now have page table structure for kernel memory which is shared
between all processes.
2023-07-05 23:41:35 +03:00
Bananymous
d99e704728 LibC: Fix syscall SYS_READ and SYS_WRITE arguments 2023-06-19 10:38:29 +03:00
Bananymous
0d620f3e0f Kernel: Rewrite and optimize DiskCache
DiskCache now consists of PageCaches which are caches of contiguous
sectors. This allows the disk cache to be ordered and faster traversal.

We seem to have a problem somewhere during reading. The stack gets
corrupted.
2023-06-19 10:31:47 +03:00
Bananymous
4dce0f9074 Userspace: u8sum fix error message 2023-06-19 10:31:23 +03:00
Bananymous
54f89cba33 Userspace: Shell now processes $ arguments 2023-06-19 01:39:24 +03:00
Bananymous
de88f60d1a Userspace: Shell argument parsing now appriciates quotes 2023-06-19 01:07:00 +03:00
Bananymous
f7060970e6 Userspace: Shell argument parse now results in BAN::String 2023-06-19 00:34:44 +03:00
Bananymous
e7a98ac6cc Userspace: Shell now sets SHELL environment variable 2023-06-18 23:35:51 +03:00
Bananymous
10544db52e LibELF: We use BAN::Vector<uint8_t> as elf storage
This is made possible by the dynamic kmalloc
2023-06-18 23:29:23 +03:00
Bananymous
5e123031aa Kernel: kmalloc has now somewhat dynamic storage
Allocations bigger than PAGE_SIZE and those not forced to be identity
mapped are now done on a GeneralAllocator. This allows us to use kmalloc
for big allocations; bigger than the fixed 1 MiB storage.

This is still a hack and the whole kmalloc will have to be rewritten at
some point, but for now this does the job :D
2023-06-18 23:27:00 +03:00
Bananymous
388f530edd Kernel: Add GeneralAllocator::paddr_of
Yoy can now query physical address of a virtual address for general
allocator allocation
2023-06-18 23:25:51 +03:00
Bananymous
d354cccd37 Kernel: Add enum for ISR name to number 2023-06-18 23:24:27 +03:00
Bananymous
714305ef56 Kernel: General allocator takes first valid vaddr as parameter 2023-06-17 22:23:34 +03:00
Bananymous
f83ae1e9c6 Kernel: Move print during boot 2023-06-12 23:45:36 +03:00
Bananymous
c38e8de6b5 BAN: Optional can be constructed inplace 2023-06-12 23:45:36 +03:00
Bananymous
97638f7ade BAN: Add operator-> and operator* to Optional 2023-06-12 22:25:14 +03:00
Bananymous
326a30d1af Userspace: Add u8sum
This program caluculates the sum of bytes in file mod 256
2023-06-12 20:36:16 +03:00
Bananymous
32e1473c94 Kernel: Make disk IO blocking thread safe
This was causing a lot of deadlocks on vms without kvm accel
2023-06-12 18:57:47 +03:00
Bananymous
bf617036c7 Kernel: Rework syscall calling
I removed the intermediate function when calling syscalls. Now syscall
handler calls the current process automatically. Only exception is
sys_fork, since it needs a assembly trampoline for the new thread.
2023-06-12 14:16:48 +03:00
Bananymous
ce55422a24 Kernel: Remove Shell from kernel
This is now obsolete since we have a userspace Shell.
2023-06-12 02:04:52 +03:00
Bananymous
388cc7c3bb Base: add home directories for root and user 2023-06-12 02:03:13 +03:00
Bananymous
37f9404d93 BuildSystem: every file except /home/* is now owned by root 2023-06-12 02:03:13 +03:00
Bananymous
38dff41e25 Userspace: Shell processes PS1 '\~' as cwd and implement cd 2023-06-12 02:03:13 +03:00
Bananymous
d360340b9e Userspace: init now sets HOME environment variable and cd's into HOME 2023-06-12 02:02:52 +03:00
Bananymous
0f63cfa43f Kernel/LibC: add SYS_{SET,GET}_PWD and chdir, getpwd 2023-06-12 02:02:52 +03:00
Bananymous
537780ee1e Kernel: allocate thread stacks from 0x300000 onwards
I had a problem where thread stack was overlapping with elf loading
2023-06-12 01:02:19 +03:00
Bananymous
4ca99fcb4e Kernel: Fix bug in elf loading
We were allocating one extra page
2023-06-12 00:59:19 +03:00
Bananymous
eb7ee13f43 Userspace: init now default logins as user 2023-06-12 00:46:07 +03:00
Bananymous
b2de706693 Userspace: Shell now uses PS1 as prompt if set 2023-06-12 00:45:47 +03:00
Bananymous
6a8180470d Userspace: Add color to ls 2023-06-11 23:00:19 +03:00
Bananymous
12d56be5cc Userspace: init now sets user and group ids before running their shell 2023-06-11 22:37:00 +03:00
Bananymous
bb4d81a4fa Userspace: Add basic id that prints {,e}{uid,gid} of the current proc 2023-06-11 22:37:00 +03:00
Bananymous
b254ade69b Kernel: Add SYS_GET_{,E}{UID,GID} 2023-06-11 22:37:00 +03:00
Bananymous
ef4ebaa969 Kernel: Add syscalls for set{,e,re}{uid,gid} 2023-06-11 22:37:00 +03:00
Bananymous
99f8133b91 LibC: gid_t and id_t are now signed types
I have no idea why I had made them unisigned
2023-06-11 22:37:00 +03:00
Bananymous
51eb44bf40 Kernel/Userspace: Add basic init process
This process parses /etc/passwd and promps login screen.
When an username is entered, it will launch that users shell
2023-06-11 22:37:00 +03:00
Bananymous
a0be415e09 BAN: Add basic Optional 2023-06-11 21:00:25 +03:00
Bananymous
071da18fa3 LibC: add strchrnul()
this is a gnu libc extension
2023-06-11 20:18:03 +03:00
Bananymous
c62e820bcf Kernel: Add basic Credentials for the system
Now filesystem access/open, etc confirm that you have access for rwxs
2023-06-11 20:06:06 +03:00
Bananymous
46c34db6cb Kernel: GeneralAllocator and FixedWidth allocator invalidate TLB caches
We were getting random exceptions when reallocating same addressess and
this fixes that problem :)
2023-06-11 15:57:48 +03:00
Bananymous
25a2a4879c Userspace: add basic ls command 2023-06-11 03:38:44 +03:00
Bananymous
8be28012ee LibC: Reorder some syscalls 2023-06-11 03:29:22 +03:00
Bananymous
5aed186827 Kernel: Add SYS_OPENAT 2023-06-11 03:29:22 +03:00
Bananymous
91f812e17f Kernel: Exceptions will now enable interrupts before calling exit()
this allows scheduler verification on reschedule() not panic
2023-06-11 03:29:22 +03:00
Bananymous
f0b22c48b2 LibC: implement close 2023-06-11 03:29:22 +03:00
Bananymous
52c4eebd77 Kernel: Implement SYS_FSTAT 2023-06-11 03:29:22 +03:00
Bananymous
24f0d26fce LibC: Implement basic dirent functionality
We don't currently support seeking
2023-06-11 03:29:22 +03:00
Bananymous
825ec221b7 Kernel: we don't panic anymore on unrecognized syscall 2023-06-11 00:18:48 +03:00
Bananymous
e31080bce3 Kernel: allow open() call with O_SEARCH 2023-06-11 00:18:34 +03:00
Bananymous
7a5d5cabad Kernel: Add syscall for reading directory entries 2023-06-11 00:18:08 +03:00
Bananymous
f7de310889 LibC: add missing O_EXEC and O_SEARCH 2023-06-11 00:17:18 +03:00
Bananymous
e209ca7c82 Kernel: Rewrite directory listing so it can be integrated to libc 2023-06-11 00:17:18 +03:00
Bananymous
ee8de77a90 Userspace: fix return values of cat and echo 2023-06-10 17:34:10 +03:00
Bananymous
db49cbd6e2 Kernel: We now store the processes exit code 2023-06-10 17:31:56 +03:00
Bananymous
e001eecb7b Userspace: add exit to shell 2023-06-09 01:51:23 +03:00
Bananymous
7f34d00c95 Userspace: add echo 2023-06-09 01:50:18 +03:00
Bananymous
2c18adbddd Userspace: add ^L support for shell 2023-06-09 01:24:33 +03:00
Bananymous
97c7fc42d1 Kernel: SpinLocks now reschedule if they cannot aquire the lock
This allows us to not actually spin doing nothing while waiting for
another (not executing) to release the lock. This api won't probably
work when we get to SMP
2023-06-09 00:53:32 +03:00
Bananymous
7da0627f8e Kernel: Process::exit() now uses the new Scheduler::reschedule()
We use this new function while waiting for all blocking threads to
resume execution
2023-06-09 00:49:19 +03:00
Bananymous
27cef23823 Kernel: Scheduler now has reschedule()
This can be called from anywhere and just causes the scheduler to
schedule the next thread. This is more efficient and verbose version
of Scheduler::set_current_thread_sleeping(0), since we don't have
to wake other threads or do other verifications.
2023-06-09 00:47:17 +03:00
Bananymous
b7fc2dc3d0 Kenrel: Rename Scheduler::reschedule -> Scheduler::timer_reschedule 2023-06-09 00:41:43 +03:00
Bananymous
8af390e0f6 Kernel: Big commit. Rewrite ELF loading code
We now load ELF files to VirtualRanges instead of using kmalloc.
We have only a fixed 1 MiB kmalloc for big allocations and this
allows loading files even when they don't fit in there.

This caused me to rewrite the whole ELF loading process since the
loaded ELF is not in memory mapped by every process.

Virtual ranges allow you to zero out the memory and to copy into
them from arbitary byte buffers.
2023-06-09 00:37:43 +03:00
Bananymous
96d6453ea8 Kernel: PageTableScope locks the PageTable before disabling interrupts
This allows replacing some PageTableScopes with PageTable::lock()
2023-06-09 00:34:41 +03:00
Bananymous
2b9900e56e Kernel: get_free_contiguous_pages works with non-page aligned addresses
also fix bug in ordering
2023-06-06 02:03:23 +03:00
Bananymous
86f58f60cb LibC: implement setenv, unsetenv, putenv 2023-06-05 22:51:02 +03:00
Bananymous
064ce568c2 Kernel: add basic support for environment variables
exec functions will search files from PATH
2023-06-05 22:51:02 +03:00
Bananymous
6aff459e1c BAN: add StringView::contains(char) 2023-06-05 22:51:02 +03:00
Bananymous
0b1b4d8f7e Kernel: exec now has better posix errors 2023-06-05 21:12:08 +03:00
Bananymous
3fc2c3529a Shell: load old termios for process execution 2023-06-05 21:12:08 +03:00
Bananymous
b0e9ab0519 Kernel/LibC: pass environ pointer to process 2023-06-05 21:12:08 +03:00
Bananymous
668517a723 Kernel: TTY now actually flushes on ^D 2023-06-05 20:21:46 +03:00
Bananymous
649f08ec78 Kernel: verify that loaded elfs are executable 2023-06-05 19:29:32 +03:00
Bananymous
2f2c298c68 Shell: add bareboness utf8 support
This should work as long as TTY provides only valid utf8.
If the utf is invalid, assertion fails and the shell dies.
2023-06-05 18:55:22 +03:00
Bananymous
90e48970e6 Shell: we now support left/right arrows 2023-06-05 18:24:41 +03:00
Bananymous
480842a203 LibC: abort now prints 'abort()' and exits
we used to call assert in abort which then recursively called
abort again.
2023-06-05 18:23:19 +03:00
Bananymous
5425394880 Kernel: TTY now supports CSI s and u
These are commonly supported values to save and load cursor
position
2023-06-05 18:19:13 +03:00
Bananymous
a365813fa9 BuildSystem: disable nls from gcc 2023-06-05 17:55:47 +03:00
Bananymous
9d64dbd5c2 Kernel/LibC: add SYS_STAT and stat(), lstat() 2023-06-05 14:37:14 +03:00
Bananymous
30bb61a775 Base: revert bin and lib symlinks to relative paths
Absolute paths fucked up toolchain building and usespace linking,
since g++ was finding host libraries from /usr/lib.
2023-06-05 10:08:01 +03:00
Bananymous
1f36ed0cf9 Userspace: Start work on proper shell 2023-06-05 01:42:57 +03:00
Bananymous
d54c76f88a Base: /lib and /bin are now absolute symlinks 2023-06-04 18:12:05 +03:00
Bananymous
cbb9f47ee5 LibC: add wait and waitpid
Note that wait() doesn't work since only waiting for specified
pid is supported. wait() will just return -1 and set errno to
ECHILD.
2023-06-04 18:00:52 +03:00
Bananymous
b68d5a5833 Kernel: Add SYS_WAIT
This syscall waits for a given pid.
2023-06-04 18:00:52 +03:00
Bananymous
94d2090777 Kernel: fork() now clones current thread
This is how posix specifies thread cloning during fork
2023-06-04 17:40:37 +03:00
Bananymous
e97585daf9 Kernel: Process FixedWidthAllocators come now in 4 sizes 2023-06-04 01:26:43 +03:00
Bananymous
924fc2118c Kernel: Allocators are now stored in UniqPtr
This allows proper memory management, we had some memory leak
2023-06-04 01:25:57 +03:00
Bananymous
51f4c0c750 Kernel: make load_elf() its own function 2023-06-04 01:24:11 +03:00
Bananymous
37b93da650 Kernel: PhysicalRange maps its nodes to kernel vaddr space
This keeps the lower half of address space cleaner
2023-06-04 01:20:47 +03:00
Bananymous
35e739dcdd Kernel: reorder process exit steps 2023-06-04 01:19:04 +03:00
Bananymous
8352392b38 Kernel: You can specify first vaddr for getting free pages 2023-06-04 01:15:48 +03:00
Bananymous
413f05bfca BAN: Add UniqPtr 2023-06-04 00:39:20 +03:00
Bananymous
dc1aff58ed Kernel: PAGE_FLAG_MASK is now only 0xF
We don't care currenly about anything but the last few bits
2023-06-03 20:08:13 +03:00
Bananymous
9f75d9cfe5 Kernel: PageTable now has debug_dump
This dumps all the mapped pages and their flags
2023-06-03 20:08:13 +03:00
Bananymous
a42af7e973 Kernel: boot.S is back to 2 MiB pages
bochs doesn't seem to support 1 GiB pages
2023-06-03 18:53:36 +03:00
Bananymous
2ce244d303 BAN: Errors now includes assert.h 2023-06-03 18:53:05 +03:00
Bananymous
a775a920d0 BuildSystem: remove sse and sse2 from userspace 2023-06-03 16:05:32 +03:00
Bananymous
4f84faf392 LibC: printf string persision works now 2023-06-03 15:07:02 +03:00
Bananymous
a4cb5d8360 Kernel: Inode/Device detection is done with overridden bool functions 2023-06-03 13:28:15 +03:00
Bananymous
da7f09cf82 Kernel: Heap will return 0 if no free page is available 2023-06-03 02:55:31 +03:00
Bananymous
0166af472b Kernel: DiskCache will try to shrink_to_fit after cache cleanup 2023-06-03 02:55:22 +03:00
Bananymous
884d986bd6 Kernel: DiskCache won't crash when running out of kmalloc memory 2023-06-03 02:36:20 +03:00
Bananymous
59b807189f Kernel: add basic disk cache
ATADevices now add disk cache to themselves
2023-06-03 02:23:14 +03:00
Bananymous
fb1c7015b1 Kernel: Shell 'memory' now prints heap memory usage 2023-06-03 02:22:18 +03:00
Bananymous
d4123f62b2 Update README.md 2023-06-02 18:43:30 +03:00
Bananymous
a3f410d1a1 Userspace: create_program creates proper cmake files again 2023-06-02 18:42:25 +03:00
Bananymous
1d19a4bffe BuildSystem: all scripts have now bash shebang
I could not use the scripts on debian
2023-06-02 18:41:45 +03:00
Bananymous
271dd91292 BuildSystem: add rule to build libstdc++
We can now build libstdc++ and actually link with g++
2023-06-02 18:39:42 +03:00
Bananymous
9bd4d68f9c Kernel: Shell ls and stat now properly show symlinks 2023-06-02 18:22:56 +03:00
Bananymous
3c3c7826ef LibC: Add simple definition for realloc
The syscall just crashes the kernel currently. I will implement
this when needed
2023-06-02 17:56:13 +03:00
Bananymous
2207357b93 LibC: add __cxa_at_exit() for libc 2023-06-02 17:50:55 +03:00
Bananymous
3a69768eb0 LibC: remove select() declaration
This already comes from sys/select.h
2023-06-02 17:29:09 +03:00
Bananymous
afb29ff3ec LibC: rename [[noreturn]] to __attribute__((__noreturn__))
This compiles with C compiler
2023-06-02 17:28:36 +03:00
Bananymous
e6f0f891a6 LibC: stdlib.h doesn't seem to typedef wchar_t without __need_wchar_t 2023-06-02 17:27:31 +03:00
Bananymous
36e5aa4683 LibC: fix INFINITY definition typo 2023-06-02 17:27:14 +03:00
Bananymous
7738050105 LibC: fix DIR typedef for C code 2023-06-02 17:26:38 +03:00
Bananymous
4bf11ec349 LibC: complex.h undefs I before defining it 2023-06-02 17:13:09 +03:00
Bananymous
d821012eed LibC: mbstate_t is empty struct 2023-06-02 17:10:29 +03:00
Bananymous
35c6edd989 LibC: fix sig_atomic_t definition 2023-06-02 17:08:43 +03:00
Bananymous
633cb4f282 Kernel: VFS now has max link depth of 100 2023-06-02 12:50:40 +03:00
Bananymous
4d4d0e26a9 Kernel: Symlinks are now working
We still have to implement loop or depth detection
2023-06-02 11:43:46 +03:00
Bananymous
feea2d4024 BAN: Fix function call in Vector 2023-06-01 00:50:04 +03:00
Bananymous
0ffd2a5c1d Kernel: Shell can now list symlinks 2023-06-01 00:25:53 +03:00
Bananymous
232fdcb82c Kernel: add basic support for symlinks 2023-06-01 00:24:45 +03:00
Bananymous
0ccc23d544 Kernel: Shell opens standard files 2023-05-31 23:14:15 +03:00
Bananymous
789ca3db1a BuildSystem: cmake creates /usr/bin 2023-05-31 23:13:53 +03:00
Bananymous
cb359a05dc BuildSystem: link libraries when they change
This also fixed the need for manual linkin on firt build
2023-05-31 23:01:40 +03:00
Bananymous
14982c137a Userspace: make test program link against libc on change 2023-05-31 22:36:47 +03:00
Bananymous
0acab11620 LibC: add execl 2023-05-31 22:36:26 +03:00
Bananymous
02f0239016 Kernel: Cleanup exec code 2023-05-31 22:36:05 +03:00
Bananymous
ab61b49aca Kernel: Add SYS_EXEC syscall 2023-05-31 20:57:33 +03:00
Bananymous
4da1d6fd27 Kernel: Implement Process::exec() 2023-05-31 20:56:29 +03:00
Bananymous
909e847369 Kernel: Move userspace entry functions to Process instead of Thread 2023-05-31 19:31:10 +03:00
Bananymous
eafa09fecf Kernel: boot.S maps GiB as single pdpte 2023-05-31 00:51:15 +03:00
Bananymous
8175348284 Kernel: Fix comment 2023-05-31 00:51:15 +03:00
Bananymous
b2832cb47a Kernel: PageTable destructor works now
we are successfully booting higher half kernel now :)
2023-05-31 00:44:14 +03:00
Bananymous
9f499991c8 Kernel: PageTable::create_userspace() now works 2023-05-31 00:44:14 +03:00
Bananymous
9a416e8ae8 Kernel: kmalloc free error prints the pointer 2023-05-31 00:34:56 +03:00
Bananymous
911922c6a3 Kernel: RSDP location is now done with virtual addresses 2023-05-31 00:34:21 +03:00
Bananymous
1f2fd59ad5 Kernel: Physical range now calculates RAM with physical addresses 2023-05-31 00:33:44 +03:00
Bananymous
708d401d2c Kernel: Heap gets multiboot pointer with P2V 2023-05-30 23:57:44 +03:00
Bananymous
ed0dcacab3 Kernel: Move V2P and P2V to Memory/Types.h 2023-05-30 23:57:03 +03:00
Bananymous
e86050f343 Kernel: PageTable::map_range_at maps correctly the last page 2023-05-30 23:56:07 +03:00
Bananymous
57f7da6ce1 Kernel: Booting with higher half kernel gets to Heap initialization 2023-05-30 22:21:12 +03:00
Bananymous
93e6455171 Kernel: start work on higher half kernel 2023-05-30 08:00:17 +03:00
Bananymous
8f38780197 Toolchain: lib gcc is wuild with mcmodel=large 2023-05-30 07:59:41 +03:00
Bananymous
341f7e41e5 LibC: Fix some headers to make gcc build again 2023-05-30 01:17:45 +03:00
Bananymous
265fe9c62e Kernel: We now identity map full GiB in boot.S
The paging structure is pre-built so no unnecessary calculations are done
2023-05-30 00:08:52 +03:00
Bananymous
3b9d60d7cb Kernel: Remove unused includes of CriticalScope 2023-05-29 21:15:55 +03:00
Bananymous
278b873e89 Kernel: Remove unnecessary usages of PageTableScope
This should be used as few times as possible since it calls 'cli'
2023-05-29 21:11:29 +03:00
Bananymous
e640344d7a Kernel: Rename MMU to PageTable
This is more descriptive name for what it actually represents
2023-05-29 21:06:09 +03:00
Bananymous
7151bb86a8 Kernel/LibC: opening standard files is done in libc 2023-05-29 20:21:19 +03:00
Bananymous
2a34391b71 LibC: open() now just returns syscall(SYS_OPEN, ...)
errno is handled in syscall()
2023-05-29 20:19:17 +03:00
Bananymous
3d95cf02f3 Kernel: We can't lock the MMU lock in load()
It needs to be callable always by scheduler
2023-05-29 19:39:35 +03:00
Bananymous
dd3f34cb2c Kernel: Make RecursiveSpinLock thread safe
also SpinLock is now implemented with gcc builtins
2023-05-29 19:38:09 +03:00
Bananymous
0c316ebfb2 Kernel: Add SYS_SLEEP 2023-05-28 22:34:48 +03:00
Bananymous
282bf24f65 Kernel: fork() now copies allocations through FixedWidthAllocator 2023-05-28 21:34:35 +03:00
Bananymous
f964f6be8d Kernel: Move page macros to Types.h 2023-05-28 21:03:08 +03:00
Bananymous
0202ccec5f Kernel: ISR will now crash userspace process instead of panicing kernel 2023-05-28 20:53:10 +03:00
Bananymous
636c308993 Kernel: fork() now copies allocation done through GeneralAllocator 2023-05-28 20:37:39 +03:00
Bananymous
6fdbe6f9c2 Kernel: Add bareboness fork() function 2023-05-28 18:08:49 +03:00
Bananymous
c19f4c019a Kernel: Add invalidate() to MMU 2023-05-28 18:05:49 +03:00
Bananymous
83eb3dc0cb Kernel: fix MMU::map_page_at()
We used to only reassign if flags changed
2023-05-28 17:57:05 +03:00
Bananymous
481c8406f3 LibC: fputs uses fputc instead of putc 2023-05-28 17:48:34 +03:00
Bananymous
0129619d9a Kernel: Processes and Threads use VirtualRange memory allocations 2023-05-28 17:48:34 +03:00
Bananymous
e0479b291d Kernel: Move PhysicalRange to its own file and add VirtualRange 2023-05-28 17:48:34 +03:00
Bananymous
b847d7dfd5 Kernel: MMU::get() is now MMU::kernel
MMU is can now be locked with RecursiveSpinLock.

Scheduler now has get_current_tid() that works before the Scheduler
is initialized. This allows RecursiveSpinLock usage early on.
2023-05-28 16:18:18 +03:00
Bananymous
245dff8027 Shell: we now link BAN (we can't use it though) 2023-05-26 22:31:21 +03:00
Bananymous
fed690a7f2 Kernel: Directory listing is working again 2023-05-26 22:31:21 +03:00
Bananymous
54d981120d Kernel: kmalloc debug_dump is marked [[maybe_unused]] 2023-05-26 22:31:21 +03:00
Bananymous
f79250c4d4 LibC: Rewrite all the headers.
We now have more or less posix issue 2018 conforming libc headers.

This was a really time consuming and boring operation but it had to
be done.

Now we get to actually start implementing libc :)
2023-05-26 22:31:21 +03:00
Bananymous
78b62776d2 BAN: libban is now build into library dir 2023-05-26 22:31:21 +03:00
Bananymous
bda4614783 BAN: Errors.h can be included from userspace 2023-05-26 22:31:21 +03:00
Bananymous
0ab3332ad3 Userspace: Start work on shell 2023-05-26 22:31:21 +03:00
Bananymous
9e0abbc2f0 Kernel: Add bareboness possibility to set termios 2023-05-26 22:31:21 +03:00
Bananymous
496adb61a4 Buildsystem: Fix userspace link order 2023-05-26 22:31:21 +03:00
Bananymous
4a4a3bf184 Kernel/LibC: move file offset back to kernel
This makes keeping track of offsets easier and more proper
2023-05-26 22:31:21 +03:00
Bananymous
f33e78882e Kernel: Add argc and argv to process entry 2023-05-16 00:27:49 +03:00
Bananymous
0ff067bdb7 Kernel: Add MMUScope
This disables interrupts and loads specified mmu for the
scope it lives in
2023-05-16 00:26:39 +03:00
Bananymous
31ac3260ed Kernel: MMU keeps track of the current 2023-05-16 00:26:39 +03:00
Bananymous
d82c6c2337 LibC: fix bugs with printf 2023-05-15 22:47:08 +03:00
Bananymous
632b699475 BAN: add is_arithmetic and is_signed to Traits.h 2023-05-15 20:26:29 +03:00
Bananymous
85039020d3 Kernel: argc is passed as zero to userspace 2023-05-11 18:28:32 +03:00
Bananymous
1a0fdc5a44 LibC: printf now prints 0 as integer 2023-05-11 18:20:37 +03:00
Bananymous
fb1bab7c30 BuildSystem: add helper to create userspace programs 2023-05-11 18:10:06 +03:00
Bananymous
7eb43990ad BuildSystem: userspace has cmake target 2023-05-11 16:19:53 +03:00
Bananymous
53f4b5a9da LibC: add function declarations to sys/stat.h 2023-05-11 15:11:33 +03:00
Bananymous
1d4a6c3a42 LibC: add function declarations to dirent.h 2023-05-11 01:42:52 +03:00
Bananymous
40083e4aa1 LibC: add definitions to math.h 2023-05-11 01:40:42 +03:00
Bananymous
bd929bff07 LibC: add defines in stdio.h 2023-05-11 01:39:16 +03:00
Bananymous
cd4a0530fa LibC: add function declarations to unistd.h 2023-05-11 00:34:03 +03:00
Bananymous
273fdd2235 LibC: add function declarations to string.h 2023-05-11 00:34:03 +03:00
Bananymous
b20f2e8d31 LibC: add function declarations to math.h 2023-05-11 00:34:03 +03:00
Bananymous
e756cde2b1 LibC: define all errnos and strerror{name,desk}_np 2023-05-11 00:34:03 +03:00
Bananymous
de18d3e64d LibC: add function declarations to time.h 2023-05-11 00:34:03 +03:00
Bananymous
441999ba9f LibC: add more types to sys/types.h 2023-05-11 00:33:53 +03:00
Bananymous
dd046b1ace LibC: Add dummy signal.h 2023-05-10 23:20:27 +03:00
Bananymous
926aa238ab LibC: add toupper, tolower in ctype.h 2023-05-10 23:13:56 +03:00
Bananymous
01fa521a03 LibC: Add dummy setjmp.h 2023-05-10 23:00:53 +03:00
Bananymous
f31da19266 LibC: Add dummy locale.h 2023-05-10 22:58:07 +03:00
Bananymous
48edc38817 LibC: implement printf conversions e, E, f, F 2023-05-10 22:36:03 +03:00
Bananymous
ac12132ac0 LibC: add math.h with floorl 2023-05-10 22:35:42 +03:00
Bananymous
13fabcc1f1 BAN: add pow, log2, log10, log in math
These are implemented using x86 floating point assembly
2023-05-10 19:03:33 +03:00
Bananymous
67005a80be LibC: add working f modifier to printf
This is implementation will write out of bounds if the conversion
takes more than 1024 characters (either super large number or very
big percision).

Also we dont handle NaN and infinity cases
2023-05-10 15:43:42 +03:00
Bananymous
f43bfcb398 LibC: add better error string support 2023-05-10 02:22:31 +03:00
Bananymous
d5ce4c9d2c LibC: add probably functional *printf
I wrote a general printf function that takes an putc function
pointer. We can use this to implement all the printf family
functions. I haven't done thorough testing with this, but it seems
to be functional for the most part
2023-05-10 02:00:28 +03:00
Bananymous
1cf7ef3de6 Kernel: Remove offset from OpenFileDescriptor
This is now handled on the libc side. There might be reasons to
have it in kernel side, but for simplicity's sake I'm moving it
to libc for now :)
2023-05-09 20:31:22 +03:00
Bananymous
5248a3fe48 LibC: Fix bug in *printf 2023-05-09 20:30:12 +03:00
Bananymous
812e61ca70 Kernel: Add barebones GeneralAllocator for >4096B 2023-05-08 22:10:49 +03:00
Bananymous
2d0a5a9e15 Kernel: FixedWidthAllocator operates on MMU
Instead of Process* we use MMU& in FixedWidthAllocator since it is
everything it actually needs :)
2023-05-08 00:06:56 +03:00
Bananymous
f32d594879 Kernel: We add FixedWidthAllocators on demand
On SYS_ALLOC we will add a new FixedWidthAllocator if the old ones
are already full or we don't have one with proper size. This allows
arbitary number of allocations as long as you have enough memory
available :)

Next I will be writing a general allocator for allocations larger
than 4096 bytes which should make SYS_ALLOC syscall complete :)
2023-05-07 23:57:01 +03:00
Bananymous
c2ad76fe4f BAN: Error uses 64 bit error codes 2023-05-07 02:09:52 +03:00
Bananymous
10d9b72da1 LibC: syscall() now returns -1 on error and updates errno 2023-05-07 01:51:39 +03:00
Bananymous
2fe9af7165 Kernel/LibC: add free function for FixedWidthAllocator
I have to rework the syscall API and allocators in process. For
now this works well enough :)
2023-05-07 01:21:50 +03:00
Bananymous
0deda83d05 BuildSystem: linker -O2 doesn't do anything? hopefully 2023-05-06 19:58:08 +03:00
Bananymous
ff5bcd4416 Kernel: Add basic fixed width allocator for userspace
We have to move process stacks to the general heap and maybe map
kernel to higher half.
2023-05-06 19:58:08 +03:00
Bananymous
b65cd1d09b Kernel: Invalid physical addresses from heap are specified now by 0 2023-05-06 17:34:22 +03:00
Bananymous
bc35a561d3 Kernel: GDT tss selector is now 16 bit value 2023-05-06 17:34:22 +03:00
Bananymous
06bc807e34 Kernel: MMU can now provide info about virtual address space 2023-05-06 17:34:22 +03:00
Bananymous
6262e41de1 Kernel: ISRs now print pid and tid 2023-05-06 00:10:15 +03:00
Bananymous
0cb53efa01 Kernel: 64 bit MMU now properly identity maps kernel 2023-05-05 14:19:28 +03:00
Bananymous
4e859bedbc Kernel: TTY input process is now single instance
Process sends key events to the active (currently only) tty
2023-04-30 16:11:14 +03:00
Bananymous
f139fc2229 Kernel: namespace and function renames
MMU moved to namespace kernel
Kernel::Memory::Heap moved to just Kernel
MMU::map_{page,range} renamed to identity_map_{page,range}

Add MMU::get_page_flags
2023-04-28 14:48:38 +03:00
Bananymous
e48acbb03b Kernel: Add set_tss_stack() to 32 bit 2023-04-28 14:44:23 +03:00
Bananymous
d1155c968e Kernel: dprintln file name is now relative
This makes file names much shorter
2023-04-28 14:43:19 +03:00
Bananymous
88a2c60065 BAN: Add is_power_of_two to Math functions 2023-04-28 14:42:49 +03:00
Bananymous
5bfcf6783e LibC: add proper stdlib.h header
Function declarations taken from the posix specifications
2023-04-27 15:14:03 +03:00
Bananymous
94f8a657f1 LibC: add link to posix stdio.h 2023-04-27 14:16:25 +03:00
Bananymous
7fac2a7526 Userspace: Simple stdio test 2023-04-25 14:50:26 +03:00
Bananymous
46dcf98fc1 Kernel: Scheduler updates tss stack on thread execution 2023-04-25 14:49:50 +03:00
Bananymous
58ce907327 Kernel: Usespace threads now have an interrupt stack 2023-04-25 14:49:18 +03:00
Bananymous
6ecc8cac0e Kernel: TSS stack can be set after initialization 2023-04-25 14:48:12 +03:00
Bananymous
bd95f17426 Kernel: Stack pointer out of bounds now panics with a message 2023-04-25 13:40:55 +03:00
Bananymous
0718bea5a1 LibC: Fix some bugs 2023-04-25 13:27:01 +03:00
Bananymous
175f07cd2f Kernel: Fix bug in Process::create_userspace()
We used to write more than we needed to. This could lead to unwanted
page faults
2023-04-25 13:21:28 +03:00
Bananymous
7b19d6e479 LibC: fread() now does a single syscall 2023-04-25 12:38:08 +03:00
Bananymous
77c83e5552 Kernel: Fix possible dead lock in Process::read() 2023-04-23 14:46:18 +03:00
Bananymous
b15deb420f LibC: Write mostly functioning stdio 2023-04-23 14:32:37 +03:00
Bananymous
b38989d594 Kernel: Add ASSERTion to Process::exit()
This is just so I don't forget that exit can currently only
be called on the executing thread itself
2023-04-22 19:05:27 +03:00
Bananymous
79e6de325f Kernel: Process can now load 32 bit elf files on i386
We are page faulting on process exit but I'm investigating
the reason.
2023-04-22 19:03:30 +03:00
Bananymous
163d2e4ba8 LibELF: Add 32 bit support 2023-04-22 19:00:18 +03:00
Bananymous
4f8f3ddc29 Kernel: Fix 32 bit MMU 2023-04-22 18:22:39 +03:00
Bananymous
82a1a29260 Kernel: More proper paging in Elf loading 2023-04-22 18:17:44 +03:00
Bananymous
8a5608df91 Kernel: d{print,warn,error}ln(...) now has a spinlock 2023-04-22 17:58:51 +03:00
Bananymous
3f1c0ec91b Kernel: Process now frees up its pages on destruction 2023-04-22 16:54:46 +03:00
Bananymous
1406a75a92 Kernel: Cleanup process creation for userspace 2023-04-22 16:51:50 +03:00
Bananymous
8001493df3 Kernel: Fix some deadlocks in the Process 2023-04-22 16:19:57 +03:00
Bananymous
8c1f5bfe1e Kernel: Remove obsolete userspace stuff from kernel 2023-04-22 15:38:45 +03:00
Bananymous
ec8b9640e2 Kernel: Usespace programs are now ran through ELF files
only 64 bit elf files are supported for now.
2023-04-22 15:35:32 +03:00
Bananymous
4ae1332a43 LibELF: Header printing can now be turned off 2023-04-22 15:34:09 +03:00
Bananymous
10c884bba4 LibELF: ELF now has methods for accessing more attributes
You can now access the program headers and the memory itself
2023-04-22 15:31:05 +03:00
Bananymous
c15f031c3f LibC: puts() now just calls syscall(SYS_WRITE, ...) 2023-04-22 15:29:38 +03:00
Bananymous
1b4c744974 LibC: syscalls have now proper argument order 2023-04-22 15:29:15 +03:00
Bananymous
d9068eebb5 Kernel: kmalloc does not dump stack trace
dump_stack_trace() page faults and i dont feel like debugging this
now :)
2023-04-21 13:45:13 +03:00
Bananymous
3ad0d2328d Kernel: Don't call 'cli' on interrupt
This is automatically done because we are using interrupt gates
in the IDT
2023-04-21 11:18:08 +03:00
Bananymous
3f2beb4547 Kernel: Fix syscall return value in 32 bit 2023-04-21 11:08:02 +03:00
Bananymous
be14a6c239 Kernel: Stack pointer is validated when updated
This allows us not to fail stack pointer when in syscall since
interrupts use their own stack
2023-04-21 10:40:24 +03:00
Bananymous
3aa0eeb4a3 Kernel: Add barebones per process virtual addresses
We now assign every (userspace) process its own MMU which we load
in scheduler. This allows every process to have separate virtual
address space.

This is very hackish implementations but it works for now
2023-04-20 00:45:41 +03:00
Bananymous
b3eeb6412f Kernel: Add some bareboness functionality to map virtual addresses 2023-04-19 23:51:36 +03:00
Bananymous
d38470c8e2 Kernel: Rename MMU::{un,}allocate... to MMU::{un,}map
This is more appropriate name for the behaviour :D
2023-04-19 21:50:30 +03:00
Bananymous
a159c980ee Kernel: kmalloc will always print debug on failed alloc 2023-04-19 18:05:01 +03:00
Bananymous
a993d997ad LibELF: remove unused file 2023-04-19 17:32:12 +03:00
Bananymous
4475e3e184 Kernel: ATAController will fail to initialize in native mode 2023-04-19 17:29:36 +03:00
Bananymous
cf0320e47d Kernel: PCI devices now report their prog_if 2023-04-19 16:43:05 +03:00
Bananymous
cd03a95128 Kernel: Shell fix file reading
We were reading 8 bytes at a time instead of the 1024 we were
supposed to :DD
2023-04-19 14:09:23 +03:00
Bananymous
51e299c7e3 Kernel: Shell now has exit() command 2023-04-19 12:53:09 +03:00
Bananymous
6f65453fd4 Kernel: Fix Process::exit() and where it is called from
cksum doesn't seem to work anymore on big files. I have to look
into this. It locks up after couple of seconds...
2023-04-19 12:52:21 +03:00
Bananymous
67e0c21e0f Update README.md
Add cool badges :D
2023-04-19 00:46:42 +03:00
Bananymous
702016a6e3 LibC: exit() calls _fini() 2023-04-19 00:42:00 +03:00
Bananymous
d74ce4950c Kernel: We now launch Shell again on boot
Adding this just before push :D
2023-04-19 00:41:24 +03:00
Bananymous
59a682c720 Kernel: init2 is now launched as a process instead of thread
Also only process can now add threads to scheduler. Nobody should
have raw access to scheduler and everything should be through
Process::current() or irqs (reschedules)
2023-04-19 00:39:06 +03:00
Bananymous
7bd4593748 Kernel: Process is not reference counted any more
This was not necessary and it made things needlessly complicated
2023-04-19 00:34:18 +03:00
Bananymous
c5b006bf19 BAN: Add {TRY,MUST}_REF for references
It is annoying that we have to have separate macros for these but
I can't find a way to cleanly return lvalue reference from statement
expression. Currently we cast the reference to pointer and return
unreference the pointer outside of the expression.

This feature will probably not be used any time soon, but atleas
it is implemented if I need it one day
2023-04-19 00:31:15 +03:00
Bananymous
115c44630d BAN: TRY and MUST macros use rvalue references 2023-04-19 00:11:15 +03:00
Bananymous
1dc81abca4 BAN: Add specialization for ErrorOr<LValueReference>
ErrorOr can now return a reference :)
2023-04-18 22:02:47 +03:00
Bananymous
5aaf2128a8 BAN: Variant with reference now supports copy/assign 2023-04-18 20:21:23 +03:00
Bananymous
6aeac17072 BAN: Variant now works with references
References can be assigned with the set() method. Construction nor
assigment operators cannot be used with references to avoid ambiguity
with what assignment to reference does.

You can set the underlying reference with the set() method and access
it with the get() method.

The references are stored as pointers to the object under the hood
which means that size of a reference is sizeof pointer.
2023-04-18 19:53:34 +03:00
Bananymous
6d425182a2 BAN: Variant::set now copy/move assigns when possible 2023-04-18 19:10:22 +03:00
Bananymous
04ac23b67c BAN: Variant now has variadic template types 2023-04-18 18:29:48 +03:00
Bananymous
5494e2c125 Kernel: Heap allows us to take free pages.
The API is kinda weird and will probably be reworked in near future
but this will work for now :)
2023-04-18 10:18:15 +03:00
Bananymous
aba82564f5 Kernel: Panic wont print stacktrace if it has already paniced
This prevents stack trace dump to panic and loop
2023-04-18 10:18:15 +03:00
Bananymous
93abee9c7c Kernel: Map all ACPI tables on initialization
This makes their usage much easier and less error prone

They won't mapped be processes when we get to there, so this won't be
a problem
2023-04-18 10:18:15 +03:00
Bananymous
4034bef42e Scripts: remove disk build from install-usb.sh
You can still use the install-usb.sh script from the build directory.
2023-04-18 10:18:15 +03:00
Bananymous
821d065eba Kernel: Handle some Heap edge cases 2023-04-18 10:18:15 +03:00
Bananymous
2614437ba0 Kernel: Reorder boot initialization
We now create the TTY as soon as possible so we can show console
output without serial port.
2023-04-18 10:18:15 +03:00
Bananymous
1aac3a0425 Kernel: Heap implementation can now give free pages from all of RAM 2023-04-18 10:18:15 +03:00
Bananymous
a4568f9263 Kernel: Remove unused file 2023-04-18 10:18:15 +03:00
Bananymous
a180e72b6f Kernel: Start working on heap 2023-04-18 10:18:15 +03:00
Bananymous
2de64b592d Kernel: Kmalloc now has its memory statically allocated
We don't use the memory map given by bootloader since this automatically
maps the memory to a available space.
2023-04-18 10:18:15 +03:00
Bananymous
9c0f3dd996 Kernel: Move kmalloc and MMU to Memory directory 2023-04-18 10:18:15 +03:00
Bananymous
079df39ca8 LibELF: Start implementing elf library 2023-04-18 10:18:15 +03:00
Bananymous
60a99d1d23 Create LICENCE 2023-04-13 00:38:24 +03:00
Bananymous
fe87c08a02 LibC: add needed stubs to build executables with our compiler 2023-04-12 17:53:02 +03:00
Bananymous
8637959289 Kernel: We can create basic userspace processes
These are still allocated on the kernel memory
2023-04-12 17:52:36 +03:00
Bananymous
6be53668b9 Kernel: Scheduler can now terminate processes threads 2023-04-12 17:49:04 +03:00
Bananymous
d1b7249803 Kernel: Debug::dump_stack_trace now 'detects' repeating function 2023-04-12 01:32:41 +03:00
Bananymous
ff7c50c627 Kernel: kmalloc does not check for corruptiong unless it cannot allocate
We 'don't care' if kmalloc is corrupted unless it prevents us from
allocating memory. Scheduler should be catching stack overflows either
way and is much more efficient
2023-04-12 00:24:02 +03:00
Bananymous
12779cdef8 Kernel: Threads now use only 4 KiB stack :) 2023-04-12 00:22:08 +03:00
Bananymous
f5e676b2b7 Kernel: Fix TTY spinlock usage 2023-04-12 00:20:04 +03:00
Bananymous
8e5e5f819f Kernel: Shell TTY_PRINT is now function instead of macro
This makes functions uses way less stack
2023-04-12 00:18:58 +03:00
Bananymous
370a958379 BuildSystem: GCC will now complain on functions with 1 KiB stack 2023-04-12 00:18:06 +03:00
Bananymous
0ee7da92a3 BAN: Variant now aligns its data properly 2023-04-12 00:17:45 +03:00
Bananymous
a0bd3dc54f Kernel: kmalloc now detects corruption
Kmalloc checks if its nodes have corrupted. This was happening
because of stack overflow.
2023-04-11 23:36:46 +03:00
Bananymous
809eb2fe3e Kernel: Mark Scheduler::start() as noreturn as appropriate 2023-04-11 23:33:20 +03:00
Bananymous
7010d8614f Kernel: kernel doesn't allocate large blocks of data on stack
We used to allocate 1 KiB blocks on multiple places on stack. This
is a problem, since kernel stack shouldn't have to be too big
2023-04-11 23:31:58 +03:00
Bananymous
69f13f1896 Kernel: Scheduler will panic if it encounters stack overflow 2023-04-11 23:29:21 +03:00
Bananymous
bdaf7cddcb Kernel: Process now locks the mutex while modifying open files
This allows processes to be actually removed from the list instead
of dead locking
2023-04-11 23:28:16 +03:00
Bananymous
8d6db168d6 Kernel: remove message from BAN::Error
We don't store the error message anymore in BAN::Error.
Instead we store a error code that can be mapped into a string.
This allows BAN::Error to only take 4 bytes instead of 128.

We should also make some kernel initialization just panic instead
of returning errors since they are required for succesfull boot
anyway.
2023-04-11 23:25:21 +03:00
Bananymous
2fabe1949c BAN: Move RefPtr to its own file and create New.h
New.h contains definitions for placement new operators and
BAN::allocator and BAN::dealloctor
2023-04-10 21:07:25 +03:00
Bananymous
c660df14ec BuildSystem: Fix header copying to sysroot
We used to copy all headers everytime to sysroot which caused
rebuild of the whole os. Now we use the cmake command
'copy_directory_if_different' which seemed to fix this issue :)
2023-04-10 21:07:25 +03:00
Bananymous
e704968f96 Kernel: Threads can now be terminated mid execution 2023-04-10 21:07:25 +03:00
Bananymous
32359df939 Kernel: Add small wait in ATA driver before reading/writing
This allows bochs to boot again
2023-04-10 21:07:25 +03:00
Bananymous
641ed23380 Kernel: Fix framepointers on started threads 2023-04-10 21:07:25 +03:00
Bananymous
9f977488fa BuildSystem: cmake can now build out libc
I can't seem to get libc++ build to work...
2023-04-10 21:07:25 +03:00
Bananymous
ac0b22f9b9 LibC: remove old unused files 2023-04-07 02:26:44 +03:00
Bananymous
7752b02fb7 BuildSystem: remove now obsolete include directories from kernel build 2023-04-07 02:25:47 +03:00
Bananymous
7610670287 Add a screenshot to README 2023-04-06 21:01:27 +03:00
Bananymous
31a1b23fb7 General: Write basic README 2023-04-06 20:59:45 +03:00
Bananymous
91c8f9a596 Scripts: linecount does not count lines from toolchain/ 2023-04-06 20:31:10 +03:00
Bananymous
f70cd3ea77 BuildSystem: Cleanup cmake code
The buildsystem is kind of a mess. I will be writingn build
instructions soon.
2023-04-06 20:31:10 +03:00
Bananymous
5db5ff069a BuildSystem: you can now build the toolchain with cmake 2023-04-06 00:23:02 +03:00
Bananymous
b8d852ddb7 Update .gitignore 2023-04-06 00:02:47 +03:00
Bananymous
46eedbd1a4 BuildSystem: Create script for os specific toolchain 2023-04-06 00:02:13 +03:00
Bananymous
e760bafeeb LibC: add stubs for a lot of functions 2023-04-05 23:58:40 +03:00
Bananymous
12351d5cb6 LibC: sys/types uses 'typedef' instead of 'using' 2023-04-05 15:03:24 +03:00
Bananymous
e84f613c4d Kernel: Shell now somewhat functions again
I will not be fixing the shell implementation until I get to
userspace
2023-04-05 11:37:41 +03:00
Bananymous
5db4e5b4d5 Kernel: Fix TTY echo and canonical flag behaviour 2023-04-05 11:35:19 +03:00
Bananymous
b00dd8d68d Kernel: Fix ansi control sequence cursor movement 2023-04-05 03:07:52 +03:00
Bananymous
abbbf7ec15 Kernel: Add tty to process and make termios modifiable 2023-04-05 02:53:28 +03:00
Bananymous
22c72d8c70 LibC: Add errno ENOTTY 2023-04-05 02:47:37 +03:00
Bananymous
d0b1457f30 Kernel: TTY now supports clearing 2023-04-05 02:04:18 +03:00
Bananymous
a423cd8bb3 Kernel: Add partial support for shell
We don't handle arrow keys, and the tty does not know how to clear
the screeen :D
2023-04-05 01:30:58 +03:00
Bananymous
db076058b9 Kernel: Process can now initialize stdio
This allows the use of the fds STD{IN,OUT,ERR}_FILENO
2023-04-05 01:10:25 +03:00
Bananymous
fe10ea85db LibC: Add unistd.h with STD{IN,OUT,ERR}_FILENO definitions 2023-04-05 00:59:48 +03:00
Bananymous
a1100624bf Kernel: Start work on making tty a file
TTY is now a file that you can read from/write to. I still have
to port shell to use this new interface
2023-04-05 00:56:09 +03:00
Bananymous
28e1497f88 Kernel: add virtual write function to inode 2023-04-03 20:29:07 +03:00
Bananymous
8d6111641e Kernel: Fix keys in PS2Keymap 2023-04-03 20:25:23 +03:00
Bananymous
3ee20d1a84 Kernel: Fix typo 2023-04-03 19:56:55 +03:00
Bananymous
002c2d0aca BuildSystem: remove non-existent file from kernel CMakeLists.txt 2023-04-03 19:02:25 +03:00
Bananymous
de9f109f2a BAN: Add data() member function to Array 2023-04-03 17:00:52 +03:00
Bananymous
461a5774f8 Kernel: Device dev and rdev number is done more properly
Also hd* partitions are now 1 indexed instead of 0
2023-04-03 11:43:16 +03:00
Bananymous
914f718767 LibC: add device macros in sys/sysmacros.h 2023-04-03 10:59:15 +03:00
Bananymous
ebfd092075 Kernel: Cleaner partition parsing errors 2023-04-03 09:55:49 +03:00
Bananymous
e322826347 Kernel: Optimize scheduler idling
Now after each interrupt we will ask the scheduler to reschedule
if the current thread is the idle thread. This allows semaphore
unblocking to be practically instant when there is only one thread
executing.

Now disk reading is back to ~3 MB/s for single threaded process
2023-04-03 01:51:05 +03:00
Bananymous
3998c5f955 Kernel: ATA now uses irqs instead of polling
Reading is now much slower at ~500 kB/s it was around 3 MB/s.
This is probably mostly due semaphore blocking taking atleast
until next reschedule (1 ms itervals). This will be a problem
as long as we are using only single processor.

I could try to use {READ/WRITE}_MULTIPLE commands, but since
most of the disk reads are 2 sectors (inode block size) this
will at most double the speed.

Most efficient speed up would of course be caching disk access
data and inodes overall.
2023-04-03 00:03:38 +03:00
Bananymous
762d22ed28 Kernel: Move ATADevice to its own file from ATAController
The API is kinda weird since device reads/writes go from
ATADevice -> ATAController -> ATADevice
but this is for now atleast necessary since ATAController has(?)
to keep all devices from using the disks at the same time
2023-04-02 18:26:19 +03:00
Bananymous
f2362b2b78 Kernel: ATA controller waits now before read/write until disk is ready
Qemu used to freeze on disk writes but now it seems fine
2023-04-02 05:37:17 +03:00
Bananymous
471ac80420 BuildSystem: building for 32-bit works now 2023-04-02 05:03:17 +03:00
Bananymous
4a887fc706 Scipts: linecount doesn't count lines in build/ 2023-04-02 04:09:54 +03:00
Bananymous
e49d3c7bfe BuildSystem: We are now using cmake instead of plain make
I have been annoyed for a while since I had to build everything
when running the os since the buildsystem was really bad.

I wanted to rewrite the whole build system and changed to using cmake

:)
2023-04-02 04:07:27 +03:00
Bananymous
c5b83074ac LibC: Combine string.h functions definitions to single file 2023-04-02 00:00:29 +03:00
Bananymous
79090c2648 Kernel: cleanup includes
I went quickly went through all files since I found some weird
includes :D
2023-04-01 02:14:49 +03:00
Bananymous
7a6b1c8e47 Kernel: Fix traversing back from mount points 2023-04-01 01:54:35 +03:00
Bananymous
8988ce2766 Kernel: Add inodes '.' and '..' to device manager 2023-04-01 01:33:04 +03:00
Bananymous
dcde2ae6b4 Kernel: Reads return 0 bytes read at the end of device
We used to not have any idea if we where already at the end of device.
Also fixed couple of copy-paste errors from read->write
2023-04-01 00:55:07 +03:00
Bananymous
c62849a783 Kernel: Shell cleanup cat command 2023-04-01 00:54:39 +03:00
Bananymous
f453e8e170 Kernel: Shell 'time' prints the time even if command fails 2023-04-01 00:30:33 +03:00
Bananymous
990887891e Kernel: Process gets absolute paths for mount 2023-04-01 00:30:11 +03:00
Bananymous
5da801d12b Kernel: fix ext2 failed creation memory leak 2023-04-01 00:22:03 +03:00
Bananymous
3a4557d417 Kernel: Cleanup ATA device initialization 2023-03-31 00:58:57 +03:00
Bananymous
26d9a3e253 Kernel: Move DeviceManager to its own file 2023-03-30 22:39:45 +03:00
Bananymous
eef3631a5a Kernel: Improve locking in Process, VFS and ATAController
We used to block on all process access. This meant that shell
reading the keyboard input would block all VFS access making disk
accesses practically impossible. We now block only when it is
necessary :)
2023-03-30 22:02:16 +03:00
Bananymous
88ee35165f Kernel: Thread is no longer RefCounted
This makes developement with Scheduler much easier against compiler
optimizations. I could now remove the pragma GCC optimize stuff.
2023-03-30 19:16:51 +03:00
Bananymous
c8f05b4a7a Kernel: Add Semaphore to block threads 2023-03-30 18:46:33 +03:00
Bananymous
c32584cca0 BAN: LinkedList::remove now returns iterator to the element after 2023-03-30 18:46:19 +03:00
Bananymous
2995a36942 Kernel: root partition is now passed from the commandline 2023-03-30 18:46:19 +03:00
Bananymous
c1dbafc101 BAN: StringView::split(char, bool) is now thread safe
I had to duplicate some code, but this is better since I would like
to not use BAN::Function for something like this
2023-03-30 16:35:38 +03:00
Bananymous
3e8ab8271d Kernel: Shell can now mount partitions 2023-03-30 15:06:41 +03:00
Bananymous
5b3a00c64f Kernel: Inode::Mode is now a struct so we can have functions in it 2023-03-30 14:41:15 +03:00
Bananymous
0ce9fd8597 Kernel: StorageDevices and Controllers are now devices 2023-03-30 14:22:15 +03:00
Bananymous
c9badb5a1c Kernel: Add IFBLK, IFLNK, IFSOCK to Inode::Mode 2023-03-30 13:15:46 +03:00
Bananymous
a513bc5749 Kernel: All devices have atime, mtime, ctime at their creation 2023-03-30 13:15:46 +03:00
Bananymous
5d5487315f Kernel: Remove the mount test from VFS 2023-03-30 11:43:24 +03:00
Bananymous
3508df67b1 Kernel: fix stat command and device numbers 2023-03-30 10:43:08 +03:00
Bananymous
06ce1f0667 Kernel: Rewrite mounting code 2023-03-29 21:34:48 +03:00
Bananymous
f9c3ae7090 BAN: String add front() and back() helpers 2023-03-29 14:10:29 +03:00
Bananymous
1fb8c211f0 Kernel: Move Partition out of StorageDevice and rename functions 2023-03-29 13:23:01 +03:00
Bananymous
9c7670847e Kernel: Shell commands 'ls' and 'stat' recognize character devices 2023-03-29 11:56:33 +03:00
Bananymous
a24c2d9be2 Kernel: DeviceManager is now a 'FileSystem' so it can expose devices
Shell reads keyboard through /dev/input :)
2023-03-29 11:50:46 +03:00
Bananymous
f4db246658 LibC: add ENOBUFS errno 2023-03-29 10:58:25 +03:00
Bananymous
7f90079ea7 Kernel: Fix keymap numlock behaviour 2023-03-29 03:18:22 +03:00
Bananymous
f4b4987d43 Kernel: Remove obsolete KeyboardLayout/
This was used by the old input system. Currently keyboard layout is
hardcoded to finnish. But it will be reworked as something read from
the filesystem
2023-03-29 03:09:14 +03:00
Bananymous
7f88ba70d4 Kernel: Add linecount.sh script
This calculates the number of lines of code in the whole project :D
2023-03-29 03:06:57 +03:00
Bananymous
ac094a48d6 Kernel: Rework the whole input system
We now use Device abstraction that will allow us to provide devices
to userspace through /dev. Currently Shell reads from first and only
device (it being PS/2 Keyboard).
2023-03-29 03:05:16 +03:00
Bananymous
779912d8af BAN: Vector now takes optional argument for default value on resize 2023-03-28 23:10:36 +03:00
Bananymous
f205b8e883 BAN: Implement basic Circular Queue 2023-03-28 21:44:02 +03:00
Bananymous
f9a0412e78 Kernel: ACPI unmap_header does not do anything
We have to work with MMU mapping/unmapping to be user friendly
2023-03-28 02:56:44 +03:00
Bananymous
0ef318633c BAN: ScopeGuard can now be disabled (it wont call the function) 2023-03-28 01:15:13 +03:00
Bananymous
2f8c9746e3 Kernel: Move ACPI to its own file 2023-03-27 17:30:45 +03:00
Bananymous
6d6bef1b04 BAN: move placement new declaration to Move.h 2023-03-27 03:38:06 +03:00
Bananymous
3dab392296 Build System: Create base directory for the FS 2023-03-27 01:11:17 +03:00
Bananymous
f8a2c60c8d Kernel/BAN: move unix time conversion to BAN and add stat to Shell 2023-03-27 00:49:58 +03:00
Bananymous
770f7716a0 Kernel: Rework processes and VFS so we don't expose inodes
Everything is now done through a file descriptor.
2023-03-26 04:30:57 +03:00
Bananymous
a011c0384f LibC: add dirent.h 2023-03-25 02:08:33 +02:00
Bananymous
0d356c5bbc LibC: Add stat structure 2023-03-24 18:08:22 +02:00
Bananymous
d67de70126 Kernel: Process::working_directory() is now thread safe
I realized you cannot return a stirng view and it to be thread safe
2023-03-24 01:46:25 +02:00
Bananymous
6f334756c5 Kernel: Create RecursiveSpinLock and add it to Process
We now lock every function within Proccess, just to be sure.
Recursive lock allows us to use lock from the same thread even if
we already have the spinlock locked
2023-03-24 01:32:35 +02:00
Bananymous
310713d203 Kernel: Lock process functions instead of the ata controller
Process has to use locks at least on some functions so multithreaded
disk io is safe. This seemed to fix corrupted reads from disk
2023-03-24 01:17:39 +02:00
Bananymous
7d2ab53baa Kernel: Ext2FS now does allocations better
We only have to allocate at the beginning of the all functions and
can properly exit before any disk reads if we run out of memory.

This makes development little bit 'harder' since the {read,write}_block
user must allocate a buffer of atleast block_size bytes.

I also made disk access to cause kernel panic on error since the error
handling during file write is something I don't want to think now.
The filesystem can easily corrupt so, I feel like when disk io starts
to fail I'll come back to this.
2023-03-23 23:22:31 +02:00
Bananymous
2152b8b95f Kernel: Add possibiliity to create empty files on Ext2
Big rewrite for Ext2 for more easy and optimized code
2023-03-23 22:26:06 +02:00
Bananymous
8ac1ae1574 LibC: add more typedefs to sys/types 2023-03-23 19:24:12 +02:00
Bananymous
4fd21bc303 Kernel: Remove block group descriptor cache from ext2fs
This will make improving the fs easier since we need to only update
the values on the disk
2023-03-23 18:52:58 +02:00
Bananymous
15037bfc7a Kernel: Move get_unix_time to RTC namespace 2023-03-23 18:14:51 +02:00
Bananymous
5831c72aad LibC: add errno NAMETOOLONG 2023-03-23 14:48:42 +02:00
Bananymous
a063d041c9 BAN: char* is now formatted as string and not pointer 2023-03-23 14:29:35 +02:00
Bananymous
3572e9794a BAN: Modify Span constructors to keep constness correctly 2023-03-23 14:26:03 +02:00
Bananymous
cef6999dc7 BAN: Add is_const to traits 2023-03-23 13:28:57 +02:00
Bananymous
6ed9651176 Kernel: StorageDevice and Ext2 "support" writing 2023-03-23 13:04:13 +02:00
Bananymous
3efbe22a1b Kernel: Shell now prints unix time with 'date' command 2023-03-23 11:13:51 +02:00
Bananymous
96579b88cf Kernel: Cleanup GPT parsing code 2023-03-23 11:13:14 +02:00
Bananymous
2ec18855f2 Kernel: TTY buffer is resized on font size change
Shell also has better line wrapping. You still can't visually go
back to previous line, but atleas we now write from the beginning
of the line
2023-03-22 02:09:22 +02:00
Bananymous
b222581d18 Kernel: Reading from fd verifies that file is opened for reading 2023-03-22 01:55:58 +02:00
Bananymous
a8e3ee6f19 Kernel: Ext2 directory functions now fail on invalid blocks
Invalid blocks should only happen while writing to a file and
I think in that case we should just bail out instead of giving
you incomlete inode list or search result.
2023-03-22 01:55:57 +02:00
Bananymous
a083e588ba Kernel: cksum uses now a different crc32_table to match linux 'cksum' 2023-03-22 01:55:21 +02:00
Bananymous
9b500842a0 Kernel: Ext2 can now read from non-block-size aligned offsets 2023-03-21 19:19:17 +02:00
Bananymous
b21348379f Kernel: Remove obsolete Ext2FS::ext2_root_inode()
This was not used by anyone and the cast was wrong anyway
2023-03-21 18:19:48 +02:00
Bananymous
633055293e Kernel: Remove for_each_block from Ext2 2023-03-21 18:14:02 +02:00
Bananymous
ae9d618803 Kernel: Cleanup font parsing
We use now the LittleEndian<> wrapper for PSF2 header and no more
magic constants in code
2023-03-20 19:48:08 +02:00
Bananymous
9c744dfc44 BAN: Add wrappers for little/big endian numbers 2023-03-20 19:48:08 +02:00
Bananymous
faf1b661bb Kernel: prefs font does not allocate extra buffer 2023-03-20 19:48:01 +02:00
Bananymous
22e45278a2 Kernel: Fix PC Screen font parsing
I had misread the format and the parsing code was incorrect. I also
changed fonts to store unicode codepoints as 32 bit integers, so
every character can be represented
2023-03-20 14:52:42 +02:00
Bananymous
43f4657566 Kernel: Font parsing uses Spans now 2023-03-20 13:35:54 +02:00
Bananymous
70f2908056 BAN: Implement basic Span
This is wrapper over contiguous block of memory e.g. Vector
2023-03-20 13:34:26 +02:00
Bananymous
ef381d0600 BAN: Add iterators to all containers with contiguous memory 2023-03-20 13:26:42 +02:00
Bananymous
cfa87526a7 BAN: Add implementation for basic iterator for contiguous memory 2023-03-20 13:15:38 +02:00
Bananymous
39b560fde3 Kernel: Add basic mounting to VFS. 2023-03-19 05:51:25 +02:00
Bananymous
0c582b4490 LibC: add errno ENOTEMPTY 2023-03-19 05:43:40 +02:00
Bananymous
61caf566fc LibC: add errno EEXISTS 2023-03-19 04:17:39 +02:00
Bananymous
76d5364a55 Kernel: Add comparison operator for inodes 2023-03-19 03:34:23 +02:00
Bananymous
5224df321e Create README.md 2023-03-18 04:05:59 +02:00
417 changed files with 188284 additions and 6318 deletions

11
.gitignore vendored
View File

@@ -1,7 +1,8 @@
*.img
isodir
sysroot
.vscode/
.idea/
bochsrc
bx_enh_dbg.ini
build/
base/
*.tar.*
toolchain/*/
!base-sysroot.tar.gz

4
.gitmodules vendored Normal file
View File

@@ -0,0 +1,4 @@
[submodule "kernel/lai"]
path = kernel/lai
url = https://github.com/managarm/lai.git
ignore = untracked

View File

@@ -1,9 +0,0 @@
#include <BAN/Memory.h>
void* operator new(size_t size) { return BAN::allocator(size); }
void* operator new[](size_t size) { return BAN::allocator(size); }
void operator delete(void* addr) { BAN::deallocator(addr); }
void operator delete[](void* addr) { BAN::deallocator(addr); }
void operator delete(void* addr, size_t) { BAN::deallocator(addr); }
void operator delete[](void* addr, size_t) { BAN::deallocator(addr); }

9
BAN/BAN/New.cpp Normal file
View File

@@ -0,0 +1,9 @@
#include <BAN/New.h>
void* operator new(size_t size) { return BAN::allocator(size); }
void* operator new[](size_t size) { return BAN::allocator(size); }
void operator delete(void* addr) { BAN::deallocator(addr); }
void operator delete[](void* addr) { BAN::deallocator(addr); }
void operator delete(void* addr, size_t) { BAN::deallocator(addr); }
void operator delete[](void* addr, size_t) { BAN::deallocator(addr); }

View File

@@ -1,7 +1,7 @@
#include <BAN/Errors.h>
#include <BAN/Math.h>
#include <BAN/Memory.h>
#include <BAN/Move.h>
#include <BAN/New.h>
#include <BAN/String.h>
#include <BAN/StringView.h>
@@ -119,7 +119,7 @@ namespace BAN
m_size -= count;
m_data[m_size] = '\0';
}
void String::clear()
{
m_size = 0;

View File

@@ -63,9 +63,38 @@ namespace BAN
ErrorOr<Vector<StringView>> StringView::split(char delim, bool allow_empties)
{
// FIXME: Won't work while multithreading
static char s_delim = delim;
return split([](char c){ return c == s_delim; }, allow_empties);
size_type count = 0;
{
size_type start = 0;
for (size_type i = 0; i < m_size; i++)
{
if (m_data[i] == delim)
{
if (allow_empties || start != i)
count++;
start = i + 1;
}
}
if (start != m_size)
count++;
}
Vector<StringView> result;
TRY(result.reserve(count));
size_type start = 0;
for (size_type i = 0; i < m_size; i++)
{
if (m_data[i] == delim)
{
if (allow_empties || start != i)
TRY(result.push_back(this->substring(start, i - start)));
start = i + 1;
}
}
if (start != m_size)
TRY(result.push_back(this->substring(start)));
return result;
}
ErrorOr<Vector<StringView>> StringView::split(bool(*comp)(char), bool allow_empties)
@@ -116,6 +145,14 @@ namespace BAN
return m_data[0];
}
bool StringView::contains(char ch) const
{
for (size_type i = 0; i < m_size; i++)
if (m_data[i] == ch)
return true;
return false;
}
StringView::size_type StringView::count(char ch) const
{
size_type result = 0;
@@ -134,7 +171,7 @@ namespace BAN
{
return m_size;
}
const char* StringView::data() const
{
return m_data;

71
BAN/BAN/Time.cpp Normal file
View File

@@ -0,0 +1,71 @@
#include <BAN/Time.h>
namespace BAN
{
static constexpr bool is_leap_year(uint64_t year)
{
if (year % 400 == 0)
return true;
if (year % 100 == 0)
return false;
if (year % 4 == 0)
return true;
return false;
}
static constexpr uint64_t leap_days_since_epoch(const BAN::Time& time)
{
uint64_t leap_years = 0;
for (uint32_t year = 1970; year < time.year; year++)
if (is_leap_year(year))
leap_years++;
if (is_leap_year(time.year) && time.month >= 3)
leap_years++;
return leap_years;
}
static constexpr uint64_t month_days[] { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
uint64_t to_unix_time(const BAN::Time& time)
{
uint64_t years = time.year - 1970;
uint64_t days = years * 365 + month_days[time.month - 1] + leap_days_since_epoch(time) + (time.day - 1);
uint64_t hours = days * 24 + time.hour;
uint64_t minutes = hours * 60 + time.minute;
uint64_t seconds = minutes * 60 + time.second;
return seconds;
}
BAN::Time from_unix_time(uint64_t unix_time)
{
BAN::Time time {};
time.second = unix_time % 60; unix_time /= 60;
time.minute = unix_time % 60; unix_time /= 60;
time.hour = unix_time % 24; unix_time /= 24;
uint64_t total_days = unix_time;
time.week_day = (total_days + 4) % 7 + 1;
time.year = 1970;
while (total_days >= 365U + is_leap_year(time.year))
{
total_days -= 365U + is_leap_year(time.year);
time.year++;
}
bool is_leap_day = is_leap_year(time.year) && total_days == month_days[2];
bool had_leap_day = is_leap_year(time.year) && total_days > month_days[2];
for (time.month = 1; time.month < 12; time.month++)
if (total_days < month_days[time.month] + (is_leap_day || had_leap_day))
break;
time.day = total_days - month_days[time.month - 1] + !had_leap_day;
return time;
}
}

26
BAN/CMakeLists.txt Normal file
View File

@@ -0,0 +1,26 @@
cmake_minimum_required(VERSION 3.26)
project(BAN CXX)
set(BAN_SOURCES
BAN/New.cpp
BAN/String.cpp
BAN/StringView.cpp
BAN/Time.cpp
)
add_custom_target(ban-headers
COMMAND sudo rsync -a ${CMAKE_CURRENT_SOURCE_DIR}/include/ ${BANAN_INCLUDE}/
DEPENDS sysroot
USES_TERMINAL
)
add_library(ban ${BAN_SOURCES})
add_dependencies(ban headers libc-install)
add_custom_target(ban-install
COMMAND sudo cp ${CMAKE_CURRENT_BINARY_DIR}/libban.a ${BANAN_LIB}/
DEPENDS ban
BYPRODUCTS ${BANAN_LIB}/libban.a
USES_TERMINAL
)

View File

@@ -1,89 +0,0 @@
DEFAULT_HOST!=../default-host.sh
HOST?=DEFAULT_HOST
HOSTARCH!=../target-triplet-to-arch.sh $(HOST)
CFLAGS?=-O2 -g
CPPFLAGS?=
LDFLAGS?=
LIBS?=
DESTDIR?=
PREFIX?=/usr/local
EXEC_PREFIX?=$(PREFIX)
INCLUDEDIR?=$(PREFIX)/include
LIBDIR?=$(EXEC_PREFIX)/lib
CFLAGS:=$(CFLAGS) -Iinclude -ffreestanding -Wall -Wextra -Werror=return-type
CPPFLAGS:=$(CPPFLAGS)
LIBBANK_CFLAGS:=$(CFLAGS) -D__is_kernel -Iinclude -ffreestanding -Wall -Wextra
LIBBANK_CPPFLAGS:=$(CPPFLAGS) -fno-rtti -fno-exceptions
ARCHDIR=arch/$(HOSTARCH)
include $(ARCHDIR)/make.config
CFLAGS:=$(CFLAGS) $(ARCH_CFLAGS)
CPPFLAGS:=$(CPPFLAGS) $(ARCH_CPPFLAGS)
LIBBANK_CFLAGS:=$(LIBBANK_CFLAGS) $(KERNEL_ARCH_CFLAGS)
LIBBANK_CPPFLAGS:=$(LIBBANK_CPPFLAGS) $(KERNEL_ARCH_CPPFLAGS)
BUILDDIR=$(abspath build)
FREEOBJS= \
$(ARCH_FREEOBJS) \
BAN/Memory.o \
BAN/String.o \
BAN/StringView.o \
HOSTEDOBJS=\
$(ARCH_HOSTEDOBJS) \
OBJS=\
$(FREEOBJS) \
$(HOSTEDOBJS) \
LIBBANK_OBJS=$(FREEOBJS:.o=.bank.o)
BINARIES=libbank.a
.PHONY: all always clean install install-headers install-libs
.SUFFIXES: .o .bank.o .cpp .S
all: $(BINARIES)
libban.a: always $(OBJS)
cd $(BUILDDIR) && $(AR) rcs $@ $(OBJS)
libbank.a: always $(LIBBANK_OBJS)
cd $(BUILDDIR) && $(AR) rcs $@ $(LIBBANK_OBJS)
.cpp.o:
$(CXX) -MD -c $< -o $(BUILDDIR)/$@ $(CFLAGS) $(CPPFLAGS)
.S.o:
$(CXX) -MD -c $< -o $(BUILDDIR)/$@ $(CFLAGS) $(CPPFLAGS)
.cpp.bank.o:
$(CXX) -MD -c $< -o $(BUILDDIR)/$@ $(LIBBANK_CFLAGS) $(LIBBANK_CPPFLAGS)
.S.bank.o:
$(CXX) -MD -c $< -o $(BUILDDIR)/$@ $(LIBBANK_CFLAGS) $(LIBBANK_CPPFLAGS)
clean:
rm -rf $(BUILDDIR)
always:
mkdir -p $(BUILDDIR)/BAN
install: install-headers install-libs
install-headers:
mkdir -p $(DESTDIR)$(INCLUDEDIR)
cp -R --preserve=timestamps include/. $(DESTDIR)$(INCLUDEDIR)/.
install-libs: $(BINARIES)
mkdir -p $(DESTDIR)$(LIBDIR)
cp $(BUILDDIR)/$(BINARIES) $(DESTDIR)$(LIBDIR)
-include $(OBJS:.o=.d)
-include $(LIBBANK_OBJS:.o=.d)

View File

@@ -1,8 +0,0 @@
ARCH_CFLAGS=
ARCH_CPPFLAGS=
KERNEL_ARCH_CFLAGS=
KERNEL_ARCH_CPPFLAGS=
ARCH_FREEOBJS=\
ARCH_HOSTEDOBJS=\

View File

@@ -1,8 +0,0 @@
ARCH_CFLAGS=
ARCH_CPPFLAGS=
KERNEL_ARCH_CFLAGS=
KERNEL_ARCH_CPPFLAGS=
ARCH_FREEOBJS=\
ARCH_HOSTEDOBJS=\

View File

@@ -1,6 +1,8 @@
#pragma once
#include <BAN/Errors.h>
#include <BAN/Iterators.h>
#include <BAN/Span.h>
#include <stddef.h>
@@ -13,11 +15,18 @@ namespace BAN
public:
using size_type = decltype(S);
using value_type = T;
using iterator = IteratorSimple<T, Array>;
using const_iterator = ConstIteratorSimple<T, Array>;
public:
Array();
Array(const T&);
iterator begin() { return iterator(m_data); }
iterator end() { return iterator(m_data + size()); }
const_iterator begin() const { return const_iterator(m_data); }
const_iterator end() const { return const_iterator(m_data + size()); }
const T& operator[](size_type) const;
T& operator[](size_type);
@@ -26,7 +35,13 @@ namespace BAN
const T& front() const;
T& front();
Span<T> span() { return Span(m_data, size()); }
const Span<T> span() const { return Span(m_data, size()); }
constexpr size_type size() const;
const T* data() const { return m_data; }
T* data() { return m_data; }
private:
T m_data[S];

View File

@@ -2,10 +2,10 @@
#if defined(__is_kernel)
#include <kernel/Panic.h>
#define ASSERT(cond) do { if (!(cond)) Kernel::panic("ASSERT("#cond") failed"); } while(false)
#define ASSERT(cond) do { if (!(cond)) Kernel::panic("ASSERT("#cond") failed"); } while (false)
#define ASSERT_NOT_REACHED() Kernel::panic("ASSERT_NOT_REACHED() failed")
#else
#include <assert.h>
#define ASSERT(cond) assert((cond) && "ASSERT("#cond") failed")
#define ASSERT_NOT_REACHED() assert(false && "ASSERT_NOT_REACHED() failed")
#define ASSERT_NOT_REACHED() do { assert(false && "ASSERT_NOT_REACHED() failed"); __builtin_unreachable(); } while (false)
#endif

View File

@@ -0,0 +1,113 @@
#pragma once
#include <BAN/Assert.h>
#include <stdint.h>
#include <stddef.h>
namespace BAN
{
template<typename T, size_t S>
class CircularQueue
{
public:
using size_type = size_t;
using value_type = T;
public:
CircularQueue() = default;
~CircularQueue();
void push(const T&);
void push(T&&);
template<typename... Args>
void emplace(Args&&... args);
void pop();
const T& front() const;
T& front();
size_type size() const { return m_size; }
bool empty() const { return size() == 0; }
bool full() const { return size() == capacity(); }
static constexpr size_type capacity() { return S; }
private:
T* element_at(size_type);
const T* element_at(size_type) const;
private:
alignas(T) uint8_t m_storage[sizeof(T) * capacity()];
size_type m_first { 0 };
size_type m_size { 0 };
};
template<typename T, size_t S>
CircularQueue<T, S>::~CircularQueue()
{
for (size_type i = 0; i < m_size; i++)
element_at((m_first + i) % capacity())->~T();
}
template<typename T, size_t S>
void CircularQueue<T, S>::push(const T& value)
{
emplace(BAN::move(T(value)));
}
template<typename T, size_t S>
void CircularQueue<T, S>::push(T&& value)
{
emplace(BAN::move(value));
}
template<typename T, size_t S>
template<typename... Args>
void CircularQueue<T, S>::emplace(Args&&... args)
{
ASSERT(!full());
new (element_at(((m_first + m_size) % capacity()))) T(BAN::forward<Args>(args)...);
m_size++;
}
template<typename T, size_t S>
void CircularQueue<T, S>::pop()
{
ASSERT(!empty());
element_at(m_first)->~T();
m_first = (m_first + 1) % capacity();
m_size--;
}
template<typename T, size_t S>
const T& CircularQueue<T, S>::front() const
{
ASSERT(!empty());
return *element_at(m_first);
}
template<typename T, size_t S>
T& CircularQueue<T, S>::front()
{
ASSERT(!empty());
return *element_at(m_first);
}
template<typename T, size_t S>
const T* CircularQueue<T, S>::element_at(size_type index) const
{
ASSERT(index < capacity());
return (const T*)(m_storage + index * sizeof(T));
}
template<typename T, size_t S>
T* CircularQueue<T, S>::element_at(size_type index)
{
ASSERT(index < capacity());
return (T*)(m_storage + index * sizeof(T));
}
}

View File

@@ -0,0 +1,80 @@
#pragma once
#include <BAN/Traits.h>
#include <stddef.h>
namespace BAN
{
template<integral T>
constexpr T swap_endianness(T value)
{
if constexpr(sizeof(T) == 1)
return value;
if constexpr(sizeof(T) == 2)
return (((value >> 8) & 0xFF) << 0)
| (((value >> 0) & 0xFF) << 8);
if constexpr(sizeof(T) == 4)
return (((value >> 24) & 0xFF) << 0)
| (((value >> 16) & 0xFF) << 8)
| (((value >> 8) & 0xFF) << 16)
| (((value >> 0) & 0xFF) << 24);
if constexpr(sizeof(T) == 8)
return (((value >> 56) & 0xFF) << 0)
| (((value >> 48) & 0xFF) << 8)
| (((value >> 40) & 0xFF) << 16)
| (((value >> 32) & 0xFF) << 24)
| (((value >> 24) & 0xFF) << 32)
| (((value >> 16) & 0xFF) << 40)
| (((value >> 8) & 0xFF) << 48)
| (((value >> 0) & 0xFF) << 56);
T result { 0 };
for (size_t i = 0; i < sizeof(T); i++)
result |= ((value >> (i * 8)) & 0xFF) << ((sizeof(T) - i - 1) * 8);
return result;
}
template<integral T>
constexpr T host_to_little_endian(T value)
{
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
return value;
#else
return swap_endianness(value);
#endif
}
template<integral T>
constexpr T host_to_big_endian(T value)
{
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
return value;
#else
return swap_endianness(value);
#endif
}
template<integral T>
struct LittleEndian
{
constexpr operator T() const
{
return host_to_little_endian(raw);
}
private:
T raw;
};
template<integral T>
struct BigEndian
{
constexpr operator T() const
{
return host_to_big_endian(raw);
}
private:
T raw;
};
}

View File

@@ -1,62 +1,76 @@
#pragma once
#include <BAN/Formatter.h>
#include <BAN/StringView.h>
#include <BAN/Variant.h>
#include <errno.h>
#include <string.h>
#if defined(__is_kernel)
#ifdef __is_kernel
#include <kernel/Panic.h>
#define MUST(expr) ({ auto e = expr; if (e.is_error()) Kernel::panic("{}", e.error()); e.release_value(); })
#include <kernel/Errors.h>
#define MUST(expr) ({ auto&& e = expr; if (e.is_error()) Kernel::panic("{}", e.error()); e.release_value(); })
#define MUST_REF(expr) *({ auto&& e = expr; if (e.is_error()) Kernel::panic("{}", e.error()); &e.release_value(); })
#else
#define MUST(expr) ({ auto e = expr; assert(!e.is_error()); e.release_value(); })
#include <assert.h>
#define MUST(expr) ({ auto&& e = expr; assert(!e.is_error()); e.release_value(); })
#define MUST_REF(expr) *({ auto&& e = expr; assert(!e.is_error()); &e.release_value(); })
#endif
#define TRY(expr) ({ auto e = expr; if (e.is_error()) return e.release_error(); e.release_value(); })
#define TRY(expr) ({ auto&& e = expr; if (e.is_error()) return e.release_error(); e.release_value(); })
#define TRY_REF(expr) *({ auto&& e = expr; if (e.is_error()) return e.release_error(); &e.release_value(); })
namespace BAN
{
class Error
{
#ifdef __is_kernel
private:
static constexpr uint64_t kernel_error_mask = uint64_t(1) << 63;
#endif
public:
static Error from_c_string(const char* message)
#ifdef __is_kernel
static Error from_error_code(Kernel::ErrorCode error)
{
Error result;
strncpy(result.m_message, message, sizeof(Error::m_message));
result.m_message[sizeof(Error::m_message) - 1] = '\0';
result.m_error_code = 0xFF;
return result;
}
template<typename... Args>
static Error from_format(const char* format, Args&&... args)
{
char buffer[sizeof(Error::m_message)] {};
size_t index = 0;
auto putc = [&](char ch)
{
if (index < sizeof(buffer) - 1)
buffer[index++] = ch;
};
Formatter::print(putc, format, forward<Args>(args)...);
return from_c_string(buffer);
return Error((uint64_t)error | kernel_error_mask);
}
#endif
static Error from_errno(int error)
{
Error result;
strncpy(result.m_message, strerror(error), sizeof(Error::m_message));
result.m_message[sizeof(Error::m_message) - 1] = '\0';
result.m_error_code = error;
return result;
return Error(error);
}
uint8_t get_error_code() const { return m_error_code; }
const char* get_message() const { return m_message; }
#ifdef __is_kernel
Kernel::ErrorCode kernel_error() const
{
return (Kernel::ErrorCode)(m_error_code & ~kernel_error_mask);
}
bool is_kernel_error() const
{
return m_error_code & kernel_error_mask;
}
#endif
uint64_t get_error_code() const { return m_error_code; }
BAN::StringView get_message() const
{
#ifdef __is_kernel
if (m_error_code & kernel_error_mask)
return Kernel::error_string(kernel_error());
#endif
return strerror(m_error_code);
}
private:
char m_message[128];
uint8_t m_error_code;
Error(uint64_t error)
: m_error_code(error)
{}
uint64_t m_error_code;
};
template<typename T>
@@ -76,19 +90,46 @@ namespace BAN
: m_data(move(error))
{}
bool is_error() const { return m_data.template is<Error>(); }
bool is_error() const { return m_data.template has<Error>(); }
const Error& error() const { return m_data.template get<Error>(); }
Error& error() { return m_data.template get<Error>(); }
const T& value() const { return m_data.template get<T>(); }
T& value() { return m_data.template get<T>(); }
Error release_error() { return move(error()); m_data.clear(); }
Error release_error() { return move(error()); m_data.clear(); }
T release_value() { return move(value()); m_data.clear(); }
private:
Variant<Error, T> m_data;
};
template<lvalue_reference T>
class [[nodiscard]] ErrorOr<T>
{
public:
ErrorOr(T value)
{
m_data.template set<T>(value);
}
ErrorOr(Error&& error)
: m_data(move(error))
{ }
ErrorOr(const Error& error)
: m_data(error)
{ }
bool is_error() const { return m_data.template has<Error>(); }
Error& error() { return m_data.template get<Error>(); }
const Error& error() const { return m_data.template get<Error>(); }
T value() { return m_data.template get<T>(); }
Error release_error() { return move(error()); m_data.clear(); }
T release_value() { return value(); m_data.clear(); }
private:
Variant<Error, T> m_data;
};
template<>
class [[nodiscard]] ErrorOr<void>
{
@@ -102,12 +143,12 @@ namespace BAN
const Error& error() const { return m_data; }
void value() { }
Error release_error() { return move(m_data); m_data = Error(); }
void release_value() { m_data = Error(); }
Error release_error() { return move(m_data); }
void release_value() { }
private:
Error m_data;
bool m_has_error = false;
Error m_data { Error::from_errno(0) };
bool m_has_error { false };
};
}
@@ -115,11 +156,8 @@ namespace BAN
namespace BAN::Formatter
{
template<typename F>
void print_argument(F putc, const Error& error, const ValueFormat&)
void print_argument(F putc, const Error& error, const ValueFormat& format)
{
if (error.get_error_code() == 0xFF)
print(putc, error.get_message());
else
print(putc, "{} ({})", error.get_message(), error.get_error_code());
print_argument(putc, error.get_message(), format);
}
}

View File

@@ -28,9 +28,8 @@ namespace BAN::Formatter
static size_t parse_format_and_print_argument(F putc, const char* format, T&& arg);
}
/*
IMPLEMENTATION
*/
@@ -42,7 +41,7 @@ namespace BAN::Formatter
int fill = 0;
bool upper = false;
};
template<typename F>
void print(F putc, const char* format)
{
@@ -232,7 +231,7 @@ namespace BAN::Formatter
}
/*
TEMPLATE SPECIALIZATIONS
*/
@@ -243,10 +242,7 @@ namespace BAN::Formatter
template<typename F> void print_argument(F putc, char value, const ValueFormat&) { putc(value); }
template<typename F> void print_argument(F putc, bool value, const ValueFormat&) { print(putc, value ? "true" : "false"); }
template<typename F> void print_argument(F putc, const char* value, const ValueFormat&) { print(putc, value);}
//template<typename F> void print_argument(F putc, signed char value, const ValueFormat& format) { detail::print_integer(putc, value, format); }
//template<typename F> void print_argument(F putc, unsigned char value, const ValueFormat& format) { detail::print_integer(putc, value, format); }
//template<typename F, typename T> void print_argument(F putc, T* value, const ValueFormat& format) { detail::print_pointer(putc, (void*)value, format); }
template<typename F> void print_argument(F putc, const char* value, const ValueFormat&) { print(putc, value); }
template<typename F> void print_argument(F putc, char* value, const ValueFormat&) { print(putc, value); }
}

View File

@@ -5,7 +5,7 @@
namespace BAN
{
template<typename, size_t> class Array;
template<typename> class ErrorOr;
template<typename> class Function;

View File

@@ -2,7 +2,7 @@
#include <BAN/Errors.h>
#include <BAN/Move.h>
#include <BAN/Memory.h>
#include <BAN/New.h>
namespace BAN
{
@@ -43,10 +43,10 @@ namespace BAN
clear();
}
Ret operator()(Args... args)
Ret operator()(Args... args) const
{
ASSERT(*this);
return reinterpret_cast<CallableBase*>(m_storage)->call(forward<Args>(args)...);
return reinterpret_cast<const CallableBase*>(m_storage)->call(forward<Args>(args)...);
}
operator bool() const
@@ -70,7 +70,7 @@ namespace BAN
struct CallableBase
{
virtual ~CallableBase() {}
virtual Ret call(Args...) = 0;
virtual Ret call(Args...) const = 0;
};
struct CallablePointer : public CallableBase
@@ -79,7 +79,7 @@ namespace BAN
: m_function(function)
{ }
virtual Ret call(Args... args) override
virtual Ret call(Args... args) const override
{
return m_function(forward<Args>(args)...);
}
@@ -96,7 +96,7 @@ namespace BAN
, m_function(function)
{ }
virtual Ret call(Args... args) override
virtual Ret call(Args... args) const override
{
return (m_owner->*m_function)(forward<Args>(args)...);
}
@@ -114,7 +114,7 @@ namespace BAN
, m_function(function)
{ }
virtual Ret call(Args... args) override
virtual Ret call(Args... args) const override
{
return (m_owner->*m_function)(forward<Args>(args)...);
}
@@ -131,7 +131,7 @@ namespace BAN
: m_lambda(lambda)
{ }
virtual Ret call(Args... args) override
virtual Ret call(Args... args) const override
{
return m_lambda(forward<Args>(args)...);
}
@@ -141,7 +141,7 @@ namespace BAN
};
private:
static constexpr size_t m_size = sizeof(void*) * 4;
static constexpr size_t m_size = sizeof(void*) * 5;
alignas(CallableBase) uint8_t m_storage[m_size] { 0 };
};

View File

@@ -7,13 +7,31 @@
namespace BAN
{
template<typename Container>
class HashMapIterator;
template<typename Key, typename T, typename HASH = BAN::hash<Key>>
class HashMap
{
public:
struct Entry
{
template<typename... Args>
Entry(const Key& key, Args&&... args)
: key(key)
, value(forward<Args>(args)...)
{}
Key key;
T value;
};
public:
using size_type = size_t;
using key_type = Key;
using value_type = T;
using iterator = IteratorDouble<Entry, Vector, LinkedList, HashMap>;
using const_iterator = ConstIteratorDouble<Entry, Vector, LinkedList, HashMap>;
public:
HashMap() = default;
@@ -29,6 +47,11 @@ namespace BAN
template<typename... Args>
ErrorOr<void> emplace(const Key&, Args&&...);
iterator begin() { return iterator(m_buckets.end(), m_buckets.begin()); }
iterator end() { return iterator(m_buckets.end(), m_buckets.end()); }
const_iterator begin() const { return const_iterator(m_buckets.end(), m_buckets.begin()); }
const_iterator end() const { return const_iterator(m_buckets.end(), m_buckets.end()); }
ErrorOr<void> reserve(size_type);
void remove(const Key&);
@@ -42,19 +65,6 @@ namespace BAN
bool empty() const;
size_type size() const;
private:
struct Entry
{
template<typename... Args>
Entry(const Key& key, Args&&... args)
: key(key)
, value(forward<Args>(args)...)
{}
Key key;
T value;
};
private:
ErrorOr<void> rebucket(size_type);
LinkedList<Entry>& get_bucket(const Key&);
@@ -63,6 +73,8 @@ namespace BAN
private:
Vector<LinkedList<Entry>> m_buckets;
size_type m_size = 0;
friend iterator;
};
template<typename Key, typename T, typename HASH>
@@ -246,4 +258,4 @@ namespace BAN
return m_buckets[index];
}
}
}

View File

@@ -85,8 +85,6 @@ namespace BAN
friend class HashSet<T, HASH>;
};
template<typename T, typename HASH>
HashSet<T, HASH>::HashSet(const HashSet<T, HASH>& other)
: m_buckets(other.m_buckets)
@@ -231,8 +229,6 @@ namespace BAN
return m_buckets[index];
}
template<typename T, typename HASH>
HashSetIterator<T, HASH>& HashSetIterator<T, HASH>::operator++()
{

View File

@@ -0,0 +1,12 @@
#pragma once
namespace BAN
{
enum class Iteration
{
Continue,
Break
};
}

229
BAN/include/BAN/Iterators.h Normal file
View File

@@ -0,0 +1,229 @@
#pragma once
#include <BAN/Assert.h>
namespace BAN
{
template<typename T, typename Container, bool CONST>
class IteratorSimpleGeneral
{
public:
IteratorSimpleGeneral() = default;
template<bool CONST2, typename = enable_if_t<CONST2 == CONST || CONST>>
IteratorSimpleGeneral(const IteratorSimpleGeneral<T, Container, CONST2>& other)
: m_pointer(other.m_pointer)
{
}
const T& operator*() const
{
ASSERT(m_pointer);
return *m_pointer;
}
template<bool CONST2 = CONST>
enable_if_t<!CONST2, T&> operator*()
{
ASSERT(m_pointer);
return *m_pointer;
}
const T* operator->() const
{
ASSERT(m_pointer);
return m_pointer;
}
template<bool CONST2 = CONST>
enable_if_t<!CONST2, T*> operator->()
{
ASSERT(m_pointer);
return m_pointer;
}
IteratorSimpleGeneral& operator++()
{
ASSERT(m_pointer);
++m_pointer;
return *this;
}
IteratorSimpleGeneral operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
IteratorSimpleGeneral& operator--()
{
ASSERT(m_pointer);
return --m_pointer;
}
IteratorSimpleGeneral operator--(int)
{
auto temp = *this;
--(*this);
return temp;
}
bool operator==(const IteratorSimpleGeneral& other) const
{
return m_pointer == other.m_pointer;
}
bool operator!=(const IteratorSimpleGeneral& other) const
{
return !(*this == other);
}
operator bool() const
{
return m_pointer;
}
private:
IteratorSimpleGeneral(maybe_const_t<CONST, T>* pointer)
: m_pointer(pointer)
{
}
private:
maybe_const_t<CONST, T>* m_pointer = nullptr;
friend IteratorSimpleGeneral<T, Container, !CONST>;
friend Container;
};
template<typename T, template<typename> typename OuterContainer, template<typename> typename InnerContainer, typename Container, bool CONST>
class IteratorDoubleGeneral
{
public:
using Inner = InnerContainer<T>;
using Outer = OuterContainer<Inner>;
using InnerIterator = either_or_t<CONST, typename Inner::const_iterator, typename Inner::iterator>;
using OuterIterator = either_or_t<CONST, typename Outer::const_iterator, typename Outer::iterator>;
public:
IteratorDoubleGeneral() = default;
template<bool CONST2, typename = enable_if_t<CONST2 == CONST || CONST>>
IteratorDoubleGeneral(const IteratorDoubleGeneral<T, OuterContainer, InnerContainer, Container, CONST2>& other)
: m_outer_end(other.m_outer_end)
, m_outer_current(other.m_outer_current)
, m_inner_current(other.m_inner_current)
{
}
const T& operator*() const
{
ASSERT(*this);
ASSERT(m_outer_current != m_outer_end);
ASSERT(m_inner_current);
return m_inner_current.operator*();
}
template<bool CONST2 = CONST>
enable_if_t<!CONST2, T&> operator*()
{
ASSERT(*this);
ASSERT(m_outer_current != m_outer_end);
ASSERT(m_inner_current);
return m_inner_current.operator*();
}
const T* operator->() const
{
ASSERT(*this);
ASSERT(m_outer_current != m_outer_end);
ASSERT(m_inner_current);
return m_inner_current.operator->();
}
template<bool CONST2 = CONST>
enable_if_t<!CONST2, T*> operator->()
{
ASSERT(*this);
ASSERT(m_outer_current != m_outer_end);
ASSERT(m_inner_current);
return m_inner_current.operator->();
}
IteratorDoubleGeneral& operator++()
{
ASSERT(*this);
ASSERT(m_outer_current != m_outer_end);
ASSERT(m_inner_current);
m_inner_current++;
find_valid_or_end();
return *this;
}
IteratorDoubleGeneral operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
bool operator==(const IteratorDoubleGeneral& other) const
{
if (!*this || !other)
return false;
if (m_outer_end != other.m_outer_end)
return false;
if (m_outer_current != other.m_outer_current)
return false;
if (m_outer_current == m_outer_end)
return true;
return m_inner_current == other.m_inner_current;
}
bool operator!=(const IteratorDoubleGeneral& other) const
{
return !(*this == other);
}
operator bool() const
{
return m_outer_end && m_outer_current;
}
private:
IteratorDoubleGeneral(const OuterIterator& outer_end, const OuterIterator& outer_current)
: m_outer_end(outer_end)
, m_outer_current(outer_current)
{
if (outer_current != outer_end)
{
m_inner_current = m_outer_current->begin();
find_valid_or_end();
}
}
void find_valid_or_end()
{
while (m_inner_current == m_outer_current->end())
{
m_outer_current++;
if (m_outer_current == m_outer_end)
break;
m_inner_current = m_outer_current->begin();
}
}
private:
OuterIterator m_outer_end;
OuterIterator m_outer_current;
InnerIterator m_inner_current;
friend class IteratorDoubleGeneral<T, OuterContainer, InnerContainer, Container, !CONST>;
friend Container;
};
template<typename T, typename Container>
using IteratorSimple = IteratorSimpleGeneral<T, Container, false>;
template<typename T, typename Container>
using ConstIteratorSimple = IteratorSimpleGeneral<T, Container, true>;
template<typename T, template<typename> typename OuterContainer, template<typename> typename InnerContainer, typename Container>
using IteratorDouble = IteratorDoubleGeneral<T, OuterContainer, InnerContainer, Container, false>;
template<typename T, template<typename> typename OuterContainer, template<typename> typename InnerContainer, typename Container>
using ConstIteratorDouble = IteratorDoubleGeneral<T, OuterContainer, InnerContainer, Container, true>;
}

View File

@@ -1,15 +1,15 @@
#pragma once
#include <BAN/Errors.h>
#include <BAN/Memory.h>
#include <BAN/Move.h>
#include <BAN/New.h>
namespace BAN
{
template<typename T, bool CONST>
class LinkedListIterator;
template<typename T>
class LinkedList
{
@@ -38,7 +38,7 @@ namespace BAN
ErrorOr<void> emplace(iterator, Args&&...);
void pop_back();
void remove(iterator);
iterator remove(iterator);
void clear();
iterator begin() { return iterator(m_data, empty()); }
@@ -114,8 +114,6 @@ namespace BAN
friend class LinkedListIterator<T, !CONST>;
};
template<typename T>
LinkedList<T>& LinkedList<T>::operator=(const LinkedList<T>& other)
{
@@ -197,11 +195,11 @@ namespace BAN
template<typename T>
void LinkedList<T>::pop_back()
{
return remove(m_last);
remove(iterator(m_last, false));
}
template<typename T>
void LinkedList<T>::remove(iterator iter)
LinkedList<T>::iterator LinkedList<T>::remove(iterator iter)
{
ASSERT(!empty() && iter);
Node* node = iter.m_current;
@@ -212,6 +210,7 @@ namespace BAN
(prev ? prev->next : m_data) = next;
(next ? next->prev : m_last) = prev;
m_size--;
return next ? iterator(next, false) : iterator(m_last, true);
}
template<typename T>
@@ -292,8 +291,6 @@ namespace BAN
return node;
}
template<typename T, bool CONST>
template<bool C>
LinkedListIterator<T, CONST>::LinkedListIterator(const LinkedListIterator<T, C>& other, enable_if_t<C == CONST || !C>*)
@@ -378,7 +375,7 @@ namespace BAN
ASSERT(m_current);
return &m_current->value;
}
template<typename T, bool CONST>
bool LinkedListIterator<T, CONST>::operator==(const LinkedListIterator<T, CONST>& other) const
{

View File

@@ -52,20 +52,53 @@ namespace BAN::Math
}
template<integral T>
inline constexpr T little_endian_to_host(const uint8_t* bytes)
inline constexpr bool is_power_of_two(T value)
{
T result = 0;
for (size_t i = 0; i < sizeof(T); i++)
result |= (T)bytes[i] << (i * 8);
if (value == 0)
return false;
return (value & (value - 1)) == 0;
}
template<floating_point T>
inline constexpr T log2(T value)
{
T result;
asm volatile("fyl2x" : "=t"(result) : "0"(value), "u"((T)1.0) : "st(1)");
return result;
}
template<integral T>
inline constexpr T big_endian_to_host(const uint8_t* bytes)
template<floating_point T>
inline constexpr T log10(T value)
{
T result = 0;
for (size_t i = 0; i < sizeof(T); i++)
result |= (T)bytes[i] << (8 * (sizeof(T) - i - 1));
constexpr T INV_LOG_2_10 = 0.3010299956639811952137388947244930267681898814621085413104274611;
T result;
asm volatile("fyl2x" : "=t"(result) : "0"(value), "u"(INV_LOG_2_10) : "st(1)");
return result;
}
template<floating_point T>
inline constexpr T log(T value, T base)
{
return log2(value) / log2(base);
}
template<floating_point T>
inline constexpr T pow(T base, T exp)
{
T result;
asm volatile(
"fyl2x;"
"fld1;"
"fld %%st(1);"
"fprem;"
"f2xm1;"
"faddp;"
"fscale;"
"fxch %%st(1);"
"fstp %%st;"
: "=t"(result)
: "0"(base), "u"(exp)
);
return result;
}

View File

@@ -2,6 +2,8 @@
#include <BAN/Traits.h>
#include <stddef.h>
namespace BAN
{
@@ -24,4 +26,7 @@ namespace BAN
return static_cast<T&&>(arg);
}
}
}
inline void* operator new(size_t, void* addr) { return addr; }
inline void* operator new[](size_t, void* addr) { return addr; }

18
BAN/include/BAN/New.h Normal file
View File

@@ -0,0 +1,18 @@
#pragma once
#if defined(__is_kernel)
#include <kernel/Memory/kmalloc.h>
#else
#include <stdlib.h>
#endif
namespace BAN
{
#if defined(__is_kernel)
static constexpr void*(&allocator)(size_t) = kmalloc;
static constexpr void(&deallocator)(void*) = kfree;
#else
static constexpr void*(&allocator)(size_t) = malloc;
static constexpr void(&deallocator)(void*) = free;
#endif
}

179
BAN/include/BAN/Optional.h Normal file
View File

@@ -0,0 +1,179 @@
#pragma once
#include <BAN/Assert.h>
#include <BAN/Move.h>
#include <stdint.h>
namespace BAN
{
template<typename T>
class Optional
{
public:
Optional();
Optional(const T&);
Optional(T&&);
template<typename... Args>
Optional(Args&&...);
~Optional();
Optional& operator=(const Optional&);
Optional& operator=(Optional&&);
template<typename... Args>
Optional& emplace(Args&&...);
T* operator->();
const T* operator->() const;
T& operator*();
const T& operator*() const;
bool has_value() const;
T&& release_value();
const T& value() const;
T& value();
void clear();
private:
alignas(T) uint8_t m_storage[sizeof(T)];
bool m_has_value { false };
};
template<typename T>
Optional<T>::Optional()
: m_has_value(false)
{}
template<typename T>
Optional<T>::Optional(const T& value)
: m_has_value(true)
{
new (m_storage) T(value);
}
template<typename T>
Optional<T>::Optional(T&& value)
: m_has_value(true)
{
new (m_storage) T(BAN::move(value));
}
template<typename T>
template<typename... Args>
Optional<T>::Optional(Args&&... args)
: m_has_value(true)
{
new (m_storage) T(BAN::forward<Args>(args)...);
}
template<typename T>
Optional<T>::~Optional()
{
clear();
}
template<typename T>
Optional<T>& Optional<T>::operator=(const Optional& other)
{
clear();
if (other.has_value())
{
m_has_value = true;
new (m_storage) T(other.value());
}
return *this;
}
template<typename T>
Optional<T>& Optional<T>::operator=(Optional&& other)
{
clear();
if (other.has_value())
{
m_has_value = true;
new (m_storage) T(BAN::move(other.release_value()));
}
return *this;
}
template<typename T>
template<typename... Args>
Optional<T>& Optional<T>::emplace(Args&&... args)
{
clear();
m_has_value = true;
new (m_storage) T(BAN::forward<Args>(args)...);
return *this;
}
template<typename T>
T* Optional<T>::operator->()
{
ASSERT(has_value());
return &value();
}
template<typename T>
const T* Optional<T>::operator->() const
{
ASSERT(has_value());
return &value();
}
template<typename T>
T& Optional<T>::operator*()
{
ASSERT(has_value());
return value();
}
template<typename T>
const T& Optional<T>::operator*() const
{
ASSERT(has_value());
return value();
}
template<typename T>
bool Optional<T>::has_value() const
{
return m_has_value;
}
template<typename T>
T&& Optional<T>::release_value()
{
ASSERT(has_value());
m_has_value = false;
return BAN::move((T&)m_storage);
}
template<typename T>
const T& Optional<T>::value() const
{
ASSERT(has_value());
return (const T&)m_storage;
}
template<typename T>
T& Optional<T>::value()
{
ASSERT(has_value());
return (T&)m_storage;
}
template<typename T>
void Optional<T>::clear()
{
if (m_has_value)
value().~T();
m_has_value = false;
}
}

View File

@@ -1,9 +1,10 @@
#pragma once
#include <BAN/Errors.h>
#include <BAN/Iterators.h>
#include <BAN/Math.h>
#include <BAN/Memory.h>
#include <BAN/Move.h>
#include <BAN/New.h>
namespace BAN
{
@@ -14,6 +15,8 @@ namespace BAN
public:
using size_type = size_t;
using value_type = T;
using iterator = IteratorSimple<T, Queue>;
using const_iterator = ConstIteratorSimple<T, Queue>;
public:
Queue() = default;
@@ -32,6 +35,11 @@ namespace BAN
ErrorOr<void> reserve(size_type);
ErrorOr<void> shrink_to_fit();
iterator begin() { return iterator(m_data); }
iterator end() { return iterator(m_data + m_size); }
const_iterator begin() const { return const_iterator(m_data); }
const_iterator end() const { return const_iterator(m_data + m_size); }
void pop();
void clear();

View File

@@ -1,27 +1,12 @@
#pragma once
#include <BAN/Errors.h>
#include <BAN/Move.h>
#include <BAN/NoCopyMove.h>
#if defined(__is_kernel)
#include <kernel/kmalloc.h>
#else
#include <stdlib.h>
#endif
#include <stdint.h>
namespace BAN
{
#if defined(__is_kernel)
static constexpr void*(&allocator)(size_t) = kmalloc;
static constexpr void(&deallocator)(void*) = kfree;
#else
static constexpr void*(&allocator)(size_t) = malloc;
static constexpr void(&deallocator)(void*) = free;
#endif
template<typename T>
class RefCounted
@@ -68,7 +53,6 @@ namespace BAN
if (m_pointer)
m_pointer->ref();
}
~RefPtr() { clear(); }
template<typename U>
@@ -90,6 +74,10 @@ namespace BAN
RefPtr(const RefPtr& other) { *this = other; }
RefPtr(RefPtr&& other) { *this = move(other); }
template<typename U>
RefPtr(const RefPtr<U>& other) { *this = other; }
template<typename U>
RefPtr(RefPtr<U>&& other) { *this = move(other); }
RefPtr& operator=(const RefPtr& other)
{
@@ -108,6 +96,25 @@ namespace BAN
return *this;
}
template<typename U>
RefPtr& operator=(const RefPtr<U>& other)
{
clear();
m_pointer = other.m_pointer;
if (m_pointer)
m_pointer->ref();
return *this;
}
template<typename U>
RefPtr& operator=(RefPtr<U>&& other)
{
clear();
m_pointer = other.m_pointer;
other.m_pointer = nullptr;
return *this;
}
T* ptr() { ASSERT(!empty()); return m_pointer; }
const T* ptr() const { ASSERT(!empty()); return m_pointer; }
@@ -129,9 +136,9 @@ namespace BAN
private:
T* m_pointer = nullptr;
template<typename U>
friend class RefPtr;
};
}
inline void* operator new(size_t, void* addr) { return addr; }
inline void* operator new[](size_t, void* addr) { return addr; }

View File

@@ -13,10 +13,16 @@ namespace BAN
{ }
~ScopeGuard()
{
m_func();
if (m_enabled)
m_func();
}
void disable()
{
m_enabled = false;
}
private:
BAN::Function<void()> m_func;
bool m_enabled { true };
};
}

132
BAN/include/BAN/Span.h Normal file
View File

@@ -0,0 +1,132 @@
#pragma once
#include <BAN/Assert.h>
#include <BAN/Iterators.h>
#include <stddef.h>
namespace BAN
{
template<typename T>
class Span
{
public:
using value_type = T;
using size_type = size_t;
using iterator = IteratorSimple<T, Span>;
using const_iterator = ConstIteratorSimple<T, Span>;
public:
Span() = default;
Span(T*, size_type);
Span(Span<T>&);
template<typename S>
requires(is_same_v<T, const S>)
Span(const Span<S>&);
iterator begin() { return iterator(m_data); }
iterator end() { return iterator(m_data + m_size); }
const_iterator begin() const { return const_iterator(m_data); }
const_iterator end() const { return const_iterator(m_data + m_size); }
T& operator[](size_type);
const T& operator[](size_type) const;
T* data();
const T* data() const;
bool empty() const;
size_type size() const;
void clear();
Span slice(size_type, size_type = ~size_type(0));
private:
T* m_data = nullptr;
size_type m_size = 0;
};
template<typename T>
Span<T>::Span(T* data, size_type size)
: m_data(data)
, m_size(size)
{
}
template<typename T>
Span<T>::Span(Span& other)
: m_data(other.data())
, m_size(other.size())
{
}
template<typename T>
template<typename S>
requires(is_same_v<T, const S>)
Span<T>::Span(const Span<S>& other)
: m_data(other.data())
, m_size(other.size())
{
}
template<typename T>
T& Span<T>::operator[](size_type index)
{
ASSERT(m_data);
ASSERT(index < m_size);
return m_data[index];
}
template<typename T>
const T& Span<T>::operator[](size_type index) const
{
ASSERT(m_data);
ASSERT(index < m_size);
return m_data[index];
}
template<typename T>
T* Span<T>::data()
{
return m_data;
}
template<typename T>
const T* Span<T>::data() const
{
return m_data;
}
template<typename T>
bool Span<T>::empty() const
{
return m_size == 0;
}
template<typename T>
typename Span<T>::size_type Span<T>::size() const
{
return m_size;
}
template<typename T>
void Span<T>::clear()
{
m_data = nullptr;
m_size = 0;
}
template<typename T>
Span<T> Span<T>::slice(size_type start, size_type length)
{
ASSERT(m_data);
ASSERT(start <= m_size);
if (length == ~size_type(0))
length = m_size - start;
ASSERT(start + length <= m_size);
return Span(m_data + start, m_size - start - length);
}
}

View File

@@ -1,8 +1,10 @@
#pragma once
#include <BAN/Errors.h>
#include <BAN/ForwardList.h>
#include <BAN/Formatter.h>
#include <BAN/Hash.h>
#include <BAN/Iterators.h>
namespace BAN
{
@@ -11,6 +13,8 @@ namespace BAN
{
public:
using size_type = size_t;
using iterator = IteratorSimple<char, String>;
using const_iterator = ConstIteratorSimple<char, String>;
public:
String();
@@ -38,6 +42,17 @@ namespace BAN
void clear();
const_iterator begin() const { return const_iterator(m_data); }
iterator begin() { return iterator(m_data); }
const_iterator end() const { return const_iterator(m_data + m_size); }
iterator end() { return iterator(m_data + m_size); }
char front() const { ASSERT(!empty()); return m_data[0]; }
char& front() { ASSERT(!empty()); return m_data[0]; }
char back() const { ASSERT(!empty()); return m_data[m_size - 1]; }
char& back() { ASSERT(!empty()); return m_data[m_size - 1]; }
char operator[](size_type) const;
char& operator[](size_type);
@@ -73,7 +88,7 @@ namespace BAN
String String::formatted(const char* format, const Args&... args)
{
String result;
BAN::Formatter::print([&](char c){ result.push_back(c); }, format, args...);
BAN::Formatter::print([&](char c){ MUST(result.push_back(c)); }, format, args...);
return result;
}

View File

@@ -2,6 +2,7 @@
#include <BAN/ForwardList.h>
#include <BAN/Formatter.h>
#include <BAN/Iterators.h>
namespace BAN
{
@@ -10,12 +11,16 @@ namespace BAN
{
public:
using size_type = size_t;
using const_iterator = ConstIteratorSimple<char, StringView>;
public:
StringView();
StringView(const String&);
StringView(const char*, size_type = -1);
const_iterator begin() const { return const_iterator(m_data); }
const_iterator end() const { return const_iterator(m_data + m_size); }
char operator[](size_type) const;
bool operator==(const String&) const;
@@ -30,6 +35,7 @@ namespace BAN
char back() const;
char front() const;
bool contains(char) const;
size_type count(char) const;
bool empty() const;

View File

@@ -9,15 +9,18 @@ namespace BAN
struct Time
{
uint8_t second;
uint8_t minute;
uint8_t hour;
uint8_t week_day;
uint8_t day;
uint32_t year;
uint8_t month;
int year;
uint8_t day;
uint8_t hour;
uint8_t minute;
uint8_t second;
uint8_t week_day;
};
uint64_t to_unix_time(const BAN::Time&);
BAN::Time from_unix_time(uint64_t);
}
namespace BAN::Formatter

View File

@@ -2,7 +2,7 @@
namespace BAN
{
template<typename T> struct remove_refenrece { using type = T; };
template<typename T> struct remove_refenrece<T&> { using type = T; };
template<typename T> struct remove_refenrece<T&&> { using type = T; };
@@ -30,6 +30,10 @@ namespace BAN
template<typename T> struct maybe_const<true, T> { using type = const T; };
template<bool B, typename T> using maybe_const_t = typename maybe_const<B, T>::type;
template<bool B, typename T1, typename T2> struct either_or { using type = T2; };
template<typename T1, typename T2> struct either_or<true, T1, T2> { using type = T1; };
template<bool B, typename T1, typename T2> using either_or_t = typename either_or<B, T1, T2>::type;
struct true_type { static constexpr bool value = true; };
struct false_type { static constexpr bool value = false; };
@@ -40,6 +44,7 @@ namespace BAN
template<typename T> struct is_lvalue_reference : false_type {};
template<typename T> struct is_lvalue_reference<T&> : true_type {};
template<typename T> inline constexpr bool is_lvalue_reference_v = is_lvalue_reference<T>::value;
template<typename T> concept lvalue_reference = is_lvalue_reference_v<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;
@@ -60,6 +65,21 @@ namespace BAN
template<typename T> inline constexpr bool is_pointer_v = is_pointer<T>::value;
template<typename T> concept pointer = is_pointer_v<T>;
template<typename T> struct is_const : false_type {};
template<typename T> struct is_const<const T> : true_type {};
template<typename T> inline constexpr bool is_const_v = is_const<T>::value;
template<typename T> struct is_arithmetic { static constexpr bool value = is_integral_v<T> || is_floating_point_v<T>; };
template<typename T> inline constexpr bool is_arithmetic_v = is_arithmetic<T>::value;
namespace detail
{
template<typename T, bool = is_arithmetic_v<T>> struct is_signed { static constexpr bool value = T(-1) < T(0); };
template<typename T> struct is_signed<T, false> : false_type {};
}
template<typename T> struct is_signed : detail::is_signed<T> {};
template<typename T> inline constexpr bool is_signed_v = is_signed<T>::value;
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 greater { constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs > rhs; } };

View File

@@ -3,26 +3,79 @@
#include <stddef.h>
#include <stdint.h>
namespace BAN
namespace BAN::UTF8
{
static constexpr uint16_t utf8_to_codepoint(uint8_t* bytes, size_t count)
static constexpr uint32_t invalid = 0xFFFFFFFF;
constexpr uint32_t byte_length(uint8_t first_byte)
{
if (count > 3)
return 0xFFFF;
if ((first_byte & 0x80) == 0x00)
return 1;
if ((first_byte & 0xE0) == 0xC0)
return 2;
if ((first_byte & 0xF0) == 0xE0)
return 3;
if ((first_byte & 0xF8) == 0xF0)
return 4;
return 0;
}
for (size_t i = 1; i < count; i++)
constexpr uint32_t to_codepoint(uint8_t* bytes)
{
uint32_t length = byte_length(bytes[0]);
for (uint32_t i = 1; i < length; i++)
if ((bytes[i] & 0xC0) != 0x80)
return 0xFFFF;
switch (count)
return UTF8::invalid;
switch (length)
{
case 1: return bytes[0];
case 2: return ((bytes[0] & 0x1F) << 6) | (bytes[1] & 0x3F);
case 3: return ((bytes[0] & 0x1F) << 12) | ((bytes[1] & 0x3F) << 6) | (bytes[2] & 0x3F);
case 1: return ((bytes[0] & 0x80) != 0x00) ? UTF8::invalid : bytes[0];
case 2: return ((bytes[0] & 0xE0) != 0xC0) ? UTF8::invalid : ((bytes[0] & 0x1F) << 6) | (bytes[1] & 0x3F);
case 3: return ((bytes[0] & 0xF0) != 0xE0) ? UTF8::invalid : ((bytes[0] & 0x0F) << 12) | ((bytes[1] & 0x3F) << 6) | (bytes[2] & 0x3F);
case 4: return ((bytes[0] & 0xF8) != 0xF0) ? UTF8::invalid : ((bytes[0] & 0x07) << 18) | ((bytes[1] & 0x3F) << 12) | ((bytes[2] & 0x3F) << 6) | (bytes[3] & 0x3F);
}
return 0xFFFF;
return UTF8::invalid;
}
template<typename T>
constexpr bool from_codepoints(const T* codepoints, size_t count, char* out)
{
uint8_t* ptr = (uint8_t*)out;
for (size_t i = 0; i < count; i++)
{
if (codepoints[i] < 0x80)
{
*ptr++ = codepoints[i];
}
else if (codepoints[i] < 0x800)
{
*ptr++ = 0xC0 | ((codepoints[i] >> 6) & 0x1F);
*ptr++ = 0x80 | ((codepoints[i] >> 0) & 0x3F);
}
else if (codepoints[i] < 0x10000)
{
*ptr++ = 0xE0 | ((codepoints[i] >> 12) & 0x0F);
*ptr++ = 0x80 | ((codepoints[i] >> 6) & 0x3F);
*ptr++ = 0x80 | ((codepoints[i] >> 0) & 0x3F);
}
else if (codepoints[i] < 0x110000)
{
*ptr++ = 0xF0 | ((codepoints[i] >> 18) & 0x07);
*ptr++ = 0x80 | ((codepoints[i] >> 12) & 0x3F);
*ptr++ = 0x80 | ((codepoints[i] >> 6) & 0x3F);
*ptr++ = 0x80 | ((codepoints[i] >> 0) & 0x3F);
}
else
{
return false;
}
}
return true;
}
}

98
BAN/include/BAN/UniqPtr.h Normal file
View File

@@ -0,0 +1,98 @@
#pragma once
#include <BAN/Errors.h>
#include <BAN/NoCopyMove.h>
namespace BAN
{
template<typename T>
class UniqPtr
{
BAN_NON_COPYABLE(UniqPtr);
public:
UniqPtr() = default;
template<typename U>
UniqPtr(UniqPtr<U>&& other)
{
m_pointer = other.m_pointer;
other.m_pointer = nullptr;
}
~UniqPtr()
{
clear();
}
static UniqPtr adopt(T* pointer)
{
UniqPtr uniq;
uniq.m_pointer = pointer;
return uniq;
}
template<typename... Args>
static BAN::ErrorOr<UniqPtr> create(Args&&... args)
{
UniqPtr uniq;
uniq.m_pointer = new T(BAN::forward<Args>(args)...);
if (uniq.m_pointer == nullptr)
return BAN::Error::from_errno(ENOMEM);
return uniq;
}
template<typename U>
UniqPtr& operator=(UniqPtr<U>&& other)
{
clear();
m_pointer = other.m_pointer;
other.m_pointer = nullptr;
return *this;
}
T& operator*()
{
ASSERT(m_pointer);
return *m_pointer;
}
const T& operator*() const
{
ASSERT(m_pointer);
return *m_pointer;
}
T* operator->()
{
ASSERT(m_pointer);
return m_pointer;
}
const T* operator->() const
{
ASSERT(m_pointer);
return m_pointer;
}
T* ptr() { return m_pointer; }
const T* ptr() const { return m_pointer; }
void clear()
{
if (m_pointer)
delete m_pointer;
m_pointer = nullptr;
}
operator bool() const { return m_pointer != nullptr; }
private:
T* m_pointer = nullptr;
template<typename U>
friend class UniqPtr;
};
}

View File

@@ -4,144 +4,290 @@
#include <BAN/Math.h>
#include <BAN/Move.h>
#include <string.h>
namespace BAN
{
template<typename T1, typename T2>
namespace detail
{
template<typename T>
constexpr size_t size_ref_as_ptr() { return is_lvalue_reference_v<T> ? sizeof(remove_reference_t<T>*) : sizeof(T); }
template<typename T>
constexpr size_t align_ref_as_ptr() { return is_lvalue_reference_v<T> ? alignof(remove_reference_t<T>*) : alignof(T); }
template<typename T>
constexpr size_t max_size_ref_as_ptr() { return size_ref_as_ptr<T>(); }
template<typename T0, typename T1, typename... Ts>
constexpr size_t max_size_ref_as_ptr() { return size_ref_as_ptr<T0>() > size_ref_as_ptr<T1>() ? max_size_ref_as_ptr<T0, Ts...>() : max_size_ref_as_ptr<T1, Ts...>(); }
template<typename T>
constexpr size_t max_align_ref_as_ptr() { return align_ref_as_ptr<T>(); }
template<typename T0, typename T1, typename... Ts>
constexpr size_t max_align_ref_as_ptr() { return align_ref_as_ptr<T0>() > align_ref_as_ptr<T1>() ? max_align_ref_as_ptr<T0, Ts...>() : max_align_ref_as_ptr<T1, Ts...>(); }
template<typename T, typename T0, typename... Ts>
constexpr size_t index()
{
if constexpr(is_same_v<T, T0>)
return 0;
else if constexpr(sizeof...(Ts) == 0)
return 1;
else
return index<T, Ts...>() + 1;
}
template<typename T, typename... Ts>
void destruct(size_t index, uint8_t* data)
{
if (index == 0)
if constexpr(!is_lvalue_reference_v<T>)
reinterpret_cast<T*>(data)->~T();
else;
else if constexpr(sizeof...(Ts) > 0)
destruct<Ts...>(index - 1, data);
else
ASSERT_NOT_REACHED();
}
template<typename T, typename... Ts>
void move_construct(size_t index, uint8_t* source, uint8_t* target)
{
if (index == 0)
if constexpr(!is_lvalue_reference_v<T>)
new (target) T(move(*reinterpret_cast<T*>(source)));
else
memcpy(target, source, sizeof(remove_reference_t<T>*));
else if constexpr(sizeof...(Ts) > 0)
move_construct<Ts...>(index - 1, source, target);
else
ASSERT_NOT_REACHED();
}
template<typename T, typename... Ts>
void copy_construct(size_t index, const uint8_t* source, uint8_t* target)
{
if (index == 0)
if constexpr(!is_lvalue_reference_v<T>)
new (target) T(*reinterpret_cast<const T*>(source));
else
memcpy(target, source, sizeof(remove_reference_t<T>*));
else if constexpr(sizeof...(Ts) > 0)
copy_construct<Ts...>(index - 1, source, target);
else
ASSERT_NOT_REACHED();
}
template<typename T, typename... Ts>
void move_assign(size_t index, uint8_t* source, uint8_t* target)
{
if (index == 0)
if constexpr(!is_lvalue_reference_v<T>)
*reinterpret_cast<T*>(target) = move(*reinterpret_cast<T*>(source));
else
memcpy(target, source, sizeof(remove_reference_t<T>*));
else if constexpr(sizeof...(Ts) > 0)
move_assign<Ts...>(index - 1, source, target);
else
ASSERT_NOT_REACHED();
}
template<typename T, typename... Ts>
void copy_assign(size_t index, const uint8_t* source, uint8_t* target)
{
if (index == 0)
if constexpr(!is_lvalue_reference_v<T>)
*reinterpret_cast<T*>(target) = *reinterpret_cast<const T*>(source);
else
memcpy(target, source, sizeof(remove_reference_t<T>*));
else if constexpr(sizeof...(Ts) > 0)
copy_assign<Ts...>(index - 1, source, target);
else
ASSERT_NOT_REACHED();
}
}
template<typename... Ts>
requires (!is_const_v<Ts> && ...)
class Variant
{
public:
static_assert(!is_same_v<T1, T2>);
private:
template<typename T>
static constexpr bool can_have() { return detail::index<T, Ts...>() != invalid_index(); }
static constexpr size_t invalid_index() { return sizeof...(Ts); }
public:
Variant() = default;
Variant(const T1& value) { set(value); }
Variant(T1&& value) { set(move(value)); }
Variant(const T2& value) { set(value); }
Variant(T2&& value) { set(move(value)); }
Variant(Variant&& other)
: m_index(other.m_index)
{
detail::move_construct<Ts...>(other.m_index, other.m_storage, m_storage);
other.clear();
}
Variant(const Variant<T1, T2>& other) { *this = other; }
Variant(Variant<T1, T2>&& other) { *this = move(other); }
Variant(const Variant& other)
: m_index(other.m_index)
{
detail::copy_construct<Ts...>(other.m_index, other.m_storage, m_storage);
}
~Variant() { clear(); }
template<typename T>
Variant(T&& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
: m_index(detail::index<T, Ts...>())
{
new (m_storage) T(move(value));
}
Variant<T1, T2>& operator=(const Variant<T1, T2>& other);
Variant<T1, T2>& operator=(Variant<T1, T2>&& other);
template<typename T>
Variant(const T& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
: m_index(detail::index<T, Ts...>())
{
new (m_storage) T(value);
}
template<typename U>
bool is() const;
~Variant()
{
clear();
}
template<typename U>
void set(U&&);
template<typename U>
void set(const U& value) { set(move(U(value))); }
Variant& operator=(Variant&& other)
{
if (m_index == other.m_index)
detail::move_assign<Ts...>(m_index, other.m_storage, m_storage);
else
{
clear();
detail::move_construct<Ts...>(other.m_index, other.m_storage, m_storage);
m_index = other.m_index;
}
other.clear();
return *this;
}
template<typename U>
const U& get() const;
template<typename U>
U& get();
Variant& operator=(const Variant& other)
{
if (m_index == other.m_index)
detail::copy_assign<Ts...>(m_index, other.m_storage, m_storage);
else
{
clear();
detail::copy_construct<Ts...>(other.m_index, other.m_storage, m_storage);
m_index = other.m_index;
}
return *this;
}
void clear();
template<typename T>
Variant& operator=(T&& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
{
if (size_t index = detail::index<T, Ts...>(); index == m_index)
get<T>() = move(value);
else
{
clear();
new (m_storage) T(move(value));
m_index = index;
}
return *this;
}
template<typename T>
Variant& operator=(const T& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
{
if (size_t index = detail::index<T, Ts...>(); index == m_index)
get<T>() = value;
else
{
clear();
new (m_storage) T(value);
m_index = index;
}
return *this;
}
template<typename T>
bool has() const requires (can_have<T>())
{
return m_index == detail::index<T, Ts...>();
}
template<typename T>
void set(T&& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
{
if (has<T>())
get<T>() = move(value);
else
{
clear();
m_index = detail::index<T, Ts...>();
new (m_storage) T(move(value));
}
}
template<typename T>
void set(const T& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
{
if (has<T>())
get<T>() = value;
else
{
clear();
m_index = detail::index<T, Ts...>();
new (m_storage) T(value);
}
}
template<typename T>
void set(T value) requires (can_have<T>() && is_lvalue_reference_v<T>)
{
clear();
m_index = detail::index<T, Ts...>();
*reinterpret_cast<remove_reference_t<T>**>(m_storage) = &value;
}
template<typename T>
T& get() requires (can_have<T>() && !is_lvalue_reference_v<T>)
{
ASSERT(has<T>());
return *reinterpret_cast<T*>(m_storage);
}
template<typename T>
const T& get() const requires (can_have<T>() && !is_lvalue_reference_v<T>)
{
ASSERT(has<T>());
return *reinterpret_cast<const T*>(m_storage);
}
template<typename T>
T get() requires (can_have<T>() && is_lvalue_reference_v<T>)
{
ASSERT(has<T>());
return **reinterpret_cast<remove_reference_t<T>**>(m_storage);
}
template<typename T>
const T get() const requires (can_have<T>() && is_lvalue_reference_v<T>)
{
ASSERT(has<T>());
return **reinterpret_cast<const remove_reference_t<T>**>(m_storage);
}
void clear()
{
if (m_index != invalid_index())
{
detail::destruct<Ts...>(m_index, m_storage);
m_index = invalid_index();
}
}
private:
static constexpr uint32_t m_size = Math::max(sizeof(T1), sizeof(T2));
uint8_t m_storage[m_size] = {};
uint32_t m_index = 0;
alignas(detail::max_align_ref_as_ptr<Ts...>()) uint8_t m_storage[detail::max_size_ref_as_ptr<Ts...>()] {};
size_t m_index { invalid_index() };
};
template<typename T1, typename T2>
Variant<T1, T2>& Variant<T1, T2>::operator=(const Variant<T1, T2>& other)
{
clear();
if (other.is<T1>())
set(other.get<T1>());
if (other.is<T2>())
set(other.get<T2>());
return *this;
}
template<typename T1, typename T2>
Variant<T1, T2>& Variant<T1, T2>::operator=(Variant<T1, T2>&& other)
{
clear();
if (other.is<T1>())
set(move(other.get<T1>()));
if (other.is<T2>())
set(move(other.get<T2>()));
other.clear();
return *this;
}
template<typename T1, typename T2>
template<typename U>
bool Variant<T1, T2>::is() const
{
if constexpr(is_same_v<T1, U>)
return m_index == 1;
if constexpr(is_same_v<T2, U>)
return m_index == 2;
return false;
}
template<typename T1, typename T2>
template<typename U>
void Variant<T1, T2>::set(U&& value)
{
static_assert(is_same_v<T1, U> || is_same_v<T2, U>);
clear();
if constexpr(is_same_v<T1, U>)
{
new (m_storage) T1(move(value));
m_index = 1;
}
if constexpr(is_same_v<T2, U>)
{
new (m_storage) T2(move(value));
m_index = 2;
}
}
template<typename T1, typename T2>
template<typename U>
const U& Variant<T1, T2>::get() const
{
static_assert(is_same_v<T1, U> || is_same_v<T2, U>);
if constexpr(is_same_v<T1, U>)
{
ASSERT(m_index == 1);
return *(T1*)m_storage;
}
if constexpr(is_same_v<T2, U>)
{
ASSERT(m_index == 2);
return *(T2*)m_storage;
}
}
template<typename T1, typename T2>
template<typename U>
U& Variant<T1, T2>::get()
{
static_assert(is_same_v<T1, U> || is_same_v<T2, U>);
if constexpr(is_same_v<T1, U>)
{
ASSERT(m_index == 1);
return *(T1*)m_storage;
}
if constexpr(is_same_v<T2, U>)
{
ASSERT(m_index == 2);
return *(T2*)m_storage;
}
}
template<typename T1, typename T2>
void Variant<T1, T2>::clear()
{
if (is<T1>()) ((T1*)m_storage)->~T1();
if (is<T2>()) ((T2*)m_storage)->~T2();
m_index = 0;
}
}

View File

@@ -1,16 +1,15 @@
#pragma once
#include <BAN/Errors.h>
#include <BAN/Iterators.h>
#include <BAN/Math.h>
#include <BAN/Memory.h>
#include <BAN/Move.h>
#include <BAN/New.h>
#include <BAN/Span.h>
namespace BAN
{
template<typename T, bool CONST>
class VectorIterator;
// T must be move assignable, move constructable (and copy constructable for some functions)
template<typename T>
class Vector
@@ -18,8 +17,8 @@ namespace BAN
public:
using size_type = size_t;
using value_type = T;
using iterator = VectorIterator<T, false>;
using const_iterator = VectorIterator<T, true>;
using iterator = IteratorSimple<T, Vector>;
using const_iterator = ConstIteratorSimple<T, Vector>;
public:
Vector() = default;
@@ -40,10 +39,10 @@ namespace BAN
ErrorOr<void> insert(size_type, T&&);
ErrorOr<void> insert(size_type, const T&);
iterator begin() { return iterator (m_data); }
const_iterator begin() const { return const_iterator(m_data); }
iterator end() { return iterator (m_data + m_size); }
const_iterator end() const { return const_iterator(m_data + m_size); }
iterator begin() { return iterator(m_data); }
iterator end() { return iterator(m_data + m_size); }
const_iterator begin() const { return const_iterator(m_data); }
const_iterator end() const { return const_iterator(m_data + m_size); }
void pop_back();
void remove(size_type);
@@ -54,6 +53,9 @@ namespace BAN
bool contains(const T&) const;
Span<T> span() { return Span(m_data, m_size); }
const Span<T> span() const { return Span(m_data, m_size); }
const T& operator[](size_type) const;
T& operator[](size_type);
@@ -62,7 +64,7 @@ namespace BAN
const T& front() const;
T& front();
ErrorOr<void> resize(size_type);
ErrorOr<void> resize(size_type, const T& = T());
ErrorOr<void> reserve(size_type);
ErrorOr<void> shrink_to_fit();
@@ -76,54 +78,9 @@ namespace BAN
private:
T* m_data = nullptr;
size_type m_capacity = 0;
size_type m_size = 0;
size_type m_size = 0;
};
template<typename T, bool CONST>
class VectorIterator
{
public:
using value_type = T;
using data_type = maybe_const_t<CONST, T>;
public:
VectorIterator() = default;
template<bool C>
VectorIterator(const VectorIterator<T, C>& other, enable_if_t<C == CONST || !C>)
: m_data(other.m_data)
{
}
VectorIterator<T, CONST>& operator++() { m_data++; return *this; }
VectorIterator<T, CONST>& operator--() { m_data--; return *this; }
VectorIterator<T, CONST> operator++(int) { auto temp = *this; ++(*this); return temp; }
VectorIterator<T, CONST> operator--(int) { auto temp = *this; --(*this); return temp; }
template<bool ENABLE = !CONST>
enable_if_t<ENABLE, T&> operator*() { ASSERT(m_data); return *m_data; }
const T& operator*() const { ASSERT(m_data); return *m_data; }
template<bool ENABLE = !CONST>
enable_if_t<ENABLE, T*> operator->() { ASSERT(m_data); return m_data; }
const T* operator->() const { ASSERT(m_data); return m_data; }
bool operator==(const VectorIterator<T, CONST>& other) const { return m_data == other.m_data; }
bool operator!=(const VectorIterator<T, CONST>& other) const { return !(*this == other); }
operator bool() const { return m_data; }
private:
VectorIterator(data_type* data) : m_data(data) { }
private:
data_type* m_data = nullptr;
friend class Vector<T>;
friend class VectorIterator<T, !CONST>;
};
template<typename T>
Vector<T>::Vector(Vector<T>&& other)
{
@@ -256,7 +213,7 @@ namespace BAN
template<typename T>
ErrorOr<void> Vector<T>::insert(size_type index, const T& value)
{
return insert(move(T(value)), index);
return insert(index, move(T(value)));
}
template<typename T>
@@ -296,7 +253,7 @@ namespace BAN
return true;
return false;
}
template<typename T>
const T& Vector<T>::operator[](size_type index) const
{
@@ -340,7 +297,7 @@ namespace BAN
}
template<typename T>
ErrorOr<void> Vector<T>::resize(size_type size)
ErrorOr<void> Vector<T>::resize(size_type size, const T& value)
{
TRY(ensure_capacity(size));
if (size < m_size)
@@ -348,7 +305,7 @@ namespace BAN
m_data[i].~T();
if (size > m_size)
for (size_type i = m_size; i < size; i++)
new (m_data + i) T();
new (m_data + i) T(value);
m_size = size;
return {};
}

107
BAN/include/BAN/WeakPtr.h Normal file
View File

@@ -0,0 +1,107 @@
#pragma once
#include <BAN/RefPtr.h>
namespace BAN
{
template<typename T>
class Weakable;
template<typename T>
class WeakPtr;
template<typename T>
class WeakLink : public RefCounted<WeakLink<T>>
{
public:
RefPtr<T> lock() { ASSERT(m_ptr); return raw_ptr(); }
T* raw_ptr() { return m_ptr; }
bool valid() const { return m_ptr; }
void invalidate() { m_ptr = nullptr; }
private:
WeakLink(T* ptr) : m_ptr(ptr) {}
private:
T* m_ptr;
friend class RefPtr<WeakLink<T>>;
};
template<typename T>
class Weakable
{
public:
~Weakable()
{
if (m_link)
m_link->invalidate();
}
ErrorOr<WeakPtr<T>> get_weak_ptr() const
{
if (!m_link)
m_link = TRY(RefPtr<WeakLink<T>>::create((T*)this));
return WeakPtr<T>(m_link);
}
private:
mutable RefPtr<WeakLink<T>> m_link;
};
template<typename T>
class WeakPtr
{
public:
WeakPtr() = default;
WeakPtr(WeakPtr&& other) { *this = move(other); }
WeakPtr(const WeakPtr& other) { *this = other; }
WeakPtr(const RefPtr<T>& other) { *this = other; }
WeakPtr& operator=(WeakPtr&& other)
{
clear();
m_link = move(other.m_link);
return *this;
}
WeakPtr& operator=(const WeakPtr& other)
{
clear();
m_link = other.m_link;
return *this;
}
WeakPtr& operator=(const RefPtr<T>& other)
{
clear();
if (other)
m_link = MUST(other->get_weak_ptr()).move_link();
return *this;
}
RefPtr<T> lock()
{
if (m_link->valid())
return m_link->lock();
return nullptr;
}
void clear() { m_link.clear(); }
bool valid() const { return m_link && m_link->valid(); }
private:
WeakPtr(const RefPtr<WeakLink<T>>& link)
: m_link(link)
{ }
RefPtr<WeakLink<T>>&& move_link() { return move(m_link); }
private:
RefPtr<WeakLink<T>> m_link;
friend class Weakable<T>;
};
}

118
CMakeLists.txt Normal file
View File

@@ -0,0 +1,118 @@
cmake_minimum_required(VERSION 3.26)
if(DEFINED ENV{BANAN_ARCH})
set(BANAN_ARCH $ENV{BANAN_ARCH})
else()
set(BANAN_ARCH x86_64)
endif()
set(TOOLCHAIN_PREFIX ${CMAKE_SOURCE_DIR}/toolchain/local)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}/bin/${BANAN_ARCH}-banan_os-g++)
set(CMAKE_CXX_COMPILER_WORKS True)
set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}/bin/${BANAN_ARCH}-banan_os-gcc)
set(CMAKE_C_COMPILER_WORKS True)
if(NOT EXISTS ${CMAKE_CXX_COMPILER})
set(CMAKE_CXX_COMPILER g++)
endif()
if(DEFINED QEMU_ACCEL)
set(QEMU_ACCEL -accel ${QEMU_ACCEL})
endif()
add_compile_options(-mno-sse -mno-sse2)
add_compile_definitions(__enable_sse=0)
project(banan-os CXX)
set(BANAN_BASE_SYSROOT ${CMAKE_SOURCE_DIR}/base-sysroot.tar.gz)
set(BANAN_SYSROOT ${CMAKE_BINARY_DIR}/sysroot)
set(BANAN_INCLUDE ${BANAN_SYSROOT}/usr/include)
set(BANAN_LIB ${BANAN_SYSROOT}/usr/lib)
set(BANAN_BIN ${BANAN_SYSROOT}/usr/bin)
set(BANAN_BOOT ${BANAN_SYSROOT}/boot)
set(DISK_IMAGE_PATH ${CMAKE_BINARY_DIR}/banan-os.img)
add_subdirectory(kernel)
add_subdirectory(BAN)
add_subdirectory(libc)
add_subdirectory(LibELF)
add_subdirectory(userspace)
add_custom_target(sysroot
COMMAND mkdir -p ${BANAN_SYSROOT}
COMMAND cd ${BANAN_SYSROOT} && sudo tar xf ${BANAN_BASE_SYSROOT}
USES_TERMINAL
)
add_custom_target(headers
DEPENDS kernel-headers
DEPENDS ban-headers
DEPENDS libc-headers
DEPENDS libelf-headers
)
add_custom_target(toolchain
COMMAND ${CMAKE_COMMAND} -E env SYSROOT="${BANAN_SYSROOT}" PREFIX="${TOOLCHAIN_PREFIX}" ARCH="${BANAN_ARCH}" ${CMAKE_SOURCE_DIR}/toolchain/build.sh
DEPENDS headers
USES_TERMINAL
)
add_custom_target(libstdc++
COMMAND ${CMAKE_COMMAND} -E env LIBSTDCPP="1" ${CMAKE_SOURCE_DIR}/toolchain/build.sh
DEPENDS libc-install
USES_TERMINAL
)
add_custom_target(image
COMMAND ${CMAKE_COMMAND} -E env SYSROOT="${BANAN_SYSROOT}" DISK_IMAGE_PATH="${DISK_IMAGE_PATH}" ${CMAKE_SOURCE_DIR}/image.sh
DEPENDS kernel-install
DEPENDS ban-install
DEPENDS libc-install
DEPENDS userspace-install
DEPENDS libelf-install
USES_TERMINAL
)
add_custom_target(image-full
COMMAND ${CMAKE_COMMAND} -E env SYSROOT="${BANAN_SYSROOT}" DISK_IMAGE_PATH="${DISK_IMAGE_PATH}" ${CMAKE_SOURCE_DIR}/image-full.sh
DEPENDS kernel-install
DEPENDS ban-install
DEPENDS libc-install
DEPENDS userspace-install
DEPENDS libelf-install
USES_TERMINAL
)
add_custom_target(check-fs
COMMAND ${CMAKE_COMMAND} -E env DISK_IMAGE_PATH="${DISK_IMAGE_PATH}" ${CMAKE_SOURCE_DIR}/check-fs.sh
USES_TERMINAL
)
add_custom_target(qemu
COMMAND ${CMAKE_COMMAND} -E env BANAN_ARCH="${BANAN_ARCH}" DISK_IMAGE_PATH="${DISK_IMAGE_PATH}" ${CMAKE_SOURCE_DIR}/qemu.sh -serial stdio ${QEMU_ACCEL}
DEPENDS image
USES_TERMINAL
)
add_custom_target(qemu-nographic
COMMAND ${CMAKE_COMMAND} -E env BANAN_ARCH="${BANAN_ARCH}" DISK_IMAGE_PATH="${DISK_IMAGE_PATH}" ${CMAKE_SOURCE_DIR}/qemu.sh -nographic ${QEMU_ACCEL}
DEPENDS image
USES_TERMINAL
)
add_custom_target(qemu-debug
COMMAND ${CMAKE_COMMAND} -E env BANAN_ARCH="${BANAN_ARCH}" DISK_IMAGE_PATH="${DISK_IMAGE_PATH}" ${CMAKE_SOURCE_DIR}/qemu.sh -serial stdio -d int -no-reboot
DEPENDS image
USES_TERMINAL
)
add_custom_target(bochs
COMMAND ${CMAKE_COMMAND} -E env DISK_IMAGE_PATH="${DISK_IMAGE_PATH}" ${CMAKE_SOURCE_DIR}/bochs.sh
DEPENDS image
USES_TERMINAL
)

24
LICENCE Normal file
View File

@@ -0,0 +1,24 @@
BSD 2-Clause License
Copyright (c) 2023, Oskari Alaranta
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

13
LibELF/CMakeLists.txt Normal file
View File

@@ -0,0 +1,13 @@
cmake_minimum_required(VERSION 3.26)
project(LibELF CXX)
add_custom_target(libelf-headers
COMMAND sudo rsync -a ${CMAKE_CURRENT_SOURCE_DIR}/include/ ${BANAN_INCLUDE}/
DEPENDS sysroot
USES_TERMINAL
)
add_custom_target(libelf-install
DEPENDS libelf-headers
)

406
LibELF/LibELF/ELF.cpp Normal file
View File

@@ -0,0 +1,406 @@
#include <BAN/ScopeGuard.h>
#include <LibELF/ELF.h>
#include <LibELF/Values.h>
#ifdef __is_kernel
#include <kernel/FS/VirtualFileSystem.h>
#include <kernel/Memory/PageTableScope.h>
#include <kernel/Process.h>
#endif
#include <fcntl.h>
#define ELF_PRINT_HEADERS 0
#ifdef __is_kernel
extern uint8_t g_kernel_end[];
using namespace Kernel;
#endif
namespace LibELF
{
#ifdef __is_kernel
BAN::ErrorOr<BAN::UniqPtr<ELF>> ELF::load_from_file(BAN::RefPtr<Inode> inode)
{
BAN::Vector<uint8_t> buffer;
TRY(buffer.resize(inode->size()));
TRY(inode->read(0, buffer.data(), inode->size()));
ELF* elf_ptr = new ELF(BAN::move(buffer));
if (elf_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM);
auto elf = BAN::UniqPtr<ELF>::adopt(elf_ptr);
TRY(elf->load());
return BAN::move(elf);
}
#else
BAN::ErrorOr<ELF*> ELF::load_from_file(BAN::StringView file_path)
{
ELF* elf = nullptr;
{
BAN::Vector<uint8_t> data;
int fd = TRY(Kernel::Process::current().open(file_path, O_RDONLY));
BAN::ScopeGuard _([fd] { MUST(Kernel::Process::current().close(fd)); });
struct stat st;
TRY(Kernel::Process::current().fstat(fd, &st));
TRY(data.resize(st.st_size));
TRY(Kernel::Process::current().read(fd, data.data(), data.size()));
elf = new ELF(BAN::move(data));
ASSERT(elf);
}
if (auto res = elf->load(); res.is_error())
{
delete elf;
return res.error();
}
return elf;
}
#endif
BAN::ErrorOr<void> ELF::load()
{
if (m_data.size() < EI_NIDENT)
{
dprintln("Too small ELF file");
return BAN::Error::from_errno(EINVAL);
}
if (m_data[EI_MAG0] != ELFMAG0 ||
m_data[EI_MAG1] != ELFMAG1 ||
m_data[EI_MAG2] != ELFMAG2 ||
m_data[EI_MAG3] != ELFMAG3)
{
dprintln("Invalid ELF header");
return BAN::Error::from_errno(EINVAL);
}
if (m_data[EI_DATA] != ELFDATA2LSB)
{
dprintln("Only little-endian is supported");
return BAN::Error::from_errno(EINVAL);
}
if (m_data[EI_VERSION] != EV_CURRENT)
{
dprintln("Invalid ELF version");
return BAN::Error::from_errno(EINVAL);
}
if (m_data[EI_CLASS] == ELFCLASS64)
{
if (m_data.size() <= sizeof(Elf64FileHeader))
{
dprintln("Too small ELF file");
return BAN::Error::from_errno(EINVAL);
}
auto& header = file_header64();
if (!parse_elf64_file_header(header))
return BAN::Error::from_errno(EINVAL);
for (size_t i = 0; i < header.e_phnum; i++)
{
auto& program_header = program_header64(i);
if (!parse_elf64_program_header(program_header))
return BAN::Error::from_errno(EINVAL);
}
for (size_t i = 1; i < header.e_shnum; i++)
{
auto& section_header = section_header64(i);
if (!parse_elf64_section_header(section_header))
return BAN::Error::from_errno(EINVAL);
}
}
else if (m_data[EI_CLASS] == ELFCLASS32)
{
if (m_data.size() <= sizeof(Elf32FileHeader))
{
dprintln("Too small ELF file");
return BAN::Error::from_errno(EINVAL);
}
auto& header = file_header32();
if (!parse_elf32_file_header(header))
return BAN::Error::from_errno(EINVAL);
for (size_t i = 0; i < header.e_phnum; i++)
{
auto& program_header = program_header32(i);
if (!parse_elf32_program_header(program_header))
return BAN::Error::from_errno(EINVAL);
}
for (size_t i = 1; i < header.e_shnum; i++)
{
auto& section_header = section_header32(i);
if (!parse_elf32_section_header(section_header))
return BAN::Error::from_errno(EINVAL);
}
}
return {};
}
bool ELF::is_x86_32() const { return m_data[EI_CLASS] == ELFCLASS32; }
bool ELF::is_x86_64() const { return m_data[EI_CLASS] == ELFCLASS64; }
/*
64 bit ELF
*/
const char* ELF::lookup_section_name64(uint32_t offset) const
{
return lookup_string64(file_header64().e_shstrndx, offset);
}
const char* ELF::lookup_string64(size_t table_index, uint32_t offset) const
{
if (table_index == SHN_UNDEF)
return nullptr;
auto& section_header = section_header64(table_index);
return (const char*)m_data.data() + section_header.sh_offset + offset;
}
bool ELF::parse_elf64_file_header(const Elf64FileHeader& header)
{
if (header.e_type != ET_EXEC)
{
dprintln("Only executable files are supported");
return false;
}
if (header.e_version != EV_CURRENT)
{
dprintln("Invalid ELF version");
return false;
}
return true;
}
bool ELF::parse_elf64_program_header(const Elf64ProgramHeader& header)
{
#if ELF_PRINT_HEADERS
dprintln("program header");
dprintln(" type {H}", header.p_type);
dprintln(" flags {H}", header.p_flags);
dprintln(" offset {H}", header.p_offset);
dprintln(" vaddr {H}", header.p_vaddr);
dprintln(" paddr {H}", header.p_paddr);
dprintln(" filesz {}", header.p_filesz);
dprintln(" memsz {}", header.p_memsz);
dprintln(" align {}", header.p_align);
#endif
(void)header;
return true;
}
bool ELF::parse_elf64_section_header(const Elf64SectionHeader& header)
{
#if ELF_PRINT_HEADERS
if (auto* name = lookup_section_name64(header.sh_name))
dprintln("{}", name);
switch (header.sh_type)
{
case SHT_NULL:
dprintln(" SHT_NULL");
break;
case SHT_PROGBITS:
dprintln(" SHT_PROGBITS");
break;
case SHT_SYMTAB:
for (size_t i = 1; i < header.sh_size / header.sh_entsize; i++)
{
auto& symbol = ((const Elf64Symbol*)(m_data.data() + header.sh_offset))[i];
if (auto* name = lookup_string64(header.sh_link, symbol.st_name))
dprintln(" {}", name);
}
break;
case SHT_STRTAB:
dprintln(" SHT_STRTAB");
break;
case SHT_RELA:
dprintln(" SHT_RELA");
break;
case SHT_NOBITS:
dprintln(" SHT_NOBITS");
break;
case SHT_REL:
dprintln(" SHT_REL");
break;
case SHT_SHLIB:
dprintln(" SHT_SHLIB");
break;
case SHT_DYNSYM:
dprintln(" SHT_DYNSYM");
break;
default:
ASSERT(false);
}
#endif
(void)header;
return true;
}
const Elf64FileHeader& ELF::file_header64() const
{
ASSERT(is_x86_64());
return *(const Elf64FileHeader*)m_data.data();
}
const Elf64ProgramHeader& ELF::program_header64(size_t index) const
{
ASSERT(is_x86_64());
const auto& file_header = file_header64();
ASSERT(index < file_header.e_phnum);
return *(const Elf64ProgramHeader*)(m_data.data() + file_header.e_phoff + file_header.e_phentsize * index);
}
const Elf64SectionHeader& ELF::section_header64(size_t index) const
{
ASSERT(is_x86_64());
const auto& file_header = file_header64();
ASSERT(index < file_header.e_shnum);
return *(const Elf64SectionHeader*)(m_data.data() + file_header.e_shoff + file_header.e_shentsize * index);
}
/*
32 bit ELF
*/
const char* ELF::lookup_section_name32(uint32_t offset) const
{
return lookup_string32(file_header32().e_shstrndx, offset);
}
const char* ELF::lookup_string32(size_t table_index, uint32_t offset) const
{
if (table_index == SHN_UNDEF)
return nullptr;
auto& section_header = section_header32(table_index);
return (const char*)m_data.data() + section_header.sh_offset + offset;
}
bool ELF::parse_elf32_file_header(const Elf32FileHeader& header)
{
if (header.e_type != ET_EXEC)
{
dprintln("Only executable files are supported");
return false;
}
if (header.e_version != EV_CURRENT)
{
dprintln("Invalid ELF version");
return false;
}
return true;
}
bool ELF::parse_elf32_program_header(const Elf32ProgramHeader& header)
{
#if ELF_PRINT_HEADERS
dprintln("program header");
dprintln(" type {H}", header.p_type);
dprintln(" flags {H}", header.p_flags);
dprintln(" offset {H}", header.p_offset);
dprintln(" vaddr {H}", header.p_vaddr);
dprintln(" paddr {H}", header.p_paddr);
dprintln(" filesz {}", header.p_filesz);
dprintln(" memsz {}", header.p_memsz);
dprintln(" align {}", header.p_align);
#endif
(void)header;
return true;
}
bool ELF::parse_elf32_section_header(const Elf32SectionHeader& header)
{
#if ELF_PRINT_HEADERS
if (auto* name = lookup_section_name32(header.sh_name))
dprintln("{}", name);
switch (header.sh_type)
{
case SHT_NULL:
dprintln(" SHT_NULL");
break;
case SHT_PROGBITS:
dprintln(" SHT_PROGBITS");
break;
case SHT_SYMTAB:
for (size_t i = 1; i < header.sh_size / header.sh_entsize; i++)
{
auto& symbol = ((const Elf32Symbol*)(m_data.data() + header.sh_offset))[i];
if (auto* name = lookup_string32(header.sh_link, symbol.st_name))
dprintln(" {}", name);
}
break;
case SHT_STRTAB:
dprintln(" SHT_STRTAB");
break;
case SHT_RELA:
dprintln(" SHT_RELA");
break;
case SHT_NOBITS:
dprintln(" SHT_NOBITS");
break;
case SHT_REL:
dprintln(" SHT_REL");
break;
case SHT_SHLIB:
dprintln(" SHT_SHLIB");
break;
case SHT_DYNSYM:
dprintln(" SHT_DYNSYM");
break;
default:
ASSERT(false);
}
#endif
(void)header;
return true;
}
const Elf32FileHeader& ELF::file_header32() const
{
ASSERT(is_x86_32());
return *(const Elf32FileHeader*)m_data.data();
}
const Elf32ProgramHeader& ELF::program_header32(size_t index) const
{
ASSERT(is_x86_32());
const auto& file_header = file_header32();
ASSERT(index < file_header.e_phnum);
return *(const Elf32ProgramHeader*)(m_data.data() + file_header.e_phoff + file_header.e_phentsize * index);
}
const Elf32SectionHeader& ELF::section_header32(size_t index) const
{
ASSERT(is_x86_32());
const auto& file_header = file_header32();
ASSERT(index < file_header.e_shnum);
return *(const Elf32SectionHeader*)(m_data.data() + file_header.e_shoff + file_header.e_shentsize * index);
}
}

View File

@@ -0,0 +1,297 @@
#include <BAN/ScopeGuard.h>
#include <kernel/Memory/Heap.h>
#include <kernel/LockGuard.h>
#include <LibELF/LoadableELF.h>
#include <LibELF/Values.h>
namespace LibELF
{
using namespace Kernel;
BAN::ErrorOr<BAN::UniqPtr<LoadableELF>> LoadableELF::load_from_inode(PageTable& page_table, BAN::RefPtr<Inode> inode)
{
auto* elf_ptr = new LoadableELF(page_table, inode);
if (elf_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM);
auto elf = BAN::UniqPtr<LoadableELF>::adopt(elf_ptr);
TRY(elf->initialize());
return BAN::move(elf);
}
LoadableELF::LoadableELF(PageTable& page_table, BAN::RefPtr<Inode> inode)
: m_inode(inode)
, m_page_table(page_table)
{
}
LoadableELF::~LoadableELF()
{
for (const auto& program_header : m_program_headers)
{
switch (program_header.p_type)
{
case PT_NULL:
continue;
case PT_LOAD:
{
vaddr_t start = program_header.p_vaddr & PAGE_ADDR_MASK;
size_t pages = range_page_count(program_header.p_vaddr, program_header.p_memsz);
for (size_t i = 0; i < pages; i++)
{
paddr_t paddr = m_page_table.physical_address_of(start + i * PAGE_SIZE);
if (paddr != 0)
Heap::get().release_page(paddr);
}
m_page_table.unmap_range(start, pages * PAGE_SIZE);
break;
}
default:
ASSERT_NOT_REACHED();
}
}
}
BAN::ErrorOr<void> LoadableELF::initialize()
{
if ((size_t)m_inode->size() < sizeof(ElfNativeFileHeader))
{
dprintln("Too small file");
return BAN::Error::from_errno(ENOEXEC);
}
size_t nread = TRY(m_inode->read(0, &m_file_header, sizeof(m_file_header)));
ASSERT(nread == sizeof(m_file_header));
if (m_file_header.e_ident[EI_MAG0] != ELFMAG0 ||
m_file_header.e_ident[EI_MAG1] != ELFMAG1 ||
m_file_header.e_ident[EI_MAG2] != ELFMAG2 ||
m_file_header.e_ident[EI_MAG3] != ELFMAG3)
{
dprintln("Invalid magic in header");
return BAN::Error::from_errno(ENOEXEC);
}
if (m_file_header.e_ident[EI_DATA] != ELFDATA2LSB)
{
dprintln("Only little-endian is supported");
return BAN::Error::from_errno(ENOEXEC);
}
if (m_file_header.e_ident[EI_VERSION] != EV_CURRENT)
{
dprintln("Invalid version");
return BAN::Error::from_errno(ENOEXEC);
}
#if ARCH(i386)
if (m_file_header.e_ident[EI_CLASS] != ELFCLASS32)
#elif ARCH(x86_64)
if (m_file_header.e_ident[EI_CLASS] != ELFCLASS64)
#endif
{
dprintln("Not in native format");
return BAN::Error::from_errno(EINVAL);
}
if (m_file_header.e_type != ET_EXEC)
{
dprintln("Only executable files are supported");
return BAN::Error::from_errno(EINVAL);
}
if (m_file_header.e_version != EV_CURRENT)
{
dprintln("Unsupported version");
return BAN::Error::from_errno(EINVAL);
}
ASSERT(m_file_header.e_phentsize <= sizeof(ElfNativeProgramHeader));
TRY(m_program_headers.resize(m_file_header.e_phnum));
for (size_t i = 0; i < m_file_header.e_phnum; i++)
{
TRY(m_inode->read(m_file_header.e_phoff + m_file_header.e_phentsize * i, &m_program_headers[i], m_file_header.e_phentsize));
const auto& pheader = m_program_headers[i];
if (pheader.p_type != PT_NULL && pheader.p_type != PT_LOAD)
{
dprintln("Unsupported program header type {}", pheader.p_type);
return BAN::Error::from_errno(ENOTSUP);
}
if (pheader.p_memsz < pheader.p_filesz)
{
dprintln("Invalid program header");
return BAN::Error::from_errno(EINVAL);
}
m_virtual_page_count += BAN::Math::div_round_up<size_t>((pheader.p_vaddr % PAGE_SIZE) + pheader.p_memsz, PAGE_SIZE);
}
return {};
}
vaddr_t LoadableELF::entry_point() const
{
return m_file_header.e_entry;
}
bool LoadableELF::contains(vaddr_t address) const
{
for (const auto& program_header : m_program_headers)
{
switch (program_header.p_type)
{
case PT_NULL:
continue;
case PT_LOAD:
if (program_header.p_vaddr <= address && address < program_header.p_vaddr + program_header.p_memsz)
return true;
break;
default:
ASSERT_NOT_REACHED();
}
}
return false;
}
void LoadableELF::reserve_address_space()
{
for (const auto& program_header : m_program_headers)
{
switch (program_header.p_type)
{
case PT_NULL:
break;
case PT_LOAD:
{
vaddr_t page_vaddr = program_header.p_vaddr & PAGE_ADDR_MASK;
size_t pages = range_page_count(program_header.p_vaddr, program_header.p_memsz);
ASSERT(m_page_table.reserve_range(page_vaddr, pages * PAGE_SIZE));
break;
}
default:
ASSERT_NOT_REACHED();
}
}
}
BAN::ErrorOr<void> LoadableELF::load_page_to_memory(vaddr_t address)
{
for (const auto& program_header : m_program_headers)
{
switch (program_header.p_type)
{
case PT_NULL:
break;
case PT_LOAD:
{
if (!(program_header.p_vaddr <= address && address < program_header.p_vaddr + program_header.p_memsz))
continue;
PageTable::flags_t flags = PageTable::Flags::UserSupervisor | PageTable::Flags::Present;
if (program_header.p_flags & LibELF::PF_W)
flags |= PageTable::Flags::ReadWrite;
if (program_header.p_flags & LibELF::PF_X)
flags |= PageTable::Flags::Execute;
vaddr_t vaddr = address & PAGE_ADDR_MASK;
paddr_t paddr = Heap::get().take_free_page();
if (paddr == 0)
return BAN::Error::from_errno(ENOMEM);
m_page_table.map_page_at(paddr, vaddr, flags);
m_physical_page_count++;
memset((void*)vaddr, 0x00, PAGE_SIZE);
if (vaddr / PAGE_SIZE < BAN::Math::div_round_up<size_t>(program_header.p_vaddr + program_header.p_filesz, PAGE_SIZE))
{
size_t vaddr_offset = 0;
if (vaddr < program_header.p_vaddr)
vaddr_offset = program_header.p_vaddr - vaddr;
size_t file_offset = 0;
if (vaddr > program_header.p_vaddr)
file_offset = vaddr - program_header.p_vaddr;
size_t bytes = BAN::Math::min<size_t>(PAGE_SIZE - vaddr_offset, program_header.p_filesz - file_offset);
TRY(m_inode->read(program_header.p_offset + file_offset, (void*)(vaddr + vaddr_offset), bytes));
}
return {};
}
default:
ASSERT_NOT_REACHED();
}
}
ASSERT_NOT_REACHED();
}
BAN::ErrorOr<BAN::UniqPtr<LoadableELF>> LoadableELF::clone(Kernel::PageTable& new_page_table)
{
auto* elf_ptr = new LoadableELF(new_page_table, m_inode);
if (elf_ptr == nullptr)
return BAN::Error::from_errno(ENOMEM);
auto elf = BAN::UniqPtr<LoadableELF>::adopt(elf_ptr);
memcpy(&elf->m_file_header, &m_file_header, sizeof(ElfNativeFileHeader));
TRY(elf->m_program_headers.resize(m_program_headers.size()));
memcpy(elf->m_program_headers.data(), m_program_headers.data(), m_program_headers.size() * sizeof(ElfNativeProgramHeader));
elf->reserve_address_space();
ASSERT(&PageTable::current() == &m_page_table);
LockGuard _(m_page_table);
ASSERT(m_page_table.is_page_free(0));
for (const auto& program_header : m_program_headers)
{
switch (program_header.p_type)
{
case PT_NULL:
break;
case PT_LOAD:
{
if (!(program_header.p_flags & LibELF::PF_W))
continue;
PageTable::flags_t flags = PageTable::Flags::UserSupervisor | PageTable::Flags::Present;
if (program_header.p_flags & LibELF::PF_W)
flags |= PageTable::Flags::ReadWrite;
if (program_header.p_flags & LibELF::PF_X)
flags |= PageTable::Flags::Execute;
vaddr_t start = program_header.p_vaddr & PAGE_ADDR_MASK;
size_t pages = range_page_count(program_header.p_vaddr, program_header.p_memsz);
for (size_t i = 0; i < pages; i++)
{
if (m_page_table.physical_address_of(start + i * PAGE_SIZE) == 0)
continue;
paddr_t paddr = Heap::get().take_free_page();
if (paddr == 0)
return BAN::Error::from_errno(ENOMEM);
m_page_table.map_page_at(paddr, 0, PageTable::Flags::ReadWrite | PageTable::Flags::Present);
memcpy((void*)0, (void*)(start + i * PAGE_SIZE), PAGE_SIZE);
m_page_table.unmap_page(0);
new_page_table.map_page_at(paddr, start + i * PAGE_SIZE, flags);
elf->m_physical_page_count++;
}
break;
}
default:
ASSERT_NOT_REACHED();
}
}
return elf;
}
}

View File

@@ -0,0 +1,89 @@
#pragma once
#ifdef __is_kernel
#include <kernel/FS/Inode.h>
#include <kernel/Memory/VirtualRange.h>
#endif
#include <BAN/StringView.h>
#include <BAN/UniqPtr.h>
#include <BAN/Vector.h>
#include <kernel/Arch.h>
#include "Types.h"
namespace LibELF
{
class ELF
{
public:
#ifdef __is_kernel
static BAN::ErrorOr<BAN::UniqPtr<ELF>> load_from_file(BAN::RefPtr<Kernel::Inode>);
#else
static BAN::ErrorOr<BAN::UniqPtr<ELF>> load_from_file(BAN::StringView);
#endif
const Elf64FileHeader& file_header64() const;
const Elf64ProgramHeader& program_header64(size_t) const;
const Elf64SectionHeader& section_header64(size_t) const;
const char* lookup_section_name64(uint32_t) const;
const char* lookup_string64(size_t, uint32_t) const;
#if ARCH(x86_64)
const Elf64FileHeader& file_header_native() const { return file_header64(); }
const Elf64ProgramHeader& program_header_native(size_t index) const { return program_header64(index); }
const Elf64SectionHeader& section_header_native(size_t index) const { return section_header64(index); }
const char* lookup_section_name_native(uint32_t offset) const { return lookup_section_name64(offset); }
const char* lookup_string_native(size_t table_index, uint32_t offset) const { return lookup_string64(table_index, offset); }
bool is_native() const { return is_x86_64(); }
#endif
const Elf32FileHeader& file_header32() const;
const Elf32ProgramHeader& program_header32(size_t) const;
const Elf32SectionHeader& section_header32(size_t) const;
const char* lookup_section_name32(uint32_t) const;
const char* lookup_string32(size_t, uint32_t) const;
#if ARCH(i386)
const Elf32FileHeader& file_header_native() const { return file_header32(); }
const Elf32ProgramHeader& program_header_native(size_t index) const { return program_header32(index); }
const Elf32SectionHeader& section_header_native(size_t index) const { return section_header32(index); }
const char* lookup_section_name_native(uint32_t offset) const { return lookup_section_name32(offset); }
const char* lookup_string_native(size_t table_index, uint32_t offset) const { return lookup_string32(table_index, offset); }
bool is_native() const { return is_x86_32(); }
#endif
const uint8_t* data() const { return m_data.data(); }
bool is_x86_32() const;
bool is_x86_64() const;
private:
//#ifdef __is_kernel
// ELF(BAN::UniqPtr<Kernel::VirtualRange>&& storage, size_t size)
// : m_storage(BAN::move(storage))
// , m_data((const uint8_t*)m_storage->vaddr(), size)
// {}
//#else
ELF(BAN::Vector<uint8_t>&& data)
: m_data(BAN::move(data))
{}
//#endif
BAN::ErrorOr<void> load();
bool parse_elf64_file_header(const Elf64FileHeader&);
bool parse_elf64_program_header(const Elf64ProgramHeader&);
bool parse_elf64_section_header(const Elf64SectionHeader&);
bool parse_elf32_file_header(const Elf32FileHeader&);
bool parse_elf32_program_header(const Elf32ProgramHeader&);
bool parse_elf32_section_header(const Elf32SectionHeader&);
private:
//#ifdef __is_kernel
// BAN::UniqPtr<Kernel::VirtualRange> m_storage;
// BAN::Span<const uint8_t> m_data;
//#else
const BAN::Vector<uint8_t> m_data;
//#endif
};
}

View File

@@ -0,0 +1,52 @@
#pragma once
#ifndef __is_kernel
#error "This is kernel only header"
#endif
#include <BAN/UniqPtr.h>
#include <BAN/Vector.h>
#include <kernel/FS/Inode.h>
#include <kernel/Memory/PageTable.h>
#include <LibELF/Types.h>
namespace LibELF
{
class LoadableELF
{
BAN_NON_COPYABLE(LoadableELF);
BAN_NON_MOVABLE(LoadableELF);
public:
static BAN::ErrorOr<BAN::UniqPtr<LoadableELF>> load_from_inode(Kernel::PageTable&, BAN::RefPtr<Kernel::Inode>);
~LoadableELF();
Kernel::vaddr_t entry_point() const;
bool contains(Kernel::vaddr_t address) const;
void reserve_address_space();
BAN::ErrorOr<void> load_page_to_memory(Kernel::vaddr_t address);
BAN::ErrorOr<BAN::UniqPtr<LoadableELF>> clone(Kernel::PageTable&);
size_t virtual_page_count() const { return m_virtual_page_count; }
size_t physical_page_count() const { return m_physical_page_count; }
private:
LoadableELF(Kernel::PageTable&, BAN::RefPtr<Kernel::Inode>);
BAN::ErrorOr<void> initialize();
private:
BAN::RefPtr<Kernel::Inode> m_inode;
Kernel::PageTable& m_page_table;
ElfNativeFileHeader m_file_header;
BAN::Vector<ElfNativeProgramHeader> m_program_headers;
size_t m_virtual_page_count = 0;
size_t m_physical_page_count = 0;
};
}

View File

@@ -0,0 +1,189 @@
#pragma once
#include <kernel/Arch.h>
#include <stdint.h>
namespace LibELF
{
using Elf32Addr = uint32_t;
using Elf32Off = uint32_t;
using Elf32Half = uint16_t;
using Elf32Word = uint32_t;
using Elf32Sword = int32_t;
struct Elf32FileHeader
{
unsigned char e_ident[16];
Elf32Half e_type;
Elf32Half e_machine;
Elf32Word e_version;
Elf32Addr e_entry;
Elf32Off e_phoff;
Elf32Off e_shoff;
Elf32Word e_flags;
Elf32Half e_ehsize;
Elf32Half e_phentsize;
Elf32Half e_phnum;
Elf32Half e_shentsize;
Elf32Half e_shnum;
Elf32Half e_shstrndx;
};
struct Elf32SectionHeader
{
Elf32Word sh_name;
Elf32Word sh_type;
Elf32Word sh_flags;
Elf32Addr sh_addr;
Elf32Off sh_offset;
Elf32Word sh_size;
Elf32Word sh_link;
Elf32Word sh_info;
Elf32Word sh_addralign;
Elf32Word sh_entsize;
};
struct Elf32Symbol
{
Elf32Word st_name;
Elf32Addr st_value;
Elf32Word st_size;
unsigned char st_info;
unsigned char st_other;
Elf32Half st_shndx;
};
struct Elf32Relocation
{
Elf32Addr r_offset;
Elf32Word r_info;
};
struct Elf32RelocationA
{
Elf32Addr r_offset;
Elf32Word r_info;
Elf32Sword r_addend;
};
struct Elf32ProgramHeader
{
Elf32Word p_type;
Elf32Off p_offset;
Elf32Addr p_vaddr;
Elf32Addr p_paddr;
Elf32Word p_filesz;
Elf32Word p_memsz;
Elf32Word p_flags;
Elf32Word p_align;
};
using Elf64Addr = uint64_t;
using Elf64Off = uint64_t;
using Elf64Half = uint16_t;
using Elf64Word = uint32_t;
using Elf64Sword = int32_t;
using Elf64Xword = uint64_t;
using Elf64Sxword = int64_t;
struct Elf64FileHeader
{
unsigned char e_ident[16];
Elf64Half e_type;
Elf64Half e_machine;
Elf64Word e_version;
Elf64Addr e_entry;
Elf64Off e_phoff;
Elf64Off e_shoff;
Elf64Word e_flags;
Elf64Half e_ehsize;
Elf64Half e_phentsize;
Elf64Half e_phnum;
Elf64Half e_shentsize;
Elf64Half e_shnum;
Elf64Half e_shstrndx;
};
struct Elf64SectionHeader
{
Elf64Word sh_name;
Elf64Word sh_type;
Elf64Xword sh_flags;
Elf64Addr sh_addr;
Elf64Off sh_offset;
Elf64Xword sh_size;
Elf64Word sh_link;
Elf64Word sh_info;
Elf64Xword sh_addralign;
Elf64Xword sh_entsize;
};
struct Elf64Symbol
{
Elf64Word st_name;
unsigned char st_info;
unsigned char st_other;
Elf64Half st_shndx;
Elf64Addr st_value;
Elf64Xword st_size;
};
struct Elf64Relocation
{
Elf64Addr r_offset;
Elf64Xword r_info;
};
struct Elf64RelocationA
{
Elf64Addr r_offset;
Elf64Xword r_info;
Elf64Sxword r_addend;
};
struct Elf64ProgramHeader
{
Elf64Word p_type;
Elf64Word p_flags;
Elf64Off p_offset;
Elf64Addr p_vaddr;
Elf64Addr p_paddr;
Elf64Xword p_filesz;
Elf64Xword p_memsz;
Elf64Xword p_align;
};
#if ARCH(i386)
using ElfNativeAddr = Elf32Addr;
using ElfNativeOff = Elf32Off;
using ElfNativeHalf = Elf32Half;
using ElfNativeWord = Elf32Word;
using ElfNativeSword = Elf32Sword;
using ElfNativeXword = Elf32Xword;
using ElfNativeSxword = Elf32Sxword;
using ElfNativeFileHeader = Elf32FileHeader;
using ElfNativeSectionHeader = Elf32SectionHeader;
using ElfNativeSymbol = Elf32Symbol;
using ElfNativeRelocation = Elf32Relocation;
using ElfNativeRelocationA = Elf32RelocationA;
using ElfNativeProgramHeader = Elf32ProgramHeader;
#elif ARCH(x86_64)
using ElfNativeAddr = Elf64Addr;
using ElfNativeOff = Elf64Off;
using ElfNativeHalf = Elf64Half;
using ElfNativeWord = Elf64Word;
using ElfNativeSword = Elf64Sword;
using ElfNativeXword = Elf64Xword;
using ElfNativeSxword = Elf64Sxword;
using ElfNativeFileHeader = Elf64FileHeader;
using ElfNativeSectionHeader = Elf64SectionHeader;
using ElfNativeSymbol = Elf64Symbol;
using ElfNativeRelocation = Elf64Relocation;
using ElfNativeRelocationA = Elf64RelocationA;
using ElfNativeProgramHeader = Elf64ProgramHeader;
#endif
}

View File

@@ -0,0 +1,140 @@
#pragma once
namespace LibELF
{
enum ELF_Ident
{
ELFMAG0 = 0x7F,
ELFMAG1 = 'E',
ELFMAG2 = 'L',
ELFMAG3 = 'F',
ELFCLASSNONE = 0,
ELFCLASS32 = 1,
ELFCLASS64 = 2,
ELFDATANONE = 0,
ELFDATA2LSB = 1,
ELFDATA2MSB = 2,
};
enum ELF_EI
{
EI_MAG0 = 0,
EI_MAG1 = 1,
EI_MAG2 = 2,
EI_MAG3 = 3,
EI_CLASS = 4,
EI_DATA = 5,
EI_VERSION = 6,
EI_OSABI = 7,
EI_ABIVERSION = 8,
EI_NIDENT = 16,
};
enum ELF_ET
{
ET_NONE = 0,
ET_REL = 1,
ET_EXEC = 2,
ET_DYN = 3,
ET_CORE = 4,
ET_LOOS = 0xfe00,
ET_HIOS = 0xfeff,
ET_LOPROC = 0xff00,
ET_HIPROC = 0xffff,
};
enum ELF_EV
{
EV_NONE = 0,
EV_CURRENT = 1,
};
enum ELF_SHT
{
SHT_NULL = 0,
SHT_PROGBITS = 1,
SHT_SYMTAB = 2,
SHT_STRTAB = 3,
SHT_RELA = 4,
SHT_NOBITS = 8,
SHT_REL = 9,
SHT_SHLIB = 10,
SHT_DYNSYM = 11,
SHT_LOOS = 0x60000000,
SHT_HIOS = 0x6FFFFFFF,
SHT_LOPROC = 0x70000000,
SHT_HIPROC = 0x7FFFFFFF,
};
enum ELF_SHF
{
SHF_WRITE = 0x1,
SHF_ALLOC = 0x2,
SHF_EXECINSTR = 0x4,
SHF_MASKOS = 0x0F000000,
SHF_MASKPROC = 0xF0000000,
};
enum ELF_SHN
{
SHN_UNDEF = 0,
SHN_LOPROC = 0xFF00,
SHN_HIPROC = 0xFF1F,
SHN_LOOS = 0xFF20,
SHN_HIOS = 0xFF3F,
SHN_ABS = 0xFFF1,
SHN_COMMON = 0xFFF2,
};
enum ELF_STB
{
STB_LOCAL = 0,
STB_GLOBAL = 1,
STB_WEAK = 2,
STB_LOOS = 10,
STB_HIOS = 12,
STB_LOPROC = 13,
STB_HIPROC = 15,
};
enum ELF_STT
{
STT_NOTYPE = 0,
STT_OBJECT = 1,
STT_FUNC = 2,
STT_SECTION = 3,
STT_FILE = 4,
STT_LOOS = 10,
STT_HIOS = 12,
STT_LOPROC = 13,
STT_HIPROC = 15,
};
enum ELF_PT
{
PT_NULL = 0,
PT_LOAD = 1,
PT_DYNAMIC = 2,
PT_INTERP = 3,
PT_NOTE = 4,
PT_SHLIB = 5,
PT_PHDR = 6,
PT_LOOS = 0x60000000,
PT_HIOS = 0x6FFFFFFF,
PT_LOPROC = 0x70000000,
PT_HIPROC = 0x7FFFFFFF,
};
enum ELF_PF
{
PF_X = 0x1,
PF_W = 0x2,
PF_R = 0x4,
PF_MASKOS = 0x00FF0000,
PF_MASKPROC = 0xFF000000,
};
}

1
PreLoad.cmake Normal file
View File

@@ -0,0 +1 @@
set(CMAKE_GENERATOR "Ninja" CACHE INTERNAL "" FORCE)

55
README.md Normal file
View File

@@ -0,0 +1,55 @@
![license](https://img.shields.io/github/license/bananymous/banan-os)
# banan-os
This is my hobby operating system written in C++. Currently supports only x86_64 architecture. We have a read-only ext2 filesystem, read-write ramfs, IDE disk drivers in ATA PIO mode, userspace processes, executable loading from ELF format, linear VBE graphics and multithreaded processing on single core.
![screenshot from qemu running banan-os](assets/banan-os.png)
## Code structure
Each major component and library has its own subdirectory (kernel, userspace, libc, ...). Each directory contains directory *include*, which has **all** of the header files of the component. Every header is included by its absolute path.
## Building
There does not exist a complete list of needed packages for building. From the top of my head I can say that *cmake*, *ninja*, *make*, *grub*, *rsync* and emulator (*qemu* or *bochs*) are needed.
You can and *should* pass cmake variable QEMU_ACCEL set to proper accelerator to cmake commands. For example on Linux this means adding -DQEMU_ACCEL=kvm to the end of all cmake commands.
Create the build directory and cofigure cmake
```sh
mkdir build
cd build
cmake ..
```
To build the toolchain for this os. You can run the following command.
> ***NOTE:*** The following step has to be done only once. This might take a long time since we are compiling binutils and gcc.
```sh
ninja toolchain
cmake --fresh .. # We need to reconfigure cmake to use the new compiler
ninja libstdc++
```
To build the os itself you can run either of the following commands. You will need root access since the sysroot has "proper" permissions.
```sh
ninja qemu
ninja bochs
```
You can also build the kernel or disk image without running it:
```sh
ninja kernel
ninja image
```
If you have corrupted your disk image or want to create new one, you can either manually delete *banan-os.img* and cmake will automatically create you a new one or you can run the following command.
```sh
ninja image-full
```
> ***NOTE*** ```ninja clean``` has to be ran with root permissions, since it deletes the root filesystem.
### Contributing
Currently I don't accept contributions to this repository unless explicitly told otherwise. This is a learning project for me and I want to do everything myself. Feel free to fork/clone this repo and tinker with it yourself.

BIN
assets/banan-os.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
base-sysroot.tar.gz Normal file

Binary file not shown.

View File

@@ -1,7 +1,6 @@
#!/bin/sh
#!/bin/bash
set -e
. ./disk.sh
BOCHS_CONFIG_FILE=bochsrc
COM1_TERMINAL=kitty
COM1_DEVICE_FILE=com1-term-device
@@ -15,7 +14,7 @@ COM1_DEVICE=$(cat $COM1_DEVICE_FILE)
rm $COM1_DEVICE_FILE
cat > $BOCHS_CONFIG_FILE << EOF
ata0-master: type=disk, path=banan-os.img, status=inserted
ata0-master: type=disk, path=$DISK_IMAGE_PATH, status=inserted
boot: disk
clock: sync=realtime, time0=local
display_library: x, options="gui_debug"

View File

@@ -1,7 +0,0 @@
#!/bin/sh
set -e
. ./headers.sh
for PROJECT in $PROJECTS; do
(cd $PROJECT && DESTDIR="$SYSROOT" $MAKE install)
done

10
check-fs.sh Executable file
View File

@@ -0,0 +1,10 @@
#!/bin/bash
set -e
LOOP_DEV=$(sudo losetup -f --show $DISK_IMAGE_PATH)
sudo partprobe $LOOP_DEV
sudo fsck.ext2 -fn ${LOOP_DEV}p2 || true
sudo losetup -d $LOOP_DEV

View File

@@ -1,11 +0,0 @@
#!/bin/sh
set -e
. ./config.sh
for PROJECT in $PROJECTS; do
(cd $PROJECT && $MAKE clean)
done
rm -rf sysroot
rm -rf isodir
rm -rf banan-os.img

View File

@@ -1,33 +0,0 @@
SYSTEM_HEADER_PROJECTS="libc BAN kernel"
PROJECTS="libc BAN kernel"
export MAKE=${MAKE:-make}
export HOST=${HOST:-$(./default-host.sh)}
export AR=${HOST}-ar
export AS=${HOST}-as
export CC=${HOST}-gcc
export CXX=${HOST}-g++
export PREFIX=/usr
export EXEC_PREFIX=$PREFIX
export BOOTDIR=/boot
export LIBDIR=$EXEC_PREFIX/lib
export INCLUDEDIR=$PREFIX/include
export CFLAGS='-O2 -g'
export CPPFLAGS='--std=c++20 -Wno-literal-suffix'
export UBSAN=0
# Configure the cross-compiler to use the desired system root.
export SYSROOT="$(pwd)/sysroot"
export CC="$CC --sysroot=$SYSROOT"
export CXX="$CXX --sysroot=$SYSROOT"
# Work around that the -elf gcc targets doesn't have a system include directory
# because it was configured with --without-headers rather than --with-sysroot.
if echo "$HOST" | grep -Eq -- '-elf($|-)'; then
export CC="$CC -isystem=$INCLUDEDIR"
export CXX="$CXX -isystem=$INCLUDEDIR"
fi

View File

@@ -1,2 +0,0 @@
#!/bin/sh
echo x86_64-elf

67
disk.sh
View File

@@ -1,67 +0,0 @@
#!/bin/sh
set -e
. ./build.sh
DISK_NAME=banan-os.img
DISK_SIZE=$[50 * 1024 * 1024]
MOUNT_DIR=/mnt
dd if=/dev/zero of=$DISK_NAME bs=512 count=$[$DISK_SIZE / 512]
sed -e 's/\s*\([-\+[:alnum:]]*\).*/\1/' << EOF | fdisk $DISK_NAME
g # gpt
n # new partition
1 # partition number 1
# default (from the beginning of the disk)
+1MiB # bios boot partiton size
n # new partition
2 # partition number 2
# default (right after bios boot partition)
# default (to the end of disk)
t # set type
1 # ... of partition 1
4 # bios boot partition
t # set type
2 # ... of partition 2
20 # Linux filesystem
x # expert menu
n # partition name
2 # ... of partition 2
banan-root
r # back to main menu
w # write changes
EOF
LOOP_DEV=$(sudo losetup -f --show $DISK_NAME)
sudo partprobe $LOOP_DEV
PARTITION1=${LOOP_DEV}p1
PARTITION2=${LOOP_DEV}p2
sudo mkfs.ext2 $PARTITION2
sudo mount $PARTITION2 $MOUNT_DIR
sudo cp -r ${SYSROOT}/* ${MOUNT_DIR}/
sudo mkdir -p ${MOUNT_DIR}/usr/share/
sudo cp -r fonts ${MOUNT_DIR}/usr/share/
sudo grub-install --no-floppy --target=i386-pc --modules="normal ext2 multiboot" --boot-directory=${MOUNT_DIR}/boot $LOOP_DEV
echo -e '
menuentry "banan-os" {
multiboot /boot/banan-os.kernel
}
menuentry "banan-os (no serial)" {
multiboot /boot/banan-os.kernel noserial
}
menuentry "banan-os (no apic)" {
multiboot /boot/banan-os.kernel noapic
}
menuentry "banan-os (no apic, no serial)" {
multiboot /boot/banan-os.kernel noapic noserial
}
' | sudo tee ${MOUNT_DIR}/boot/grub/grub.cfg
sudo umount $MOUNT_DIR
sudo losetup -d $LOOP_DEV

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,9 +0,0 @@
#!/bin/sh
set -e
. ./config.sh
mkdir -p "$SYSROOT"
for PROJECT in $SYSTEM_HEADER_PROJECTS; do
(cd $PROJECT && DESTDIR="$SYSROOT" $MAKE install-headers)
done

41
image-full.sh Executable file
View File

@@ -0,0 +1,41 @@
#!/bin/bash
set -e
DISK_SIZE=$[50 * 1024 * 1024]
MOUNT_DIR=/mnt
truncate -s 0 $DISK_IMAGE_PATH
truncate -s $DISK_SIZE $DISK_IMAGE_PATH
sed -e 's/\s*\([-\+[:alnum:]]*\).*/\1/' << EOF | fdisk $DISK_IMAGE_PATH > /dev/null
g # gpt
n # new partition
1 # partition number 1
# default (from the beginning of the disk)
+1MiB # bios boot partiton size
n # new partition
2 # partition number 2
# default (right after bios boot partition)
# default (to the end of disk)
t # set type
1 # ... of partition 1
4 # bios boot partition
t # set type
2 # ... of partition 2
20 # Linux filesystem
w # write changes
EOF
LOOP_DEV=$(sudo losetup -f --show $DISK_IMAGE_PATH)
sudo partprobe $LOOP_DEV
PARTITION1=${LOOP_DEV}p1
PARTITION2=${LOOP_DEV}p2
sudo mkfs.ext2 -d $SYSROOT -b 1024 -q $PARTITION2
sudo mount $PARTITION2 $MOUNT_DIR
sudo grub-install --no-floppy --target=i386-pc --modules="normal ext2 multiboot" --boot-directory=${MOUNT_DIR}/boot $LOOP_DEV
sudo umount $MOUNT_DIR
sudo losetup -d $LOOP_DEV

22
image.sh Executable file
View File

@@ -0,0 +1,22 @@
#!/bin/bash
set -e
if [ ! -f $DISK_IMAGE_PATH ]; then
$(dirname "$0")/image-full.sh
exit 0
fi
MOUNT_DIR=/mnt
LOOP_DEV=$(sudo losetup -f --show $DISK_IMAGE_PATH)
sudo partprobe $LOOP_DEV
ROOT_PARTITON=${LOOP_DEV}p2
sudo mount $ROOT_PARTITON $MOUNT_DIR
sudo rsync -a ${SYSROOT}/* ${MOUNT_DIR}/
sudo umount $MOUNT_DIR
sudo losetup -d $LOOP_DEV

View File

@@ -1,8 +0,0 @@
#!/bin/sh
set -e
. ./disk.sh
SIZE=$(stat -c '%s' banan-os.img | numfmt --to=iec)
echo Writing ${SIZE}iB
sudo dd if=banan-os.img of=/dev/sda status=progress

3
kernel/.gitignore vendored
View File

@@ -1,3 +0,0 @@
*.d
*.kernel
*.o

207
kernel/CMakeLists.txt Normal file
View File

@@ -0,0 +1,207 @@
cmake_minimum_required(VERSION 3.26)
project(kernel CXX C ASM)
if("${BANAN_ARCH}" STREQUAL "x86_64")
set(ELF_FORMAT elf64-x86-64)
elseif("${BANAN_ARCH}" STREQUAL "i386")
set(ELF_FORMAT elf32-i386)
endif()
set(KERNEL_SOURCES
font/prefs.psf.o
kernel/ACPI.cpp
kernel/APIC.cpp
kernel/CPUID.cpp
kernel/Debug.cpp
kernel/Device/Device.cpp
kernel/Device/NullDevice.cpp
kernel/Device/ZeroDevice.cpp
kernel/Errors.cpp
kernel/Font.cpp
kernel/FS/DevFS/FileSystem.cpp
kernel/FS/Ext2/FileSystem.cpp
kernel/FS/Ext2/Inode.cpp
kernel/FS/Inode.cpp
kernel/FS/Pipe.cpp
kernel/FS/ProcFS/FileSystem.cpp
kernel/FS/ProcFS/Inode.cpp
kernel/FS/RamFS/FileSystem.cpp
kernel/FS/RamFS/Inode.cpp
kernel/FS/VirtualFileSystem.cpp
kernel/Input/PS2Controller.cpp
kernel/Input/PS2Keyboard.cpp
kernel/Input/PS2Keymap.cpp
kernel/InterruptController.cpp
kernel/kernel.cpp
kernel/Memory/FileBackedRegion.cpp
kernel/Memory/GeneralAllocator.cpp
kernel/Memory/Heap.cpp
kernel/Memory/kmalloc.cpp
kernel/Memory/MemoryBackedRegion.cpp
kernel/Memory/MemoryRegion.cpp
kernel/Memory/PhysicalRange.cpp
kernel/Memory/VirtualRange.cpp
kernel/Networking/E1000.cpp
kernel/OpenFileDescriptorSet.cpp
kernel/Panic.cpp
kernel/PCI.cpp
kernel/PIC.cpp
kernel/Process.cpp
kernel/Scheduler.cpp
kernel/Semaphore.cpp
kernel/SpinLock.cpp
kernel/SSP.cpp
kernel/Storage/ATABus.cpp
kernel/Storage/ATAController.cpp
kernel/Storage/ATADevice.cpp
kernel/Storage/DiskCache.cpp
kernel/Storage/StorageDevice.cpp
kernel/Syscall.cpp
kernel/Syscall.S
kernel/Terminal/Serial.cpp
kernel/Terminal/TTY.cpp
kernel/Terminal/VesaTerminalDriver.cpp
kernel/Terminal/VirtualTTY.cpp
kernel/Thread.cpp
kernel/Timer/HPET.cpp
kernel/Timer/PIT.cpp
kernel/Timer/RTC.cpp
kernel/Timer/Timer.cpp
icxxabi.cpp
)
#set(ENABLE_KERNEL_UBSAN True)
if(ENABLE_KERNEL_UBSAN)
set(KERNEL_SOURCES ${KERNEL_SOURCES} ubsan.cpp)
endif()
if("${BANAN_ARCH}" STREQUAL "x86_64")
set(KERNEL_SOURCES
${KERNEL_SOURCES}
arch/x86_64/boot.S
arch/x86_64/GDT.cpp
arch/x86_64/IDT.cpp
arch/x86_64/interrupts.S
arch/x86_64/PageTable.cpp
arch/x86_64/Signal.S
arch/x86_64/Thread.S
)
elseif("${BANAN_ARCH}" STREQUAL "i386")
set(KERNEL_SOURCES
${KERNEL_SOURCES}
arch/i386/boot.S
arch/i386/GDT.cpp
arch/i386/IDT.cpp
arch/i386/MMU.cpp
arch/i386/SpinLock.S
arch/i386/Thread.S
)
else()
message(FATAL_ERROR "unsupported architecure ${BANAN_ARCH}")
endif()
file(GLOB_RECURSE LAI_SOURCES
lai/*.c
)
set(LAI_SOURCES
${LAI_SOURCES}
kernel/lai_host.cpp
)
set(BAN_SOURCES
../BAN/BAN/New.cpp
../BAN/BAN/String.cpp
../BAN/BAN/StringView.cpp
../BAN/BAN/Time.cpp
)
set(LIBC_SOURCES
../libc/ctype.cpp
../libc/string.cpp
)
set(LIBELF_SOURCES
../LibELF/LibELF/LoadableELF.cpp
)
set(KERNEL_SOURCES
${KERNEL_SOURCES}
${LAI_SOURCES}
${BAN_SOURCES}
${LIBC_SOURCES}
${LIBELF_SOURCES}
)
add_executable(kernel ${KERNEL_SOURCES})
add_dependencies(kernel headers)
target_compile_definitions(kernel PUBLIC __is_kernel)
target_compile_definitions(kernel PUBLIC __arch=${BANAN_ARCH})
target_compile_options(kernel PUBLIC -O2 -g)
target_compile_options(kernel PUBLIC $<$<COMPILE_LANGUAGE:CXX>:-Wno-literal-suffix -fno-rtti -fno-exceptions>)
target_compile_options(kernel PUBLIC -fmacro-prefix-map=${CMAKE_CURRENT_SOURCE_DIR}=.)
target_compile_options(kernel PUBLIC -fstack-protector -ffreestanding -Wall -Werror=return-type -Wstack-usage=1024 -fno-omit-frame-pointer -mgeneral-regs-only)
if(ENABLE_KERNEL_UBSAN)
target_compile_options(kernel PUBLIC -fsanitize=undefined)
endif()
if("${BANAN_ARCH}" STREQUAL "x86_64")
target_compile_options(kernel PUBLIC -mcmodel=kernel -mno-red-zone -mno-mmx)
target_link_options(kernel PUBLIC LINKER:-z,max-page-size=4096)
target_link_options(kernel PUBLIC LINKER:-T,${CMAKE_CURRENT_SOURCE_DIR}/arch/x86_64/linker.ld)
elseif("${BANAN_ARCH}" STREQUAL "i386")
target_link_options(kernel PUBLIC LINKER:-T,${CMAKE_CURRENT_SOURCE_DIR}/arch/i386/linker.ld)
endif()
target_link_options(kernel PUBLIC -ffreestanding -nostdlib)
add_custom_target(crt0
COMMAND ${CMAKE_CXX_COMPILER} -c ${CMAKE_CURRENT_SOURCE_DIR}/arch/${BANAN_ARCH}/crt0.S -o ${CMAKE_CURRENT_BINARY_DIR}/crt0.o
DEPENDS headers
)
add_custom_command(
TARGET crt0
POST_BUILD
COMMAND sudo cp ${CMAKE_CURRENT_BINARY_DIR}/crt0.o ${BANAN_LIB}/
)
add_custom_target(kernel-headers
COMMAND sudo rsync -a ${CMAKE_CURRENT_SOURCE_DIR}/include/ ${BANAN_INCLUDE}/
COMMAND sudo rsync -a ${CMAKE_CURRENT_SOURCE_DIR}/lai/include/ ${BANAN_INCLUDE}/
DEPENDS sysroot
USES_TERMINAL
)
add_custom_target(kernel-install
COMMAND sudo cp ${CMAKE_CURRENT_BINARY_DIR}/kernel ${BANAN_BOOT}/banan-os.kernel
DEPENDS kernel
USES_TERMINAL
)
execute_process(COMMAND ${CMAKE_CXX_COMPILER} -print-file-name=crtbegin.o OUTPUT_VARIABLE CRTBEGIN OUTPUT_STRIP_TRAILING_WHITESPACE)
execute_process(COMMAND ${CMAKE_CXX_COMPILER} -print-file-name=crtend.o OUTPUT_VARIABLE CRTEND OUTPUT_STRIP_TRAILING_WHITESPACE)
add_custom_command(
TARGET kernel PRE_LINK
COMMAND ${CMAKE_CXX_COMPILER} -MD -c ${CMAKE_CURRENT_SOURCE_DIR}/arch/${BANAN_ARCH}/crti.S ${COMPILE_OPTIONS}
COMMAND ${CMAKE_CXX_COMPILER} -MD -c ${CMAKE_CURRENT_SOURCE_DIR}/arch/${BANAN_ARCH}/crtn.S ${COMPILE_OPTIONS}
COMMAND cp ${CRTBEGIN} .
COMMAND cp ${CRTEND} .
)
add_custom_command(
TARGET kernel POST_BUILD
COMMAND x86_64-banan_os-strip ${CMAKE_CURRENT_BINARY_DIR}/kernel
)
add_custom_command(
OUTPUT font/prefs.psf.o
COMMAND cd ${CMAKE_CURRENT_SOURCE_DIR} && objcopy -O ${ELF_FORMAT} -B i386 -I binary font/prefs.psf ${CMAKE_CURRENT_BINARY_DIR}/font/prefs.psf.o
)
set(CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_COMPILER} <CMAKE_CXX_LINK_FLAGS> <FLAGS> <LINK_FLAGS> -o <TARGET> ${CMAKE_CURRENT_BINARY_DIR}/crti.o ${CMAKE_CURRENT_BINARY_DIR}/crtbegin.o <OBJECTS> ${CMAKE_CURRENT_BINARY_DIR}/crtend.o ${CMAKE_CURRENT_BINARY_DIR}/crtn.o -lgcc ")

View File

@@ -1,131 +0,0 @@
DEFAULT_HOST!=../default-host.sh
HOST?=DEFAULT_HOST
HOSTARCH!=../target-triplet-to-arch.sh $(HOST)
CFLAGS?=-O2 -g
CPPFLAGS?=
LDFLAGS?=
LIBS?=
DESTDIR?=
PREFIX?=/usr/local
EXEC_PREFIX?=$(PREFIX)
BOOTDIR?=$(EXEC_PREFIX)/boot
INCLUDEDIR?=$(PREFIX)/include
CFLAGS:=$(CFLAGS) -D__is_kernel -D__arch=$(HOSTARCH) -Iinclude -fstack-protector -ffreestanding -Wall -Wextra -Werror=return-type -fno-omit-frame-pointer -mno-sse -mno-sse2
CPPFLAGS:=$(CPPFLAGS) -fno-rtti -fno-exceptions
LDFLAGS:=$(LDFLAGS)
LIBS:=$(LIBS) -nostdlib -lk -lbank -lgcc
ARCHDIR=arch/$(HOSTARCH)
include $(ARCHDIR)/make.config
CFLAGS:=$(CFLAGS) $(KERNEL_ARCH_CFLAGS)
CPPFLAGS:=$(CPPFLAGS) $(KERNEL_ARCH_CPPFLAGS)
LDFLAGS:=$(LDFLAGS) $(KERNEL_ARCH_LDFLAGS)
LIBS:=$(LIBS) $(KERNEL_ARCH_LIBS)
ifeq ($(UBSAN), 1)
CFLAGS:=$(CFLAGS) -fsanitize=undefined
endif
BUILDDIR=$(abspath build)
KERNEL_OBJS= \
$(KERNEL_ARCH_OBJS) \
font/prefs.o \
kernel/APIC.o \
kernel/build_libc.o \
kernel/CPUID.o \
kernel/Debug.o \
kernel/Font.o \
kernel/FS/Ext2.o \
kernel/FS/VirtualFileSystem.o \
kernel/Input.o \
kernel/InterruptController.o \
kernel/kernel.o \
kernel/kmalloc.o \
kernel/PCI.o \
kernel/PIC.o \
kernel/PIT.o \
kernel/Process.o \
kernel/RTC.o \
kernel/Scheduler.o \
kernel/Serial.o \
kernel/Shell.o \
kernel/SpinLock.o \
kernel/SSP.o \
kernel/Storage/ATAController.o \
kernel/Storage/StorageDevice.o \
kernel/Syscall.o \
kernel/Thread.o \
kernel/TTY.o \
kernel/VesaTerminalDriver.o \
userspace/userspace.o \
icxxabi.o \
ubsan.o \
OBJS= \
$(ARCHDIR)/crti.o \
$(ARCHDIR)/crtbegin.o \
$(KERNEL_OBJS) \
$(ARCHDIR)/crtend.o \
$(ARCHDIR)/crtn.o \
LINK_LIST= \
$(LDFLAGS) \
$(ARCHDIR)/crti.o \
$(ARCHDIR)/crtbegin.o \
$(KERNEL_OBJS) \
$(LIBS) \
$(ARCHDIR)/crtend.o \
$(ARCHDIR)/crtn.o \
.PHONY: all always clean install install-headers install-kernel
.SUFFIXES: .o .c .cpp .S .psf
all: banan-os.kernel
banan-os.kernel: always $(OBJS) $(ARCHDIR)/linker.ld
cd $(BUILDDIR) && $(CXX) -T ../$(ARCHDIR)/linker.ld -o banan-os.kernel $(CFLAGS) $(CPPFLAGS) $(LINK_LIST)
cd $(BUILDDIR) && grub-file --is-x86-multiboot banan-os.kernel
$(ARCHDIR)/crtbegin.o $(ARCHDIR)/crtend.o:
OBJ=`$(CC) $(CFLAGS) $(LDFLAGS) -print-file-name=$(@F)` && cp "$$OBJ" $(BUILDDIR)/$@
.c.o:
$(CC) -MD -c $< -o $(BUILDDIR)/$@ $(CFLAGS)
.cpp.o:
$(CXX) -MD -c $< -o $(BUILDDIR)/$@ $(CFLAGS) $(CPPFLAGS)
.S.o:
$(CC) -MD -c $< -o $(BUILDDIR)/$@ $(CFLAGS)
.psf.o:
objcopy -O $(ELF_FORMAT) -B i386 -I binary $< $(BUILDDIR)/$@
always:
mkdir -p $(BUILDDIR)/$(ARCHDIR)
mkdir -p $(BUILDDIR)/kernel
mkdir -p $(BUILDDIR)/kernel/FS
mkdir -p $(BUILDDIR)/kernel/Storage
mkdir -p $(BUILDDIR)/userspace
mkdir -p $(BUILDDIR)/font
clean:
rm -rf $(BUILDDIR)
install: install-headers install-kernel
install-headers:
mkdir -p $(DESTDIR)$(INCLUDEDIR)
cp -R --preserve=timestamps include/. $(DESTDIR)$(INCLUDEDIR)/.
install-kernel: banan-os.kernel
mkdir -p $(DESTDIR)$(BOOTDIR)
cp $(BUILDDIR)/banan-os.kernel $(DESTDIR)$(BOOTDIR)
-include $(OBJS:.o=.d)

View File

@@ -109,6 +109,11 @@ namespace Kernel::GDT
write_entry(offset, (uint32_t)s_tss, sizeof(TaskStateSegment), 0x89, 0x0);
}
void set_tss_stack(uintptr_t esp)
{
s_tss->esp0 = esp;
}
static void flush_gdt()
{
asm volatile("lgdt %0" :: "m"(s_gdtr));

View File

@@ -1,8 +1,9 @@
#include <BAN/Errors.h>
#include <kernel/IDT.h>
#include <kernel/InterruptController.h>
#include <kernel/kmalloc.h>
#include <kernel/Memory/kmalloc.h>
#include <kernel/Panic.h>
#include <kernel/Scheduler.h>
#define INTERRUPT_HANDLER____(i, msg) \
static void interrupt ## i () \
@@ -132,6 +133,8 @@ found:
// NOTE: Scheduler sends PIT eoi's
if (irq != PIT_IRQ)
InterruptController::get().eoi(irq);
Kernel::Scheduler::get().reschedule_if_idling();
}
extern "C" void handle_irq_common();
@@ -151,7 +154,7 @@ found:
"popa;"
"iret;"
);
extern "C" void syscall_asm();
asm(
".global syscall_asm;"
@@ -171,7 +174,18 @@ found:
"addl $16, %esp;"
"popw %es;"
"popw %ds;"
"popa;"
// NOTE: following instructions are same as in 'popa', except we skip eax
// since it holds the return value of the syscall.
"popl %edi;"
"popl %esi;"
"popl %ebp;"
"addl $4, %esp;"
"popl %ebx;"
"popl %edx;"
"popl %ecx;"
"addl $4, %esp;"
"iret;"
);

View File

@@ -1,136 +1,227 @@
#include <BAN/Errors.h>
#include <kernel/Debug.h>
#include <kernel/MMU.h>
#include <kernel/kmalloc.h>
#include <kernel/Memory/MMU.h>
#include <kernel/Memory/kmalloc.h>
#include <string.h>
#define MMU_DEBUG_PRINT 0
// bits 31-12 set
#define PAGE_MASK 0xfffff000
#define PAGE_SIZE 0x00001000
#define PAGE_MASK 0xfffff000
#define FLAGS_MASK 0x00000fff
static MMU* s_instance = nullptr;
void MMU::intialize()
namespace Kernel
{
ASSERT(s_instance == nullptr);
s_instance = new MMU();
}
MMU& MMU::get()
{
ASSERT(s_instance);
return *s_instance;
}
static MMU* s_instance = nullptr;
static uint64_t* allocate_page_aligned_page()
{
uint64_t* page = (uint64_t*)kmalloc(PAGE_SIZE, PAGE_SIZE);
ASSERT(page);
ASSERT(((uintptr_t)page % PAGE_SIZE) == 0);
memset(page, 0, PAGE_SIZE);
return page;
}
MMU::MMU()
{
m_highest_paging_struct = (uint64_t*)kmalloc(sizeof(uint64_t) * 4, 32);
ASSERT(m_highest_paging_struct);
ASSERT(((uintptr_t)m_highest_paging_struct % 32) == 0);
// allocate all page directories
for (int i = 0; i < 4; i++)
void MMU::initialize()
{
uint64_t* page_directory = allocate_page_aligned_page();
m_highest_paging_struct[i] = (uint64_t)page_directory | Flags::Present;
ASSERT(s_instance == nullptr);
s_instance = new MMU();
ASSERT(s_instance);
s_instance->initialize_kernel();
s_instance->load();
}
// create and identity map first 6 MiB
uint64_t* page_directory1 = (uint64_t*)(m_highest_paging_struct[0] & PAGE_MASK);
for (uint64_t i = 0; i < 3; i++)
MMU& MMU::get()
{
uint64_t* page_table = allocate_page_aligned_page();
for (uint64_t j = 0; j < 512; j++)
page_table[j] = (i << 21) | (j << 12) | Flags::ReadWrite | Flags::Present;
page_directory1[i] = (uint64_t)page_table | Flags::ReadWrite | Flags::Present;
ASSERT(s_instance);
return *s_instance;
}
// dont map first page (0 -> 4 KiB) so that nullptr dereference
// causes page fault :)
uint64_t* page_table1 = (uint64_t*)(page_directory1[0] & PAGE_MASK);
page_table1[0] = 0;
// reload this new pdpt
asm volatile("movl %0, %%cr3" :: "r"(m_highest_paging_struct));
}
void MMU::allocate_page(uintptr_t address, uint8_t flags)
{
#if MMU_DEBUG_PRINT
dprintln("AllocatePage(0x{8H})", address);
#endif
ASSERT(flags & Flags::Present);
address &= PAGE_MASK;
uint32_t pdpte = (address & 0xC0000000) >> 30;
uint32_t pde = (address & 0x3FE00000) >> 21;
uint32_t pte = (address & 0x001FF000) >> 12;
uint64_t* page_directory = (uint64_t*)(m_highest_paging_struct[pdpte] & PAGE_MASK);
if (!(page_directory[pde] & Flags::Present))
static uint64_t* allocate_page_aligned_page()
{
uint64_t* page_table = allocate_page_aligned_page();
page_directory[pde] = (uint64_t)page_table;
uint64_t* page = (uint64_t*)kmalloc(PAGE_SIZE, PAGE_SIZE);
ASSERT(page);
ASSERT(((uintptr_t)page % PAGE_SIZE) == 0);
memset(page, 0, PAGE_SIZE);
return page;
}
page_directory[pde] |= flags;
uint64_t* page_table = (uint64_t*)(page_directory[pde] & PAGE_MASK);
page_table[pte] = address | flags;
void MMU::initialize_kernel()
{
m_highest_paging_struct = (uint64_t*)kmalloc(sizeof(uint64_t) * 4, 32);
ASSERT(m_highest_paging_struct);
ASSERT(((uintptr_t)m_highest_paging_struct % 32) == 0);
// allocate all page directories
for (int i = 0; i < 4; i++)
{
uint64_t* page_directory = allocate_page_aligned_page();
m_highest_paging_struct[i] = (uint64_t)page_directory | Flags::Present;
}
// FIXME: We should just identity map until g_kernel_end
// create and identity map first 6 MiB
uint64_t* page_directory1 = (uint64_t*)(m_highest_paging_struct[0] & PAGE_MASK);
for (uint64_t i = 0; i < 3; i++)
{
uint64_t* page_table = allocate_page_aligned_page();
for (uint64_t j = 0; j < 512; j++)
page_table[j] = (i << 21) | (j << 12) | Flags::ReadWrite | Flags::Present;
page_directory1[i] = (uint64_t)page_table | Flags::ReadWrite | Flags::Present;
}
// dont map first page (0 -> 4 KiB) so that nullptr dereference
// causes page fault :)
uint64_t* page_table1 = (uint64_t*)(page_directory1[0] & PAGE_MASK);
page_table1[0] = 0;
}
MMU::MMU()
{
if (s_instance == nullptr)
return;
// Here we copy the s_instances paging structs since they are
// global for every process
uint64_t* global_pdpt = s_instance->m_highest_paging_struct;
uint64_t* pdpt = (uint64_t*)kmalloc(sizeof(uint64_t) * 4, 32);
ASSERT(pdpt);
for (uint32_t pdpte = 0; pdpte < 4; pdpte++)
{
if (!(global_pdpt[pdpte] & Flags::Present))
continue;
uint64_t* global_pd = (uint64_t*)(global_pdpt[pdpte] & PAGE_MASK);
uint64_t* pd = allocate_page_aligned_page();
pdpt[pdpte] = (uint64_t)pd | (global_pdpt[pdpte] & ~PAGE_MASK);
for (uint32_t pde = 0; pde < 512; pde++)
{
if (!(global_pd[pde] & Flags::Present))
continue;
uint64_t* global_pt = (uint64_t*)(global_pd[pde] & PAGE_MASK);
uint64_t* pt = allocate_page_aligned_page();
pd[pde] = (uint64_t)pt | (global_pd[pde] & ~PAGE_MASK);
memcpy(pt, global_pt, PAGE_SIZE);
}
}
m_highest_paging_struct = pdpt;
}
MMU::~MMU()
{
uint64_t* pdpt = m_highest_paging_struct;
for (uint32_t pdpte = 0; pdpte < 512; pdpte++)
{
if (!(pdpt[pdpte] & Flags::Present))
continue;
uint64_t* pd = (uint64_t*)(pdpt[pdpte] & PAGE_MASK);
for (uint32_t pde = 0; pde < 512; pde++)
{
if (!(pd[pde] & Flags::Present))
continue;
kfree((void*)(pd[pde] & PAGE_MASK));
}
kfree(pd);
}
kfree(pdpt);
}
void MMU::load()
{
asm volatile("movl %0, %%cr3" :: "r"(m_highest_paging_struct));
}
void MMU::map_page_at(paddr_t paddr, vaddr_t vaddr, uint8_t flags)
{
#if MMU_DEBUG_PRINT
dprintln("AllocatePage(0x{8H})", address);
#endif
ASSERT(flags & Flags::Present);
ASSERT(!(paddr & ~PAGE_MASK));
ASSERT(!(vaddr & ~PAGE_MASK));
uint32_t pdpte = (vaddr & 0xC0000000) >> 30;
uint32_t pde = (vaddr & 0x3FE00000) >> 21;
uint32_t pte = (vaddr & 0x001FF000) >> 12;
uint64_t* page_directory = (uint64_t*)(m_highest_paging_struct[pdpte] & PAGE_MASK);
if (!(page_directory[pde] & Flags::Present))
{
uint64_t* page_table = allocate_page_aligned_page();
page_directory[pde] = (uint64_t)page_table;
}
page_directory[pde] |= flags;
uint64_t* page_table = (uint64_t*)(page_directory[pde] & PAGE_MASK);
page_table[pte] = paddr | flags;
}
void MMU::identity_map_page(paddr_t address, uint8_t flags)
{
address &= PAGE_MASK;
map_page_at(address, address, flags);
}
void MMU::identity_map_range(paddr_t address, ptrdiff_t size, uint8_t flags)
{
paddr_t s_page = address & PAGE_MASK;
paddr_t e_page = (address + size - 1) & PAGE_MASK;
for (paddr_t page = s_page; page <= e_page; page += PAGE_SIZE)
identity_map_page(page, flags);
}
void MMU::unmap_page(vaddr_t address)
{
#if MMU_DEBUG_PRINT
dprintln("UnAllocatePage(0x{8H})", address & PAGE_MASK);
#endif
uint32_t pdpte = (address & 0xC0000000) >> 30;
uint32_t pde = (address & 0x3FE00000) >> 21;
uint32_t pte = (address & 0x001FF000) >> 12;
uint64_t* page_directory = (uint64_t*)(m_highest_paging_struct[pdpte] & PAGE_MASK);
if (!(page_directory[pde] & Flags::Present))
return;
uint64_t* page_table = (uint64_t*)(page_directory[pde] & PAGE_MASK);
if (!(page_table[pte] & Flags::Present))
return;
page_table[pte] = 0;
// TODO: Unallocate the page table if this was the only allocated page
}
void MMU::unmap_range(vaddr_t address, ptrdiff_t size)
{
uintptr_t s_page = address & PAGE_MASK;
uintptr_t e_page = (address + size - 1) & PAGE_MASK;
for (uintptr_t page = s_page; page <= e_page; page += PAGE_SIZE)
unmap_page(page);
}
uint8_t MMU::get_page_flags(vaddr_t address) const
{
uint32_t pdpte = (address & 0xC0000000) >> 30;
uint32_t pde = (address & 0x3FE00000) >> 21;
uint32_t pte = (address & 0x001FF000) >> 12;
uint64_t* page_directory = (uint64_t*)(m_highest_paging_struct[pdpte] & PAGE_MASK);
if (!(page_directory[pde] & Flags::Present))
return 0;
uint64_t* page_table = (uint64_t*)(page_directory[pde] & PAGE_MASK);
if (!(page_table[pte] & Flags::Present))
return 0;
return page_table[pte] & FLAGS_MASK;
}
asm volatile("invlpg (%0)" :: "r"(address) : "memory");
}
void MMU::allocate_range(uintptr_t address, ptrdiff_t size, uint8_t flags)
{
uintptr_t s_page = address & PAGE_MASK;
uintptr_t e_page = (address + size - 1) & PAGE_MASK;
for (uintptr_t page = s_page; page <= e_page; page += PAGE_SIZE)
allocate_page(page, flags);
}
void MMU::unallocate_page(uintptr_t address)
{
#if MMU_DEBUG_PRINT
dprintln("UnAllocatePage(0x{8H})", address & PAGE_MASK);
#endif
uint32_t pdpte = (address & 0xC0000000) >> 30;
uint32_t pde = (address & 0x3FE00000) >> 21;
uint32_t pte = (address & 0x001FF000) >> 12;
uint64_t* page_directory = (uint64_t*)(m_highest_paging_struct[pdpte] & PAGE_MASK);
if (!(page_directory[pde] & Flags::Present))
return;
uint64_t* page_table = (uint64_t*)(page_directory[pde] & PAGE_MASK);
if (!(page_table[pte] & Flags::Present))
return;
page_table[pte] = 0;
// TODO: Unallocate the page table if this was the only allocated page
asm volatile("invlpg (%0)" :: "r"(address & PAGE_MASK) : "memory");
}
void MMU::unallocate_range(uintptr_t address, ptrdiff_t size)
{
uintptr_t s_page = address & PAGE_MASK;
uintptr_t e_page = (address + size - 1) & PAGE_MASK;
for (uintptr_t page = s_page; page <= e_page; page += PAGE_SIZE)
unallocate_page(page);
}

View File

@@ -25,4 +25,23 @@ continue_thread:
movl 8(%esp), %ecx
movl 4(%esp), %esp
movl $0, %eax
jmp *%ecx
jmp *%ecx
# void thread_jump_userspace(uint32_t rsp, uint32_t rip)
.global thread_jump_userspace
thread_jump_userspace:
movl $0x23, %eax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movl 8(%esp), %ecx
movl 4(%esp), %esp
pushl $0x23
pushl %esp
pushfl
pushl $0x1B
pushl %ecx
iret

View File

@@ -28,9 +28,7 @@ g_boot_stack_bottom:
g_boot_stack_top:
# 0 MiB -> 1 MiB: bootloader stuff
# 1 MiB -> 2 MiB: kernel
# 2 MiB -> 3 MiB: kmalloc
# 3 MiB -> 4 Mib: kmalloc_fixed
# 1 MiB -> : kernel
.align 32
boot_page_directory_pointer_table:
.skip 4 * 8

23
kernel/arch/i386/crt0.S Normal file
View File

@@ -0,0 +1,23 @@
.section .text
.global _start
_start:
# Set up end of the stack frame linked list.
movl $0, %ebp
pushl %ebp # rip=0
pushl %ebp # rbp=0
movl %esp, %ebp
# Prepare signals, memory allocation, stdio and such.
#call initialize_standard_library
# Run the global constructors.
call _init
# Run main
call main
# Terminate the process with the exit code.
movl %eax, %edi
call exit
.size _start, . - _start

View File

@@ -4,6 +4,7 @@ SECTIONS
{
. = 0x00100000;
g_kernel_start = .;
.text BLOCK(4K) : ALIGN(4K)
{
*(.multiboot)
@@ -11,9 +12,7 @@ SECTIONS
}
.rodata BLOCK(4K) : ALIGN(4K)
{
g_rodata_start = .;
*(.rodata.*)
g_rodata_end = .;
}
.data BLOCK(4K) : ALIGN(4K)
{
@@ -26,13 +25,4 @@ SECTIONS
}
g_kernel_end = .;
. = 0x00A00000;
g_userspace_start = .;
.userspace BLOCK(4K) : ALIGN(4K)
{
*(.userspace)
}
g_userspace_end = .;
}

View File

@@ -1,15 +0,0 @@
KERNEL_ARCH_CFLAGS=
KERNEL_ARCH_CPPFLAGS=
KERNEL_ARCH_LDFLAGS=
KERNEL_ARCH_LIBS=
ELF_FORMAT=elf32-i386
KERNEL_ARCH_OBJS= \
$(ARCHDIR)/boot.o \
$(ARCHDIR)/GDT.o \
$(ARCHDIR)/IDT.o \
$(ARCHDIR)/MMU.o \
$(ARCHDIR)/SpinLock.o \
$(ARCHDIR)/Thread.o \

View File

@@ -54,6 +54,8 @@ namespace Kernel::GDT
uint64_t address;
} __attribute__((packed));
static constexpr uint16_t s_tss_offset = 0x28;
static TaskStateSegment* s_tss = nullptr;
static SegmentDescriptor* s_gdt = nullptr;
static GDTR s_gdtr;
@@ -73,30 +75,35 @@ namespace Kernel::GDT
desc.flags = flags;
}
static void write_tss(uint8_t offset)
static void write_tss()
{
s_tss = new TaskStateSegment();
ASSERT(s_tss);
memset(s_tss, 0x00, sizeof(TaskStateSegment));
s_tss->rsp0 = (uintptr_t)g_boot_stack_top;
s_tss->rsp0 = 0;
uintptr_t base = (uintptr_t)s_tss;
write_entry(offset, (uint32_t)base, sizeof(TaskStateSegment), 0x89, 0x0);
SegmentDescriptor& desc = *(SegmentDescriptor*)((uintptr_t)s_gdt + offset + 0x08);
write_entry(s_tss_offset, (uint32_t)base, sizeof(TaskStateSegment), 0x89, 0x0);
SegmentDescriptor& desc = *(SegmentDescriptor*)((uintptr_t)s_gdt + s_tss_offset + 0x08);
desc.low = base >> 32;
desc.high = 0;
}
void set_tss_stack(uintptr_t rsp)
{
s_tss->rsp0 = rsp;
}
static void flush_gdt()
{
asm volatile("lgdt %0" :: "m"(s_gdtr));
}
extern "C" void flush_tss(uint16_t offset)
static void flush_tss()
{
asm volatile("ltr %0" :: "m"(offset));
asm volatile("ltr %0" :: "m"(s_tss_offset));
}
void initialize()
@@ -113,10 +120,10 @@ namespace Kernel::GDT
write_entry(0x10, 0x00000000, 0xFFFFF, 0x92, 0xC); // kernel data
write_entry(0x18, 0x00000000, 0xFFFFF, 0xFA, 0xA); // user code
write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, 0xC); // user data
write_tss(0x28);
write_tss();
flush_gdt();
flush_tss(0x28);
flush_tss();
}
}

View File

@@ -1,8 +1,14 @@
#include <BAN/Errors.h>
#include <kernel/IDT.h>
#include <kernel/InterruptController.h>
#include <kernel/kmalloc.h>
#include <kernel/InterruptStack.h>
#include <kernel/Memory/kmalloc.h>
#include <kernel/Panic.h>
#include <kernel/Process.h>
#include <kernel/Scheduler.h>
#include <kernel/Timer/PIT.h>
#include <unistd.h>
#define REGISTER_ISR_HANDLER(i) register_interrupt_handler(i, isr ## i)
#define REGISTER_IRQ_HANDLER(i) register_interrupt_handler(IRQ_VECTOR_BASE + i, irq ## i)
@@ -59,6 +65,65 @@ namespace IDT
static void(*s_irq_handlers[0x10])() { nullptr };
enum ISR
{
DivisionError,
Debug,
NonMaskableInterrupt,
Breakpoint,
Overflow,
BoundRangeException,
InvalidOpcode,
DeviceNotAvailable,
DoubleFault,
CoprocessorSegmentOverrun,
InvalidTSS,
SegmentNotPresent,
StackSegmentFault,
GeneralProtectionFault,
PageFault,
UnknownException0x0F,
x87FloatingPointException,
AlignmentCheck,
MachineCheck,
SIMDFloatingPointException,
VirtualizationException,
ControlProtectionException,
UnknownException0x16,
UnknownException0x17,
UnknownException0x18,
UnknownException0x19,
UnknownException0x1A,
UnknownException0x1B,
HypervisorInjectionException,
VMMCommunicationException,
SecurityException,
UnkownException0x1F,
};
struct PageFaultError
{
union
{
uint32_t raw;
struct
{
uint32_t present : 1;
uint32_t write : 1;
uint32_t userspace : 1;
uint32_t reserved_write : 1;
uint32_t instruction : 1;
uint32_t protection_key : 1;
uint32_t shadow_stack : 1;
uint32_t reserved1 : 8;
uint32_t sgx_violation : 1;
uint32_t reserved2 : 16;
};
};
};
static_assert(sizeof(PageFaultError) == 4);
static const char* isr_exceptions[] =
{
"Division Error",
@@ -95,40 +160,170 @@ namespace IDT
"Unkown Exception 0x1F",
};
extern "C" void cpp_isr_handler(uint64_t isr, uint64_t error, const Registers* regs)
extern "C" void cpp_isr_handler(uint64_t isr, uint64_t error, Kernel::InterruptStack& interrupt_stack, const Registers* regs)
{
Kernel::panic(
"{} (error code: 0x{16H})\r\n"
#if __enable_sse
bool from_userspace = (interrupt_stack.cs & 0b11) == 0b11;
if (from_userspace)
Kernel::Thread::current().save_sse();
#endif
pid_t tid = Kernel::Scheduler::current_tid();
pid_t pid = tid ? Kernel::Process::current().pid() : 0;
if (pid && isr == ISR::PageFault)
{
PageFaultError page_fault_error;
page_fault_error.raw = error;
// Try demand paging on non present pages
if (!page_fault_error.present)
{
asm volatile("sti");
auto result = Kernel::Process::current().allocate_page_for_demand_paging(regs->cr2);
asm volatile("cli");
if (!result.is_error() && result.value())
return;
if (result.is_error())
{
dwarnln("Demand paging: {}", result.error());
Kernel::Thread::current().handle_signal(SIGTERM);
}
}
}
if (tid)
{
auto start = Kernel::Thread::current().stack_base();
auto end = start + Kernel::Thread::current().stack_size();
if (interrupt_stack.rsp < start)
derrorln("Stack overflow");
if (interrupt_stack.rsp >= end)
derrorln("Stack underflow");
}
if (Kernel::PageTable::current().get_page_flags(interrupt_stack.rip & PAGE_ADDR_MASK) & Kernel::PageTable::Flags::Present)
{
uint8_t* machine_code = (uint8_t*)interrupt_stack.rip;
dwarnln("While executing: {2H}{2H}{2H}{2H}{2H}{2H}{2H}{2H}",
machine_code[0],
machine_code[1],
machine_code[2],
machine_code[3],
machine_code[4],
machine_code[5],
machine_code[6],
machine_code[7]
);
}
dwarnln(
"{} (error code: 0x{16H}), pid {}, tid {}\r\n"
"Register dump\r\n"
"rax=0x{16H}, rbx=0x{16H}, rcx=0x{16H}, rdx=0x{16H}\r\n"
"rsp=0x{16H}, rbp=0x{16H}, rdi=0x{16H}, rsi=0x{16H}\r\n"
"rip=0x{16H}, rflags=0x{16H}\r\n"
"cr0=0x{16H}, cr2=0x{16H}, cr3=0x{16H}, cr4=0x{16H}\r\n",
isr_exceptions[isr], error,
"cr0=0x{16H}, cr2=0x{16H}, cr3=0x{16H}, cr4=0x{16H}",
isr_exceptions[isr], error, pid, tid,
regs->rax, regs->rbx, regs->rcx, regs->rdx,
regs->rsp, regs->rbp, regs->rdi, regs->rsi,
regs->rip, regs->rflags,
regs->cr0, regs->cr2, regs->cr3, regs->cr4
);
}
if (isr == ISR::PageFault)
Kernel::PageTable::current().debug_dump();
Debug::dump_stack_trace();
extern "C" void cpp_irq_handler(uint64_t irq)
{
if (s_irq_handlers[irq])
s_irq_handlers[irq]();
else
if (tid)
{
if (!InterruptController::get().is_in_service(irq))
{
dprintln("spurious irq 0x{2H}", irq);
return;
}
dprintln("no handler for irq 0x{2H}\n", irq);
Kernel::Thread::current().set_return_rsp(interrupt_stack.rsp);
Kernel::Thread::current().set_return_rip(interrupt_stack.rip);
}
// NOTE: Scheduler sends PIT eoi's
if (irq != PIT_IRQ)
if (tid && Kernel::Thread::current().is_userspace())
{
// TODO: Confirm and fix the exception to signal mappings
int signal = 0;
switch (isr)
{
case ISR::DeviceNotAvailable:
case ISR::DivisionError:
case ISR::SIMDFloatingPointException:
case ISR::x87FloatingPointException:
signal = SIGFPE;
break;
case ISR::AlignmentCheck:
signal = SIGBUS;
break;
case ISR::InvalidOpcode:
signal = SIGILL;
break;
case ISR::PageFault:
signal = SIGSEGV;
break;
default:
dwarnln("Unhandled exception");
signal = SIGABRT;
break;
}
Kernel::Thread::current().handle_signal(signal);
}
else
{
Kernel::panic("Unhandled exception");
}
ASSERT(Kernel::Thread::current().state() != Kernel::Thread::State::Terminated);
#if __enable_sse
if (from_userspace)
{
ASSERT(Kernel::Thread::current().state() == Kernel::Thread::State::Executing);
Kernel::Thread::current().load_sse();
}
#endif
}
extern "C" void cpp_irq_handler(uint64_t irq, Kernel::InterruptStack& interrupt_stack)
{
#if __enable_sse
bool from_userspace = (interrupt_stack.cs & 0b11) == 0b11;
if (from_userspace)
Kernel::Thread::current().save_sse();
#endif
if (Kernel::Scheduler::current_tid())
{
Kernel::Thread::current().set_return_rsp(interrupt_stack.rsp);
Kernel::Thread::current().set_return_rip(interrupt_stack.rip);
}
if (!InterruptController::get().is_in_service(irq))
dprintln("spurious irq 0x{2H}", irq);
else
{
InterruptController::get().eoi(irq);
if (s_irq_handlers[irq])
s_irq_handlers[irq]();
else
dprintln("no handler for irq 0x{2H}\n", irq);
}
Kernel::Scheduler::get().reschedule_if_idling();
ASSERT(Kernel::Thread::current().state() != Kernel::Thread::State::Terminated);
#if __enable_sse
if (from_userspace)
{
ASSERT(Kernel::Thread::current().state() == Kernel::Thread::State::Executing);
Kernel::Thread::current().load_sse();
}
#endif
}
static void flush_idt()
@@ -275,4 +470,14 @@ namespace IDT
flush_idt();
}
[[noreturn]] void force_triple_fault()
{
// load 0 sized IDT and trigger an interrupt to force triple fault
asm volatile("cli");
s_idtr.size = 0;
flush_idt();
asm volatile("int $0x00");
ASSERT_NOT_REACHED();
}
}

View File

@@ -1,195 +0,0 @@
#include <BAN/Errors.h>
#include <kernel/kmalloc.h>
#include <kernel/MMU.h>
#define PAGE_SIZE 0x1000
#define PAGE_MASK ~(PAGE_SIZE - 1)
#define CLEANUP_STRUCTURE(s) \
for (uint64_t i = 0; i < 512; i++) \
if (s[i] & Flags::Present) \
goto cleanup_done; \
kfree(s)
static MMU* s_instance = nullptr;
void MMU::intialize()
{
ASSERT(s_instance == nullptr);
s_instance = new MMU();
}
MMU& MMU::get()
{
ASSERT(s_instance);
return *s_instance;
}
static uint64_t* allocate_page_aligned_page()
{
void* page = kmalloc(PAGE_SIZE, PAGE_SIZE);
ASSERT(page);
memset(page, 0, PAGE_SIZE);
return (uint64_t*)page;
}
MMU::MMU()
{
// Identity map from 4 KiB -> 6 MiB
m_highest_paging_struct = allocate_page_aligned_page();
uint64_t* pdpt = allocate_page_aligned_page();
m_highest_paging_struct[0] = (uint64_t)pdpt | Flags::ReadWrite | Flags::Present;
uint64_t* pd = allocate_page_aligned_page();
pdpt[0] = (uint64_t)pd | Flags::ReadWrite | Flags::Present;
for (uint32_t i = 0; i < 3; i++)
{
uint64_t* pt = allocate_page_aligned_page();
for (uint64_t j = 0; j < 512; j++)
pt[j] = (i << 21) | (j << 12) | Flags::ReadWrite | Flags::Present;
pd[i] = (uint64_t)pt | Flags::ReadWrite | Flags::Present;
}
// Unmap 0 -> 4 KiB
uint64_t* pt1 = (uint64_t*)(pd[0] & PAGE_MASK);
pt1[0] = 0;
// Load the new pml4
asm volatile("movq %0, %%cr3" :: "r"(m_highest_paging_struct));
}
MMU::~MMU()
{
uint64_t* pml4 = m_highest_paging_struct;
for (uint32_t pml4e = 0; pml4e < 512; pml4e++)
{
if (!(pml4[pml4e] & Flags::Present))
continue;
uint64_t* pdpt = (uint64_t*)(pml4[pml4e] & PAGE_MASK);
for (uint32_t pdpte = 0; pdpte < 512; pdpte++)
{
if (!(pdpt[pdpte] & Flags::Present))
continue;
uint64_t* pd = (uint64_t*)(pdpt[pdpte] & PAGE_MASK);
for (uint32_t pde = 0; pde < 512; pde++)
{
if (!(pd[pde] & Flags::Present))
continue;
kfree((void*)(pd[pde] & PAGE_MASK));
}
kfree(pd);
}
kfree(pdpt);
}
kfree(pml4);
}
void MMU::allocate_page(uintptr_t address, uint8_t flags)
{
ASSERT((address >> 48) == 0);
ASSERT(flags & Flags::Present);
bool should_invalidate = false;
address &= PAGE_MASK;
uint64_t pml4e = (address >> 39) & 0x1FF;
uint64_t pdpte = (address >> 30) & 0x1FF;
uint64_t pde = (address >> 21) & 0x1FF;
uint64_t pte = (address >> 12) & 0x1FF;
uint64_t* pml4 = m_highest_paging_struct;
if ((pml4[pml4e] & flags) != flags)
{
if (!(pml4[pml4e] & Flags::Present))
pml4[pml4e] = (uint64_t)allocate_page_aligned_page();
pml4[pml4e] = (pml4[pml4e] & PAGE_MASK) | flags;
should_invalidate = true;
}
uint64_t* pdpt = (uint64_t*)(pml4[pml4e] & PAGE_MASK);
if ((pdpt[pdpte] & flags) != flags)
{
if (!(pdpt[pdpte] & Flags::Present))
pdpt[pdpte] = (uint64_t)allocate_page_aligned_page();
pdpt[pdpte] = (pdpt[pdpte] & PAGE_MASK) | flags;
should_invalidate = true;
}
uint64_t* pd = (uint64_t*)(pdpt[pdpte] & PAGE_MASK);
if ((pd[pde] & flags) != flags)
{
if (!(pd[pde] & Flags::Present))
pd[pde] = (uint64_t)allocate_page_aligned_page();
pd[pde] = (pd[pde] & PAGE_MASK) | flags;
should_invalidate = true;
}
uint64_t* pt = (uint64_t*)(pd[pde] & PAGE_MASK);
if ((pt[pte] & flags) != flags)
{
pt[pte] = address | flags;
should_invalidate = true;
}
if (should_invalidate)
asm volatile("invlpg (%0)" :: "r"(address) : "memory");
}
void MMU::allocate_range(uintptr_t address, ptrdiff_t size, uint8_t flags)
{
uintptr_t s_page = address & PAGE_MASK;
uintptr_t e_page = (address + size - 1) & PAGE_MASK;
for (uintptr_t page = s_page; page <= e_page; page += PAGE_SIZE)
allocate_page(page, flags);
}
void MMU::unallocate_page(uintptr_t address)
{
ASSERT((address >> 48) == 0);
address &= PAGE_MASK;
uint64_t pml4e = (address >> 39) & 0x1FF;
uint64_t pdpte = (address >> 30) & 0x1FF;
uint64_t pde = (address >> 21) & 0x1FF;
uint64_t pte = (address >> 12) & 0x1FF;
uint64_t* pml4 = m_highest_paging_struct;
if (!(pml4[pml4e] & Flags::Present))
return;
uint64_t* pdpt = (uint64_t*)(pml4[pml4e] & PAGE_MASK);
if (!(pdpt[pdpte] & Flags::Present))
return;
uint64_t* pd = (uint64_t*)(pdpt[pdpte] & PAGE_MASK);
if (!(pd[pde] & Flags::Present))
return;
uint64_t* pt = (uint64_t*)(pd[pde] & PAGE_MASK);
if (!(pt[pte] & Flags::Present))
return;
pt[pte] = 0;
CLEANUP_STRUCTURE(pt);
pd[pde] = 0;
CLEANUP_STRUCTURE(pd);
pdpt[pdpte] = 0;
CLEANUP_STRUCTURE(pdpt);
pml4[pml4e] = 0;
cleanup_done:
asm volatile("invlpg (%0)" :: "r"(address) : "memory");
}
void MMU::unallocate_range(uintptr_t address, ptrdiff_t size)
{
uintptr_t s_page = address & PAGE_MASK;
uintptr_t e_page = (address + size - 1) & PAGE_MASK;
for (uintptr_t page = s_page; page <= e_page; page += PAGE_SIZE)
unallocate_page(page);
}

View File

@@ -0,0 +1,625 @@
#include <BAN/Errors.h>
#include <kernel/Arch.h>
#include <kernel/CPUID.h>
#include <kernel/LockGuard.h>
#include <kernel/Memory/kmalloc.h>
#include <kernel/Memory/PageTable.h>
extern uint8_t g_kernel_start[];
extern uint8_t g_kernel_end[];
extern uint8_t g_kernel_execute_start[];
extern uint8_t g_kernel_execute_end[];
extern uint8_t g_userspace_start[];
extern uint8_t g_userspace_end[];
namespace Kernel
{
static PageTable* s_kernel = nullptr;
static PageTable* s_current = nullptr;
static bool s_has_nxe = false;
static bool s_has_pge = false;
// PML4 entry for kernel memory
static paddr_t s_global_pml4e = 0;
static constexpr inline bool is_canonical(uintptr_t addr)
{
constexpr uintptr_t mask = 0xFFFF800000000000;
addr &= mask;
return addr == mask || addr == 0;
}
static constexpr inline uintptr_t uncanonicalize(uintptr_t addr)
{
if (addr & 0x0000800000000000)
return addr & ~0xFFFF000000000000;
return addr;
}
static constexpr inline uintptr_t canonicalize(uintptr_t addr)
{
if (addr & 0x0000800000000000)
return addr | 0xFFFF000000000000;
return addr;
}
static inline PageTable::flags_t parse_flags(uint64_t entry)
{
using Flags = PageTable::Flags;
PageTable::flags_t result = 0;
if (s_has_nxe && !(entry & (1ull << 63)))
result |= Flags::Execute;
if (entry & Flags::Reserved)
result |= Flags::Reserved;
if (entry & Flags::CacheDisable)
result |= Flags::CacheDisable;
if (entry & Flags::UserSupervisor)
result |= Flags::UserSupervisor;
if (entry & Flags::ReadWrite)
result |= Flags::ReadWrite;
if (entry & Flags::Present)
result |= Flags::Present;
return result;
}
void PageTable::initialize()
{
if (CPUID::has_nxe())
{
asm volatile(
"movl $0xC0000080, %ecx;"
"rdmsr;"
"orl $0x800, %eax;"
"wrmsr"
);
s_has_nxe = true;
}
uint32_t ecx, edx;
CPUID::get_features(ecx, edx);
if (edx & CPUID::EDX_PGE)
{
asm volatile(
"movq %cr4, %rax;"
"orq $0x80, %rax;"
"movq %rax, %cr4;"
);
s_has_pge = true;
}
ASSERT(s_kernel == nullptr);
s_kernel = new PageTable();
ASSERT(s_kernel);
s_kernel->initialize_kernel();
s_kernel->load();
}
PageTable& PageTable::kernel()
{
ASSERT(s_kernel);
return *s_kernel;
}
PageTable& PageTable::current()
{
ASSERT(s_current);
return *s_current;
}
bool PageTable::is_valid_pointer(uintptr_t pointer)
{
if (!is_canonical(pointer))
return false;
return true;
}
static uint64_t* allocate_zeroed_page_aligned_page()
{
void* page = kmalloc(PAGE_SIZE, PAGE_SIZE, true);
ASSERT(page);
memset(page, 0, PAGE_SIZE);
return (uint64_t*)page;
}
void PageTable::initialize_kernel()
{
ASSERT(s_global_pml4e == 0);
s_global_pml4e = V2P(allocate_zeroed_page_aligned_page());
m_highest_paging_struct = V2P(allocate_zeroed_page_aligned_page());
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
pml4[511] = s_global_pml4e;
// Map (0 -> phys_kernel_end) to (KERNEL_OFFSET -> virt_kernel_end)
map_range_at(0, KERNEL_OFFSET, (uintptr_t)g_kernel_end - KERNEL_OFFSET, Flags::ReadWrite | Flags::Present);
// Map executable kernel memory as executable
map_range_at(
V2P(g_kernel_execute_start),
(vaddr_t)g_kernel_execute_start,
g_kernel_execute_end - g_kernel_execute_start,
Flags::Execute | Flags::Present
);
// Map userspace memory
map_range_at(
V2P(g_userspace_start),
(vaddr_t)g_userspace_start,
g_userspace_end - g_userspace_start,
Flags::Execute | Flags::UserSupervisor | Flags::Present
);
}
BAN::ErrorOr<PageTable*> PageTable::create_userspace()
{
LockGuard _(s_kernel->m_lock);
PageTable* page_table = new PageTable;
if (page_table == nullptr)
return BAN::Error::from_errno(ENOMEM);
page_table->map_kernel_memory();
return page_table;
}
void PageTable::map_kernel_memory()
{
ASSERT(s_kernel);
ASSERT(s_global_pml4e);
ASSERT(m_highest_paging_struct == 0);
m_highest_paging_struct = V2P(allocate_zeroed_page_aligned_page());
uint64_t* kernel_pml4 = (uint64_t*)P2V(s_kernel->m_highest_paging_struct);
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
pml4[511] = kernel_pml4[511];
}
PageTable::~PageTable()
{
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
// NOTE: we only loop until 511 since the last one is the kernel memory
for (uint64_t pml4e = 0; pml4e < 511; pml4e++)
{
if (!(pml4[pml4e] & Flags::Present))
continue;
uint64_t* pdpt = (uint64_t*)P2V(pml4[pml4e] & PAGE_ADDR_MASK);
for (uint64_t pdpte = 0; pdpte < 512; pdpte++)
{
if (!(pdpt[pdpte] & Flags::Present))
continue;
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
for (uint64_t pde = 0; pde < 512; pde++)
{
if (!(pd[pde] & Flags::Present))
continue;
kfree((void*)P2V(pd[pde] & PAGE_ADDR_MASK));
}
kfree(pd);
}
kfree(pdpt);
}
kfree(pml4);
}
void PageTable::load()
{
asm volatile("movq %0, %%cr3" :: "r"(m_highest_paging_struct));
s_current = this;
}
void PageTable::invalidate(vaddr_t vaddr)
{
ASSERT(vaddr % PAGE_SIZE == 0);
if (this == s_current)
asm volatile("invlpg (%0)" :: "r"(vaddr) : "memory");
}
void PageTable::unmap_page(vaddr_t vaddr)
{
if (vaddr && (vaddr >= KERNEL_OFFSET) != (this == s_kernel))
Kernel::panic("unmapping {8H}, kernel: {}", vaddr, this == s_kernel);
ASSERT(is_canonical(vaddr));
vaddr_t uc_vaddr = uncanonicalize(vaddr);
ASSERT(vaddr % PAGE_SIZE == 0);
uint64_t pml4e = (uc_vaddr >> 39) & 0x1FF;
uint64_t pdpte = (uc_vaddr >> 30) & 0x1FF;
uint64_t pde = (uc_vaddr >> 21) & 0x1FF;
uint64_t pte = (uc_vaddr >> 12) & 0x1FF;
LockGuard _(m_lock);
if (is_page_free(vaddr))
{
dwarnln("unmapping unmapped page {8H}", vaddr);
return;
}
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
uint64_t* pdpt = (uint64_t*)P2V(pml4[pml4e] & PAGE_ADDR_MASK);
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
pt[pte] = 0;
invalidate(vaddr);
}
void PageTable::unmap_range(vaddr_t vaddr, size_t size)
{
vaddr_t s_page = vaddr / PAGE_SIZE;
vaddr_t e_page = BAN::Math::div_round_up<vaddr_t>(vaddr + size, PAGE_SIZE);
LockGuard _(m_lock);
for (vaddr_t page = s_page; page < e_page; page++)
unmap_page(page * PAGE_SIZE);
}
void PageTable::map_page_at(paddr_t paddr, vaddr_t vaddr, flags_t flags)
{
if (vaddr && (vaddr >= KERNEL_OFFSET) != (this == s_kernel))
Kernel::panic("mapping {8H} to {8H}, kernel: {}", paddr, vaddr, this == s_kernel);
ASSERT(is_canonical(vaddr));
vaddr_t uc_vaddr = uncanonicalize(vaddr);
ASSERT(paddr % PAGE_SIZE == 0);
ASSERT(vaddr % PAGE_SIZE == 0);
ASSERT(flags & Flags::Used);
uint64_t pml4e = (uc_vaddr >> 39) & 0x1FF;
uint64_t pdpte = (uc_vaddr >> 30) & 0x1FF;
uint64_t pde = (uc_vaddr >> 21) & 0x1FF;
uint64_t pte = (uc_vaddr >> 12) & 0x1FF;
uint64_t extra_flags = 0;
if (s_has_pge && pml4e == 511) // Map kernel memory as global
extra_flags |= 1ull << 8;
if (s_has_nxe && !(flags & Flags::Execute))
extra_flags |= 1ull << 63;
if (flags & Flags::Reserved)
extra_flags |= Flags::Reserved;
if (flags & Flags::CacheDisable)
extra_flags |= Flags::CacheDisable;
// NOTE: we add present here, since it has to be available in higher level structures
flags_t uwr_flags = (flags & (Flags::UserSupervisor | Flags::ReadWrite)) | Flags::Present;
LockGuard _(m_lock);
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
if ((pml4[pml4e] & uwr_flags) != uwr_flags)
{
if (!(pml4[pml4e] & Flags::Present))
pml4[pml4e] = V2P(allocate_zeroed_page_aligned_page());
pml4[pml4e] |= uwr_flags;
}
uint64_t* pdpt = (uint64_t*)P2V(pml4[pml4e] & PAGE_ADDR_MASK);
if ((pdpt[pdpte] & uwr_flags) != uwr_flags)
{
if (!(pdpt[pdpte] & Flags::Present))
pdpt[pdpte] = V2P(allocate_zeroed_page_aligned_page());
pdpt[pdpte] |= uwr_flags;
}
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
if ((pd[pde] & uwr_flags) != uwr_flags)
{
if (!(pd[pde] & Flags::Present))
pd[pde] = V2P(allocate_zeroed_page_aligned_page());
pd[pde] |= uwr_flags;
}
if (!(flags & Flags::Present))
uwr_flags &= ~Flags::Present;
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
pt[pte] = paddr | uwr_flags | extra_flags;
invalidate(vaddr);
}
void PageTable::map_range_at(paddr_t paddr, vaddr_t vaddr, size_t size, flags_t flags)
{
ASSERT(is_canonical(vaddr));
ASSERT(paddr % PAGE_SIZE == 0);
ASSERT(vaddr % PAGE_SIZE == 0);
size_t first_page = vaddr / PAGE_SIZE;
size_t last_page = (vaddr + size - 1) / PAGE_SIZE;
size_t page_count = last_page - first_page + 1;
LockGuard _(m_lock);
for (size_t page = 0; page < page_count; page++)
map_page_at(paddr + page * PAGE_SIZE, vaddr + page * PAGE_SIZE, flags);
}
uint64_t PageTable::get_page_data(vaddr_t vaddr) const
{
ASSERT(is_canonical(vaddr));
vaddr_t uc_vaddr = uncanonicalize(vaddr);
ASSERT(vaddr % PAGE_SIZE == 0);
uint64_t pml4e = (uc_vaddr >> 39) & 0x1FF;
uint64_t pdpte = (uc_vaddr >> 30) & 0x1FF;
uint64_t pde = (uc_vaddr >> 21) & 0x1FF;
uint64_t pte = (uc_vaddr >> 12) & 0x1FF;
LockGuard _(m_lock);
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
if (!(pml4[pml4e] & Flags::Present))
return 0;
uint64_t* pdpt = (uint64_t*)P2V(pml4[pml4e] & PAGE_ADDR_MASK);
if (!(pdpt[pdpte] & Flags::Present))
return 0;
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
if (!(pd[pde] & Flags::Present))
return 0;
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
if (!(pt[pte] & Flags::Used))
return 0;
return pt[pte];
}
PageTable::flags_t PageTable::get_page_flags(vaddr_t addr) const
{
return parse_flags(get_page_data(addr));
}
paddr_t PageTable::physical_address_of(vaddr_t addr) const
{
uint64_t page_data = get_page_data(addr);
return (page_data & PAGE_ADDR_MASK) & ~(1ull << 63);
}
bool PageTable::reserve_page(vaddr_t vaddr, bool only_free)
{
LockGuard _(m_lock);
ASSERT(vaddr % PAGE_SIZE == 0);
if (only_free && !is_page_free(vaddr))
return false;
map_page_at(0, vaddr, Flags::Reserved);
return true;
}
bool PageTable::reserve_range(vaddr_t vaddr, size_t bytes, bool only_free)
{
if (size_t rem = bytes % PAGE_SIZE)
bytes += PAGE_SIZE - rem;
ASSERT(vaddr % PAGE_SIZE == 0);
LockGuard _(m_lock);
if (only_free && !is_range_free(vaddr, bytes))
return false;
for (size_t offset = 0; offset < bytes; offset += PAGE_SIZE)
reserve_page(vaddr + offset);
return true;
}
vaddr_t PageTable::reserve_free_page(vaddr_t first_address, vaddr_t last_address)
{
if (size_t rem = first_address % PAGE_SIZE)
first_address += PAGE_SIZE - rem;
if (size_t rem = last_address % PAGE_SIZE)
last_address -= rem;
ASSERT(is_canonical(first_address));
ASSERT(is_canonical(last_address));
const vaddr_t uc_vaddr_start = uncanonicalize(first_address);
const vaddr_t uc_vaddr_end = uncanonicalize(last_address);
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;
LockGuard _(m_lock);
// Try to find free page that can be mapped without
// allocations (page table with unused entries)
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
for (; pml4e < 512; pml4e++)
{
if (pml4e > e_pml4e)
break;
if (!(pml4[pml4e] & Flags::Present))
continue;
uint64_t* pdpt = (uint64_t*)P2V(pml4[pml4e] & PAGE_ADDR_MASK);
for (; pdpte < 512; pdpte++)
{
if (pml4e == e_pml4e && pdpte > e_pdpte)
break;
if (!(pdpt[pdpte] & Flags::Present))
continue;
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
for (; pde < 512; pde++)
{
if (pml4e == e_pml4e && pdpte == e_pdpte && pde > e_pde)
break;
if (!(pd[pde] & Flags::Present))
continue;
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
for (; pte < 512; pte++)
{
if (pml4e == e_pml4e && pdpte == e_pdpte && pde == e_pde && pte >= e_pte)
break;
if (!(pt[pte] & Flags::Used))
{
vaddr_t vaddr = 0;
vaddr |= (uint64_t)pml4e << 39;
vaddr |= (uint64_t)pdpte << 30;
vaddr |= (uint64_t)pde << 21;
vaddr |= (uint64_t)pte << 12;
ASSERT(reserve_page(vaddr));
return canonicalize(vaddr);
}
}
}
}
}
// Find any free page
vaddr_t uc_vaddr = uc_vaddr_start;
while (uc_vaddr < uc_vaddr_end)
{
if (vaddr_t vaddr = canonicalize(uc_vaddr); is_page_free(vaddr))
{
ASSERT(reserve_page(vaddr));
return vaddr;
}
uc_vaddr += PAGE_SIZE;
}
ASSERT_NOT_REACHED();
}
vaddr_t PageTable::reserve_free_contiguous_pages(size_t page_count, vaddr_t first_address, vaddr_t last_address)
{
if (size_t rem = first_address % PAGE_SIZE)
first_address += PAGE_SIZE - rem;
if (size_t rem = last_address % PAGE_SIZE)
last_address -= rem;
ASSERT(is_canonical(first_address));
ASSERT(is_canonical(last_address));
LockGuard _(m_lock);
for (vaddr_t vaddr = first_address; vaddr < last_address;)
{
bool valid { true };
for (size_t page = 0; page < page_count; page++)
{
if (!is_canonical(vaddr + page * PAGE_SIZE))
{
vaddr = canonicalize(uncanonicalize(vaddr) + page * PAGE_SIZE);
valid = false;
break;
}
if (!is_page_free(vaddr + page * PAGE_SIZE))
{
vaddr += (page + 1) * PAGE_SIZE;
valid = false;
break;
}
}
if (valid)
{
ASSERT(reserve_range(vaddr, page_count * PAGE_SIZE));
return vaddr;
}
}
ASSERT_NOT_REACHED();
}
bool PageTable::is_page_free(vaddr_t page) const
{
ASSERT(page % PAGE_SIZE == 0);
return !(get_page_flags(page) & Flags::Used);
}
bool PageTable::is_range_free(vaddr_t vaddr, size_t size) const
{
vaddr_t s_page = vaddr / PAGE_SIZE;
vaddr_t e_page = BAN::Math::div_round_up<vaddr_t>(vaddr + size, PAGE_SIZE);
LockGuard _(m_lock);
for (vaddr_t page = s_page; page < e_page; page++)
if (!is_page_free(page * PAGE_SIZE))
return false;
return true;
}
static void dump_range(vaddr_t start, vaddr_t end, PageTable::flags_t flags)
{
if (start == 0)
return;
dprintln("{}-{}: {}{}{}{}",
(void*)canonicalize(start),
(void*)canonicalize(end - 1),
flags & PageTable::Flags::Execute ? 'x' : '-',
flags & PageTable::Flags::UserSupervisor ? 'u' : '-',
flags & PageTable::Flags::ReadWrite ? 'w' : '-',
flags & PageTable::Flags::Present ? 'r' : '-'
);
}
void PageTable::debug_dump()
{
LockGuard _(m_lock);
flags_t flags = 0;
vaddr_t start = 0;
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
for (uint64_t pml4e = 0; pml4e < 512; pml4e++)
{
if (!(pml4[pml4e] & Flags::Present))
{
dump_range(start, (pml4e << 39), flags);
start = 0;
continue;
}
uint64_t* pdpt = (uint64_t*)P2V(pml4[pml4e] & PAGE_ADDR_MASK);
for (uint64_t pdpte = 0; pdpte < 512; pdpte++)
{
if (!(pdpt[pdpte] & Flags::Present))
{
dump_range(start, (pml4e << 39) | (pdpte << 30), flags);
start = 0;
continue;
}
uint64_t* pd = (uint64_t*)P2V(pdpt[pdpte] & PAGE_ADDR_MASK);
for (uint64_t pde = 0; pde < 512; pde++)
{
if (!(pd[pde] & Flags::Present))
{
dump_range(start, (pml4e << 39) | (pdpte << 30) | (pde << 21), flags);
start = 0;
continue;
}
uint64_t* pt = (uint64_t*)P2V(pd[pde] & PAGE_ADDR_MASK);
for (uint64_t pte = 0; pte < 512; pte++)
{
if (parse_flags(pt[pte]) != flags)
{
dump_range(start, (pml4e << 39) | (pdpte << 30) | (pde << 21) | (pte << 12), flags);
start = 0;
}
if (!(pt[pte] & Flags::Used))
continue;
if (start == 0)
{
flags = parse_flags(pt[pte]);
start = (pml4e << 39) | (pdpte << 30) | (pde << 21) | (pte << 12);
}
}
}
}
}
}
}

View File

@@ -0,0 +1,57 @@
.section .userspace, "aw"
#include <sys/syscall.h>
// stack contains
// return address
// signal number
// signal handler
.global signal_trampoline
signal_trampoline:
pushq %rax
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 %r15
// This is 16 byte aligned
movq 128(%rsp), %rdi
movq 120(%rsp), %rax
call *%rax
movq $SYS_SIGNAL_DONE, %rax
movq 128(%rsp), %rbx
int $0x80
popq %r15
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
addq $16, %rsp
// return over red-zone
ret $128

View File

@@ -1,17 +0,0 @@
.global spinlock_lock_asm
spinlock_lock_asm:
lock; btsq $0, (%rdi)
jnc .done
.retry:
pause
testq $1, (%rdi)
jne .retry
lock; btsq $0, (%rdi)
jc .retry
.done:
ret
.global spinlock_unlock_asm
spinlock_unlock_asm:
movl $0, (%rdi)
ret

View File

@@ -23,4 +23,17 @@ start_thread:
continue_thread:
movq %rdi, %rsp
movq $0, %rax
jmp *%rsi
jmp *%rsi
# void thread_userspace_trampoline(uint64_t rsp, uint64_t rip, int argc, char** argv, char** envp)
.global thread_userspace_trampoline
thread_userspace_trampoline:
pushq $0x23
pushq %rdi
pushfq
pushq $0x1B
pushq %rsi
movq %rdx, %rdi
movq %rcx, %rsi
movq %r8, %rdx
iretq

View File

@@ -10,6 +10,9 @@
.set PG_READ_WRITE, 1<<1
.set PG_PAGE_SIZE, 1<<7
#define KERNEL_OFFSET 0xFFFFFFFF80000000
#define V2P(vaddr) ((vaddr) - KERNEL_OFFSET)
.code32
# Multiboot header
@@ -32,34 +35,45 @@
.skip 16384
.global g_boot_stack_top
g_boot_stack_top:
.global g_kernel_cmdline
g_kernel_cmdline:
.skip 4096
# Reserve memory for paging structures,
# we will identity map first 4 MiB
.global g_multiboot_info
g_multiboot_info:
.skip 8
.global g_multiboot_magic
g_multiboot_magic:
.skip 8
# 0 MiB -> 1 MiB: bootloader stuff
# 1 MiB -> 4 MiB: kernel
# 4 MiB -> 5 MiB: kmalloc
# 5 MiB -> 6 MiB: kmalloc_fixed
.align 4096
boot_pml4:
.skip 512 * 8
boot_pdpt1:
.skip 512 * 8
boot_pd1:
.skip 512 * 8
.section .data
.global g_multiboot_info
g_multiboot_info:
.skip 8
.global g_multiboot_magic
g_multiboot_magic:
.skip 8
.section .text
# Map first GiB to 0x00000000 and 0xFFFFFFFF80000000
.align 4096
boot_pml4:
.quad V2P(boot_pdpt_lo) + (PG_READ_WRITE | PG_PRESENT)
.rept 510
.quad 0
.endr
.quad V2P(boot_pdpt_hi) + (PG_READ_WRITE | PG_PRESENT)
boot_pdpt_lo:
.quad V2P(boot_pd) + (PG_READ_WRITE | PG_PRESENT)
.rept 511
.quad 0
.endr
boot_pdpt_hi:
.rept 510
.quad 0
.endr
.quad V2P(boot_pd) + (PG_READ_WRITE | PG_PRESENT)
.quad 0
boot_pd:
.set i, 0
.rept 512
.quad i + (PG_PAGE_SIZE | PG_READ_WRITE | PG_PRESENT)
.set i, i + 0x200000
.endr
boot_gdt:
.quad 0x0000000000000000 # null descriptor
@@ -67,7 +81,9 @@ boot_gdt:
.quad 0x00AF92000000FFFF # kernel data
boot_gdtr:
.short . - boot_gdt - 1
.quad boot_gdt
.quad V2P(boot_gdt)
.section .text
has_cpuid:
pushfl
@@ -106,11 +122,11 @@ check_requirements:
copy_kernel_commandline:
pushl %esi
pushl %edi
movl g_multiboot_info, %esi
movl V2P(g_multiboot_info), %esi
addl $16, %esi
movl (%esi), %esi
movl $1024, %ecx
movl $g_kernel_cmdline, %edi
movl $V2P(g_kernel_cmdline), %edi
rep movsl
popl %edi
popl %esi
@@ -127,15 +143,6 @@ enable_sse:
ret
initialize_paging:
# identity map first 6 MiB
movl $(0x00000000 + PG_PAGE_SIZE + PG_READ_WRITE + PG_PRESENT), boot_pd1 + 0
movl $(0x00200000 + PG_PAGE_SIZE + PG_READ_WRITE + PG_PRESENT), boot_pd1 + 8
movl $(0x00400000 + PG_PAGE_SIZE + PG_READ_WRITE + PG_PRESENT), boot_pd1 + 16
# set pdpte1 and pml4e1
movl $(boot_pd1 + PG_READ_WRITE + PG_PRESENT), boot_pdpt1
movl $(boot_pdpt1 + PG_READ_WRITE + PG_PRESENT), boot_pml4
# enable PAE
movl %cr4, %ecx
orl $0x20, %ecx
@@ -148,7 +155,7 @@ initialize_paging:
wrmsr
# set address of paging structures
movl $boot_pml4, %ecx
movl $V2P(boot_pml4), %ecx
movl %ecx, %cr3
# enable paging
@@ -162,9 +169,9 @@ initialize_paging:
.type _start, @function
_start:
# Initialize stack and multiboot info
movl $g_boot_stack_top, %esp
movl %eax, g_multiboot_magic
movl %ebx, g_multiboot_info
movl $V2P(g_boot_stack_top), %esp
movl %eax, V2P(g_multiboot_magic)
movl %ebx, V2P(g_multiboot_info)
call copy_kernel_commandline
call check_requirements
@@ -173,8 +180,8 @@ _start:
call initialize_paging
# flush gdt and jump to 64 bit
lgdt boot_gdtr
ljmpl $0x08, $long_mode
lgdt V2P(boot_gdtr)
ljmpl $0x08, $V2P(long_mode)
.code64
long_mode:
@@ -188,6 +195,14 @@ long_mode:
movw %ax, %fs
movw %ax, %gs
# jump to higher half
movq $g_boot_stack_top, %rsp
movabsq $higher_half, %rcx
jmp *%rcx
higher_half:
addq $KERNEL_OFFSET, g_multiboot_info
# call global constuctors
call _init

34
kernel/arch/x86_64/crt0.S Normal file
View File

@@ -0,0 +1,34 @@
.section .text
.global _start
_start:
# Set up end of the stack frame linked list.
movq $0, %rbp
pushq %rbp # rip=0
pushq %rbp # rbp=0
movq %rsp, %rbp
# We need those in a moment when we call main.
pushq %rdx
pushq %rsi
pushq %rdi
# Prepare signals, memory allocation, stdio and such.
movq %rdx, %rdi
call _init_libc
# Run the global constructors.
call _init
# Restore argc and argv.
popq %rdi
popq %rsi
popq %rdx
# Run main
call main
# Terminate the process with the exit code.
movl %eax, %edi
call exit
.size _start, . - _start

View File

@@ -64,7 +64,11 @@ isr_stub:
movq 176(%rsp), %rdi
movq 184(%rsp), %rsi
movq %rsp, %rdx
addq $192, %rdx
movq %rsp, %rcx
call cpp_isr_handler
addq $56, %rsp
@@ -75,6 +79,8 @@ isr_stub:
irq_stub:
pushaq
movq 0x78(%rsp), %rdi # irq number
movq %rsp, %rsi
addq $136, %rsi
call cpp_irq_handler
popaq
addq $16, %rsp
@@ -83,7 +89,6 @@ irq_stub:
.macro isr n
.global isr\n
isr\n:
cli
pushq $0
pushq $\n
jmp isr_stub
@@ -92,7 +97,6 @@ irq_stub:
.macro isr_err n
.global isr\n
isr\n:
cli
pushq $\n
jmp isr_stub
.endm
@@ -100,7 +104,6 @@ irq_stub:
.macro irq n
.global irq\n
irq\n:
cli
pushq $0
pushq $\n
jmp irq_stub
@@ -156,14 +159,21 @@ irq 13
irq 14
irq 15
// arguments in RAX, RBX, RCX, RDX, RSI, RDI
// System V ABI: RDI, RSI, RDX, RCX, R8, R9
.global syscall_asm
syscall_asm:
cli
pushaq
movq %rsi, %r8
movq %rdi, %r9
movq %rax, %rdi
movq %rbx, %rsi
xchgq %rcx, %rdx
movq %rsp, %rbx
addq $120, %rbx
pushq %rbx
call cpp_syscall_handler
addq $8, %rsp
popaq_no_rax
addq $8, %rsp
iretq

View File

@@ -1,38 +1,37 @@
ENTRY (_start)
KERNEL_OFFSET = 0xFFFFFFFF80000000;
SECTIONS
{
. = 0x00100000;
. = 0x00100000 + KERNEL_OFFSET;
.text BLOCK(4K) : ALIGN(4K)
g_kernel_start = .;
.text ALIGN(4K) : AT(ADDR(.text) - KERNEL_OFFSET)
{
g_kernel_execute_start = .;
*(.multiboot)
*(.text)
*(.text.*)
}
.rodata BLOCK(4K) : ALIGN(4K)
.userspace ALIGN(4K) : AT(ADDR(.userspace) - KERNEL_OFFSET)
{
g_rodata_start = .;
*(.rodata.*)
g_rodata_end = .;
g_userspace_start = .;
*(.userspace)
g_userspace_end = .;
}
.data BLOCK(4K) : ALIGN(4K)
.rodata ALIGN(4K) : AT(ADDR(.rodata) - KERNEL_OFFSET)
{
*(.rodata.*)
g_kernel_execute_end = .;
}
.data ALIGN(4K) : AT(ADDR(.data) - KERNEL_OFFSET)
{
*(.data)
}
.bss BLOCK(4K) : ALIGN(4K)
.bss ALIGN(4K) : AT(ADDR(.bss) - KERNEL_OFFSET)
{
*(COMMON)
*(.bss)
}
g_kernel_end = .;
. = 0x00A00000;
g_userspace_start = .;
.userspace BLOCK(4K) : ALIGN(4K)
{
*(.userspace)
}
g_userspace_end = .;
}

View File

@@ -1,16 +0,0 @@
KERNEL_ARCH_CFLAGS=-mcmodel=large -mno-red-zone -mno-mmx
KERNEL_ARCH_CPPFLAGS=
KERNEL_ARCH_LDFLAGS=-z max-page-size=4096
KERNEL_ARCH_LIBS=
ELF_FORMAT=elf64-x86-64
KERNEL_ARCH_OBJS= \
$(ARCHDIR)/boot.o \
$(ARCHDIR)/GDT.o \
$(ARCHDIR)/IDT.o \
$(ARCHDIR)/interrupts.o \
$(ARCHDIR)/MMU.o \
$(ARCHDIR)/SpinLock.o \
$(ARCHDIR)/Thread.o \

View File

@@ -104,7 +104,7 @@ void __cxa_finalize(void *f)
**/
(*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr);
__atexit_funcs[i].destructor_func = 0;
/*
* Notice that we didn't decrement __atexit_func_count: this is because this algorithm
* requires patching to deal with the FIXME outlined above.
@@ -113,8 +113,6 @@ void __cxa_finalize(void *f)
};
};
namespace __cxxabiv1
{
/* guard variables */
@@ -122,19 +120,19 @@ namespace __cxxabiv1
/* The ABI requires a 64-bit type. */
__extension__ typedef int __guard __attribute__((mode(__DI__)));
int __cxa_guard_acquire (__guard* g)
{
Kernel::LockGuard lock_guard(s_spin_lock);
return !*(int*)g;
}
void __cxa_guard_release (__guard* g)
{
Kernel::LockGuard lock_guard(s_spin_lock);
*(int*)g = 1;
}
void __cxa_guard_abort (__guard*)
{
Kernel::panic("__cxa_guard_abort");

View File

@@ -0,0 +1,144 @@
#pragma once
#include <BAN/Vector.h>
#include <kernel/Memory/Types.h>
namespace Kernel
{
class ACPI
{
public:
struct GAS
{
uint8_t address_space_id;
uint8_t register_bit_width;
uint8_t register_bit_offset;
uint8_t access_size;
uint64_t address;
} __attribute__((packed));
struct SDTHeader
{
uint8_t signature[4];
uint32_t length;
uint8_t revision;
uint8_t checksum;
uint8_t oemid[6];
uint64_t oem_table_id;
uint32_t oem_revision;
uint32_t creator_id;
uint32_t creator_revision;
} __attribute__((packed));
struct FADT : public SDTHeader
{
uint32_t firmware_ctrl;
uint32_t dsdt;
uint8_t __reserved;
uint8_t preferred_pm_profile;
uint16_t sci_int;
uint32_t smi_cmd;
uint8_t acpi_enable;
uint8_t acpi_disable;
uint8_t s4bios_req;
uint8_t pstate_cnt;
uint32_t pm1a_evt_blk;
uint32_t pm1b_evt_blk;
uint32_t pm1a_cnt_blk;
uint32_t pm1b_cnt_blk;
uint32_t pm2_cnt_blk;
uint32_t pm_tmr_blk;
uint32_t gpe0_blk;
uint32_t gpe1_blk;
uint8_t pm1_evt_len;
uint8_t pm1_cnt_len;
uint8_t pm2_cnt_len;
uint8_t pm_tmr_len;
uint8_t gpe0_blk_len;
uint8_t gpe1_blk_len;
uint8_t gpe1_base;
uint8_t cst_cnt;
uint16_t p_lvl2_lat;
uint16_t p_lvl3_lat;
uint16_t flush_size;
uint16_t flush_stride;
uint8_t duty_offset;
uint8_t duty_width;
uint8_t day_alrm;
uint8_t mon_alrm;
uint8_t century;
uint16_t iapc_boot_arch;
uint8_t __reserved2;
uint32_t flags;
uint8_t reset_reg[12];
uint8_t reset_value;
uint16_t arm_boot_arch;
uint8_t fadt_minor_version;
uint64_t x_firmware_version;
uint64_t x_dsdt;
uint8_t x_pm1a_evt_blk[12];
uint8_t x_pm1b_evt_blk[12];
uint8_t x_pm1a_cnt_blk[12];
uint8_t x_pm1b_cnt_blk[12];
uint8_t x_pm2_cnt_blk[12];
uint8_t x_pm_tmr_blk[12];
uint8_t x_gpe0_blk[12];
uint8_t x_gpe1_blk[12];
uint8_t sleep_control_reg[12];
uint8_t sleep_status_reg[12];
uint64_t hypervison_vendor_identity;
} __attribute__((packed));
struct HPET : public SDTHeader
{
uint8_t hardware_rev_id;
uint8_t comparator_count : 5;
uint8_t count_size_cap : 1;
uint8_t reserved : 1;
uint8_t legacy_replacement_irq_routing_cable : 1;
uint16_t pci_vendor_id;
GAS base_address;
uint8_t hpet_number;
uint16_t main_counter_minimum_clock_tick;
uint8_t page_protection_and_oem_attribute;
} __attribute__((packed));
public:
static BAN::ErrorOr<void> initialize();
static ACPI& get();
const SDTHeader* get_header(const char[4]);
private:
ACPI() = default;
BAN::ErrorOr<void> initialize_impl();
private:
paddr_t m_header_table_paddr = 0;
vaddr_t m_header_table_vaddr = 0;
uint32_t m_entry_size = 0;
struct MappedPage
{
Kernel::paddr_t paddr;
Kernel::vaddr_t vaddr;
SDTHeader* as_header() { return (SDTHeader*)vaddr; }
};
BAN::Vector<MappedPage> m_mapped_headers;
};
}
namespace BAN::Formatter
{
template<typename F>
void print_argument(F putc, const Kernel::ACPI::SDTHeader& header, const ValueFormat& format)
{
putc(header.signature[0]);
putc(header.signature[1]);
putc(header.signature[2]);
putc(header.signature[3]);
}
}

View File

@@ -0,0 +1,21 @@
#pragma once
#include <dirent.h>
namespace Kernel::API
{
struct DirectoryEntry
{
size_t rec_len { 0 };
struct dirent dirent;
DirectoryEntry* next() const { return (DirectoryEntry*)((uintptr_t)this + rec_len); }
};
struct DirectoryEntryList
{
size_t entry_count { 0 };
DirectoryEntry array[];
};
}

View File

@@ -2,6 +2,7 @@
#include <BAN/Vector.h>
#include <kernel/InterruptController.h>
#include <kernel/Memory/Types.h>
class APIC final : public InterruptController
{
@@ -15,6 +16,7 @@ private:
void write_to_local_apic(ptrdiff_t, uint32_t);
private:
~APIC() { ASSERT_NOT_REACHED(); }
static APIC* create();
friend class InterruptController;
@@ -34,7 +36,8 @@ private:
struct IOAPIC
{
uint8_t id;
uintptr_t address;
Kernel::paddr_t paddr;
Kernel::vaddr_t vaddr;
uint32_t gsi_base;
uint8_t max_redirs;
@@ -44,7 +47,8 @@ private:
private:
BAN::Vector<Processor> m_processors;
uintptr_t m_local_apic = 0;
Kernel::paddr_t m_local_apic_paddr = 0;
Kernel::vaddr_t m_local_apic_vaddr = 0;
BAN::Vector<IOAPIC> m_io_apics;
uint8_t m_irq_overrides[0x100] {};
};

View File

@@ -17,4 +17,12 @@
#define read_rsp(rsp) asm volatile("movl %%esp, %0" : "=r"(rsp))
#define push_callee_saved() asm volatile("pushal")
#define pop_callee_saved() asm volatile("popal")
#endif
#endif
#include <stdint.h>
#ifdef __cplusplus
extern "C" uintptr_t read_rip();
#else
extern uintptr_t read_rip();
#endif

View File

@@ -73,9 +73,10 @@ namespace CPUID
const char* feature_string_ecx(uint32_t feat);
const char* feature_string_edx(uint32_t feat);
const char* get_vendor();
void get_features(uint32_t& ecx, uint32_t& edx);
bool is_64_bit();
bool has_nxe();
}

View File

@@ -0,0 +1,50 @@
#pragma once
#include <sys/types.h>
namespace Kernel
{
class Credentials
{
public:
Credentials(uid_t ruid, uid_t euid, gid_t rgid, gid_t egid)
: m_ruid(ruid), m_euid(euid), m_suid(0)
, m_rgid(rgid), m_egid(egid), m_sgid(0)
{ }
uid_t ruid() const { return m_ruid; }
uid_t euid() const { return m_euid; }
uid_t suid() const { return m_suid; }
gid_t rgid() const { return m_rgid; }
gid_t egid() const { return m_egid; }
gid_t sgid() const { return m_sgid; }
void set_ruid(uid_t uid) { m_ruid = uid; }
void set_euid(uid_t uid) { m_euid = uid; }
void set_suid(uid_t uid) { m_suid = uid; }
void set_rgid(gid_t gid) { m_rgid = gid; }
void set_egid(gid_t gid) { m_egid = gid; }
void set_sgid(gid_t gid) { m_sgid = gid; }
bool is_superuser() const { return m_euid == 0; }
private:
uid_t m_ruid, m_euid, m_suid;
gid_t m_rgid, m_egid, m_sgid;
};
}
namespace BAN::Formatter
{
template<typename F>
void print_argument(F putc, const Kernel::Credentials& credentials, const ValueFormat&)
{
print(putc, "(ruid {}, euid {})", credentials.ruid(), credentials.euid());
}
}

View File

@@ -11,7 +11,7 @@ namespace Kernel
{
BAN_NON_COPYABLE(CriticalScope);
BAN_NON_MOVABLE(CriticalScope);
public:
CriticalScope()
{

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