Compare commits

..

885 Commits
main ... main

Author SHA1 Message Date
Sinipelto 46a31b8efa Merge pull request 'update main 21.11.23' (#2) from Bananymous/banan-os:main into main
Reviewed-on: Sinipelto/banan-os#2
2023-11-21 14:58:13 +02:00
Bananymous 85a5e81224 BuildSystem: Check value of BANAN_UEFI_BOOT with `if ((...)); then` 2023-11-21 14:58:13 +02:00
Bananymous 7d4cdcd1fd BuildSystem: Add missing bootloader install script 2023-11-21 14:58:13 +02:00
Sinipelto d72db1f81c BuildSystem: image sh
mount in build dir

Signed-off-by: Sinipelto <sinipelto@noreply.bananymous.com>
2023-11-20 14:12:35 +02:00
Sinipelto 6cfa56dcec BuildSystem: image create sh
use banan build dir

Signed-off-by: Sinipelto <sinipelto@noreply.bananymous.com>
2023-11-20 14:11:29 +02:00
Sinipelto f97922a2b5 Update script/image.sh
mount dir default value

Signed-off-by: Sinipelto <sinipelto@noreply.bananymous.com>
2023-11-20 13:28:53 +02:00
Sinipelto 566724d986 Update script/image-create.sh
custom mount dir

Signed-off-by: Sinipelto <sinipelto@noreply.bananymous.com>
2023-11-20 13:28:10 +02:00
Sinipelto a7b1810aa2 Update script/image.sh
handle custom mount dir

Signed-off-by: Sinipelto <sinipelto@noreply.bananymous.com>
2023-11-20 13:24:15 +02:00
Sinipelto a6a5c00763 Merge pull request 'update main' (#1) from Bananymous/banan-os:main into main
Reviewed-on: Sinipelto/banan-os#1
2023-11-20 13:20:51 +02:00
Bananymous f2397b775c BuildSystem: Remove old bootloader target
And creating image now builds the bootloader
2023-11-20 00:56:06 +02:00
Bananymous 8b81406b81 Toolchain: Build full toolchain with one call to toolchain/build.sh 2023-11-20 00:56:06 +02:00
Bananymous e2515c1109 Buildsystem: default bootloader is not my custom one
You can set BANAN_BOOTLOADER=GRUB to use grub instead. Image creation
does not convert disk image now automatically between bootloaders and
calling ./bos image-full is now required.
2023-11-18 17:18:03 +02:00
Bananymous 5293ae070d Kernel: ProcFS inodes reflect processes ruid/rgid
setgid/setuid did not change the permissions of procfs inodes. This
made Shell launched by init not appear in meminfo.
2023-11-18 14:26:44 +02:00
Bananymous 6e2443ca72 Bootloader do some directory restructuring 2023-11-18 13:59:45 +02:00
Bananymous a312d75bb2 Bootloader: Implement VESA video mode query and pass it to kernel
Kernel now gets framebuffer from bootloader. Framebuffer dimensions
and bpp are hardcoded in bootloader, but will probably be read from
config file at some point.
2023-11-17 22:45:35 +02:00
Bananymous a554bd0fd8 Bootloader: Fix kernel memset to zero 2023-11-17 21:05:02 +02:00
Bananymous f0d2a211ea Bootloader add temporary initial command line
This will probably be read from some config file at some point
2023-11-17 20:38:38 +02:00
Bananymous 065eec430e Kernel/Bootloader: banan-os can now be booted with my bootloader :D 2023-11-17 20:33:02 +02:00
Bananymous 5f4d81a502 Bootloader: Clear screen, better memcpy
Clear screen before jumping to kernel. Memcpy now uses ebx as offset
register, so only one register has to updated every loop
2023-11-17 20:31:42 +02:00
Bananymous 41065d2f9a Kernel: Don't calculate divisor in a for loop in ext2 inodes 2023-11-17 19:02:01 +02:00
Bananymous 3daf3d53a3 Kernel: Serial now uses random size for some serial ports
If the serial port doesn't repond with a size, just use a random
one. There is no reason to ditch the whole output if you cannot
determine its size.
2023-11-17 18:56:02 +02:00
Bananymous ec56e9c6f1 Kernel: Don't use multiboot2 explicitly. Parse it to common structure
This allows support of multiple different bootloaders
2023-11-17 18:54:59 +02:00
Bananymous 07ae1bbf34 Bootloader: Load kernel to memory and jump to it! 2023-11-17 16:36:29 +02:00
Bananymous 03b80ed113 Bootloader enter unreal mode at the start of stage2 2023-11-17 14:22:21 +02:00
Bananymous 407a7b80c5 Bootloader: Fix getting command line 2023-11-17 13:17:44 +02:00
Bananymous 8b4f169d0f Bootloader: implement reading from inode 2023-11-17 13:17:44 +02:00
Bananymous 6f9b3ab5de Bootloader: add support for indirect inode blocks 2023-11-16 13:34:21 +02:00
Bananymous aa7a8124ce Bootloader: Add helpers for printing n bit hexadecimal numbers 2023-11-16 13:30:01 +02:00
Bananymous a9412aa741 Bootloader: Implement basic ext2 filesystem
This can search for files in an ext2 filesystem. Only 12 blocks
are currently supported.

Now only ELF loading is missing for loading the actual kernel!
2023-11-15 16:58:26 +02:00
Bananymous 8aab3a62cc Bootloader: Build with cmake instead of custom script 2023-11-14 03:44:47 +02:00
Bananymous b0b39c56ba Bootloader: Split bootloader into multiple files
This cleans up the code since bootloader is starting to near 1k lines
2023-11-14 03:27:52 +02:00
Bananymous 055b1a2a1a Bootloader move bootloader code from arch directory
The os itself only supports x86 so this won't matter. x86_64 and i386
use the same bootloader assembly.
2023-11-13 21:42:58 +02:00
Bananymous d99ef11e48 Bootloader: installer now uses banan os elf headers intead of Linux's 2023-11-13 21:40:15 +02:00
Bananymous 732eb9da41 fixup 2023-11-13 21:39:48 +02:00
Bananymous 8faad47843 LibELF: Remove 2 32 bit types that don't exist 2023-11-13 21:39:39 +02:00
Bananymous aa4f3046ff Bootloader: Find root partition from GPT header 2023-11-13 18:55:48 +02:00
Bananymous b4775fbe75 Bootloader: installer now patches GPT GUID's 2023-11-13 18:53:55 +02:00
Bananymous 8a5753b0fe Bootloader: Add API to create GUID from string 2023-11-13 18:52:41 +02:00
Bananymous 1a75262b04 BuildSystem: add bootloader target
Use this target to run banan-os with custom bootloader
2023-11-12 01:50:30 +02:00
Bananymous 39801e51da BuildSystem: add proper clean target 2023-11-12 01:14:42 +02:00
Bananymous 6e3f176457 ls: print link targets when listing files 2023-11-11 23:17:18 +02:00
Bananymous 447da99f0b Kernel/LibC: Implement readlink and readlinkat 2023-11-11 23:16:52 +02:00
Bananymous a3a287f5ca Bootloader: Continue work on bootloader
Bootloader can now get the memory map and read cmdline from user.

Now 'just' video mode query, ext2 and ELF parsing are needed :D
2023-11-11 22:49:00 +02:00
Bananymous c47f6a78bc Bootloader: Start work on bootloader
I wrote a fast first stage bootloader and a installer to put it into
a disk image.
2023-11-09 22:42:47 +02:00
Bananymous 430a006acf Toolchain: Fix typo when setting make flags
I defaultet MAKEFLAGS to -j which will launch processes in parallel
without any limit.
2023-11-09 21:57:45 +02:00
Bananymous 845ed66e5e Toolchain: add em=gnu to gas. This allows using / in expressions 2023-11-09 21:43:13 +02:00
Bananymous 2191ca46bb Kernel: Make TmpFS enforce max page count. 2023-11-07 16:13:21 +02:00
Bananymous cec04a2858 Kernel: Remove now obsolete RamFS
Everything is using now the better TmpFS which uses physical pages
for page allocation instead of the static kmalloc memory.
2023-11-07 16:07:11 +02:00
Bananymous b87351f6d5 Kernel: Make DevFS use the new and better TmpFS instead of RamFS 2023-11-07 16:05:05 +02:00
Bananymous 464737fbe9 Kernel: Add method to TmpFS for looping over all (cached) inodes 2023-11-07 16:04:34 +02:00
Bananymous 8b4f661acb Kernel: Lock TmpFS in all its methods 2023-11-07 16:03:52 +02:00
Bananymous 27963febc0 Kernel: Implement symlinks to TmpFS 2023-11-07 15:59:50 +02:00
Bananymous 6d4b684219 Kernel: Make PS/2 keyboard wait until interrupts are enabled 2023-11-07 15:58:50 +02:00
Bananymous 670c787af3 BuildSystem: Fix temporary sysroot creation in toolchain compilation 2023-11-07 14:16:49 +02:00
Bananymous a0fbf18d3b meminfo: better format for files without permissions 2023-11-07 02:41:01 +02:00
Bananymous 1acc0abf2e Kernel: Make unlinking from /proc always fail with EPERM 2023-11-07 02:40:27 +02:00
Bananymous c20f773c5d Kernel: /tmp is now TmpFS instead of RamFS 2023-11-07 02:36:22 +02:00
Bananymous a46b2f43d9 Kernel: Make ProcFS use the new TmpFS internally 2023-11-07 02:35:44 +02:00
Bananymous a20f8607de Kernel: Implement TmpFS Inode unlinking and deletion 2023-11-06 21:49:12 +02:00
Bananymous af330f7b8e Kernel: TmpFS directory inodes now iterate over only valid entries 2023-11-06 21:41:51 +02:00
Bananymous e33b3bcdff Kernel: Fix TmpFS directory entry enumeration early return 2023-11-06 21:06:10 +02:00
Bananymous 181d139c7d Kernel: Fix ext2 directory listing for big directories 2023-11-06 21:05:58 +02:00
Bananymous 639fd8804c Kernel: Implement TmpFS directory listing 2023-11-06 21:05:58 +02:00
Bananymous cbb2c37e00 Kernel: Implement TmpFS inode chmod 2023-11-06 20:11:34 +02:00
Bananymous ab4f033385 Kernel: Cleanup TmpFS code and block access doesn't require allocs
TmpFS blocks are now accessed with a simple wrapper
2023-11-06 20:07:09 +02:00
Bananymous 1ed08f62d3 Kernel: TmpInode blocks are on demand allocated 2023-11-06 10:44:37 +02:00
Bananymous 8164c15b6c Kernel: Implement read/write/truncate for TmpFileInode 2023-11-05 02:28:43 +02:00
Bananymous f9bf47ab30 Kernel: Start work on proper TmpFS in Heap instead of kmalloc memory 2023-11-04 18:18:45 +02:00
Bananymous e5ffadb109 Kernel: Add better APIs for fast page 2023-11-04 18:13:16 +02:00
Bananymous 061d10e635 BAN: Update bytespan -> span API 2023-11-04 18:12:46 +02:00
Bananymous 6d899aa6ce BuildSystem: using sysroot doesn't need root privileges anymore!
Sysroot is now created with fakeroot. This allows root access to be
only needed for disk image creation, since it uses loopback devices.
2023-11-04 17:50:43 +02:00
Bananymous 120f7329b1 BAN: Update ASSERT api
its now much harder to mix < with <= and > with >=
2023-11-02 00:01:12 +02:00
Bananymous 4f25c20c97 Kernel: Canonicalize vaddr before using it 2023-10-30 19:20:17 +02:00
Bananymous 5e396851f4 Kernel: Remove unused externs in kernel.cpp 2023-10-30 19:09:31 +02:00
Bananymous a44482639d Kernel: Temporarily force FileBackedRegion mappings writable
Now that write-protect bit is enabled this is neccessary.
2023-10-30 19:08:33 +02:00
Bananymous 3bac19e518 Kernel: Add fast page to page table
Add "fast page" to KERNEL_OFFSET. This is always present in page
tables and only requires changing the page table entry to map. This
requires no interrupts since it should only be for very operations
like memcpy.

I used to map all temporary mappings to vaddr 0, but this is much
better. C++ standard always says that nullptr access is undefined
and this gets rid of it.

Fixed some bugs I found along the way
2023-10-30 19:02:09 +02:00
Bananymous 4dbe15aa0e Kernel: Remove GeneralAllocator since it was not used 2023-10-30 18:13:17 +02:00
Bananymous 1c5985148c Kernel: Allow offsetof with packed fields
This is not standard C++ but should be fine with my toolchain.
2023-10-30 17:51:18 +02:00
Bananymous ce2461d0e8 Kernel: panic takes arguments as rvalue references 2023-10-30 16:22:02 +02:00
Bananymous 4e785a133c Kernel: Fix ext2 small link deallocation
Also fix deallocation bug
2023-10-30 16:22:02 +02:00
Bananymous 26c7aee327 Kernel: only map kernel from g_kernel_start onwards 2023-10-30 16:22:02 +02:00
Bananymous 0405461742 BAN: Implement better ASSERT macros
Implement macros for all basic binary ops. These macros print failed
values when the fail.
2023-10-30 16:22:02 +02:00
Bananymous 8a10853ba7 Kernel: Enable Write Protect. This seems to be good for security 2023-10-30 12:23:22 +02:00
Bananymous 5d34cebeca Kernel: Fix stack OOB detection
I now check both interrupt and normal stack to detect OOB. Processes
are killed if they encouner stack over/under flow.
2023-10-30 12:17:08 +02:00
Bananymous 3d899d2e44 Kernel/LibELF: Map pages always as RW so kernel can write to them
Kernel doesn't seem to require W permissions to a page without UEFI
so this had not been found earlier.
2023-10-30 12:14:12 +02:00
Bananymous f72fdeeb59 BAN: String now uses union for its sso storage
This allows String to shrink by 8 bytes since Variant's 8 index is
no longer stored in here.

This required me to make Strings max size one bit less, but that
should still be fine. There should never be strings with size of
over half of the computer's address space.
2023-10-30 11:13:16 +02:00
Bananymous 382f9d9bb3 Userspace: Add quick test for global ctors and dtors 2023-10-30 11:11:10 +02:00
Bananymous bc1d1bf919 LibC: implement and call __cxa_finalize() on exit()
This allows global destructors to be actually called
2023-10-30 11:10:08 +02:00
Bananymous f05b9a6877 Kernel/LibC: Add crt* files to LibC and remove crt0 from kernel
There was no reason for libc get crt0 from kernel.
2023-10-30 11:06:13 +02:00
Bananymous ea5ed3001e Toolchain: Clone GCC and Binutils from git
This feels much cleaner than just downloading tar balls from
pregiven urls. Also patching works much better like this!

I added --disable-initfini-array since global constructors were
not called.
2023-10-30 11:02:57 +02:00
Bananymous f312c3a4d7 Kernel: Fix ACPI DSDT address
Read x_dsdt address only if fadt's length contains it. Bochs seems
to have version 1 fadt without the x_* fields.
2023-10-29 21:35:11 +02:00
Bananymous 1af3ca19ab BAN: Rewrite String with small string optimizations
String now holds a 15 byte sso buffer. I'm not sure what the size
should actually be but 15 will work for now. Maybe the sso buffer
should be contained in an union with one bit flag in size instead of
variant that uses extra 8 bytes for type index.

This patch buffs sizeof(String) from 24 bytes to 32 bytes on 64 bit.
I assume this is much better version than the old which had to make
allocation even for empty strings :D.
2023-10-29 03:11:13 +03:00
Bananymous 09fcc613c7 BAN: Add variant to ForwardList
I should be using the forward list more
2023-10-29 02:28:55 +03:00
Bananymous 3940f53231 BuildSystem: Add bos short hand for building with zsh completions :) 2023-10-28 22:23:29 +03:00
Bananymous 0757834176 Kernel: Rewrite a lot of ext2 code
This commit consists of multiple big changes

1. blocks for inodes are now allocated on demand
  - reading from non allocated block will just return zeroes
  - writing to non allocated block allocates it

2. code doesn't really use raw pointers anymore
  - all casts to uint32_t or structures are now replaced with
    spans. either as<T> or as_span<T> which both are bounds
	checked

3. code doesn't depend on random macros for accessing indirect blocks
  - i added some recursive functions which take care of this :)
2023-10-28 22:13:28 +03:00
Bananymous 3bffbe330d BAN: Update ByteSpan API
Add ByteSpan::as_span<T> and const versions of as() and as_span()
require T to be const.
2023-10-28 22:10:47 +03:00
Bananymous 8d583c8b67 Kernel: Fix ext2 inode block allocation with triply indirect blocks 2023-10-28 16:53:00 +03:00
Bananymous 99bde9aa49 Kernel: Fix ext2 inode deletion cleanup
I now cleanup all blocks (including direct) in i_block array
2023-10-28 16:52:56 +03:00
Bananymous 98d702ac60 All: Remove read only from ext2 filesystem :) 2023-10-26 13:26:10 +03:00
Bananymous 1ec341e2dd rm: add option to remove recursively 2023-10-26 02:32:49 +03:00
Bananymous d09310f388 Kernel: Fix ext2 inode deletion
fsck now reports clean filesystem even after deleting files
2023-10-26 02:05:05 +03:00
Bananymous 126edea119 Userspace: implement basic rm command 2023-10-25 21:45:27 +03:00
Bananymous 74bfb930f2 Kernel/LibC: Add syscall and wrapper for unlink 2023-10-25 21:45:04 +03:00
Bananymous 091c5b6a66 BAN: Implement Ext2 file unlinking
Ext2 inodes can now be unlinked from directories and after last
inode closes (destructor gets called) we check if link count is 0
and cleanup the inode from filesystem
2023-10-25 21:43:36 +03:00
Bananymous fda4a4ad24 BAN: ByteSpan can be sliced without specified size
This will give span with all remaining size after offset
2023-10-25 21:41:11 +03:00
Bananymous 8bb47aee02 Kernel/LibC/Userspace: Implement mkdir and creat
Touch now uses creat insteadd of open with O_CREAT flag
2023-10-25 21:07:26 +03:00
Bananymous 1f794e4ac0 Kernel: Implement directory creation for RamFS 2023-10-25 19:41:34 +03:00
Bananymous e85f9ac6a1 Kernel: Implement Ext2 directory creation 2023-10-25 19:37:04 +03:00
Bananymous 6ee5576dcc Kernel: Add Inode API for creating directories 2023-10-25 19:36:04 +03:00
Bananymous b890e2fc14 Kernel: Ext2FS now uses Ext2Inodes as cached values 2023-10-25 19:34:00 +03:00
Bananymous 4f4b8ada8c Kernel: Fix read offset of RamFileInode 2023-10-25 02:53:20 +03:00
Bananymous 9e4adc1264 cp: abort copy if write fails 2023-10-25 02:43:02 +03:00
Bananymous 7a54a088b4 Userspace: Add basic chmod command 2023-10-25 02:37:19 +03:00
Bananymous 15bb1804ef Kernel/LibC: implement chmod syscall + libc wrapper 2023-10-25 02:35:37 +03:00
Bananymous e8890062d6 Userspace: Implement basic cp
This does not support any meaningful command line arguments but
is a good start.
2023-10-25 00:07:25 +03:00
Bananymous 1e2c2fb973 Shell: Set get old termios earlier
I sourced the config file before getting old termios. Sourcing
updated the termios so old_termios was always in non canonical, non
echoing mode.
2023-10-24 19:10:53 +03:00
Bananymous 988a4e1cd8 BAN: Fix bug of size of splice after slice()
I have no idea what was I doing before :D
2023-10-24 17:23:45 +03:00
Bananymous adbbdf73c4 meminfo: fix g++ warning for oob write
g++ doesn't realize that read can only return -1
2023-10-24 16:50:21 +03:00
Bananymous e8d20bc653 BuildSystem: Fix bugs in new build system
I had not tested the new build system with clean toolchain build
but it seems to work now.
2023-10-24 16:48:46 +03:00
Bananymous 00ee86920a Kernel: Add timeout to ACHI commands
ACHI commands can now fail from timeouts.
2023-10-24 11:56:25 +03:00
Bananymous 51ad27ea3c BuildSystem: Match README.md with the new buildsystem 2023-10-24 11:56:00 +03:00
Bananymous df69612bb1 BuildSystem: Rewrite whole build system structure
Now you have to use script/build.sh for building and running banan-os
2023-10-24 11:56:00 +03:00
Bananymous 5bfeb9f3ca Kernel: Rewrite all read/write functions to use BAN::ByteSpan
This allows us to not work with raw pointers and use sized containers
for reading and writing.
2023-10-24 11:56:00 +03:00
Bananymous db5c24b2a5 BAN: Implement ByteSpan
This is a span over exisiting containers/data types. I'm not too
happy with the constructors and assignment operators, but they will
work for now
2023-10-20 04:59:29 +03:00
Bananymous 781c950af6 BAN: add helper to cast Span<T> to Span<const T> 2023-10-20 04:59:08 +03:00
Bananymous e2e5c31d54 Kernel: Map multiboot2 memory in PageTable initialization
It cannot be assumed that multiboot data lies between kernel_end
and 2 GiB mark, so I properly allocate virtual address space for it.
2023-10-17 01:15:08 +03:00
Bananymous be3efb0b92 Kernel: Start using multiboot2 instead of multiboot
This allows better compatibility with (U)EFI and gives RSDP location
instead of me having to scan ram to find it.
2023-10-17 01:06:24 +03:00
Bananymous 792bb2df1c Kernel: TTY doesn't panic if it doesn't find input device 2023-10-16 16:58:39 +03:00
Bananymous e01928d186 Kernel: Fix device identification with all bits as ones
If device identification sends all ones, don't initialize the device.
2023-10-16 16:57:07 +03:00
Bananymous 48980b56ab Kernel: ATABuses are but to compatibility mode if possible
I don't support native mode ata bus (irq sharing) so ata buses are
but to compatibility mode if possible.
2023-10-16 16:56:12 +03:00
Bananymous b767317a7a Kernel: Fix ATADevice naming
ATADevice now stores its name instead of using static buffer. Old
static buffer was changing on every name query. I just hadn't noticed
since virtual machine disks were always sda.
2023-10-16 16:52:15 +03:00
Bananymous 6f8fce94a0 Kernel: Fix PCI bugs
IO BarRegion used vaddr instead of the correct paddr. Add API for
memory region iobase query.
2023-10-16 16:50:49 +03:00
Bananymous 31aa157201 Kernel: Don't require framebuffer
Initializes virtual tty only if framebuffer is initialized
2023-10-16 01:44:54 +03:00
Bananymous 5977341610 Kernel: PCI checks if ethernet device is E1000 before initialization
I used to treat all ethernet deivices as E1000 but now it is actually
verified before initialization
2023-10-16 01:44:54 +03:00
Bananymous 76f17bd569 Kernel: PCIDevice stores its vendor id and device id 2023-10-16 01:44:54 +03:00
Bananymous 6b1b3d333c BuildSystem: add cmake variable UEFI_BOOT
If this variable is defined in cmake, image will be build with esp
and booted with uefi.
2023-10-16 01:44:54 +03:00
Bananymous cb65be3e33 Toolchain: Build grub with efi capabilities 2023-10-16 01:37:12 +03:00
Bananymous dafc016293 Kernel: Clear TTY when setting as current
Actually this should replace from old buffer, but this works
for now.
2023-10-13 17:20:26 +03:00
Bananymous c7b6fc950a Kernel: Don't crash if header type != 0 in bar region creation
Also remove spammy debug printing
2023-10-13 16:32:32 +03:00
Bananymous 45a6783c3d Kernel: Cleanup GDT code 2023-10-13 16:18:22 +03:00
Bananymous 6b180da4e8 Kernel: Separate scheduler execution and stack loading
Not sure if this is actually needed, but this allows actual
executing function to be in clean environment
2023-10-13 16:17:27 +03:00
Bananymous cf4f5f64a5 Kernel: add NEVER_INLINE and make Interruptable not constructable 2023-10-13 16:17:27 +03:00
Bananymous 5630f64175 Kernel: Add 16 more irq handlers
IDT will now panic if trying to assing handler for non supported
irq.
2023-10-13 16:17:27 +03:00
Bananymous 1d61bccfc3 Kernel: Debug temporary debug print just to beginning when full 2023-10-13 12:43:52 +03:00
Bananymous f842a9255f Kernel: Allow getting ACPI headers with same signature 2023-10-13 11:24:21 +03:00
Bananymous 72f3c378dd Kernel: Fix PhysicalRange mapping size 2023-10-13 03:45:01 +03:00
Bananymous 39be6ab099 Kernel: Add temporary terminal output before controlling terminal
Starting work on getting this boot on real hardware.
2023-10-13 03:31:36 +03:00
Bananymous 773dcdd3a2 Kernel: Check whether ELF address space can be loaded
Before reserving address space in SYS_EXEC verify that ELF address
space is actually loadable. For example when trying to execute the
kernel binary in userspace, binarys address space would overlap with
current kernel address space. Now kernel won't crash anymore and
will just send SIGKILL to the process calling exec*().
2023-10-12 22:59:36 +03:00
Bananymous f0820e6f24 Shell: Fix parsing $ with unknown character 2023-10-12 22:24:27 +03:00
Bananymous a2b5e71654 Kernel: Implement AHCI driver
SATA drives can now be used with banan-os. This allows much faster
disk access (writing 10 MiB from 30s to 1.5s). This can definitely
be optimized but the main slow down is probably the whole disk
structure in the os.

AHCI drive is now the default when running qemu.
2023-10-12 21:53:48 +03:00
Bananymous d3e5c8e0aa Kernel: Generalize ATA device and cleanup code 2023-10-12 21:35:25 +03:00
Bananymous f4b901a646 Kernel: Add Timer::ns_since_boot() 2023-10-12 21:16:39 +03:00
Bananymous 790064d248 Kernel: Add vaddr/paddr conversion functions to DMARegion 2023-10-12 15:20:05 +03:00
Bananymous ab8b77406d Kernel: PCI can now get interrupts for devices 2023-10-11 22:18:58 +03:00
Bananymous 1b9e14a53b Kernel: PCI cleanup PCI::Device API 2023-10-11 21:52:08 +03:00
Bananymous d2cfc843e4 BAN: Optional can now be constructed from another Optional
Also fix bug in release_value() where we did not call the
destructor.
2023-10-11 20:10:06 +03:00
Bananymous 521513bed2 Kernel: make DMARegion::create static and fix mapping 2023-10-08 18:18:36 +03:00
Bananymous 400db176d1 Kernel: fix some math in physical ranges
I allocated 1 bitmap page per 8 data pages. Bitmap page can actually
store 8*PAGE_SIZE data pages.

Also properly set last bits in bitmap. I did not care about endianness
but now we set the bits on unsigned long longs instead of bytes.
2023-10-08 13:25:34 +03:00
Bananymous 211cad03ff Kernel: Implement bare boness DMA Region
This does nothing but allocate contiguous physical and virtual memory
and map it as CacheDisable. Also memory is automatically freed RAII style.
2023-10-08 02:57:22 +03:00
Bananymous 8a9816d6e0 Kernel: Add API for getting contiguous physcial pages
This will be used to create DMA regions.
2023-10-08 02:57:22 +03:00
Bananymous 03d2bf4002 Kernel: Rework physical memory allocation
PhysicalRange is now much simpler bitmap. This makes expanding
PhysicalRange API much easier.
2023-10-08 02:50:23 +03:00
Bananymous f071240b33 Kernel: Fix PCI BarRegion offsets
Calculations accidentally assumed bar registers are 8 byte instead
of 4.
2023-10-08 02:50:23 +03:00
Bananymous 27364f64a6 Kernel: Rework whole ATA driver structure
Make ATA driver more compatible when we are adding SATA support
2023-10-08 02:50:23 +03:00
Bananymous bcf62c5f2e Kernel: Rework interrupt mechanism
All interruptrable classes now inherit from Interruptable which
has methdo handle_irq which is called on a interrupt.
2023-10-05 18:53:45 +03:00
Bananymous 4d6322ff9c BuildSystem: Don't strip kernel 2023-10-05 18:52:44 +03:00
Bananymous 2eef581737 BuildSystem: Try to set compiler only if it exists 2023-10-05 18:52:05 +03:00
Bananymous 7ce8e2d57b cat: Use write() instead of puts to print file contents
This allows printing files that contain null bytes behave more like
you would expect
2023-10-04 22:16:19 +03:00
Bananymous e780eaa45f meminfo: Print allocated physical memory percentage 2023-10-03 10:39:27 +03:00
Bananymous 44cb0af64f Shell: source $HOME/.shellrc if found on Shell startup 2023-10-03 10:39:27 +03:00
Bananymous bb0989fdef Shell: Implement sourcing scripts 2023-10-03 10:24:10 +03:00
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
739 changed files with 10319 additions and 41519 deletions

4
.gitmodules vendored
View File

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

View File

@ -1,8 +0,0 @@
# .pre-commit-config.yaml
exclude: '.patch$'
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.1.0 # this is optional, use `pre-commit autoupdate` to get the latest rev!
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace

View File

@ -1,36 +0,0 @@
{
"configurations": [
{
"name": "banan-os",
"includePath": [
"${workspaceFolder}/BAN/include",
"${workspaceFolder}/kernel/include",
"${workspaceFolder}/userspace/libraries/*/include"
],
"defines": [
"__arch=x86_64"
],
"compilerPath": "${workspaceFolder}/toolchain/local/bin/x86_64-banan_os-gcc",
"cStandard": "c17",
"cppStandard": "gnu++20",
"intelliSenseMode": "linux-gcc-x64"
},
{
"name": "banan-os-kernel",
"includePath": [
"${workspaceFolder}/BAN/include",
"${workspaceFolder}/kernel/include",
"${workspaceFolder}/userspace/libraries/*/include"
],
"defines": [
"__arch=x86_64",
"__is_kernel"
],
"compilerPath": "${workspaceFolder}/toolchain/local/bin/x86_64-banan_os-gcc",
"cStandard": "c17",
"cppStandard": "gnu++20",
"intelliSenseMode": "linux-gcc-x64"
}
],
"version": 4
}

View File

@ -1,6 +0,0 @@
{
"cmake.configureOnOpen": false,
"editor.tabSize": 4,
"editor.insertSpaces": false,
"editor.detectIndentation": false
}

3
BAN/.gitignore vendored Normal file
View File

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

View File

@ -1,22 +0,0 @@
#include <BAN/Assert.h>
#if __is_kernel
#include <kernel/Panic.h>
[[noreturn]] void __ban_assertion_failed(const char* location, const char* msg)
{
Kernel::panic_impl(location, msg);
}
#else
#include <BAN/Debug.h>
[[noreturn]] void __ban_assertion_failed(const char* location, const char* msg)
{
derrorln("{}: {}", location, msg);
__builtin_trap();
}
#endif

269
BAN/BAN/String.cpp Normal file
View File

@ -0,0 +1,269 @@
#include <BAN/String.h>
#include <BAN/New.h>
namespace BAN
{
String::String()
{
}
String::String(const String& other)
{
*this = other;
}
String::String(String&& other)
{
*this = move(other);
}
String::String(StringView other)
{
*this = other;
}
String::~String()
{
clear();
}
String& String::operator=(const String& other)
{
clear();
MUST(ensure_capacity(other.size()));
memcpy(data(), other.data(), other.size() + 1);
m_size = other.size();
return *this;
}
String& String::operator=(String&& other)
{
clear();
if (other.has_sso())
memcpy(data(), other.data(), other.size() + 1);
else
{
m_storage.general_storage = other.m_storage.general_storage;
m_has_sso = false;
}
m_size = other.m_size;
other.m_size = 0;
other.m_storage.sso_storage = SSOStorage();
other.m_has_sso = true;
return *this;
}
String& String::operator=(StringView other)
{
clear();
MUST(ensure_capacity(other.size()));
memcpy(data(), other.data(), other.size());
m_size = other.size();
data()[m_size] = '\0';
return *this;
}
ErrorOr<void> String::push_back(char c)
{
TRY(ensure_capacity(m_size + 1));
data()[m_size] = c;
m_size++;
data()[m_size] = '\0';
return {};
}
ErrorOr<void> String::insert(char c, size_type index)
{
ASSERT(index <= m_size);
TRY(ensure_capacity(m_size + 1));
memmove(data() + index + 1, data() + index, m_size - index);
data()[index] = c;
m_size++;
data()[m_size] = '\0';
return {};
}
ErrorOr<void> String::insert(StringView str, size_type index)
{
ASSERT(index <= m_size);
TRY(ensure_capacity(m_size + str.size()));
memmove(data() + index + str.size(), data() + index, m_size - index);
memcpy(data() + index, str.data(), str.size());
m_size += str.size();
data()[m_size] = '\0';
return {};
}
ErrorOr<void> String::append(StringView str)
{
TRY(ensure_capacity(m_size + str.size()));
memcpy(data() + m_size, str.data(), str.size());
m_size += str.size();
data()[m_size] = '\0';
return {};
}
void String::pop_back()
{
ASSERT(m_size > 0);
m_size--;
data()[m_size] = '\0';
}
void String::remove(size_type index)
{
ASSERT(index < m_size);
memcpy(data() + index, data() + index + 1, m_size - index);
m_size--;
data()[m_size] = '\0';
}
void String::clear()
{
if (!has_sso())
{
deallocator(m_storage.general_storage.data);
m_storage.sso_storage = SSOStorage();
m_has_sso = true;
}
m_size = 0;
data()[m_size] = '\0';
}
bool String::operator==(StringView str) const
{
if (size() != str.size())
return false;
for (size_type i = 0; i < m_size; i++)
if (data()[i] != str.data()[i])
return false;
return true;
}
bool String::operator==(const char* cstr) const
{
for (size_type i = 0; i < m_size; i++)
if (data()[i] != cstr[i])
return false;
if (cstr[size()] != '\0')
return false;
return true;
}
ErrorOr<void> String::resize(size_type new_size, char init_c)
{
if (m_size == new_size)
return {};
// expanding
if (m_size < new_size)
{
TRY(ensure_capacity(new_size));
memset(data() + m_size, init_c, new_size - m_size);
m_size = new_size;
data()[m_size] = '\0';
return {};
}
m_size = new_size;
data()[m_size] = '\0';
return {};
}
ErrorOr<void> String::reserve(size_type new_size)
{
TRY(ensure_capacity(new_size));
return {};
}
ErrorOr<void> String::shrink_to_fit()
{
if (has_sso())
return {};
if (fits_in_sso())
{
char* data = m_storage.general_storage.data;
m_storage.sso_storage = SSOStorage();
m_has_sso = true;
memcpy(this->data(), data, m_size + 1);
deallocator(data);
return {};
}
GeneralStorage& storage = m_storage.general_storage;
if (storage.capacity == m_size)
return {};
char* new_data = (char*)allocator(m_size + 1);
if (new_data == nullptr)
return Error::from_errno(ENOMEM);
memcpy(new_data, storage.data, m_size);
deallocator(storage.data);
storage.capacity = m_size;
storage.data = new_data;
return {};
}
String::size_type String::capacity() const
{
if (has_sso())
return sso_capacity;
return m_storage.general_storage.capacity;
}
char* String::data()
{
if (has_sso())
return m_storage.sso_storage.data;
return m_storage.general_storage.data;
}
const char* String::data() const
{
if (has_sso())
return m_storage.sso_storage.data;
return m_storage.general_storage.data;
}
ErrorOr<void> String::ensure_capacity(size_type new_size)
{
if (m_size >= new_size)
return {};
if (has_sso() && fits_in_sso(new_size))
return {};
char* new_data = (char*)allocator(new_size + 1);
if (new_data == nullptr)
return Error::from_errno(ENOMEM);
memcpy(new_data, data(), m_size + 1);
if (has_sso())
{
m_storage.general_storage = GeneralStorage();
m_has_sso = false;
}
else
deallocator(m_storage.general_storage.data);
auto& storage = m_storage.general_storage;
storage.capacity = new_size;
storage.data = new_data;
return {};
}
bool String::has_sso() const
{
return m_has_sso;
}
}

View File

@ -1,11 +1,180 @@
#include <BAN/String.h>
#include <BAN/StringView.h>
#include <BAN/Vector.h>
#include <string.h>
namespace BAN
{
StringView::StringView()
{ }
StringView::StringView(const String& other)
: StringView(other.data(), other.size())
{ }
}
StringView::StringView(const char* string, size_type len)
{
if (len == size_type(-1))
len = strlen(string);
m_data = string;
m_size = len;
}
char StringView::operator[](size_type index) const
{
ASSERT(index < m_size);
return m_data[index];
}
bool StringView::operator==(const String& other) const
{
if (m_size != other.size())
return false;
return memcmp(m_data, other.data(), m_size) == 0;
}
bool StringView::operator==(StringView other) const
{
if (m_size != other.m_size)
return false;
return memcmp(m_data, other.m_data, m_size) == 0;
}
bool StringView::operator==(const char* other) const
{
if (memcmp(m_data, other, m_size))
return false;
return other[m_size] == '\0';
}
StringView StringView::substring(size_type index, size_type len) const
{
ASSERT(index <= m_size);
if (len == size_type(-1))
len = m_size - index;
ASSERT(len <= m_size - index); // weird order to avoid overflow
StringView result;
result.m_data = m_data + index;
result.m_size = len;
return result;
}
ErrorOr<Vector<StringView>> StringView::split(char delim, bool 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)
{
size_type count = 0;
{
size_type start = 0;
for (size_type i = 0; i < m_size; i++)
{
if (comp(m_data[i]))
{
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 (comp(m_data[i]))
{
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;
}
char StringView::back() const
{
ASSERT(m_size > 0);
return m_data[m_size - 1];
}
char StringView::front() const
{
ASSERT(m_size > 0);
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;
for (size_type i = 0; i < m_size; i++)
if (m_data[i] == ch)
result++;
return result;
}
bool StringView::empty() const
{
return m_size == 0;
}
StringView::size_type StringView::size() const
{
return m_size;
}
const char* StringView::data() const
{
return m_data;
}
}

View File

@ -38,7 +38,7 @@ namespace BAN
}
BAN::Time from_unix_time(uint64_t unix_time)
{
{
BAN::Time time {};
time.second = unix_time % 60; unix_time /= 60;
@ -68,4 +68,4 @@ namespace BAN
return time;
}
}
}

View File

@ -1,12 +1,24 @@
cmake_minimum_required(VERSION 3.26)
project(BAN CXX)
set(BAN_SOURCES
BAN/Assert.cpp
BAN/New.cpp
BAN/String.cpp
BAN/StringView.cpp
BAN/Time.cpp
)
add_library(ban ${BAN_SOURCES})
banan_link_library(ban libc)
add_custom_target(ban-headers
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CMAKE_CURRENT_SOURCE_DIR}/include/ ${BANAN_INCLUDE}/
DEPENDS sysroot
)
banan_install_headers(ban)
install(TARGETS ban OPTIONAL)
add_library(ban ${BAN_SOURCES})
add_dependencies(ban headers libc-install)
add_custom_target(ban-install
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_BINARY_DIR}/libban.a ${BANAN_LIB}/
DEPENDS ban
BYPRODUCTS ${BANAN_LIB}/libban.a
)

View File

@ -1,5 +1,6 @@
#pragma once
#include <BAN/Errors.h>
#include <BAN/Iterators.h>
#include <BAN/Span.h>
@ -18,7 +19,7 @@ namespace BAN
using const_iterator = ConstIteratorSimple<T, Array>;
public:
Array() = default;
Array();
Array(const T&);
iterator begin() { return iterator(m_data); }
@ -38,14 +39,21 @@ namespace BAN
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] {};
T m_data[S];
};
template<typename T, size_t S>
Array<T, S>::Array()
{
for (size_type i = 0; i < S; i++)
m_data[i] = T();
}
template<typename T, size_t S>
Array<T, S>::Array(const T& value)
{
@ -101,4 +109,4 @@ namespace BAN
return S;
}
}
}

View File

@ -1,14 +1,33 @@
#pragma once
#define __ban_assert_stringify_helper(s) #s
#define __ban_assert_stringify(s) __ban_assert_stringify_helper(s)
#include <BAN/Traits.h>
#define ASSERT(cond) \
(__builtin_expect(!(cond), 0) \
? __ban_assertion_failed(__FILE__ ":" __ban_assert_stringify(__LINE__), "ASSERT(" #cond ") failed") \
: (void)0)
#if defined(__is_kernel)
#include <kernel/Panic.h>
#define ASSERT_NOT_REACHED() \
__ban_assertion_failed(__FILE__ ":" __ban_assert_stringify(__LINE__), "ASSERT_NOT_REACHED() reached")
#define ASSERT(cond) \
do { \
if (!(cond)) \
Kernel::panic("ASSERT(" #cond ") failed"); \
} while (false)
[[noreturn]] void __ban_assertion_failed(const char* location, const char* msg);
#define __ASSERT_BIN_OP(lhs, rhs, name, op) \
do { \
auto&& _lhs = lhs; \
auto&& _rhs = rhs; \
if (!(_lhs op _rhs)) \
Kernel::panic(name "(" #lhs ", " #rhs ") ({} " #op " {}) failed", _lhs, _rhs); \
} while (false)
#define ASSERT_LT(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_LT", <)
#define ASSERT_LTE(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_LTE", <=)
#define ASSERT_GT(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_GT", >)
#define ASSERT_GTE(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_GTE", >=)
#define ASSERT_EQ(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_EQ", ==)
#define ASSERT_NEQ(lhs, rhs) __ASSERT_BIN_OP(lhs, rhs, "ASSERT_NEQ", !=)
#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() do { assert(false && "ASSERT_NOT_REACHED() failed"); __builtin_unreachable(); } while (false)
#endif

View File

@ -1,69 +0,0 @@
#pragma once
namespace BAN
{
enum MemoryOrder
{
memory_order_relaxed = __ATOMIC_RELAXED,
memory_order_consume = __ATOMIC_CONSUME,
memory_order_acquire = __ATOMIC_ACQUIRE,
memory_order_release = __ATOMIC_RELEASE,
memory_order_acq_rel = __ATOMIC_ACQ_REL,
memory_order_seq_cst = __ATOMIC_SEQ_CST,
};
template<typename T, MemoryOrder MEM_ORDER = MemoryOrder::memory_order_seq_cst>
requires requires { __atomic_always_lock_free(sizeof(T), 0); }
class Atomic
{
Atomic(const Atomic&) = delete;
Atomic(Atomic&&) = delete;
Atomic& operator=(const Atomic&) volatile = delete;
Atomic& operator=(Atomic&&) volatile = delete;
public:
constexpr Atomic() : m_value(0) {}
constexpr Atomic(T val) : m_value(val) {}
inline T load(MemoryOrder mem_order = MEM_ORDER) const volatile { return __atomic_load_n(&m_value, mem_order); }
inline void store(T val, MemoryOrder mem_order = MEM_ORDER) volatile { __atomic_store_n(&m_value, val, mem_order); }
inline T operator=(T val) volatile { store(val); return val; }
inline operator T() const volatile { return load(); }
inline T operator+=(T val) volatile { return __atomic_add_fetch(&m_value, val, MEM_ORDER); }
inline T operator-=(T val) volatile { return __atomic_sub_fetch(&m_value, val, MEM_ORDER); }
inline T operator&=(T val) volatile { return __atomic_and_fetch(&m_value, val, MEM_ORDER); }
inline T operator^=(T val) volatile { return __atomic_xor_fetch(&m_value, val, MEM_ORDER); }
inline T operator|=(T val) volatile { return __atomic_or_fetch(&m_value, val, MEM_ORDER); }
inline T operator--() volatile { return __atomic_sub_fetch(&m_value, 1, MEM_ORDER); }
inline T operator++() volatile { return __atomic_add_fetch(&m_value, 1, MEM_ORDER); }
inline T operator--(int) volatile { return __atomic_fetch_sub(&m_value, 1, MEM_ORDER); }
inline T operator++(int) volatile { return __atomic_fetch_add(&m_value, 1, MEM_ORDER); }
inline bool compare_exchange(T& expected, T desired, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_compare_exchange_n(&m_value, &expected, desired, false, mem_order, mem_order); }
inline T exchange(T desired, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_exchange_n(&m_value, desired, mem_order); };
inline T add_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_add_fetch (&m_value, val, mem_order); }
inline T sub_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_sub_fetch (&m_value, val, mem_order); }
inline T and_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_and_fetch (&m_value, val, mem_order); }
inline T xor_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_xor_fetch (&m_value, val, mem_order); }
inline T or_fetch (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_or_fetch (&m_value, val, mem_order); }
inline T nand_fetch(T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_nand_fetch(&m_value, val, mem_order); }
inline T fetch_add (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch_add (&m_value, val, mem_order); }
inline T fetch_sub (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch_sub (&m_value, val, mem_order); }
inline T fetch_and (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch_and (&m_value, val, mem_order); }
inline T fetch_xor (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch_xor (&m_value, val, mem_order); }
inline T fetch_or (T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_fetch__or (&m_value, val, mem_order); }
inline T fetch_nand(T val, MemoryOrder mem_order = MEM_ORDER) volatile { return __atomic_nfetch_and(&m_value, val, mem_order); }
private:
T m_value;
};
}

View File

@ -1,12 +0,0 @@
#pragma once
namespace BAN
{
template<typename To, typename From>
constexpr To bit_cast(const From& from)
{
return __builtin_bit_cast(To, from);
}
}

View File

@ -2,8 +2,6 @@
#include <BAN/Span.h>
#include <stdint.h>
namespace BAN
{
@ -25,26 +23,11 @@ namespace BAN
: m_data(other.data())
, m_size(other.size())
{ }
ByteSpanGeneral(ByteSpanGeneral&& other)
: m_data(other.data())
, m_size(other.size())
{
other.m_data = nullptr;
other.m_size = 0;
}
template<bool C2>
ByteSpanGeneral(const ByteSpanGeneral<C2>& other) requires(CONST)
: m_data(other.data())
, m_size(other.size())
{ }
template<bool C2>
ByteSpanGeneral(ByteSpanGeneral<C2>&& other) requires(CONST)
: m_data(other.data())
, m_size(other.size())
{
other.m_data = nullptr;
other.m_size = 0;
}
ByteSpanGeneral(Span<uint8_t> other)
: m_data(other.data())
, m_size(other.size())
@ -142,18 +125,16 @@ namespace BAN
}
value_type* data() { return m_data; }
const value_type* data() const { return m_data; }
const value_type* data() const { return m_data; }
size_type size() const { return m_size; }
private:
value_type* m_data { nullptr };
size_type m_size { 0 };
friend class ByteSpanGeneral<!CONST>;
};
using ByteSpan = ByteSpanGeneral<false>;
using ConstByteSpan = ByteSpanGeneral<true>;
}
}

View File

@ -1,8 +1,6 @@
#pragma once
#include <BAN/Assert.h>
#include <BAN/Move.h>
#include <BAN/PlacementNew.h>
#include <stdint.h>
#include <stddef.h>
@ -31,13 +29,10 @@ namespace BAN
const T& front() const;
T& front();
const T& back() const;
T& back();
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:
@ -101,20 +96,6 @@ namespace BAN
return *element_at(m_first);
}
template<typename T, size_t S>
const T& CircularQueue<T, S>::back() const
{
ASSERT(!empty());
return *element_at((m_first + m_size - 1) % capacity());
}
template<typename T, size_t S>
T& CircularQueue<T, S>::back()
{
ASSERT(!empty());
return *element_at((m_first + m_size - 1) % capacity());
}
template<typename T, size_t S>
const T* CircularQueue<T, S>::element_at(size_type index) const
{
@ -129,4 +110,4 @@ namespace BAN
return (T*)(m_storage + index * sizeof(T));
}
}
}

View File

@ -1,55 +0,0 @@
#pragma once
#if __is_kernel
#include <kernel/Debug.h>
#else
#include <BAN/Formatter.h>
#include <stdio.h>
#define __debug_putchar [](int c) { putc(c, stddbg); }
#define dprintln(...) \
do { \
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
BAN::Formatter::print(__debug_putchar,"\r\n"); \
fflush(stddbg); \
} while (false)
#define dwarnln(...) \
do { \
BAN::Formatter::print(__debug_putchar, "\e[33m"); \
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
BAN::Formatter::print(__debug_putchar, "\e[m\r\n"); \
fflush(stddbg); \
} while(false)
#define derrorln(...) \
do { \
BAN::Formatter::print(__debug_putchar, "\e[31m"); \
BAN::Formatter::print(__debug_putchar, __VA_ARGS__); \
BAN::Formatter::print(__debug_putchar, "\e[m\r\n"); \
fflush(stddbg); \
} while(false)
#define dprintln_if(cond, ...) \
do { \
if constexpr(cond) \
dprintln(__VA_ARGS__); \
} while(false)
#define dwarnln_if(cond, ...) \
do { \
if constexpr(cond) \
dwarnln(__VA_ARGS__); \
} while(false)
#define derrorln_if(cond, ...) \
do { \
if constexpr(cond) \
derrorln(__VA_ARGS__); \
} while(false)
#endif

View File

@ -45,12 +45,6 @@ namespace BAN
#endif
}
template<integral T>
constexpr T little_endian_to_host(T value)
{
return host_to_little_endian(value);
}
template<integral T>
constexpr T host_to_big_endian(T value)
{
@ -61,20 +55,9 @@ namespace BAN
#endif
}
template<integral T>
constexpr T big_endian_to_host(T value)
{
return host_to_big_endian(value);
}
template<integral T>
struct LittleEndian
{
constexpr LittleEndian(T value)
{
raw = host_to_little_endian(value);
}
constexpr operator T() const
{
return host_to_little_endian(raw);
@ -86,11 +69,6 @@ namespace BAN
template<integral T>
struct BigEndian
{
constexpr BigEndian(T value)
{
raw = host_to_big_endian(value);
}
constexpr operator T() const
{
return host_to_big_endian(raw);
@ -99,19 +77,4 @@ namespace BAN
T raw;
};
template<integral T>
using NetworkEndian = BigEndian<T>;
template<integral T>
constexpr T host_to_network_endian(T value)
{
return host_to_big_endian(value);
}
template<integral T>
constexpr T network_endian_to_host(T value)
{
return big_endian_to_host(value);
}
}
}

View File

@ -1,6 +1,7 @@
#pragma once
#include <BAN/Formatter.h>
#include <BAN/StringView.h>
#include <BAN/Variant.h>
#include <errno.h>
@ -55,15 +56,13 @@ namespace BAN
#endif
uint64_t get_error_code() const { return m_error_code; }
const char* get_message() const
BAN::StringView get_message() const
{
#ifdef __is_kernel
if (m_error_code & kernel_error_mask)
return Kernel::error_string(kernel_error());
#endif
if (auto* desc = strerrordesc_np(m_error_code))
return desc;
return "Unknown error";
return strerror(m_error_code);
}
private:

View File

@ -192,7 +192,7 @@ namespace BAN::Formatter
if (sign)
*(--ptr) = '-';
print(putc, ptr);
}
@ -205,10 +205,10 @@ namespace BAN::Formatter
frac_part = -frac_part;
print_integer(putc, int_part, format);
if (format.percision > 0)
putc('.');
for (int i = 0; i < format.percision; i++)
{
frac_part *= format.base;

View File

@ -2,7 +2,7 @@
#include <BAN/Errors.h>
#include <BAN/Move.h>
#include <BAN/PlacementNew.h>
#include <BAN/New.h>
namespace BAN
{
@ -32,7 +32,7 @@ namespace BAN
new (m_storage) CallableMemberConst<Own>(function, owner);
}
template<typename Lambda>
Function(Lambda lambda) requires requires(Lambda lamda, Args&&... args) { { lambda(forward<Args>(args)...) } -> BAN::same_as<Ret>; }
Function(Lambda lambda)
{
static_assert(sizeof(CallableLambda<Lambda>) <= m_size);
new (m_storage) CallableLambda<Lambda>(lambda);
@ -56,7 +56,7 @@ namespace BAN
return true;
return false;
}
void clear()
{
if (*this)
@ -141,8 +141,8 @@ namespace BAN
};
private:
static constexpr size_t m_size = sizeof(void*) * 8;
static constexpr size_t m_size = sizeof(void*) * 5;
alignas(CallableBase) uint8_t m_storage[m_size] { 0 };
};
}
}

View File

@ -1,25 +0,0 @@
#pragma once
#include <BAN/Optional.h>
#include <BAN/StringView.h>
#include <string.h>
namespace BAN
{
struct GUID
{
uint32_t component1 { 0 };
uint16_t component2 { 0 };
uint16_t component3 { 0 };
uint8_t component45[8] { };
bool operator==(const GUID& other) const
{
return memcmp(this, &other, sizeof(GUID)) == 0;
}
};
static_assert(sizeof(GUID) == 16);
}

View File

@ -47,4 +47,4 @@ namespace BAN
}
};
}
}

View File

@ -7,6 +7,9 @@
namespace BAN
{
template<typename Container>
class HashMapIterator;
template<typename Key, typename T, typename HASH = BAN::hash<Key>>
class HashMap
{
@ -52,14 +55,11 @@ namespace BAN
ErrorOr<void> reserve(size_type);
void remove(const Key&);
void remove(iterator it);
void clear();
T& operator[](const Key&);
const T& operator[](const Key&) const;
iterator find(const Key& key);
const_iterator find(const Key& key) const;
bool contains(const Key&) const;
bool empty() const;
@ -69,9 +69,7 @@ namespace BAN
ErrorOr<void> rebucket(size_type);
LinkedList<Entry>& get_bucket(const Key&);
const LinkedList<Entry>& get_bucket(const Key&) const;
Vector<LinkedList<Entry>>::iterator get_bucket_iterator(const Key&);
Vector<LinkedList<Entry>>::const_iterator get_bucket_iterator(const Key&) const;
private:
Vector<LinkedList<Entry>> m_buckets;
size_type m_size = 0;
@ -135,7 +133,9 @@ namespace BAN
ASSERT(!contains(key));
TRY(rebucket(m_size + 1));
auto& bucket = get_bucket(key);
TRY(bucket.emplace_back(key, forward<Args>(args)...));
auto result = bucket.emplace_back(key, forward<Args>(args)...);
if (result.is_error())
return Error::from_errno(ENOMEM);
m_size++;
return {};
}
@ -150,16 +150,17 @@ namespace BAN
template<typename Key, typename T, typename HASH>
void HashMap<Key, T, HASH>::remove(const Key& key)
{
auto it = find(key);
if (it != end())
remove(it);
}
template<typename Key, typename T, typename HASH>
void HashMap<Key, T, HASH>::remove(iterator it)
{
it.outer_current()->remove(it.inner_current());
m_size--;
if (empty()) return;
auto& bucket = get_bucket(key);
for (auto it = bucket.begin(); it != bucket.end(); it++)
{
if (it->key == key)
{
bucket.remove(it);
m_size--;
return;
}
}
}
template<typename Key, typename T, typename HASH>
@ -191,34 +192,15 @@ namespace BAN
ASSERT(false);
}
template<typename Key, typename T, typename HASH>
typename HashMap<Key, T, HASH>::iterator HashMap<Key, T, HASH>::find(const Key& key)
{
if (empty())
return end();
auto bucket_it = get_bucket_iterator(key);
for (auto it = bucket_it->begin(); it != bucket_it->end(); it++)
if (it->key == key)
return iterator(m_buckets.end(), bucket_it, it);
return end();
}
template<typename Key, typename T, typename HASH>
typename HashMap<Key, T, HASH>::const_iterator HashMap<Key, T, HASH>::find(const Key& key) const
{
if (empty())
return end();
auto bucket_it = get_bucket_iterator(key);
for (auto it = bucket_it->begin(); it != bucket_it->end(); it++)
if (it->key == key)
return const_iterator(m_buckets.end(), bucket_it, it);
return end();
}
template<typename Key, typename T, typename HASH>
bool HashMap<Key, T, HASH>::contains(const Key& key) const
{
return find(key) != end();
if (empty()) return false;
const auto& bucket = get_bucket(key);
for (const Entry& entry : bucket)
if (entry.key == key)
return true;
return false;
}
template<typename Key, typename T, typename HASH>
@ -241,14 +223,18 @@ namespace BAN
size_type new_bucket_count = BAN::Math::max<size_type>(bucket_count, m_buckets.size() * 2);
Vector<LinkedList<Entry>> new_buckets;
TRY(new_buckets.resize(new_bucket_count));
if (new_buckets.resize(new_bucket_count).is_error())
return Error::from_errno(ENOMEM);
// NOTE: We have to copy the old entries to the new entries and not move
// since we might run out of memory half way through.
for (auto& bucket : m_buckets)
{
for (auto it = bucket.begin(); it != bucket.end();)
for (Entry& entry : bucket)
{
size_type new_bucket_index = HASH()(it->key) % new_buckets.size();
it = bucket.move_element_to_other_linked_list(new_buckets[new_bucket_index], new_buckets[new_bucket_index].end(), it);
size_type bucket_index = HASH()(entry.key) % new_buckets.size();
if (new_buckets[bucket_index].push_back(entry).is_error())
return Error::from_errno(ENOMEM);
}
}
@ -259,29 +245,17 @@ namespace BAN
template<typename Key, typename T, typename HASH>
LinkedList<typename HashMap<Key, T, HASH>::Entry>& HashMap<Key, T, HASH>::get_bucket(const Key& key)
{
return *get_bucket_iterator(key);
ASSERT(!m_buckets.empty());
auto index = HASH()(key) % m_buckets.size();
return m_buckets[index];
}
template<typename Key, typename T, typename HASH>
const LinkedList<typename HashMap<Key, T, HASH>::Entry>& HashMap<Key, T, HASH>::get_bucket(const Key& key) const
{
return *get_bucket_iterator(key);
}
template<typename Key, typename T, typename HASH>
Vector<LinkedList<typename HashMap<Key, T, HASH>::Entry>>::iterator HashMap<Key, T, HASH>::get_bucket_iterator(const Key& key)
{
ASSERT(!m_buckets.empty());
auto index = HASH()(key) % m_buckets.size();
return next(m_buckets.begin(), index);
}
template<typename Key, typename T, typename HASH>
Vector<LinkedList<typename HashMap<Key, T, HASH>::Entry>>::const_iterator HashMap<Key, T, HASH>::get_bucket_iterator(const Key& key) const
{
ASSERT(!m_buckets.empty());
auto index = HASH()(key) % m_buckets.size();
return next(m_buckets.begin(), index);
return m_buckets[index];
}
}

View File

@ -2,8 +2,6 @@
#include <BAN/Errors.h>
#include <BAN/Hash.h>
#include <BAN/Iterators.h>
#include <BAN/LinkedList.h>
#include <BAN/Math.h>
#include <BAN/Move.h>
#include <BAN/Vector.h>
@ -11,22 +9,24 @@
namespace BAN
{
template<typename T, typename HASH>
class HashSetIterator;
template<typename T, typename HASH = hash<T>>
class HashSet
{
public:
using value_type = T;
using size_type = size_t;
using iterator = IteratorDouble<T, Vector, LinkedList, HashSet>;
using const_iterator = ConstIteratorDouble<T, Vector, LinkedList, HashSet>;
using size_type = hash_t;
using const_iterator = HashSetIterator<T, HASH>;
public:
HashSet() = default;
HashSet(const HashSet&);
HashSet(HashSet&&);
HashSet(const HashSet<T, HASH>&);
HashSet(HashSet<T, HASH>&&);
HashSet& operator=(const HashSet&);
HashSet& operator=(HashSet&&);
HashSet<T, HASH>& operator=(const HashSet<T, HASH>&);
HashSet<T, HASH>& operator=(HashSet<T, HASH>&&);
ErrorOr<void> insert(const T&);
ErrorOr<void> insert(T&&);
@ -35,10 +35,8 @@ namespace BAN
ErrorOr<void> reserve(size_type);
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()); }
const_iterator begin() const { return const_iterator(this, m_buckets.begin()); }
const_iterator end() const { return const_iterator(this, m_buckets.end()); }
bool contains(const T&) const;
@ -47,23 +45,55 @@ namespace BAN
private:
ErrorOr<void> rebucket(size_type);
LinkedList<T>& get_bucket(const T&);
const LinkedList<T>& get_bucket(const T&) const;
Vector<T>& get_bucket(const T&);
const Vector<T>& get_bucket(const T&) const;
private:
Vector<LinkedList<T>> m_buckets;
Vector<Vector<T>> m_buckets;
size_type m_size = 0;
friend class HashSetIterator<T, HASH>;
};
template<typename T, typename HASH>
HashSet<T, HASH>::HashSet(const HashSet& other)
class HashSetIterator
{
public:
HashSetIterator() = default;
HashSetIterator(const HashSetIterator<T, HASH>&);
HashSetIterator<T, HASH>& operator++();
HashSetIterator<T, HASH> operator++(int);
const T& operator*() const;
const T* operator->() const;
bool operator==(const HashSetIterator<T, HASH>&) const;
bool operator!=(const HashSetIterator<T, HASH>&) const;
operator bool() const { return m_owner && m_current_bucket; }
private:
HashSetIterator(const HashSet<T, HASH>* owner, Vector<Vector<T>>::const_iterator bucket);
void find_next();
private:
const HashSet<T, HASH>* m_owner = nullptr;
Vector<Vector<T>>::const_iterator m_current_bucket;
Vector<T>::const_iterator m_current_key;
friend class HashSet<T, HASH>;
};
template<typename T, typename HASH>
HashSet<T, HASH>::HashSet(const HashSet<T, HASH>& other)
: m_buckets(other.m_buckets)
, m_size(other.m_size)
{
}
template<typename T, typename HASH>
HashSet<T, HASH>::HashSet(HashSet&& other)
HashSet<T, HASH>::HashSet(HashSet<T, HASH>&& other)
: m_buckets(move(other.m_buckets))
, m_size(other.m_size)
{
@ -71,7 +101,7 @@ namespace BAN
}
template<typename T, typename HASH>
HashSet<T, HASH>& HashSet<T, HASH>::operator=(const HashSet& other)
HashSet<T, HASH>& HashSet<T, HASH>::operator=(const HashSet<T, HASH>& other)
{
clear();
m_buckets = other.m_buckets;
@ -80,7 +110,7 @@ namespace BAN
}
template<typename T, typename HASH>
HashSet<T, HASH>& HashSet<T, HASH>::operator=(HashSet&& other)
HashSet<T, HASH>& HashSet<T, HASH>::operator=(HashSet<T, HASH>&& other)
{
clear();
m_buckets = move(other.m_buckets);
@ -111,15 +141,15 @@ namespace BAN
void HashSet<T, HASH>::remove(const T& key)
{
if (empty()) return;
auto& bucket = get_bucket(key);
for (auto it = bucket.begin(); it != bucket.end(); it++)
Vector<T>& bucket = get_bucket(key);
for (size_type i = 0; i < bucket.size(); i++)
{
if (*it == key)
if (bucket[i] == key)
{
bucket.remove(it);
bucket.remove(i);
m_size--;
break;
}
}
}
}
@ -162,17 +192,20 @@ namespace BAN
if (m_buckets.size() >= bucket_count)
return {};
size_type new_bucket_count = Math::max<size_type>(bucket_count, m_buckets.size() * 2);
Vector<LinkedList<T>> new_buckets;
size_type new_bucket_count = BAN::Math::max<size_type>(bucket_count, m_buckets.size() * 2);
Vector<Vector<T>> new_buckets;
if (new_buckets.resize(new_bucket_count).is_error())
return Error::from_errno(ENOMEM);
for (auto& bucket : m_buckets)
// NOTE: We have to copy the old keys to the new keys and not move
// since we might run out of memory half way through.
for (Vector<T>& bucket : m_buckets)
{
for (auto it = bucket.begin(); it != bucket.end();)
for (T& key : bucket)
{
size_type new_bucket_index = HASH()(*it) % new_buckets.size();
it = bucket.move_element_to_other_linked_list(new_buckets[new_bucket_index], new_buckets[new_bucket_index].end(), it);
size_type bucket_index = HASH()(key) % new_buckets.size();
if (new_buckets[bucket_index].push_back(key).is_error())
return Error::from_errno(ENOMEM);
}
}
@ -181,7 +214,7 @@ namespace BAN
}
template<typename T, typename HASH>
LinkedList<T>& HashSet<T, HASH>::get_bucket(const T& key)
Vector<T>& HashSet<T, HASH>::get_bucket(const T& key)
{
ASSERT(!m_buckets.empty());
size_type index = HASH()(key) % m_buckets.size();
@ -189,11 +222,83 @@ namespace BAN
}
template<typename T, typename HASH>
const LinkedList<T>& HashSet<T, HASH>::get_bucket(const T& key) const
const Vector<T>& HashSet<T, HASH>::get_bucket(const T& key) const
{
ASSERT(!m_buckets.empty());
size_type index = HASH()(key) % m_buckets.size();
return m_buckets[index];
}
}
template<typename T, typename HASH>
HashSetIterator<T, HASH>& HashSetIterator<T, HASH>::operator++()
{
ASSERT(*this);
if (m_current_key == m_current_bucket->end())
m_current_bucket++;
else
m_current_key++;
find_next();
return *this;
}
template<typename T, typename HASH>
HashSetIterator<T, HASH> HashSetIterator<T, HASH>::operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
template<typename T, typename HASH>
const T& HashSetIterator<T, HASH>::operator*() const
{
ASSERT(m_owner && m_current_bucket && m_current_key);
return *m_current_key;
}
template<typename T, typename HASH>
const T* HashSetIterator<T, HASH>::operator->() const
{
return &**this;
}
template<typename T, typename HASH>
bool HashSetIterator<T, HASH>::operator==(const HashSetIterator<T, HASH>& other) const
{
if (!m_owner || m_owner != other.m_owner)
return false;
return m_current_bucket == other.m_current_bucket
&& m_current_key == other.m_current_key;
}
template<typename T, typename HASH>
bool HashSetIterator<T, HASH>::operator!=(const HashSetIterator<T, HASH>& other) const
{
return !(*this == other);
}
template<typename T, typename HASH>
HashSetIterator<T, HASH>::HashSetIterator(const HashSet<T, HASH>* owner, Vector<Vector<T>>::const_iterator bucket)
: m_owner(owner)
, m_current_bucket(bucket)
{
if (m_current_bucket != m_owner->m_buckets.end())
m_current_key = m_current_bucket->begin();
find_next();
}
template<typename T, typename HASH>
void HashSetIterator<T, HASH>::find_next()
{
ASSERT(m_owner && m_current_bucket);
while (m_current_bucket != m_owner->m_buckets.end())
{
if (m_current_key && m_current_key != m_current_bucket->end())
return;
m_current_bucket++;
m_current_key = m_current_bucket->begin();
}
m_current_key = typename Vector<T>::const_iterator();
}
}

View File

@ -1,75 +0,0 @@
#pragma once
#include <BAN/Endianness.h>
#include <BAN/Formatter.h>
#include <BAN/Hash.h>
namespace BAN
{
struct IPv4Address
{
constexpr IPv4Address(uint32_t u32_address)
{
raw = u32_address;
}
constexpr IPv4Address(uint8_t oct1, uint8_t oct2, uint8_t oct3, uint8_t oct4)
{
octets[0] = oct1;
octets[1] = oct2;
octets[2] = oct3;
octets[3] = oct4;
}
constexpr bool operator==(const IPv4Address& other) const
{
return raw == other.raw;
}
constexpr IPv4Address mask(const IPv4Address& other) const
{
return IPv4Address(raw & other.raw);
}
union
{
uint8_t octets[4];
uint32_t raw;
} __attribute__((packed));
};
static_assert(sizeof(IPv4Address) == 4);
template<>
struct hash<IPv4Address>
{
constexpr hash_t operator()(IPv4Address ipv4) const
{
return hash<uint32_t>()(ipv4.raw);
}
};
}
namespace BAN::Formatter
{
template<typename F>
void print_argument(F putc, const IPv4Address& ipv4, const ValueFormat&)
{
ValueFormat format {
.base = 10,
.percision = 0,
.fill = 0,
.upper = false,
};
print_argument(putc, ipv4.octets[0], format);
for (size_t i = 1; i < 4; i++)
{
putc('.');
print_argument(putc, ipv4.octets[i], format);
}
}
}

View File

@ -9,4 +9,4 @@ namespace BAN
Break
};
}
}

View File

@ -1,180 +1,92 @@
#pragma once
#include <BAN/Assert.h>
#include <BAN/Traits.h>
#include <stddef.h>
namespace BAN
{
template<typename It>
constexpr It next(It it, size_t count)
{
for (size_t i = 0; i < count; i++)
++it;
return it;
}
template<typename It>
requires requires(It it, size_t n) { requires is_same_v<decltype(it + n), It>; }
constexpr It next(It it, size_t count)
{
return it + count;
}
template<typename It>
constexpr It prev(It it, size_t count)
{
for (size_t i = 0; i < count; i++)
--it;
return it;
}
template<typename It>
requires requires(It it, size_t n) { requires is_same_v<decltype(it - n), It>; }
constexpr It prev(It it, size_t count)
{
return it - count;
}
template<typename It>
constexpr size_t distance(It it1, It it2)
{
size_t dist = 0;
while (it1 != it2)
{
++it1;
++dist;
}
return dist;
}
template<typename It>
requires requires(It it1, It it2) { requires is_integral_v<decltype(it2 - it1)>; }
constexpr size_t distance(It it1, It it2)
{
return it2 - it1;
}
template<typename T, typename Container, bool CONST>
class IteratorSimpleGeneral
{
public:
using value_type = T;
public:
constexpr IteratorSimpleGeneral() = default;
IteratorSimpleGeneral() = default;
template<bool CONST2, typename = enable_if_t<CONST2 == CONST || CONST>>
constexpr IteratorSimpleGeneral(const IteratorSimpleGeneral<T, Container, CONST2>& other)
IteratorSimpleGeneral(const IteratorSimpleGeneral<T, Container, CONST2>& other)
: m_pointer(other.m_pointer)
, m_valid(other.m_valid)
{
}
constexpr const T& operator*() const
const T& operator*() const
{
ASSERT(m_pointer);
return *m_pointer;
}
template<bool CONST2 = CONST>
constexpr enable_if_t<!CONST2, T&> operator*()
enable_if_t<!CONST2, T&> operator*()
{
ASSERT(*this);
ASSERT(m_pointer);
return *m_pointer;
}
constexpr const T* operator->() const
const T* operator->() const
{
ASSERT(*this);
ASSERT(m_pointer);
return m_pointer;
}
template<bool CONST2 = CONST>
constexpr enable_if_t<!CONST2, T*> operator->()
enable_if_t<!CONST2, T*> operator->()
{
ASSERT(*this);
ASSERT(m_pointer);
return m_pointer;
}
constexpr IteratorSimpleGeneral& operator++()
IteratorSimpleGeneral& operator++()
{
ASSERT(*this);
ASSERT(m_pointer);
++m_pointer;
return *this;
}
constexpr IteratorSimpleGeneral operator++(int)
IteratorSimpleGeneral operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
constexpr IteratorSimpleGeneral& operator--()
IteratorSimpleGeneral& operator--()
{
ASSERT(*this);
ASSERT(m_pointer);
--m_pointer;
return *this;
return --m_pointer;
}
constexpr IteratorSimpleGeneral operator--(int)
IteratorSimpleGeneral operator--(int)
{
auto temp = *this;
--(*this);
return temp;
}
constexpr size_t operator-(const IteratorSimpleGeneral& other) const
bool operator==(const IteratorSimpleGeneral& other) const
{
ASSERT(*this && other);
return m_pointer - other.m_pointer;
}
constexpr IteratorSimpleGeneral operator+(size_t offset) const
{
return IteratorSimpleGeneral(m_pointer + offset);
}
constexpr IteratorSimpleGeneral operator-(size_t offset) const
{
return IteratorSimpleGeneral(m_pointer - offset);
}
constexpr bool operator<(const IteratorSimpleGeneral& other) const
{
ASSERT(*this);
return m_pointer < other.m_pointer;
}
constexpr bool operator==(const IteratorSimpleGeneral& other) const
{
ASSERT(*this);
return m_pointer == other.m_pointer;
}
constexpr bool operator!=(const IteratorSimpleGeneral& other) const
bool operator!=(const IteratorSimpleGeneral& other) const
{
ASSERT(*this);
return !(*this == other);
}
constexpr explicit operator bool() const
operator bool() const
{
return m_valid;
return m_pointer;
}
private:
constexpr IteratorSimpleGeneral(maybe_const_t<CONST, T>* pointer)
IteratorSimpleGeneral(maybe_const_t<CONST, T>* pointer)
: m_pointer(pointer)
, m_valid(true)
{
}
private:
maybe_const_t<CONST, T>* m_pointer = nullptr;
bool m_valid = false;
friend IteratorSimpleGeneral<T, Container, !CONST>;
friend Container;
@ -190,19 +102,17 @@ namespace BAN
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>;
using value_type = T;
public:
constexpr IteratorDoubleGeneral() = default;
IteratorDoubleGeneral() = default;
template<bool CONST2, typename = enable_if_t<CONST2 == CONST || CONST>>
constexpr IteratorDoubleGeneral(const IteratorDoubleGeneral<T, OuterContainer, InnerContainer, Container, CONST2>& other)
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)
{
}
constexpr const T& operator*() const
const T& operator*() const
{
ASSERT(*this);
ASSERT(m_outer_current != m_outer_end);
@ -210,7 +120,7 @@ namespace BAN
return m_inner_current.operator*();
}
template<bool CONST2 = CONST>
constexpr enable_if_t<!CONST2, T&> operator*()
enable_if_t<!CONST2, T&> operator*()
{
ASSERT(*this);
ASSERT(m_outer_current != m_outer_end);
@ -218,7 +128,7 @@ namespace BAN
return m_inner_current.operator*();
}
constexpr const T* operator->() const
const T* operator->() const
{
ASSERT(*this);
ASSERT(m_outer_current != m_outer_end);
@ -226,7 +136,7 @@ namespace BAN
return m_inner_current.operator->();
}
template<bool CONST2 = CONST>
constexpr enable_if_t<!CONST2, T*> operator->()
enable_if_t<!CONST2, T*> operator->()
{
ASSERT(*this);
ASSERT(m_outer_current != m_outer_end);
@ -234,7 +144,7 @@ namespace BAN
return m_inner_current.operator->();
}
constexpr IteratorDoubleGeneral& operator++()
IteratorDoubleGeneral& operator++()
{
ASSERT(*this);
ASSERT(m_outer_current != m_outer_end);
@ -243,37 +153,37 @@ namespace BAN
find_valid_or_end();
return *this;
}
constexpr IteratorDoubleGeneral operator++(int)
IteratorDoubleGeneral operator++(int)
{
auto temp = *this;
++(*this);
return temp;
}
constexpr bool operator==(const IteratorDoubleGeneral& other) const
bool operator==(const IteratorDoubleGeneral& other) const
{
ASSERT(*this && other);
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;
ASSERT(m_inner_current && other.m_inner_current);
return m_inner_current == other.m_inner_current;
}
constexpr bool operator!=(const IteratorDoubleGeneral& other) const
bool operator!=(const IteratorDoubleGeneral& other) const
{
return !(*this == other);
}
constexpr explicit operator bool() const
operator bool() const
{
return !!m_outer_current;
return m_outer_end && m_outer_current;
}
private:
constexpr IteratorDoubleGeneral(const OuterIterator& outer_end, const OuterIterator& outer_current)
IteratorDoubleGeneral(const OuterIterator& outer_end, const OuterIterator& outer_current)
: m_outer_end(outer_end)
, m_outer_current(outer_current)
{
@ -284,15 +194,7 @@ namespace BAN
}
}
constexpr IteratorDoubleGeneral(const OuterIterator& outer_end, const OuterIterator& outer_current, const InnerIterator& inner_current)
: m_outer_end(outer_end)
, m_outer_current(outer_current)
, m_inner_current(inner_current)
{
find_valid_or_end();
}
constexpr void find_valid_or_end()
void find_valid_or_end()
{
while (m_inner_current == m_outer_current->end())
{
@ -303,9 +205,6 @@ namespace BAN
}
}
constexpr OuterIterator outer_current() { return m_outer_current; }
constexpr InnerIterator inner_current() { return m_inner_current; }
private:
OuterIterator m_outer_end;
OuterIterator m_outer_current;

View File

@ -1,156 +0,0 @@
#pragma once
#include <BAN/Traits.h>
#include <stdint.h>
namespace BAN
{
template<typename T>
class numeric_limits
{
public:
numeric_limits() = delete;
static inline constexpr T max()
{
if constexpr(is_same_v<T, char>)
return __SCHAR_MAX__;
if constexpr(is_same_v<T, signed char>)
return __SCHAR_MAX__;
if constexpr(is_same_v<T, unsigned char>)
return (T)__SCHAR_MAX__ * 2 + 1;
if constexpr(is_same_v<T, short>)
return __SHRT_MAX__;
if constexpr(is_same_v<T, int>)
return __INT_MAX__;
if constexpr(is_same_v<T, long>)
return __LONG_MAX__;
if constexpr(is_same_v<T, long long>)
return __LONG_LONG_MAX__;
if constexpr(is_same_v<T, unsigned short>)
return (T)__SHRT_MAX__ * 2 + 1;
if constexpr(is_same_v<T, unsigned int>)
return (T)__INT_MAX__ * 2 + 1;
if constexpr(is_same_v<T, unsigned long>)
return (T)__LONG_MAX__ * 2 + 1;
if constexpr(is_same_v<T, unsigned long long>)
return (T)__LONG_LONG_MAX__ * 2 + 1;
if constexpr(is_same_v<T, float>)
return __FLT_MAX__;
if constexpr(is_same_v<T, double>)
return __DBL_MAX__;
if constexpr(is_same_v<T, long double>)
return __LDBL_MAX__;
}
static inline constexpr T min()
{
if constexpr(is_signed_v<T> && is_integral_v<T>)
return -max() - 1;
if constexpr(is_unsigned_v<T> && is_integral_v<T>)
return 0;
if constexpr(is_same_v<T, float>)
return __FLT_MIN__;
if constexpr(is_same_v<T, double>)
return __DBL_MIN__;
if constexpr(is_same_v<T, long double>)
return __LDBL_MIN__;
}
static inline constexpr bool has_infinity()
{
if constexpr(is_same_v<T, float>)
return __FLT_HAS_INFINITY__;
if constexpr(is_same_v<T, double>)
return __DBL_HAS_INFINITY__;
if constexpr(is_same_v<T, long double>)
return __LDBL_HAS_INFINITY__;
return false;
}
static inline constexpr T infinity() requires(has_infinity())
{
if constexpr(is_same_v<T, float>)
return __builtin_inff();
if constexpr(is_same_v<T, double>)
return __builtin_inf();
if constexpr(is_same_v<T, long double>)
return __builtin_infl();
}
static inline constexpr bool has_quiet_NaN()
{
if constexpr(is_same_v<T, float>)
return __FLT_HAS_QUIET_NAN__;
if constexpr(is_same_v<T, double>)
return __DBL_HAS_QUIET_NAN__;
if constexpr(is_same_v<T, long double>)
return __LDBL_HAS_QUIET_NAN__;
return false;
}
static inline constexpr T quiet_NaN() requires(has_quiet_NaN())
{
if constexpr(is_same_v<T, float>)
return __builtin_nanf("");
if constexpr(is_same_v<T, double>)
return __builtin_nan("");
if constexpr(is_same_v<T, long double>)
return __builtin_nanl("");
}
static inline constexpr int max_exponent2()
{
static_assert(__FLT_RADIX__ == 2);
if constexpr(is_same_v<T, float>)
return __FLT_MAX_EXP__;
if constexpr(is_same_v<T, double>)
return __DBL_MAX_EXP__;
if constexpr(is_same_v<T, long double>)
return __LDBL_MAX_EXP__;
return 0;
}
static inline constexpr int max_exponent10()
{
if constexpr(is_same_v<T, float>)
return __FLT_MAX_10_EXP__;
if constexpr(is_same_v<T, double>)
return __DBL_MAX_10_EXP__;
if constexpr(is_same_v<T, long double>)
return __LDBL_MAX_10_EXP__;
return 0;
}
static inline constexpr int min_exponent2()
{
static_assert(__FLT_RADIX__ == 2);
if constexpr(is_same_v<T, float>)
return __FLT_MIN_EXP__;
if constexpr(is_same_v<T, double>)
return __DBL_MIN_EXP__;
if constexpr(is_same_v<T, long double>)
return __LDBL_MIN_EXP__;
return 0;
}
static inline constexpr int min_exponent10()
{
if constexpr(is_same_v<T, float>)
return __FLT_MIN_10_EXP__;
if constexpr(is_same_v<T, double>)
return __DBL_MIN_10_EXP__;
if constexpr(is_same_v<T, long double>)
return __LDBL_MIN_10_EXP__;
return 0;
}
};
}

View File

@ -3,7 +3,6 @@
#include <BAN/Errors.h>
#include <BAN/Move.h>
#include <BAN/New.h>
#include <BAN/PlacementNew.h>
namespace BAN
{
@ -22,11 +21,11 @@ namespace BAN
public:
LinkedList() = default;
LinkedList(const LinkedList<T>& other) requires is_copy_constructible_v<T> { *this = other; }
LinkedList(const LinkedList<T>& other) { *this = other; }
LinkedList(LinkedList<T>&& other) { *this = move(other); }
~LinkedList() { clear(); }
LinkedList<T>& operator=(const LinkedList<T>&) requires is_copy_constructible_v<T>;
LinkedList<T>& operator=(const LinkedList<T>&);
LinkedList<T>& operator=(LinkedList<T>&&);
ErrorOr<void> push_back(const T&);
@ -42,8 +41,6 @@ namespace BAN
iterator remove(iterator);
void clear();
iterator move_element_to_other_linked_list(LinkedList& dest_list, iterator dest_iter, iterator src_iter);
iterator begin() { return iterator(m_data, empty()); }
const_iterator begin() const { return const_iterator(m_data, empty()); }
iterator end() { return iterator(m_last, true); }
@ -67,11 +64,7 @@ namespace BAN
Node* prev;
};
template<typename... Args>
ErrorOr<Node*> allocate_node(Args&&...) const;
Node* remove_node(iterator);
void insert_node(iterator, Node*);
ErrorOr<Node*> allocate_node() const;
Node* m_data = nullptr;
Node* m_last = nullptr;
@ -122,7 +115,7 @@ namespace BAN
};
template<typename T>
LinkedList<T>& LinkedList<T>::operator=(const LinkedList<T>& other) requires is_copy_constructible_v<T>
LinkedList<T>& LinkedList<T>::operator=(const LinkedList<T>& other)
{
clear();
for (const T& elem : other)
@ -143,31 +136,6 @@ namespace BAN
return *this;
}
template<typename T>
LinkedList<T>::Node* LinkedList<T>::remove_node(iterator iter)
{
ASSERT(!empty() && iter);
Node* node = iter.m_current;
Node* prev = node->prev;
Node* next = node->next;
(prev ? prev->next : m_data) = next;
(next ? next->prev : m_last) = prev;
m_size--;
return node;
}
template<typename T>
void LinkedList<T>::insert_node(iterator iter, Node* node)
{
Node* next = iter.m_past_end ? nullptr : iter.m_current;
Node* prev = next ? next->prev : m_last;
node->next = next;
node->prev = prev;
(prev ? prev->next : m_data) = node;
(next ? next->prev : m_last) = node;
m_size++;
}
template<typename T>
ErrorOr<void> LinkedList<T>::push_back(const T& value)
{
@ -189,8 +157,15 @@ namespace BAN
template<typename T>
ErrorOr<void> LinkedList<T>::insert(iterator iter, T&& value)
{
Node* new_node = TRY(allocate_node(move(value)));
insert_node(iter, new_node);
Node* next = iter.m_past_end ? nullptr : iter.m_current;
Node* prev = next ? next->prev : m_last;
Node* new_node = TRY(allocate_node());
new (&new_node->value) T(move(value));
new_node->next = next;
new_node->prev = prev;
(prev ? prev->next : m_data) = new_node;
(next ? next->prev : m_last) = new_node;
m_size++;
return {};
}
@ -205,15 +180,21 @@ namespace BAN
template<typename... Args>
ErrorOr<void> LinkedList<T>::emplace(iterator iter, Args&&... args)
{
Node* new_node = TRY(allocate_node(forward<Args>(args)...));
insert_node(iter, new_node);
Node* next = iter.m_past_end ? nullptr : iter.m_current;
Node* prev = next ? next->prev : m_last;
Node* new_node = TRY(allocate_node());
new (&new_node->value) T(forward<Args>(args)...);
new_node->next = next;
new_node->prev = prev;
(prev ? prev->next : m_data) = new_node;
(next ? next->prev : m_last) = new_node;
m_size++;
return {};
}
template<typename T>
void LinkedList<T>::pop_back()
{
ASSERT(!empty());
remove(iterator(m_last, false));
}
@ -221,10 +202,14 @@ namespace BAN
LinkedList<T>::iterator LinkedList<T>::remove(iterator iter)
{
ASSERT(!empty() && iter);
Node* node = remove_node(iter);
Node* node = iter.m_current;
Node* prev = node->prev;
Node* next = node->next;
node->value.~T();
BAN::deallocator(node);
(prev ? prev->next : m_data) = next;
(next ? next->prev : m_last) = prev;
m_size--;
return next ? iterator(next, false) : iterator(m_last, true);
}
@ -244,16 +229,6 @@ namespace BAN
m_size = 0;
}
template<typename T>
LinkedList<T>::iterator LinkedList<T>::move_element_to_other_linked_list(LinkedList& dest_list, iterator dest_iter, iterator src_iter)
{
ASSERT(!empty() && src_iter);
Node* node = remove_node(src_iter);
iterator ret = node->next ? iterator(node->next, false) : iterator(m_last, true);
dest_list.insert_node(dest_iter, node);
return ret;
}
template<typename T>
const T& LinkedList<T>::back() const
{
@ -308,13 +283,11 @@ namespace BAN
}
template<typename T>
template<typename... Args>
ErrorOr<typename LinkedList<T>::Node*> LinkedList<T>::allocate_node(Args&&... args) const
ErrorOr<typename LinkedList<T>::Node*> LinkedList<T>::allocate_node() const
{
Node* node = (Node*)BAN::allocator(sizeof(Node));
if (node == nullptr)
return Error::from_errno(ENOMEM);
new (&node->value) T(forward<Args>(args)...);
return Error::from_errno(ENOMEM);
return node;
}
@ -423,4 +396,4 @@ namespace BAN
return m_current;
}
}
}

View File

@ -1,47 +0,0 @@
#pragma once
#include <BAN/Formatter.h>
namespace BAN
{
struct MACAddress
{
uint8_t address[6];
constexpr bool operator==(const MACAddress& other) const
{
return
address[0] == other.address[0] &&
address[1] == other.address[1] &&
address[2] == other.address[2] &&
address[3] == other.address[3] &&
address[4] == other.address[4] &&
address[5] == other.address[5];
}
};
}
namespace BAN::Formatter
{
template<typename F>
void print_argument(F putc, const MACAddress& mac, const ValueFormat&)
{
ValueFormat format {
.base = 16,
.percision = 0,
.fill = 2,
.upper = true,
};
print_argument(putc, mac.address[0], format);
for (size_t i = 1; i < 6; i++)
{
putc(':');
print_argument(putc, mac.address[i], format);
}
}
}

View File

@ -1,6 +1,5 @@
#pragma once
#include <BAN/Limits.h>
#include <BAN/Traits.h>
#include <stddef.h>
@ -9,12 +8,6 @@
namespace BAN::Math
{
template<typename T>
inline constexpr T abs(T val)
{
return val < 0 ? -val : val;
}
template<typename T>
inline constexpr T min(T a, T b)
{
@ -66,38 +59,6 @@ namespace BAN::Math
return (value & (value - 1)) == 0;
}
template<BAN::integral T>
static constexpr bool will_multiplication_overflow(T a, T b)
{
if (a == 0 || b == 0)
return false;
if ((a > 0) == (b > 0))
return a > BAN::numeric_limits<T>::max() / b;
else
return a < BAN::numeric_limits<T>::min() / b;
}
template<BAN::integral T>
static constexpr bool will_addition_overflow(T a, T b)
{
if (a > 0 && b > 0)
return a > BAN::numeric_limits<T>::max() - b;
if (a < 0 && b < 0)
return a < BAN::numeric_limits<T>::min() - b;
return false;
}
template<typename T>
requires is_same_v<T, unsigned int> || is_same_v<T, unsigned long> || is_same_v<T, unsigned long long>
inline constexpr T ilog2(T value)
{
if constexpr(is_same_v<T, unsigned int>)
return sizeof(T) * 8 - __builtin_clz(value) - 1;
if constexpr(is_same_v<T, unsigned long>)
return sizeof(T) * 8 - __builtin_clzl(value) - 1;
return sizeof(T) * 8 - __builtin_clzll(value) - 1;
}
template<floating_point T>
inline constexpr T log2(T value)
{
@ -141,4 +102,4 @@ namespace BAN::Math
return result;
}
}
}

View File

@ -27,3 +27,6 @@ namespace BAN
}
}
inline void* operator new(size_t, void* addr) { return addr; }
inline void* operator new[](size_t, void* addr) { return addr; }

View File

@ -2,7 +2,6 @@
#include <BAN/Assert.h>
#include <BAN/Move.h>
#include <BAN/PlacementNew.h>
#include <stdint.h>
@ -13,35 +12,35 @@ namespace BAN
class Optional
{
public:
constexpr Optional();
constexpr Optional(Optional&&);
constexpr Optional(const Optional&);
constexpr Optional(const T&);
constexpr Optional(T&&);
Optional();
Optional(Optional&&);
Optional(const Optional&);
Optional(const T&);
Optional(T&&);
template<typename... Args>
constexpr Optional(Args&&...);
Optional(Args&&...);
~Optional();
constexpr Optional& operator=(Optional&&);
constexpr Optional& operator=(const Optional&);
Optional& operator=(Optional&&);
Optional& operator=(const Optional&);
template<typename... Args>
constexpr Optional& emplace(Args&&...);
Optional& emplace(Args&&...);
constexpr T* operator->();
constexpr const T* operator->() const;
T* operator->();
const T* operator->() const;
constexpr T& operator*();
constexpr const T& operator*() const;
T& operator*();
const T& operator*() const;
constexpr bool has_value() const;
bool has_value() const;
constexpr T release_value();
constexpr T& value();
constexpr const T& value() const;
T release_value();
T& value();
const T& value() const;
constexpr void clear();
void clear();
private:
alignas(T) uint8_t m_storage[sizeof(T)];
@ -49,12 +48,12 @@ namespace BAN
};
template<typename T>
constexpr Optional<T>::Optional()
Optional<T>::Optional()
: m_has_value(false)
{}
template<typename T>
constexpr Optional<T>::Optional(Optional<T>&& other)
Optional<T>::Optional(Optional<T>&& other)
: m_has_value(other.has_value())
{
if (other.has_value())
@ -62,7 +61,7 @@ namespace BAN
}
template<typename T>
constexpr Optional<T>::Optional(const Optional<T>& other)
Optional<T>::Optional(const Optional<T>& other)
: m_has_value(other.has_value())
{
if (other.has_value())
@ -70,14 +69,14 @@ namespace BAN
}
template<typename T>
constexpr Optional<T>::Optional(const T& value)
Optional<T>::Optional(const T& value)
: m_has_value(true)
{
new (m_storage) T(value);
new (m_storage) T(value);
}
template<typename T>
constexpr Optional<T>::Optional(T&& value)
Optional<T>::Optional(T&& value)
: m_has_value(true)
{
new (m_storage) T(move(value));
@ -85,7 +84,7 @@ namespace BAN
template<typename T>
template<typename... Args>
constexpr Optional<T>::Optional(Args&&... args)
Optional<T>::Optional(Args&&... args)
: m_has_value(true)
{
new (m_storage) T(forward<Args>(args)...);
@ -98,7 +97,7 @@ namespace BAN
}
template<typename T>
constexpr Optional<T>& Optional<T>::operator=(Optional&& other)
Optional<T>& Optional<T>::operator=(Optional&& other)
{
clear();
m_has_value = other.has_value();
@ -108,7 +107,7 @@ namespace BAN
}
template<typename T>
constexpr Optional<T>& Optional<T>::operator=(const Optional& other)
Optional<T>& Optional<T>::operator=(const Optional& other)
{
clear();
m_has_value = other.has_value();
@ -119,7 +118,7 @@ namespace BAN
template<typename T>
template<typename... Args>
constexpr Optional<T>& Optional<T>::emplace(Args&&... args)
Optional<T>& Optional<T>::emplace(Args&&... args)
{
clear();
m_has_value = true;
@ -128,41 +127,41 @@ namespace BAN
}
template<typename T>
constexpr T* Optional<T>::operator->()
T* Optional<T>::operator->()
{
ASSERT(has_value());
return &value();
}
template<typename T>
constexpr const T* Optional<T>::operator->() const
const T* Optional<T>::operator->() const
{
ASSERT(has_value());
return &value();
}
template<typename T>
constexpr T& Optional<T>::operator*()
T& Optional<T>::operator*()
{
ASSERT(has_value());
return value();
}
template<typename T>
constexpr const T& Optional<T>::operator*() const
const T& Optional<T>::operator*() const
{
ASSERT(has_value());
return value();
}
template<typename T>
constexpr bool Optional<T>::has_value() const
bool Optional<T>::has_value() const
{
return m_has_value;
}
template<typename T>
constexpr T Optional<T>::release_value()
T Optional<T>::release_value()
{
ASSERT(has_value());
T released_value = move(value());
@ -172,25 +171,25 @@ namespace BAN
}
template<typename T>
constexpr T& Optional<T>::value()
T& Optional<T>::value()
{
ASSERT(has_value());
return (T&)m_storage;
}
template<typename T>
constexpr const T& Optional<T>::value() const
const T& Optional<T>::value() const
{
ASSERT(has_value());
return (const T&)m_storage;
}
template<typename T>
constexpr void Optional<T>::clear()
void Optional<T>::clear()
{
if (m_has_value)
value().~T();
m_has_value = false;
}
}
}

View File

@ -1,6 +0,0 @@
#pragma once
#include <stddef.h>
inline void* operator new(size_t, void* addr) { return addr; }
inline void* operator new[](size_t, void* addr) { return addr; }

View File

@ -5,7 +5,6 @@
#include <BAN/Math.h>
#include <BAN/Move.h>
#include <BAN/New.h>
#include <BAN/PlacementNew.h>
namespace BAN
{
@ -45,7 +44,6 @@ namespace BAN
void clear();
bool empty() const;
size_type capacity() const;
size_type size() const;
const T& front() const;
@ -187,12 +185,6 @@ namespace BAN
return m_size == 0;
}
template<typename T>
typename Queue<T>::size_type Queue<T>::capacity() const
{
return m_capacity;
}
template<typename T>
typename Queue<T>::size_type Queue<T>::size() const
{
@ -233,4 +225,4 @@ namespace BAN
return {};
}
}
}

View File

@ -1,6 +1,5 @@
#pragma once
#include <BAN/Atomic.h>
#include <BAN/Errors.h>
#include <BAN/Move.h>
#include <BAN/NoCopyMove.h>
@ -23,36 +22,24 @@ namespace BAN
void ref() const
{
uint32_t old = m_ref_count.fetch_add(1, MemoryOrder::memory_order_relaxed);
ASSERT(old > 0);
}
bool try_ref() const
{
uint32_t expected = m_ref_count.load(MemoryOrder::memory_order_relaxed);
for (;;)
{
if (expected == 0)
return false;
if (m_ref_count.compare_exchange(expected, expected + 1, MemoryOrder::memory_order_acquire))
return true;
}
ASSERT(m_ref_count > 0);
m_ref_count++;
}
void unref() const
{
uint32_t old = m_ref_count.fetch_sub(1);
ASSERT(old > 0);
if (old == 1)
ASSERT(m_ref_count > 0);
m_ref_count--;
if (m_ref_count == 0)
delete (const T*)this;
}
protected:
RefCounted() = default;
virtual ~RefCounted() { ASSERT(m_ref_count == 0); }
~RefCounted() { ASSERT(m_ref_count == 0); }
private:
mutable Atomic<uint32_t> m_ref_count = 1;
mutable uint32_t m_ref_count = 1;
};
template<typename T>
@ -137,11 +124,8 @@ namespace BAN
T* operator->() { return ptr(); }
const T* operator->() const { return ptr(); }
bool operator==(RefPtr other) const { return m_pointer == other.m_pointer; }
bool operator!=(RefPtr other) const { return m_pointer != other.m_pointer; }
bool empty() const { return m_pointer == nullptr; }
explicit operator bool() const { return m_pointer; }
operator bool() const { return m_pointer; }
void clear()
{

View File

@ -25,4 +25,4 @@ namespace BAN
bool m_enabled { true };
};
}
}

View File

@ -1,240 +0,0 @@
#pragma once
#include <BAN/Math.h>
#include <BAN/Swap.h>
#include <BAN/Traits.h>
#include <BAN/Vector.h>
namespace BAN::sort
{
template<typename It, typename Comp = less<typename It::value_type>>
void exchange_sort(It begin, It end, Comp comp = {})
{
for (It lhs = begin; lhs != end; ++lhs)
for (It rhs = next(lhs, 1); rhs != end; ++rhs)
if (!comp(*lhs, *rhs))
swap(*lhs, *rhs);
}
namespace detail
{
template<typename It, typename Comp>
It partition(It begin, It end, Comp comp)
{
It pivot = prev(end, 1);
It it1 = begin;
for (It it2 = begin; it2 != pivot; ++it2)
{
if (comp(*it2, *pivot))
{
swap(*it1, *it2);
++it1;
}
}
swap(*it1, *pivot);
return it1;
}
}
template<typename It, typename Comp = less<typename It::value_type>>
void quick_sort(It begin, It end, Comp comp = {})
{
if (distance(begin, end) <= 1)
return;
It mid = detail::partition(begin, end, comp);
quick_sort(begin, mid, comp);
quick_sort(++mid, end, comp);
}
template<typename It, typename Comp = less<typename It::value_type>>
void insertion_sort(It begin, It end, Comp comp = {})
{
if (distance(begin, end) <= 1)
return;
for (It it1 = next(begin, 1); it1 != end; ++it1)
{
typename It::value_type x = move(*it1);
It it2 = it1;
for (; it2 != begin && comp(x, *prev(it2, 1)); --it2)
*it2 = move(*prev(it2, 1));
*it2 = move(x);
}
}
namespace detail
{
template<typename It, typename Comp>
void push_heap(It begin, size_t hole_index, size_t top_index, typename It::value_type value, Comp comp)
{
size_t parent = (hole_index - 1) / 2;
while (hole_index > top_index && comp(*next(begin, parent), value))
{
*next(begin, hole_index) = move(*next(begin, parent));
hole_index = parent;
parent = (hole_index - 1) / 2;
}
*next(begin, hole_index) = move(value);
}
template<typename It, typename Comp>
void adjust_heap(It begin, size_t hole_index, size_t len, typename It::value_type value, Comp comp)
{
const size_t top_index = hole_index;
size_t child = hole_index;
while (child < (len - 1) / 2)
{
child = 2 * (child + 1);
if (comp(*next(begin, child), *next(begin, child - 1)))
child--;
*next(begin, hole_index) = move(*next(begin, child));
hole_index = child;
}
if (len % 2 == 0 && child == (len - 2) / 2)
{
child = 2 * (child + 1);
*next(begin, hole_index) = move(*next(begin, child - 1));
hole_index = child - 1;
}
push_heap(begin, hole_index, top_index, move(value), comp);
}
}
template<typename It, typename Comp = less<typename It::value_type>>
void make_heap(It begin, It end, Comp comp = {})
{
const size_t len = distance(begin, end);
if (len <= 1)
return;
size_t parent = (len - 2) / 2;
while (true)
{
detail::adjust_heap(begin, parent, len, move(*next(begin, parent)), comp);
if (parent == 0)
break;
parent--;
}
}
template<typename It, typename Comp = less<typename It::value_type>>
void sort_heap(It begin, It end, Comp comp = {})
{
const size_t len = distance(begin, end);
if (len <= 1)
return;
size_t last = len;
while (last > 1)
{
last--;
typename It::value_type x = move(*next(begin, last));
*next(begin, last) = move(*begin);
detail::adjust_heap(begin, 0, last, move(x), comp);
}
}
template<typename It, typename Comp = less<typename It::value_type>>
void heap_sort(It begin, It end, Comp comp = {})
{
make_heap(begin, end, comp);
sort_heap(begin, end, comp);
}
namespace detail
{
template<typename It, typename Comp>
void intro_sort_impl(It begin, It end, size_t max_depth, Comp comp)
{
if (distance(begin, end) <= 16)
return insertion_sort(begin, end, comp);
if (max_depth == 0)
return heap_sort(begin, end, comp);
It mid = detail::partition(begin, end, comp);
intro_sort_impl(begin, mid, max_depth - 1, comp);
intro_sort_impl(++mid, end, max_depth - 1, comp);
}
}
template<typename It, typename Comp = less<typename It::value_type>>
void intro_sort(It begin, It end, Comp comp = {})
{
const size_t len = distance(begin, end);
if (len <= 1)
return;
detail::intro_sort_impl(begin, end, 2 * Math::ilog2(len), comp);
}
namespace detail
{
template<unsigned_integral T>
consteval T lsb_index(T value)
{
for (T result = 0;; result++)
if (value & (1 << result))
return result;
}
}
template<typename It, size_t radix = 256>
requires is_unsigned_v<typename It::value_type> && (radix > 0 && (radix & (radix - 1)) == 0)
BAN::ErrorOr<void> radix_sort(It begin, It end)
{
using value_type = typename It::value_type;
const size_t len = distance(begin, end);
if (len <= 1)
return {};
Vector<value_type> temp;
TRY(temp.resize(len));
Vector<size_t> counts;
TRY(counts.resize(radix));
constexpr size_t mask = radix - 1;
constexpr size_t shift = detail::lsb_index(radix);
for (size_t s = 0; s < sizeof(value_type) * 8; s += shift)
{
for (auto& cnt : counts)
cnt = 0;
for (It it = begin; it != end; ++it)
counts[(*it >> s) & mask]++;
for (size_t i = 0; i < radix - 1; i++)
counts[i + 1] += counts[i];
for (It it = end; it != begin;)
{
--it;
temp[--counts[(*it >> s) & mask]] = *it;
}
for (size_t j = 0; j < temp.size(); j++)
*next(begin, j) = temp[j];
}
return {};
}
template<typename It, typename Comp = less<typename It::value_type>>
void sort(It begin, It end, Comp comp = {})
{
return intro_sort(begin, end, comp);
}
}

View File

@ -131,4 +131,4 @@ namespace BAN
return Span(m_data + start, length);
}
}
}

View File

@ -2,10 +2,9 @@
#include <BAN/Errors.h>
#include <BAN/Formatter.h>
#include <BAN/ForwardList.h>
#include <BAN/Hash.h>
#include <BAN/Iterators.h>
#include <BAN/New.h>
#include <BAN/StringView.h>
namespace BAN
{
@ -19,130 +18,28 @@ namespace BAN
static constexpr size_type sso_capacity = 15;
public:
String() {}
String(const String& other) { *this = other; }
String(String&& other) { *this = move(other); }
String(StringView other) { *this = other; }
~String() { clear(); }
String();
String(const String&);
String(String&&);
String(StringView);
~String();
template<typename... Args>
static BAN::ErrorOr<String> formatted(const char* format, Args&&... args)
{
size_type length = 0;
BAN::Formatter::print([&](char) { length++; }, format, BAN::forward<Args>(args)...);
static String formatted(const char* format, const Args&... args);
String result;
TRY(result.reserve(length));
BAN::Formatter::print([&](char c){ MUST(result.push_back(c)); }, format, BAN::forward<Args>(args)...);
String& operator=(const String&);
String& operator=(String&&);
String& operator=(StringView);
return result;
}
ErrorOr<void> push_back(char);
ErrorOr<void> insert(char, size_type);
ErrorOr<void> insert(StringView, size_type);
ErrorOr<void> append(StringView);
String& operator=(const String& other)
{
clear();
MUST(ensure_capacity(other.size()));
memcpy(data(), other.data(), other.size() + 1);
m_size = other.size();
return *this;
}
void pop_back();
void remove(size_type);
String& operator=(String&& other)
{
clear();
if (other.has_sso())
memcpy(data(), other.data(), other.size() + 1);
else
{
m_storage.general_storage = other.m_storage.general_storage;
m_has_sso = false;
}
m_size = other.m_size;
other.m_size = 0;
other.m_storage.sso_storage = SSOStorage();
other.m_has_sso = true;
return *this;
}
String& operator=(StringView other)
{
clear();
MUST(ensure_capacity(other.size()));
memcpy(data(), other.data(), other.size());
m_size = other.size();
data()[m_size] = '\0';
return *this;
}
ErrorOr<void> push_back(char c)
{
TRY(ensure_capacity(m_size + 1));
data()[m_size] = c;
m_size++;
data()[m_size] = '\0';
return {};
}
ErrorOr<void> insert(char c, size_type index)
{
ASSERT(index <= m_size);
TRY(ensure_capacity(m_size + 1));
memmove(data() + index + 1, data() + index, m_size - index);
data()[index] = c;
m_size++;
data()[m_size] = '\0';
return {};
}
ErrorOr<void> insert(StringView str, size_type index)
{
ASSERT(index <= m_size);
TRY(ensure_capacity(m_size + str.size()));
memmove(data() + index + str.size(), data() + index, m_size - index);
memcpy(data() + index, str.data(), str.size());
m_size += str.size();
data()[m_size] = '\0';
return {};
}
ErrorOr<void> append(StringView str)
{
TRY(ensure_capacity(m_size + str.size()));
memcpy(data() + m_size, str.data(), str.size());
m_size += str.size();
data()[m_size] = '\0';
return {};
}
void pop_back()
{
ASSERT(m_size > 0);
m_size--;
data()[m_size] = '\0';
}
void remove(size_type index)
{
ASSERT(index < m_size);
memcpy(data() + index, data() + index + 1, m_size - index);
m_size--;
data()[m_size] = '\0';
}
void clear()
{
if (!has_sso())
{
deallocator(m_storage.general_storage.data);
m_storage.sso_storage = SSOStorage();
m_has_sso = true;
}
m_size = 0;
data()[m_size] = '\0';
}
void clear();
const_iterator begin() const { return const_iterator(data()); }
iterator begin() { return iterator(data()); }
@ -158,151 +55,26 @@ namespace BAN
char operator[](size_type index) const { ASSERT(index < m_size); return data()[index]; }
char& operator[](size_type index) { ASSERT(index < m_size); return data()[index]; }
bool operator==(const String& str) const
{
if (size() != str.size())
return false;
for (size_type i = 0; i < m_size; i++)
if (data()[i] != str.data()[i])
return false;
return true;
}
bool operator==(StringView) const;
bool operator==(const char*) const;
bool operator==(StringView str) const
{
if (size() != str.size())
return false;
for (size_type i = 0; i < m_size; i++)
if (data()[i] != str.data()[i])
return false;
return true;
}
bool operator==(const char* cstr) const
{
for (size_type i = 0; i < m_size; i++)
if (data()[i] != cstr[i])
return false;
if (cstr[size()] != '\0')
return false;
return true;
}
ErrorOr<void> resize(size_type new_size, char init_c = '\0')
{
if (m_size == new_size)
return {};
// expanding
if (m_size < new_size)
{
TRY(ensure_capacity(new_size));
memset(data() + m_size, init_c, new_size - m_size);
m_size = new_size;
data()[m_size] = '\0';
return {};
}
m_size = new_size;
data()[m_size] = '\0';
return {};
}
ErrorOr<void> reserve(size_type new_size)
{
TRY(ensure_capacity(new_size));
return {};
}
ErrorOr<void> shrink_to_fit()
{
if (has_sso())
return {};
if (fits_in_sso())
{
char* data = m_storage.general_storage.data;
m_storage.sso_storage = SSOStorage();
m_has_sso = true;
memcpy(this->data(), data, m_size + 1);
deallocator(data);
return {};
}
GeneralStorage& storage = m_storage.general_storage;
if (storage.capacity == m_size)
return {};
char* new_data = (char*)allocator(m_size + 1);
if (new_data == nullptr)
return Error::from_errno(ENOMEM);
memcpy(new_data, storage.data, m_size);
deallocator(storage.data);
storage.capacity = m_size;
storage.data = new_data;
return {};
}
ErrorOr<void> resize(size_type, char = '\0');
ErrorOr<void> reserve(size_type);
ErrorOr<void> shrink_to_fit();
StringView sv() const { return StringView(data(), size()); }
bool empty() const { return m_size == 0; }
size_type size() const { return m_size; }
size_type capacity() const;
size_type capacity() const
{
if (has_sso())
return sso_capacity;
return m_storage.general_storage.capacity;
}
char* data()
{
if (has_sso())
return m_storage.sso_storage.data;
return m_storage.general_storage.data;
}
const char* data() const
{
if (has_sso())
return m_storage.sso_storage.data;
return m_storage.general_storage.data;
}
char* data();
const char* data() const;
private:
ErrorOr<void> ensure_capacity(size_type new_size)
{
if (m_size >= new_size)
return {};
if (has_sso() && fits_in_sso(new_size))
return {};
ErrorOr<void> ensure_capacity(size_type);
char* new_data = (char*)allocator(new_size + 1);
if (new_data == nullptr)
return Error::from_errno(ENOMEM);
if (m_size)
memcpy(new_data, data(), m_size + 1);
if (has_sso())
{
m_storage.general_storage = GeneralStorage();
m_has_sso = false;
}
else
deallocator(m_storage.general_storage.data);
auto& storage = m_storage.general_storage;
storage.capacity = new_size;
storage.data = new_data;
return {};
}
bool has_sso() const { return m_has_sso; }
bool has_sso() const;
bool fits_in_sso() const { return fits_in_sso(m_size); }
static bool fits_in_sso(size_type size) { return size < sso_capacity; }
@ -327,6 +99,14 @@ namespace BAN
size_type m_has_sso : 1 { true };
};
template<typename... Args>
String String::formatted(const char* format, const Args&... args)
{
String result;
BAN::Formatter::print([&](char c){ MUST(result.push_back(c)); }, format, args...);
return result;
}
template<>
struct hash<String>
{

View File

@ -1,11 +1,8 @@
#pragma once
#include <BAN/Formatter.h>
#include <BAN/ForwardList.h>
#include <BAN/Hash.h>
#include <BAN/Formatter.h>
#include <BAN/Iterators.h>
#include <BAN/Optional.h>
#include <BAN/Vector.h>
namespace BAN
{
@ -17,234 +14,43 @@ namespace BAN
using const_iterator = ConstIteratorSimple<char, StringView>;
public:
constexpr StringView() {}
constexpr StringView(const char* string, size_type len = -1)
{
if (len == size_type(-1))
len = strlen(string);
m_data = string;
m_size = len;
}
StringView();
StringView(const String&);
StringView(const char*, size_type = -1);
constexpr const_iterator begin() const { return const_iterator(m_data); }
constexpr const_iterator end() const { return const_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); }
constexpr char operator[](size_type index) const
{
ASSERT(index < m_size);
return m_data[index];
}
char operator[](size_type) const;
constexpr bool operator==(StringView other) const
{
if (m_size != other.m_size)
return false;
for (size_type i = 0; i < m_size; i++)
if (m_data[i] != other.m_data[i])
return false;
return true;
}
bool operator==(const String&) const;
bool operator==(StringView) const;
bool operator==(const char*) const;
constexpr bool operator==(const char* other) const
{
for (size_type i = 0; i < m_size; i++)
if (m_data[i] != other[i])
return false;
return other[m_size] == '\0';
}
StringView substring(size_type, size_type = -1) const;
constexpr StringView substring(size_type index, size_type len = -1) const
{
ASSERT(index <= m_size);
if (len == size_type(-1))
len = m_size - index;
ASSERT(len <= m_size - index); // weird order to avoid overflow
StringView result;
result.m_data = m_data + index;
result.m_size = len;
return result;
}
ErrorOr<Vector<StringView>> split(char, bool = false);
ErrorOr<Vector<StringView>> split(bool(*comp)(char), bool = false);
ErrorOr<Vector<StringView>> split(char delim, bool allow_empties = false) const
{
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++;
}
char back() const;
char front() const;
Vector<StringView> result;
TRY(result.reserve(count));
bool contains(char) const;
size_type count(char) const;
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 || (start == m_size && allow_empties))
TRY(result.push_back(this->substring(start)));
return result;
}
ErrorOr<Vector<StringView>> split(bool(*comp)(char), bool allow_empties = false) const
{
size_type count = 0;
{
size_type start = 0;
for (size_type i = 0; i < m_size; i++)
{
if (comp(m_data[i]))
{
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 (comp(m_data[i]))
{
if (allow_empties || start != i)
TRY(result.push_back(this->substring(start, i - start)));
start = i + 1;
}
}
if (start < m_size || (start == m_size && allow_empties))
TRY(result.push_back(this->substring(start)));
return result;
}
constexpr char back() const
{
ASSERT(m_size > 0);
return m_data[m_size - 1];
}
constexpr char front() const
{
ASSERT(m_size > 0);
return m_data[0];
}
BAN::Optional<size_type> find(char ch) const
{
for (size_type i = 0; i < m_size; i++)
if (m_data[i] == ch)
return i;
return {};
}
BAN::Optional<size_type> find(bool(*comp)(char)) const
{
for (size_type i = 0; i < m_size; i++)
if (comp(m_data[i]))
return i;
return {};
}
BAN::Optional<size_type> rfind(char ch) const
{
for (size_type i = m_size; i > 0; i--)
if (m_data[i - 1] == ch)
return i - 1;
return {};
}
BAN::Optional<size_type> rfind(bool(*comp)(char)) const
{
for (size_type i = m_size; i > 0; i--)
if (comp(m_data[i - 1]))
return i - 1;
return {};
}
constexpr bool starts_with(BAN::StringView target) const
{
if (target.size() > m_size)
return false;
for (size_type i = 0; i < m_size - target.size(); i++)
{
bool valid = true;
for (size_type j = 0; j < target.size() && valid; j++)
valid = (m_data[i + j] == target[j]);
if (valid)
return true;
}
return false;
}
constexpr bool contains(char ch) const
{
for (size_type i = 0; i < m_size; i++)
if (m_data[i] == ch)
return true;
return false;
}
constexpr size_type count(char ch) const
{
size_type result = 0;
for (size_type i = 0; i < m_size; i++)
if (m_data[i] == ch)
result++;
return result;
}
constexpr bool empty() const { return m_size == 0; }
constexpr size_type size() const { return m_size; }
constexpr const char* data() const { return m_data; }
bool empty() const;
size_type size() const;
const char* data() const;
private:
const char* m_data = nullptr;
size_type m_size = 0;
};
template<>
struct hash<StringView>
{
hash_t operator()(StringView string) const
{
constexpr hash_t FNV_offset_basis = 0x811c9dc5;
constexpr hash_t FNV_prime = 0x01000193;
hash_t hash = FNV_offset_basis;
for (StringView::size_type i = 0; i < string.size(); i++)
{
hash *= FNV_prime;
hash ^= (uint8_t)string[i];
}
return hash;
}
};
}
inline constexpr BAN::StringView operator""_sv(const char* str, BAN::StringView::size_type len) { return BAN::StringView(str, len); }
inline BAN::StringView operator""sv(const char* str, BAN::StringView::size_type len) { return BAN::StringView(str, len); }
namespace BAN::Formatter
{

View File

@ -1,16 +0,0 @@
#pragma once
#include <BAN/Move.h>
namespace BAN
{
template<typename T>
void swap(T& lhs, T& rhs)
{
T tmp = move(lhs);
lhs = move(rhs);
rhs = move(tmp);
}
}

View File

@ -34,4 +34,4 @@ namespace BAN::Formatter
print(putc, "{} {} {} {2}:{2}:{2} GMT+0 {4}", week_days[time.week_day], months[time.month], time.day, time.hour, time.minute, time.second, time.year);
}
}
}

View File

@ -34,33 +34,18 @@ namespace BAN
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;
template<typename T, T V> struct integral_constant { static constexpr T value = V; };
template<typename T, T V > inline constexpr T integral_constant_v = integral_constant<T, V>::value;
using true_type = integral_constant<bool, true>;
using false_type = integral_constant<bool, false>;
struct true_type { static constexpr bool value = true; };
struct false_type { static constexpr bool value = false; };
template<typename T, typename S> struct is_same : false_type {};
template<typename T> struct is_same<T, T> : true_type {};
template<typename T, typename S> inline constexpr bool is_same_v = is_same<T, S>::value;
template<typename T, typename S> concept same_as = BAN::is_same_v<T, S>;
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, typename... Args> struct is_constructible { static constexpr bool value = __is_constructible(T, Args...); };
template<typename T, typename... Args> inline constexpr bool is_constructible_v = is_constructible<T, Args...>::value;
template<typename T> struct is_default_constructible { static constexpr bool value = is_constructible_v<T>; };
template<typename T> inline constexpr bool is_default_constructible_v = is_default_constructible<T>::value;
template<typename T> struct is_copy_constructible { static constexpr bool value = is_constructible_v<T, const T&>; };
template<typename T> inline constexpr bool is_copy_constructible_v = is_copy_constructible<T>::value;
template<typename T> struct is_move_constructible { static constexpr bool value = is_constructible_v<T, T&&>; };
template<typename T> inline constexpr bool is_move_constructible_v = is_move_constructible<T>::value;
template<typename T> struct is_integral { static constexpr bool value = requires (T t, T* p, void (*f)(T)) { reinterpret_cast<T>(t); f(0); p + t; }; };
template<typename T> inline constexpr bool is_integral_v = is_integral<T>::value;
template<typename T> concept integral = is_integral_v<T>;
@ -87,57 +72,16 @@ namespace BAN
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;
template<typename Base, typename Derived> struct is_base_of { static constexpr bool value = __is_base_of(Base, Derived); };
template<typename Base, typename Derived> inline constexpr bool is_base_of_v = is_base_of<Base, Derived>::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, bool = is_arithmetic_v<T>> struct is_unsigned { static constexpr bool value = T(0) < T(-1); };
template<typename T> struct is_unsigned<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> concept signed_integral = is_signed_v<T> && is_integral_v<T>;
template<typename T> struct is_unsigned : detail::is_unsigned<T> {};
template<typename T> inline constexpr bool is_unsigned_v = is_unsigned<T>::value;
template<typename T> concept unsigned_integral = is_unsigned_v<T> && is_integral_v<T>;
#define __BAN_TRAITS_MAKE_UNSIGNED_CV(__type) \
template<> struct make_unsigned<__type> { using type = unsigned __type; }; \
template<> struct make_unsigned<const __type> { using type = unsigned const __type; }; \
template<> struct make_unsigned<volatile __type> { using type = unsigned volatile __type; }; \
template<> struct make_unsigned<const volatile __type> { using type = unsigned const volatile __type; };
template<typename T> requires is_arithmetic_v<T> struct make_unsigned { using type = T; };
__BAN_TRAITS_MAKE_UNSIGNED_CV(char)
__BAN_TRAITS_MAKE_UNSIGNED_CV(short)
__BAN_TRAITS_MAKE_UNSIGNED_CV(int)
__BAN_TRAITS_MAKE_UNSIGNED_CV(long)
__BAN_TRAITS_MAKE_UNSIGNED_CV(long long)
template<typename T> using make_unsigned_t = typename make_unsigned<T>::type;
#undef __BAN_TRAITS_MAKE_UNSIGNED_CV
#define __BAN_TRAITS_MAKE_SIGNED_CV(__type) \
template<> struct make_signed<unsigned __type> { using type = __type; }; \
template<> struct make_signed<unsigned const __type> { using type = const __type; }; \
template<> struct make_signed<unsigned volatile __type> { using type = volatile __type; }; \
template<> struct make_signed<unsigned const volatile __type> { using type = const volatile __type; };
template<typename T> requires is_arithmetic_v<T> struct make_signed { using type = T; };
__BAN_TRAITS_MAKE_SIGNED_CV(char)
__BAN_TRAITS_MAKE_SIGNED_CV(short)
__BAN_TRAITS_MAKE_SIGNED_CV(int)
__BAN_TRAITS_MAKE_SIGNED_CV(long)
__BAN_TRAITS_MAKE_SIGNED_CV(long long)
template<typename T> using make_signed_t = typename make_signed<T>::type;
#undef __BAN_TRAITS_MAKE_SIGNED_CV
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

@ -21,21 +21,20 @@ namespace BAN::UTF8
return 0;
}
template<typename T> requires (sizeof(T) == 1)
constexpr uint32_t to_codepoint(const T* bytes)
constexpr uint32_t to_codepoint(uint8_t* bytes)
{
uint32_t length = byte_length(bytes[0]);
for (uint32_t i = 1; i < length; i++)
if (((uint8_t)bytes[i] & 0xC0) != 0x80)
if ((bytes[i] & 0xC0) != 0x80)
return UTF8::invalid;
switch (length)
{
case 1: return (((uint8_t)bytes[0] & 0x80) != 0x00) ? UTF8::invalid : (uint8_t)bytes[0];
case 2: return (((uint8_t)bytes[0] & 0xE0) != 0xC0) ? UTF8::invalid : (((uint8_t)bytes[0] & 0x1F) << 6) | ((uint8_t)bytes[1] & 0x3F);
case 3: return (((uint8_t)bytes[0] & 0xF0) != 0xE0) ? UTF8::invalid : (((uint8_t)bytes[0] & 0x0F) << 12) | (((uint8_t)bytes[1] & 0x3F) << 6) | ((uint8_t)bytes[2] & 0x3F);
case 4: return (((uint8_t)bytes[0] & 0xF8) != 0xF0) ? UTF8::invalid : (((uint8_t)bytes[0] & 0x07) << 18) | (((uint8_t)bytes[1] & 0x3F) << 12) | (((uint8_t)bytes[2] & 0x3F) << 6) | ((uint8_t)bytes[3] & 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 UTF8::invalid;
@ -79,4 +78,4 @@ namespace BAN::UTF8
return true;
}
}
}

View File

@ -67,7 +67,7 @@ namespace BAN
T* operator->()
{
ASSERT(m_pointer);
return m_pointer;
return m_pointer;
}
const T* operator->() const
@ -95,4 +95,4 @@ namespace BAN
friend class UniqPtr;
};
}
}

View File

@ -3,7 +3,6 @@
#include <BAN/Assert.h>
#include <BAN/Math.h>
#include <BAN/Move.h>
#include <BAN/PlacementNew.h>
#include <string.h>
@ -43,10 +42,9 @@ namespace BAN
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
@ -140,14 +138,14 @@ namespace BAN
Variant(T&& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
: m_index(detail::index<T, Ts...>())
{
new (m_storage) T(move(value));
new (m_storage) T(move(value));
}
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);
new (m_storage) T(value);
}
~Variant()
@ -216,14 +214,6 @@ namespace BAN
return m_index == detail::index<T, Ts...>();
}
template<typename T, typename... Args>
void emplace(Args&&... args) requires (can_have<T>())
{
clear();
m_index = detail::index<T, Ts...>();
new (m_storage) T(BAN::forward<Args>(args)...);
}
template<typename T>
void set(T&& value) requires (can_have<T>() && !is_lvalue_reference_v<T>)
{
@ -300,4 +290,4 @@ namespace BAN
size_t m_index { invalid_index() };
};
}
}

View File

@ -5,7 +5,6 @@
#include <BAN/Math.h>
#include <BAN/Move.h>
#include <BAN/New.h>
#include <BAN/PlacementNew.h>
#include <BAN/Span.h>
namespace BAN
@ -39,7 +38,7 @@ namespace BAN
ErrorOr<void> emplace(size_type, Args&&...);
ErrorOr<void> insert(size_type, T&&);
ErrorOr<void> insert(size_type, const T&);
iterator begin() { return iterator(m_data); }
iterator end() { return iterator(m_data + m_size); }
const_iterator begin() const { return const_iterator(m_data); }
@ -65,8 +64,7 @@ namespace BAN
const T& front() const;
T& front();
ErrorOr<void> resize(size_type) requires is_default_constructible_v<T>;
ErrorOr<void> resize(size_type, const T&) requires is_copy_constructible_v<T>;
ErrorOr<void> resize(size_type, const T& = T());
ErrorOr<void> reserve(size_type);
ErrorOr<void> shrink_to_fit();
@ -138,13 +136,10 @@ namespace BAN
template<typename T>
Vector<T>& Vector<T>::operator=(const Vector<T>& other)
{
clear();
MUST(ensure_capacity(other.size()));
for (size_type i = 0; i < BAN::Math::min(size(), other.size()); i++)
m_data[i] = other.m_data[i];
for (size_type i = size(); i < other.size(); i++)
for (size_type i = 0; i < other.size(); i++)
new (m_data + i) T(other[i]);
for (size_type i = other.size(); i < size(); i++)
m_data[i].~T();
m_size = other.m_size;
return *this;
}
@ -302,21 +297,7 @@ namespace BAN
}
template<typename T>
ErrorOr<void> Vector<T>::resize(size_type size) requires is_default_constructible_v<T>
{
TRY(ensure_capacity(size));
if (size < m_size)
for (size_type i = size; i < m_size; i++)
m_data[i].~T();
if (size > m_size)
for (size_type i = m_size; i < size; i++)
new (m_data + i) T();
m_size = size;
return {};
}
template<typename T>
ErrorOr<void> Vector<T>::resize(size_type size, const T& value) requires is_copy_constructible_v<T>
ErrorOr<void> Vector<T>::resize(size_type size, const T& value)
{
TRY(ensure_capacity(size));
if (size < m_size)

View File

@ -2,10 +2,6 @@
#include <BAN/RefPtr.h>
#if __is_kernel
#include <kernel/Lock/SpinLock.h>
#endif
namespace BAN
{
@ -15,37 +11,22 @@ namespace BAN
template<typename T>
class WeakPtr;
// FIXME: Write this without using locks...
template<typename T>
class WeakLink : public RefCounted<WeakLink<T>>
{
public:
RefPtr<T> try_lock()
{
#if __is_kernel
Kernel::SpinLockGuard _(m_weak_lock);
#endif
if (m_ptr && m_ptr->try_ref())
return RefPtr<T>::adopt(m_ptr);
return nullptr;
}
RefPtr<T> lock() { ASSERT(m_ptr); return raw_ptr(); }
T* raw_ptr() { return m_ptr; }
bool valid() const { return m_ptr; }
void invalidate()
{
#if __is_kernel
Kernel::SpinLockGuard _(m_weak_lock);
#endif
m_ptr = nullptr;
}
void invalidate() { m_ptr = nullptr; }
private:
WeakLink(T* ptr) : m_ptr(ptr) {}
private:
T* m_ptr;
#if __is_kernel
Kernel::SpinLock m_weak_lock;
#endif
friend class RefPtr<WeakLink<T>>;
};
@ -53,7 +34,7 @@ namespace BAN
class Weakable
{
public:
virtual ~Weakable()
~Weakable()
{
if (m_link)
m_link->invalidate();
@ -101,8 +82,8 @@ namespace BAN
RefPtr<T> lock()
{
if (m_link)
return m_link->try_lock();
if (m_link->valid())
return m_link->lock();
return nullptr;
}
@ -110,8 +91,6 @@ namespace BAN
bool valid() const { return m_link && m_link->valid(); }
explicit operator bool() const { return valid(); }
private:
WeakPtr(const RefPtr<WeakLink<T>>& link)
: m_link(link)
@ -125,4 +104,4 @@ namespace BAN
friend class Weakable<T>;
};
}
}

View File

@ -4,55 +4,41 @@ if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "banan-os")
message(FATAL_ERROR "CMAKE_SYSTEM_NAME is not banan-os")
endif ()
#add_compile_options(-mno-sse -mno-sse2)
add_compile_definitions(__enable_sse=1)
add_compile_options(-mno-sse -mno-sse2)
add_compile_definitions(__enable_sse=0)
project(banan-os CXX C ASM)
set(BANAN_BASE_SYSROOT ${CMAKE_SOURCE_DIR}/base-sysroot.tar.gz)
set(BANAN_INCLUDE ${BANAN_SYSROOT}/usr/include)
set(BANAN_LIB ${BANAN_SYSROOT}/usr/lib)
set(BANAN_BIN ${BANAN_SYSROOT}/usr/bin)
set(BANAN_ETC ${BANAN_SYSROOT}/usr/etc)
set(BANAN_SHARE ${BANAN_SYSROOT}/usr/share)
set(BANAN_BOOT ${BANAN_SYSROOT}/boot)
set(CMAKE_INSTALL_BINDIR ${BANAN_BIN})
set(CMAKE_INSTALL_SBINDIR ${BANAN_BIN})
set(CMAKE_INSTALL_LIBDIR ${BANAN_LIB})
set(CMAKE_INSTALL_INCLUDEDIR ${BANAN_INCLUDE})
set(CMAKE_INSTALL_SYSCONF ${BANAN_ETC})
set(CMAKE_INSTALL_MESSAGE NEVER)
set(CMAKE_SKIP_INSTALL_ALL_DEPENDENCY True)
# include headers of ${library} to ${target}
function(banan_include_headers target library)
target_include_directories(${target} PRIVATE $<TARGET_PROPERTY:${library},SOURCE_DIR>/include)
endfunction()
# include headers and link ${library} to ${target}
function(banan_link_library target library)
target_link_libraries(${target} PRIVATE ${library})
banan_include_headers(${target} ${library})
endfunction()
# add install step for all header files of target
function(banan_install_headers target)
file(GLOB_RECURSE headers RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/include *.h)
foreach(header ${headers})
get_filename_component(subdirectory ${header} DIRECTORY)
install(FILES include/${header} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/${subdirectory})
endforeach()
target_include_directories(${target} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
endfunction()
set(BANAN_LIB ${BANAN_SYSROOT}/usr/lib)
set(BANAN_BIN ${BANAN_SYSROOT}/usr/bin)
set(BANAN_BOOT ${BANAN_SYSROOT}/boot)
add_subdirectory(kernel)
add_subdirectory(bootloader)
add_subdirectory(BAN)
add_subdirectory(libc)
add_subdirectory(LibELF)
add_subdirectory(userspace)
add_custom_target(sysroot
COMMAND ${CMAKE_COMMAND} -E make_directory ${BANAN_SYSROOT}
COMMAND cd ${BANAN_SYSROOT} && tar xf ${BANAN_BASE_SYSROOT}
)
add_custom_target(headers
DEPENDS kernel-headers
DEPENDS ban-headers
DEPENDS libc-headers
DEPENDS libelf-headers
)
add_custom_target(install-sysroot
COMMAND cd ${BANAN_SYSROOT} && tar cf ${BANAN_SYSROOT_TAR} *
DEPENDS kernel-install
DEPENDS ban-install
DEPENDS libc-install
DEPENDS userspace-install
DEPENDS libelf-install
)

View File

12
LibELF/CMakeLists.txt Normal file
View File

@ -0,0 +1,12 @@
cmake_minimum_required(VERSION 3.26)
project(LibELF CXX)
add_custom_target(libelf-headers
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CMAKE_CURRENT_SOURCE_DIR}/include/ ${BANAN_INCLUDE}/
DEPENDS sysroot
)
add_custom_target(libelf-install
DEPENDS libelf-headers
)

View File

@ -4,6 +4,7 @@
#ifdef __is_kernel
#include <kernel/FS/VirtualFileSystem.h>
#include <kernel/Memory/PageTableScope.h>
#include <kernel/Process.h>
#endif
@ -76,7 +77,7 @@ namespace LibELF
return BAN::Error::from_errno(EINVAL);
}
if (m_data[EI_MAG0] != ELFMAG0 ||
if (m_data[EI_MAG0] != ELFMAG0 ||
m_data[EI_MAG1] != ELFMAG1 ||
m_data[EI_MAG2] != ELFMAG2 ||
m_data[EI_MAG3] != ELFMAG3)
@ -251,7 +252,7 @@ namespace LibELF
break;
default:
ASSERT(false);
}
}
#endif
(void)header;
return true;
@ -374,7 +375,7 @@ namespace LibELF
break;
default:
ASSERT(false);
}
}
#endif
(void)header;
return true;

View File

@ -1,6 +1,7 @@
#include <BAN/ScopeGuard.h>
#include <kernel/CriticalScope.h>
#include <kernel/Memory/Heap.h>
#include <kernel/Lock/LockGuard.h>
#include <kernel/LockGuard.h>
#include <LibELF/LoadableELF.h>
#include <LibELF/Values.h>
@ -65,7 +66,7 @@ namespace LibELF
size_t nread = TRY(m_inode->read(0, BAN::ByteSpan::from(m_file_header)));
ASSERT(nread == sizeof(m_file_header));
if (m_file_header.e_ident[EI_MAG0] != ELFMAG0 ||
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)
@ -86,13 +87,13 @@ namespace LibELF
return BAN::Error::from_errno(ENOEXEC);
}
#if ARCH(i686)
#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");
dprintln("Not in native format");
return BAN::Error::from_errno(EINVAL);
}
@ -202,14 +203,6 @@ namespace LibELF
m_loaded = true;
}
void LoadableELF::update_suid_sgid(Kernel::Credentials& credentials)
{
if (m_inode->mode().mode & +Inode::Mode::ISUID)
credentials.set_euid(m_inode->uid());
if (m_inode->mode().mode & +Inode::Mode::ISGID)
credentials.set_egid(m_inode->gid());
}
BAN::ErrorOr<void> LoadableELF::load_page_to_memory(vaddr_t address)
{
for (const auto& program_header : m_program_headers)
@ -239,13 +232,13 @@ namespace LibELF
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;
@ -266,7 +259,7 @@ namespace LibELF
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);
@ -281,6 +274,10 @@ namespace LibELF
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)
@ -310,9 +307,12 @@ namespace LibELF
if (paddr == 0)
return BAN::Error::from_errno(ENOMEM);
PageTable::with_fast_page(paddr, [&] {
{
CriticalScope _;
PageTable::map_fast_page(paddr);
memcpy(PageTable::fast_page_as_ptr(), (void*)(start + i * PAGE_SIZE), PAGE_SIZE);
});
PageTable::unmap_fast_page();
}
new_page_table.map_page_at(paddr, start + i * PAGE_SIZE, flags);
elf->m_physical_page_count++;

View File

@ -42,7 +42,7 @@ namespace LibELF
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(i686)
#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); }
@ -68,7 +68,7 @@ namespace LibELF
{}
//#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&);
@ -86,4 +86,4 @@ namespace LibELF
//#endif
};
}
}

View File

@ -7,7 +7,6 @@
#include <BAN/UniqPtr.h>
#include <BAN/Vector.h>
#include <kernel/Credentials.h>
#include <kernel/FS/Inode.h>
#include <kernel/Memory/PageTable.h>
@ -31,8 +30,6 @@ namespace LibELF
bool is_address_space_free() const;
void reserve_address_space();
void update_suid_sgid(Kernel::Credentials&);
BAN::ErrorOr<void> load_page_to_memory(Kernel::vaddr_t address);
BAN::ErrorOr<BAN::UniqPtr<LoadableELF>> clone(Kernel::PageTable&);
@ -54,4 +51,4 @@ namespace LibELF
bool m_loaded { false };
};
}
}

View File

@ -155,7 +155,7 @@ namespace LibELF
Elf64Xword p_align;
};
#if ARCH(i686)
#if ARCH(i386)
using ElfNativeAddr = Elf32Addr;
using ElfNativeOff = Elf32Off;
using ElfNativeHalf = Elf32Half;
@ -183,4 +183,4 @@ namespace LibELF
using ElfNativeProgramHeader = Elf64ProgramHeader;
#endif
}
}

View File

@ -137,4 +137,4 @@ namespace LibELF
PF_MASKPROC = 0xFF000000,
};
}
}

102
README.md
View File

@ -1,58 +1,8 @@
[![](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fbananymous.com%2Fbanan-os%2Ftokei.json&query=%24.lines&label=total%20lines)](https://git.bananymous.com/Bananymous/banan-os)
[![](https://img.shields.io/github/commit-activity/m/Bananymous/banan-os)](https://git.bananymous.com/Bananymous/banan-os)
[![](https://img.shields.io/github/license/bananymous/banan-os)](https://git.bananymous.com/Bananymous/banan-os/src/branch/main/LICENSE)
[![](https://img.shields.io/discord/1242165176032297040?logo=discord&label=discord)](https://discord.gg/ehjGySwYdK)
![license](https://img.shields.io/github/license/bananymous/banan-os)
# banan-os
This is my hobby operating system written in C++. Currently supports x86\_64 and i686 architectures.
You can find a live demo [here](https://bananymous.com/banan-os)
### Features
#### General
- [x] Ring3 userspace
- [x] SMP (multiprocessing)
- [x] Linear framebuffer (VESA and GOP)
- [x] Network stack
- [x] ELF executable loading
- [x] AML interpreter (partial)
- [ ] ELF dynamic linking
- [ ] Graphical desktop
- [ ] copy-on-write memory
#### Drivers
- [x] NVMe disks
- [x] ATA (IDE, SATA) disks
- [x] E1000 and E1000E NICs
- [x] PS2 keyboard (all scancode sets)
- [x] PS2 mouse
- [ ] USB
- [ ] virtio devices (network, storage)
#### Network
- [x] ARP
- [x] ICMP
- [x] IPv4
- [x] UDP
- [x] TCP (partial and buggy)
- [x] Unix domain sockets
#### Filesystems
- [x] Virtual filesystem
- [x] Ext2
- [x] FAT12/16/32
- [x] Dev
- [x] Ram
- [x] Proc
- [ ] Sys
- [ ] 9P
#### Bootloader support
- [x] GRUB
- [x] Custom BIOS bootloader
- [ ] Custom UEFI bootloader
This is my hobby operating system written in C++. Currently supports only x86\_64 architecture. We have a ext2 filesystem, basic ramfs, IDE disk drivers in ATA PIO mode, ATA AHCI drivers, 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)
@ -62,59 +12,37 @@ Each major component and library has its own subdirectory (kernel, userspace, li
## Building
### Needed packages
#### apt (tested on ubuntu 22.04)
```# apt install build-essential git ninja-build texinfo bison flex libgmp-dev libmpfr-dev libmpc-dev parted qemu-system-x86 cpu-checker```
#### pacman
```# pacman -S --needed base-devel git wget cmake ninja parted qemu-system-x86```
### Compilation
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.
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
./bos toolchain
./script/build.sh toolchain
```
To build the os itself you can run one of the following commands. You will need root access for disk image creation/modification.
```sh
./bos qemu
./bos qemu-nographic
./bos qemu-debug
./bos bochs
./script/build.sh qemu
./script/build.sh qemu-nographic
./script/build.sh qemu-debug
./script/build.sh bochs
```
You can also build the kernel or disk image without running it:
```sh
./bos kernel
./bos image
./script/build.sh kernel
./script/build.sh image
```
To build for other architectures set environment variable BANAN\_ARCH=*arch* (e.g. BANAN\_ARCH=i686).
To change the bootloader you can set environment variable BANAN\_BOOTLOADER; supported values are BANAN (my custom bootloader) and GRUB.
To run with UEFI set environment variable BANAN\_UEFI\_BOOT=1. You will also have to set OVMF\_PATH to the correct OVMF (default */usr/share/ovmf/x64/OVMF.fd*).
If you have corrupted your disk image or want to create new one, you can either manually delete *build/banan-os.img* and build system will automatically create you a new one or you can run the following command.
```sh
./bos image-full
./script/build.sh image-full
```
If you feel like ```./script/build.sh``` is too verbose, there exists a symlink _bos_ in this projects root directory. All build commands can be used with ```./bos args...``` instead.
I have also created shell completion script for zsh. You can either copy the file in _script/shell-completion/zsh/\_bos_ to _/usr/share/zsh/site-functions/_ or add the _script/shell-completion/zsh_ to your fpath in _.zshrc_.
## Contributing
### Contributing
As the upstream is hosted on my server https://git.bananymous.com/Bananymous/banan-os, please contact me about account creation ([email](mailto:oskari.alaranta@bananymous.com), [discord](https://discord.gg/xMXKt9Wf)) and I will add a account for you. This is done to limit the people with access to the server.
As this is mostly a learning experience for me, I would appreciate if you first contacted me about adding new features (email, discord, issue, ...). Bug fixes are always welcome!
Commit message should be formatted followingly
1. First line is of the form "_Subject: Description_", where _Subject_ tells the area touched (Kernel, Shell, BuildSystem, ...) and _Description_ is brief description of the change done. First line should fit fully in 70 characters.
2. Body of the message should further describe the change and reasoning behind the change.
All commits should pass the pre-commit hook defined in _.pre-commit-config.yaml_. For instructions on how to setup pre-commit, please see https://pre-commit.com/#install.
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.

Binary file not shown.

View File

@ -3,7 +3,6 @@ cmake_minimum_required(VERSION 3.26)
project(bootloader ASM)
set(BOOTLOADER_SOURCES
a20_line.S
boot.S
command_line.S
disk.S
@ -15,6 +14,5 @@ set(BOOTLOADER_SOURCES
)
add_executable(bootloader ${BOOTLOADER_SOURCES})
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
target_link_options(bootloader PRIVATE LINKER:-T,${CMAKE_CURRENT_SOURCE_DIR}/linker.ld)
target_link_options(bootloader PRIVATE -nostdlib)

View File

@ -1,168 +0,0 @@
.code16
.section .stage2
# checks whether A20 line is enabled or disabled
# return
# ax: 1 if enabled, 0 otherwise
check_a20:
pushf
pushw %si
pushw %di
pushw %ds
pushw %es
cli
xorw %ax, %ax
movw %ax, %es
notw %ax
movw %ax, %ds
movw $0x0500, %di
movw $0x0510, %si
movb %es:(%di), %al
pushw %ax
movb %ds:(%si), %al
pushw %ax
movb $0x00, %es:(%di)
movb $0xFF, %ds:(%si)
cmpb $0xFF, %es:(%di)
pop %ax
movb %al, %ds:(%si)
pop %ax
movb %al, %es:(%di)
movw $0, %ax
je .check_a20_done
movw $1, %ax
.check_a20_done:
popw %es
popw %ds
popw %di
popw %si
popf
ret
# Try to enable A20 using PS2 controller
enable_a20_ps2:
pushf
pushw %ax
cli
# disable first port
call .enable_a20_ps2_wait1
movb $0xAD, %al
outb %al, $0x64
# read controller output
call .enable_a20_ps2_wait1
movb $0xD0, %al
outb %al, $0x64
call .enable_a20_ps2_wait2
inb $0x60, %al
pushw %ax
# write controller output
call .enable_a20_ps2_wait1
movb $0xD1, %al
outb %al, $0x64
call .enable_a20_ps2_wait1
popw %ax
orw $2, %ax
outb %al, $0x60
# enable first port
call .enable_a20_ps2_wait1
movb $0xAE, %al
outb %al, $0x64
call .enable_a20_ps2_wait1
popw %ax
popf
ret
.enable_a20_ps2_wait1:
inb $0x64, %al
test $2, %al
jnz .enable_a20_ps2_wait1
ret
.enable_a20_ps2_wait2:
inb $0x64, %al
test $1, %al
jnz .enable_a20_ps2_wait1
ret
# Check if A20 line is disabled. If it is, try to enable it
.global enable_a20
enable_a20:
pushw %ax
pushw %si
call check_a20
testw %ax, %ax
jnz .enable_a20_done
movw $a20_line_disabled_msg, %si
call puts; call print_newline
# Try to enable A20 line using bios interrupt
movw $0x2401, %ax
int $0x15
call check_a20
testw %ax, %ax
jnz .enable_a20_done
# Try to enable A20 line using ps2 controller
call enable_a20_ps2
call check_a20
testw %ax, %ax
jnz .enable_a20_done
# Try to enable A20 line using fast A20 gate
inb $0x92, %al
testb $2, %al
jnz .enable_a20_fast_done
orb $2, %al
outb %al, $0x92
.enable_a20_fast_done:
call check_a20
testw %ax, %ax
jnz .enable_a20_done
movw $a20_could_not_enable_msg, %si
call print_and_halt
.enable_a20_done:
movw $a20_line_enabled_msg, %si
call puts; call print_newline
popw %si
popw %ax
ret
.section .data
a20_line_disabled_msg:
.asciz "A20 line disabled. Trying to enable it"
a20_line_enabled_msg:
.asciz "A20 line enabled"
a20_could_not_enable_msg:
.asciz "Could not enable A20 line"

View File

@ -1,5 +1,3 @@
.include "common.S"
.code16
#########################################
@ -15,10 +13,12 @@
.global stage1_main
stage1_main:
# setup segments and stack
xorw %ax, %ax
# setup segments
movw $0, %ax
movw %ax, %ds
movw %ax, %es
# setup stack
movw %ax, %ss
movl $0x7C00, %esp
@ -53,18 +53,14 @@ stage2_main:
movw $hello_msg, %si
call puts; call print_newline
lgdt gdtr
call enter_unreal_mode
movw $unreal_enter_msg, %si
call puts; call print_newline
call enable_a20
call get_memory_map
call print_newline
call read_user_command_line
call vesa_find_video_mode
call print_newline
@ -88,36 +84,36 @@ stage2_main:
call elf_read_kernel_to_memory
call vesa_set_video_mode
call vesa_set_target_mode
cli
# kernel entry point
movl %eax, %ecx
# setup kernel parameters
movl $0xD3C60CFF, %eax
movl $banan_boot_info, %ebx
# setup protected mode
movl %cr0, %edx
orb $1, %dl
movl %edx, %cr0
movl %cr0, %ebx
orb $1, %bl
movl %ebx, %cr0
# jump to kernel in protected mode
ljmpl $0x18, $protected_mode
# jump to protected mode
ljmpl $GDT_CODE32, $protected_mode
.code32
protected_mode:
# setup protected mode segments
movw $GDT_DATA32, %dx
movw %dx, %ds
movw %dx, %es
movw %dx, %fs
movw %dx, %gs
movw %dx, %ss
movw $0x10, %bx
movw %bx, %ds
movw %bx, %es
movw %bx, %fs
movw %bx, %gs
movw %bx, %ss
movl %eax, %ecx
movl $0xD3C60CFF, %eax
movl $banan_boot_info, %ebx
xorl %edx, %edx
xorl %esi, %esi
xorl %edi, %edi
# jump to kernel entry
jmp *%ecx
@ -126,18 +122,20 @@ enter_unreal_mode:
cli
pushw %ds
lgdt gdtr
movl %cr0, %eax
orb $1, %al
movl %eax, %cr0
ljmpl $GDT_CODE16, $.enter_unreal_mode_pmode
ljmpl $0x8, $.enter_unreal_mode_pmode
.enter_unreal_mode_pmode:
movw $GDT_DATA32, %bx
movw $0x10, %bx
movw %bx, %ds
andb $0xFE, %al
andb 0xFE, %al
movl %eax, %cr0
ljmpl $0x00, $.enter_unreal_mode_unreal
ljmpl $0x0, $.enter_unreal_mode_unreal
.enter_unreal_mode_unreal:
popw %ds
@ -145,8 +143,6 @@ enter_unreal_mode:
ret
.section .data
hello_msg:
.asciz "This is banan-os bootloader"
@ -158,12 +154,12 @@ start_kernel_load_msg:
gdt:
.quad 0x0000000000000000
.quad 0x008F9A000000FFFF # 16-bit code
.quad 0x00CF92000000FFFF # 32-bit data
.quad 0x00CF9A000000FFFF # 32-bit code
.quad 0x00009A000000FFFF
.quad 0x00CF92000000FFFF
.quad 0x00CF9A000000FFFF
gdtr:
.short . - gdt - 1
.long gdt
.quad gdt
banan_boot_info:
boot_command_line:

View File

@ -26,8 +26,6 @@ read_user_command_line:
cmpb $'\b', %al
je .read_user_command_line_backspace
cmpb $0x7F, %al
je .read_user_command_line_backspace
# Not sure if some BIOSes return '\n' as enter, but check it just in case
cmpb $'\r', %al
@ -74,8 +72,6 @@ read_user_command_line:
ret
.section .data
command_line_enter_msg:
.asciz "cmdline: "

View File

@ -1,3 +0,0 @@
.set GDT_CODE16, 0x08
.set GDT_DATA32, 0x10
.set GDT_CODE32, 0x18

View File

@ -41,7 +41,7 @@ read_from_disk:
call drive_has_int13_ext
# prepare disk read packet
movw $disk_address_packet, %si
mov $disk_address_packet, %si
movb $0x10, 0x00(%si) # packet size
movb $0x00, 0x01(%si) # always 0
movw %cx, 0x02(%si) # lba count
@ -389,8 +389,10 @@ find_root_partition:
# increment 8 byte entry array lba
incl 0(%esp)
adcl $0, 4(%esp)
jnc .find_root_partition_no_overflow
incl 4(%esp)
.find_root_partition_no_overflow:
# loop to read next section if entries remaining
cmpl $0, 12(%esp)
jnz .find_root_partition_read_entry_section
@ -414,11 +416,13 @@ find_root_partition:
# ebx:eax -= first lba - 1
subl (root_partition_entry + 36), %ebx
movl (root_partition_entry + 32), %ecx
movl (root_partition_entry + 32), %ecx;
decl %ecx
subl %ecx, %eax
sbbl $0, %ebx
jnc .find_root_partition_count_sub_no_carry
decl %ebx
.find_root_partition_count_sub_no_carry:
# ecx: min(partition count, 0xFFFFFFFF)
movl $0xFFFFFFFF, %edx
movl %eax, %ecx
@ -470,7 +474,6 @@ print_root_partition_info:
popw %ax
ret
.section .data
# These will be patched during bootloader installation
root_disk_guid:

View File

@ -5,26 +5,15 @@
.set e_machine, 18
.set e_version, 20
.set e_entry, 24
.set e32_phoff, 28
.set e32_shoff, 32
.set e32_flags, 36
.set e32_ehsize, 40
.set e32_phentsize, 42
.set e32_phnum, 44
.set e32_shentsize, 46
.set e32_shnum, 48
.set e32_shstrndx, 50
.set e64_phoff, 32
.set e64_shoff, 40
.set e64_flags, 48
.set e64_ehsize, 52
.set e64_phentsize, 54
.set e64_phnum, 56
.set e64_shentsize, 58
.set e64_shnum, 60
.set e64_shstrndx, 62
.set e_phoff, 32
.set e_shoff, 40
.set e_flags, 48
.set e_ehsize, 52
.set e_phentsize, 54
.set e_phnum, 56
.set e_shentsize, 58
.set e_shnum, 60
.set e_shstrndx, 62
# e_ident offsets
.set EI_CLASS, 4
@ -33,7 +22,6 @@
# e_ident constants
.set ELFMAGIC, 0x464C457F
.set ELFCLASS32, 1
.set ELFCLASS64, 2
.set ELFDATA2LSB, 1
.set EV_CURRENT, 1
@ -43,30 +31,18 @@
# program header field offsets
.set p_type, 0
.set p32_offset, 4
.set p32_vaddr, 8
.set p32_paddr, 12
.set p32_filesz, 16
.set p32_memsz, 20
.set p32_flags, 24
.set p32_align, 28
.set p64_flags, 4
.set p64_offset, 8
.set p64_vaddr, 16
.set p64_paddr, 24
.set p64_filesz, 32
.set p64_memsz, 40
.set p64_align, 48
.set p_flags, 4
.set p_offset, 8
.set p_vaddr, 16
.set p_paddr, 24
.set p_filesz, 32
.set p_memsz, 40
.set p_align, 48
# p_type constants
.set PT_NULL, 0
.set PT_LOAD, 1
# mask for entry point and segment loading
.set LOAD_MASK, 0x07FFFFFF
.code16
.section .stage2
@ -76,12 +52,8 @@ elf_validate_file_header:
cmpl $ELFMAGIC, (elf_file_header)
jne .elf_validate_file_header_invalid_magic
cmpb $ELFCLASS32, (elf_file_header + EI_CLASS)
je .elf_validate_file_header_class_valid
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
je .elf_validate_file_header_class_valid
jmp .elf_validate_file_header_invalid_class
.elf_validate_file_header_class_valid:
jne .elf_validate_file_header_only_64bit_supported
cmpb $ELFDATA2LSB, (elf_file_header + EI_DATA)
jne .elf_validate_file_header_only_little_endian_supported
@ -100,8 +72,8 @@ elf_validate_file_header:
.elf_validate_file_header_invalid_magic:
movw $elf_validate_file_header_invalid_magic_msg, %si
jmp print_and_halt
.elf_validate_file_header_invalid_class:
movw $elf_validate_file_header_invalid_class_msg, %si
.elf_validate_file_header_only_64bit_supported:
movw $elf_validate_file_header_only_64bit_supported_msg, %si
jmp print_and_halt
.elf_validate_file_header_only_little_endian_supported:
movw $elf_validate_file_header_only_little_endian_supported_msg, %si
@ -113,59 +85,6 @@ elf_validate_file_header:
movw $elf_validate_file_header_not_executable_msg, %si
jmp print_and_halt
# reads memory specified by 32 bit elf_program_header to memory
elf_read_program_header32_to_memory:
pushal
pushl %ebp
movl %esp, %ebp
# memset p_filesz -> p_memsz to 0
movl (elf_program_header + p32_filesz), %ebx
movl (elf_program_header + p32_vaddr), %edi
andl $LOAD_MASK, %edi
addl %ebx, %edi
movl (elf_program_header + p32_memsz), %ecx
subl %ebx, %ecx
xorb %al, %al; call memset32
# read file specified in program header to memory
movl (elf_program_header + p32_offset), %eax
movl (elf_program_header + p32_vaddr), %edi
andl $LOAD_MASK, %edi
movl (elf_program_header + p32_filesz), %ecx
call *%esi
leavel
popal
ret
# reads memory specified by 64 bit elf_program_header to memory
elf_read_program_header64_to_memory:
pushal
pushl %ebp
movl %esp, %ebp
# memset p_filesz -> p_memsz to 0
movl (elf_program_header + p64_filesz), %ebx
movl (elf_program_header + p64_vaddr), %edi
andl $LOAD_MASK, %edi
addl %ebx, %edi
movl (elf_program_header + p64_memsz), %ecx
subl %ebx, %ecx
xorb %al, %al; call memset32
# read file specified in program header to memory
movl (elf_program_header + p64_offset), %eax
movl (elf_program_header + p64_vaddr), %edi
andl $LOAD_MASK, %edi
movl (elf_program_header + p64_filesz), %ecx
call *%esi
leavel
popal
ret
# read callback format
# eax: first byte
@ -185,72 +104,42 @@ elf_read_kernel_to_memory:
movl %esp, %ebp
subl $2, %esp
# read start of file header
# read file header
movl $0, %eax
movl $24, %ecx
movl $64, %ecx
movl $elf_file_header, %edi
call *%esi
call elf_validate_file_header
# determine file header size
movl $52, %ecx
movl $64, %edx
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
cmovel %edx, %ecx
# read full file header
movl $0, %eax
movl $elf_file_header, %edi
call *%esi
# verify that e_phoff fits in 32 bits
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
jne .elf_read_kernel_to_memory_valid_offset
cmpl $0, (elf_file_header + e64_phoff + 4)
cmpl $0, (elf_file_header + e_phoff + 4)
jnz .elf_read_kernel_to_memory_unsupported_offset
.elf_read_kernel_to_memory_valid_offset:
# read architecture phentsize and phnum to fixed locations
movw (elf_file_header + e32_phentsize), %ax
movw (elf_file_header + e32_phnum), %bx
movl (elf_file_header + e32_phoff), %ecx
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
cmovew (elf_file_header + e64_phentsize), %ax
cmovew (elf_file_header + e64_phnum), %bx
cmovel (elf_file_header + e64_phoff), %ecx
movw %ax, (elf_file_header_phentsize)
movw %bx, (elf_file_header_phnum)
movl %ecx, (elf_file_header_phoff)
# current program header
movw $0, -2(%ebp)
.elf_read_kernel_to_memory_loop_program_headers:
movw -2(%ebp), %cx
cmpw (elf_file_header_phnum), %cx
cmpw (elf_file_header + e_phnum), %cx
jae .elf_read_kernel_to_memory_done
# eax := program_header_index * e_phentsize + e_phoff
xorl %eax, %eax
movw %cx, %ax
xorl %ebx, %ebx
movw (elf_file_header_phentsize), %bx
movw (elf_file_header + e_phentsize), %bx
mull %ebx
addl (elf_file_header_phoff), %eax
addl (elf_file_header + e_phoff), %eax
jc .elf_read_kernel_to_memory_unsupported_offset
# determine program header size
movl $32, %ecx
movl $56, %edx
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
cmovel %edx, %ecx
# read program header
# setup program header size and address
movl $56, %ecx
movl $elf_program_header, %edi
# read the program header
call *%esi
# test if program header is NULL header
# test if program header is empty
cmpl $PT_NULL, (elf_program_header + p_type)
je .elf_read_kernel_to_memory_null_program_header
@ -258,12 +147,33 @@ elf_read_kernel_to_memory:
cmpl $PT_LOAD, (elf_program_header + p_type)
jne .elf_read_kernel_to_memory_not_loadable_header
# read program header to memory
movl $elf_read_program_header32_to_memory, %eax
movl $elf_read_program_header64_to_memory, %ebx
cmpb $ELFCLASS64, (elf_file_header + EI_CLASS)
cmovel %ebx, %eax
call *%eax
# memset p_filesz -> p_memsz to 0
movl (elf_program_header + p_filesz), %ebx
movl (elf_program_header + p_vaddr), %edi
andl $0x7FFFFFFF, %edi
addl %ebx, %edi
movl (elf_program_header + p_memsz), %ecx
subl %ebx, %ecx
jz .elf_read_kernel_to_memory_memset_done
.elf_read_kernel_to_memory_memset:
movb $0, (%edi)
incl %edi
decl %ecx
jnz .elf_read_kernel_to_memory_memset
.elf_read_kernel_to_memory_memset_done:
# read file specified in program header to memory
movl (elf_program_header + p_offset), %eax
movl (elf_program_header + p_vaddr), %edi
andl $0x7FFFFFFF, %edi
movl (elf_program_header + p_filesz), %ecx
#call print_hex32; call print_newline
call *%esi
.elf_read_kernel_to_memory_null_program_header:
incw -2(%ebp)
@ -275,7 +185,7 @@ elf_read_kernel_to_memory:
# set kernel entry address
movl (elf_file_header + e_entry), %eax
andl $LOAD_MASK, %eax
andl $0x7FFFFF, %eax
ret
@ -286,12 +196,11 @@ elf_read_kernel_to_memory:
movw $elf_read_kernel_to_memory_not_loadable_header_msg, %si
jmp print_and_halt
.section .data
elf_validate_file_header_invalid_magic_msg:
.asciz "ELF: file has invalid ELF magic"
elf_validate_file_header_invalid_class_msg:
.asciz "ELF: file has invalid ELF class"
elf_validate_file_header_only_64bit_supported_msg:
.asciz "ELF: file is not targettint 64 bit"
elf_validate_file_header_only_little_endian_supported_msg:
.asciz "ELF: file is not in little endian format"
elf_validate_file_header_not_current_version_msg:
@ -309,12 +218,5 @@ elf_read_kernel_to_memory_not_loadable_header_msg:
elf_file_header:
.skip 64
elf_file_header_phentsize:
.skip 2
elf_file_header_phnum:
.skip 2
elf_file_header_phoff:
.skip 4 # NOTE: only 32 bit offsets are supported
elf_program_header:
.skip 56

View File

@ -2,7 +2,9 @@
.set SECTOR_SHIFT, 9
.set SECTOR_SIZE, 1 << SECTOR_SHIFT
.set EXT2_MAX_BLOCK_SIZE, 4096
# FIXME: don't assume 1024 byte blocks
.set EXT2_BLOCK_SHIFT, 10
.set EXT2_BLOCK_SIZE, 1 << EXT2_BLOCK_SHIFT
.set EXT2_SUPERBLOCK_SIZE, 264
.set EXT2_BGD_SHIFT, 5
.set EXT2_BGD_SIZE, 1 << EXT2_BGD_SHIFT
@ -16,7 +18,6 @@
.set EXT2_S_IFREG, 0x8000
# superblock offsets
.set s_first_data_block, 20
.set s_log_block_size, 24
.set s_inodes_per_group, 40
.set s_magic, 56
@ -65,7 +66,9 @@ has_ext2_filesystem:
# from byte offset 1024
addl $(1024 / SECTOR_SIZE), %eax
adcw $0, %bx
jnc .has_ext2_filesystem_no_overflow
incw %bx
.has_ext2_filesystem_no_overflow:
# into sector buffer
movw $ext2_block_buffer, %di
@ -87,16 +90,11 @@ has_ext2_filesystem:
movl (ext2_superblock_buffer + s_log_block_size), %ecx
testl $0xFFFFFF00, %ecx
jnz .has_ext2_filesystem_unsupported_block_size
# verify 1024 << s_log_block_size <= EXT2_MAX_BLOCK_SIZE
# verify 1024 << s_log_block_size == EXT2_BLOCK_SIZE
movl $1024, %eax
shll %cl, %eax
cmpl $EXT2_MAX_BLOCK_SIZE, %eax
ja .has_ext2_filesystem_unsupported_block_size
# fill block size and shift
movl %eax, (ext2_block_size)
addl $10, %ecx
movl %ecx, (ext2_block_shift)
cmpl $EXT2_BLOCK_SIZE, %eax
jne .has_ext2_filesystem_unsupported_block_size
# fill inode size
movl $128, %eax
@ -132,23 +130,38 @@ has_ext2_filesystem:
# reads block in to ext2_block_buffer
# eax: block number
ext2_read_block:
pushal
pushl %eax
pushl %ebx
pushw %cx
pushl %edx
pushw %di
# ecx := sectors_per_block := block_size / sector_size
movl (ext2_block_size), %ecx
shrl $SECTOR_SHIFT, %ecx
# NOTE: this assumes 1024 block size
# eax := (block * block_size) / sector_size := (eax << EXT2_BLOCK_SHIFT) >> SECTOR_SHIFT
xorl %edx, %edx
shll $EXT2_BLOCK_SHIFT, %eax
shrl $SECTOR_SHIFT, %eax
# ebx:eax := block * sectors_per_block + (ext2_partition_first_sector)
xorl %ebx, %ebx
mull %ecx
# ebx:eax := eax + (ext2_partition_first_sector)
movl (ext2_partition_first_sector + 4), %ebx
addl (ext2_partition_first_sector + 0), %eax
adcl (ext2_partition_first_sector + 4), %ebx
jnc .ext2_read_block_no_carry
incl %ebx
.ext2_read_block_no_carry:
# sectors per block
movw $(EXT2_BLOCK_SIZE / SECTOR_SIZE), %cx
movw $ext2_block_buffer, %di
movb (ext2_drive_number), %dl
call read_from_disk
popal
popw %di
popl %edx
popw %cx
popl %ebx
popl %eax
ret
@ -157,23 +170,15 @@ ext2_read_block:
ext2_read_block_group_descriptor:
pushal
# ebx := bgd_block_byte_offset := (s_first_data_block + 1) * block_size
# := (s_first_data_block + 1) << ext2_block_shift
movl (ext2_superblock_buffer + s_first_data_block), %ebx
incl %ebx
movb (ext2_block_shift), %cl
shll %cl, %ebx
# eax := bgd_byte_offset := 2048 + EXT2_BGD_SIZE * eax := (eax << EXT2_BGD_SHIFT) + 2048
shll $EXT2_BGD_SHIFT, %eax
addl $2048, %eax
# eax := bgd_byte_offset := bgd_block_byte_offset + EXT2_BGD_SIZE * block_group;
# := bgd_block_byte_offset + (block_group << EXT2_BGD_SHIFT)
movb $EXT2_BGD_SHIFT, %cl
shll %cl, %eax
addl %ebx, %eax
# eax: bgd_block := bgd_byte_offset / block_size
# ebx: bgd_offset := bgd_byte_offset % block_size
# eax: bgd_block := bgd_byte_offset / EXT2_BLOCK_SIZE
# ebx: bgd_offset := bgd_byte_offset % EXT2_BLOCK_SIZE
xorl %edx, %edx
divl (ext2_block_size)
movl $EXT2_BLOCK_SIZE, %ebx
divl %ebx
movl %edx, %ebx
call ext2_read_block
@ -199,19 +204,23 @@ ext2_read_inode:
# ebx := inode_index = (ino - 1) % s_inodes_per_group
xorl %edx, %edx
decl %eax
divl (ext2_superblock_buffer + s_inodes_per_group)
movl (ext2_superblock_buffer + s_inodes_per_group), %ebx
divl %ebx
movl %edx, %ebx
call ext2_read_block_group_descriptor
# eax := inode_table_block := (inode_index * inode_size) / block_size
# ebx := inode_table_offset := (inode_index * inode_size) % block_size
# eax := inode_table_block := (inode_index * inode_size) / EXT2_BLOCK_SIZE
# ebx := inode_table_offset := (inode_index * inode_size) % EXT2_BLOCK_SIZE
xorl %edx, %edx
movl %ebx, %eax
mull (ext2_inode_size)
divl (ext2_block_size)
movl (ext2_inode_size), %ebx
mull %ebx
movl $EXT2_BLOCK_SIZE, %ebx
divl %ebx
movl %edx, %ebx
# eax := filesystem_block := eax + bg_inode_table
# eax := file system block := eax + bg_inode_table
addl (ext2_block_group_descriptor_buffer + bg_inode_table), %eax
movb (ext2_drive_number), %dl
@ -227,10 +236,6 @@ ext2_read_inode:
movl (ext2_inode_size), %ecx
rep movsb
# reset indirect cache to zero
movl $0, (ext2_inode_indirect_number)
.ext2_read_inode_done:
popal
ret
@ -244,19 +249,15 @@ ext2_data_block_index:
pushl %ecx
pushl %edx
pushl %esi
pushl %edi
# ebx := max_data_blocks := (file_size + block_size - 1) / block_size
# := (i_size + ext2_block_size - 1) >> ext2_block_shift
# cl := ext2_block_shift
movl (ext2_inode_buffer + i_size), %ebx
addl (ext2_block_size), %ebx
decl %ebx
movb (ext2_block_shift), %cl
shrl %cl, %ebx
# calculate max data blocks
movl (ext2_inode_buffer + i_size), %ecx
addl (ext2_inode_size), %ecx
decl %ecx
shll $EXT2_BLOCK_SHIFT, %ecx
# verify data block is within bounds
cmpl %ebx, %eax
cmpl %ecx, %eax
jae .ext2_data_block_index_out_of_bounds
# check if this is direct block access
@ -264,26 +265,18 @@ ext2_data_block_index:
jb .ext2_data_block_index_direct
subl $12, %eax
# cl := indices_per_block_shift := ext2_block_shift - 2
# ebx := comp
subb $2, %cl
movl $1, %ebx
shll %cl, %ebx
# check if this is singly indirect block access
cmpl %ebx, %eax
cmpl $(EXT2_BLOCK_SIZE / 4), %eax
jb .ext2_data_block_index_singly_indirect
subl %ebx, %eax
shll %cl, %ebx
subl $(EXT2_BLOCK_SIZE / 4), %eax
# check if this is doubly indirect block access
cmpl %ebx, %eax
cmpl $((EXT2_BLOCK_SIZE / 4) * (EXT2_BLOCK_SIZE / 4)), %eax
jb .ext2_data_block_index_doubly_indirect
subl %ebx, %eax
shll %cl, %ebx
subl $((EXT2_BLOCK_SIZE / 4) * (EXT2_BLOCK_SIZE / 4)), %eax
# check if this is triply indirect block access
cmpl %ebx, %eax
cmpl $((EXT2_BLOCK_SIZE / 4) * (EXT2_BLOCK_SIZE / 4) * (EXT2_BLOCK_SIZE / 4)), %eax
jb .ext2_data_block_index_triply_indirect
# otherwise this is invalid access
@ -316,28 +309,6 @@ ext2_data_block_index:
# ebx := index
# cx := depth
.ext2_data_block_index_indirect:
# edx := cache index := (index & ~(block_size / 4 - 1)) | depth
# := (index & -(block_size >> 2)) | depth
movl (ext2_block_size), %edx
shrl $2, %edx
negl %edx
andl %ebx, %edx
orw %cx, %dx
# check whether this block is already cached
cmpl $0, (ext2_inode_indirect_number)
je .ext2_data_block_index_indirect_no_cache
cmpl %edx, (ext2_inode_indirect_number)
je .ext2_data_block_index_indirect_cached
.ext2_data_block_index_indirect_no_cache:
# update cache block number, will be cached when found
movl %edx, (ext2_inode_indirect_number)
# eax := current block
# ebx := index
# cx := depth
.ext2_data_block_index_indirect_loop:
call ext2_read_block
# store depth and index
@ -348,21 +319,20 @@ ext2_data_block_index:
jbe .ext2_data_block_index_no_shift
# cl := shift
movb (ext2_block_shift), %al
subb $2, %al
movb $(EXT2_BLOCK_SHIFT - 2), %al
decb %cl
mulb %cl
movb %al, %cl
# ebx := ebx >> shift
# ebx := ebx >> cl
shrl %cl, %ebx
.ext2_data_block_index_no_shift:
# edx := index of next block (ebx & (block_size / 4 - 1))
movl (ext2_block_size), %edx
shrl $2, %edx
decl %edx
andl %ebx, %edx
# edx := index of next block
movl %ebx, %eax
xorl %edx, %edx
movl $(EXT2_BLOCK_SIZE / 4), %ebx
divl %ebx
# eax := next block
movl $ext2_block_buffer, %esi
@ -372,13 +342,7 @@ ext2_data_block_index:
popl %ebx
popw %cx
loop .ext2_data_block_index_indirect_loop
# cache last read block
movw $ext2_block_buffer, %si
movw $ext2_inode_indirect_buffer, %di
movw (ext2_block_size), %cx
rep movsb
loop .ext2_data_block_index_indirect
jmp .ext2_data_block_index_done
@ -394,16 +358,7 @@ ext2_data_block_index:
movl $0, %eax
jmp .ext2_data_block_index_done
.ext2_data_block_index_indirect_cached:
movl $ext2_inode_indirect_buffer, %esi
movl (ext2_block_size), %edx
shrl $2, %edx
decl %edx
andl %edx, %ebx
movl (%esi, %ebx, 4), %eax
.ext2_data_block_index_done:
popl %edi
popl %esi
popl %edx
popl %ecx
@ -419,7 +374,6 @@ ext2_data_block_index:
.global ext2_inode_read_bytes
ext2_inode_read_bytes:
pushal
pushl %ebp
movl %esp, %ebp
subl $8, %esp
@ -428,11 +382,11 @@ ext2_inode_read_bytes:
movl %eax, 0(%esp)
movl %ecx, 4(%esp)
# eax := first_byte / block_size
# edx := first_byte % block_size
# when edx == 0, no partial read needed
# check if eax % EXT2_BLOCK_SIZE != 0,
# then we need to read a partial block starting from an offset
xorl %edx, %edx
divl (ext2_block_size)
movl $EXT2_BLOCK_SIZE, %ebx
divl %ebx
testl %edx, %edx
jz .ext2_inode_read_bytes_no_partial_start
@ -441,7 +395,7 @@ ext2_inode_read_bytes:
call ext2_read_block
# ecx := byte count (min(block_size - edx, remaining_bytes))
movl (ext2_block_size), %ecx
movl $EXT2_BLOCK_SIZE, %ecx
subl %edx, %ecx
cmpl %ecx, 4(%esp)
cmovbl 4(%esp), %ecx
@ -454,7 +408,15 @@ ext2_inode_read_bytes:
movl $ext2_block_buffer, %esi
addl %edx, %esi
call memcpy32
# very dumb memcpy with 32 bit addresses
movl $0, %ebx
.ext2_inode_read_bytes_memcpy_partial:
movb (%esi, %ebx), %al
movb %al, (%edi, %ebx)
incl %ebx
decl %ecx
jnz .ext2_inode_read_bytes_memcpy_partial
addl %ebx, %edi
# check if all sectors are read
cmpl $0, 4(%esp)
@ -463,15 +425,14 @@ ext2_inode_read_bytes:
.ext2_inode_read_bytes_no_partial_start:
# eax := data block index (byte_start / block_size)
movl 0(%esp), %eax
movb (ext2_block_shift), %cl
shrl %cl, %eax
shrl $(EXT2_BLOCK_SHIFT), %eax
# get data block index and read block
call ext2_data_block_index
call ext2_read_block
# calculate bytes to copy (min(block_size, remaining_bytes))
movl (ext2_block_size), %ecx
movl $EXT2_BLOCK_SIZE, %ecx
cmpl %ecx, 4(%esp)
cmovbl 4(%esp), %ecx
@ -479,8 +440,16 @@ ext2_inode_read_bytes:
addl %ecx, 0(%esp)
subl %ecx, 4(%esp)
# very dumb memcpy with 32 bit addresses
movl $ext2_block_buffer, %esi
call memcpy32
movl $0, %ebx
.ext2_inode_read_bytes_memcpy:
movb (%esi, %ebx), %al
movb %al, (%edi, %ebx)
incl %ebx
decl %ecx
jnz .ext2_inode_read_bytes_memcpy
addl %ebx, %edi
# read next block if more sectors remaining
cmpl $0, 4(%esp)
@ -519,12 +488,11 @@ ext2_directory_find_inode:
cmpw $0xFF, %cx
ja .ext2_directory_find_inode_not_found
# ebx := max data blocks: ceil(i_size / block_size)
# ebx := max data blocks: ceil(i_size / EXT2_BLOCK_SIZE)
movl (ext2_inode_buffer + i_size), %ebx
addl (ext2_block_size), %ebx
addl $EXT2_BLOCK_SHIFT, %ebx
decl %ebx
movb (ext2_block_shift), %cl
shrl %cl, %ebx
shrl $EXT2_BLOCK_SHIFT, %ebx
jz .ext2_directory_find_inode_not_found
# 4(%esp) := current block
@ -571,9 +539,7 @@ ext2_directory_find_inode:
# go to next entry if this block contains one
addw 4(%si), %si
movw $ext2_block_buffer, %di
addw (ext2_block_size), %di
cmpw %di, %si
cmpw $(ext2_block_buffer + EXT2_BLOCK_SIZE), %si
jb .ext2_directory_find_inode_loop_entries
.ext2_directory_find_inode_next_block:
@ -582,7 +548,7 @@ ext2_directory_find_inode:
jb .ext2_directory_find_inode_block_read_loop
.ext2_directory_find_inode_not_found:
xorb %al, %al
movb $0, %al
jmp .ext2_directory_find_inode_done
.ext2_directory_find_inode_found:
@ -676,7 +642,6 @@ ext2_find_kernel:
movw $ext2_kernel_not_reg_msg, %si
jmp print_and_halt
.section .data
kernel_path:
.short kernel_path1
@ -689,12 +654,13 @@ kernel_path2:
.short 15
.asciz "banan-os.kernel"
root_partition_does_not_fit_ext2_filesystem_msg:
.asciz "Root partition is too small to contain ext2 filesystem"
root_partition_has_invalid_ext2_magic_msg:
.asciz "Root partition doesn't contain ext2 magic number"
root_partition_has_unsupported_ext2_block_size_msg:
.asciz "Root partition has unsupported ext2 block size (1 KiB, 2 KiB and 4 KiB are supported)"
.asciz "Root partition has unsupported ext2 block size (only 1024 supported)"
ext2_part_not_dir_msg:
.asciz "inode in root path is not directory"
@ -715,14 +681,8 @@ ext2_looking_for_msg:
.section .bss
.align SECTOR_SIZE
ext2_block_buffer:
.skip EXT2_MAX_BLOCK_SIZE
ext2_inode_indirect_buffer:
.skip EXT2_MAX_BLOCK_SIZE
ext2_inode_indirect_number:
.skip 4
.skip EXT2_BLOCK_SIZE
ext2_partition_first_sector:
.skip 8
@ -734,10 +694,6 @@ ext2_drive_number:
# NOTE: fits in 2 bytes
ext2_inode_size:
.skip 4
ext2_block_size:
.skip 4
ext2_block_shift:
.skip 4
ext2_superblock_buffer:
.skip EXT2_SUPERBLOCK_SIZE

View File

@ -1,67 +1,19 @@
.set TARGET_WIDTH, 800
.set TARGET_HEIGHT, 600
.set TARGET_BPP, 32
.code16
.section .stage2
# kernel framebuffer information format
# .align 8
# .long 0xBABAB007
# .long -(0xBABAB007 + width + height + bpp)
# .long width (2 bytes used, 4 bytes for ease of calculation)
# .long height (2 bytes used, 4 bytes for ease of calculation)
# .long bpp (1 bytes used, 4 bytes for ease of calculation)
# scan memory 0x100000 -> 0x200000 for framebuffer information
# Find suitable video mode
# return:
# ax: target width
# bx: target height
# cx: target bpp
vesa_scan_kernel_image:
pushl %edx
pushl %esi
movl $0x100000, %esi
.vesa_scan_kernel_image_loop:
# check magic
cmpl $0xBABAB007, (%esi)
jne .vesa_scan_kernel_image_next_addr
# check checksum
movl 0x00(%esi), %edx
addl 0x04(%esi), %edx
addl 0x08(%esi), %edx
addl 0x0C(%esi), %edx
addl 0x10(%esi), %edx
testl %edx, %edx
jnz .vesa_scan_kernel_image_next_addr
# set return registers
movw 0x08(%esi), %ax
movw 0x0C(%esi), %bx
movw 0x10(%esi), %cx
jmp .vesa_scan_kernel_image_done
.vesa_scan_kernel_image_next_addr:
addl $8, %esi
cmpl $0x200000, %esi
jb .vesa_scan_kernel_image_loop
# zero out return registers
xorw %ax, %ax
xorw %bx, %bx
xorw %cx, %cx
.vesa_scan_kernel_image_done:
popl %esi
popl %edx
ret
# Find suitable video mode and save it in (vesa_target_mode)
# ax: video mode number if found, 0 otherwise
.global vesa_find_video_mode
vesa_find_video_mode:
pushal
pushl %ebp
movl %esp, %ebp
subl $6, %esp
pushw %ax
pushw %cx
pushw %di
pushl %esi
# clear target mode and frame buffer
movw $0, (vesa_target_mode)
@ -71,19 +23,10 @@ vesa_find_video_mode:
movl $0, (framebuffer + 12)
movw $0, (framebuffer + 16)
call vesa_scan_kernel_image
testw %ax, %ax
jz .vesa_find_video_mode_loop_modes_done
# save arguments in stack
movw %ax, -2(%ebp)
movw %bx, -4(%ebp)
movw %cx, -6(%ebp)
# get vesa information
movw $0x4F00, %ax
movw $vesa_info_buffer, %di
pushl %ebp; int $0x10; popl %ebp # BOCHS doesn't seem to reserve ebp
int $0x10
cmpb $0x4F, %al; jne .vesa_unsupported
cmpb $0x00, %ah; jne .vesa_error
@ -95,7 +38,8 @@ vesa_find_video_mode:
cmpw $0x0200, (vesa_info_buffer + 0x04)
jb .vesa_unsupported_version
movl (vesa_info_buffer + 0x0E), %esi
movl $(vesa_info_buffer + 0x0E), %esi
movl (%esi), %esi
.vesa_find_video_mode_loop_modes:
cmpw $0xFFFF, (%esi)
je .vesa_find_video_mode_loop_modes_done
@ -104,7 +48,7 @@ vesa_find_video_mode:
movw $0x4F01, %ax
movw (%esi), %cx
movw $vesa_mode_info_buffer, %di
pushl %ebp; int $0x10; popl %ebp # BOCHS doesn't seem to reserve ebp
int $0x10
cmpb $0x4F, %al; jne .vesa_unsupported
cmpb $0x00, %ah; jne .vesa_error
@ -113,24 +57,21 @@ vesa_find_video_mode:
jz .vesa_find_video_mode_next_mode
# compare mode's dimensions
movw -2(%ebp), %ax; cmpw %ax, (vesa_mode_info_buffer + 0x12)
cmpw $TARGET_WIDTH, (vesa_mode_info_buffer + 0x12)
jne .vesa_find_video_mode_next_mode
movw -4(%ebp), %ax; cmpw %ax, (vesa_mode_info_buffer + 0x14)
cmpw $TARGET_HEIGHT, (vesa_mode_info_buffer + 0x14)
jne .vesa_find_video_mode_next_mode
movb -6(%ebp), %al; cmpb %al, (vesa_mode_info_buffer + 0x19)
cmpb $TARGET_BPP, (vesa_mode_info_buffer + 0x19)
jne .vesa_find_video_mode_next_mode
# set address, pitch, type
movl (vesa_mode_info_buffer + 0x28), %esi
movl %esi, (framebuffer + 0)
movl %esi, (framebuffer + 0)
movw (vesa_mode_info_buffer + 0x10), %ax
movw %ax, (framebuffer + 4)
movb $1, (framebuffer + 17)
# set width, height, bpp
movw -2(%ebp), %ax; movw %ax, (framebuffer + 8)
movw -4(%ebp), %ax; movw %ax, (framebuffer + 12)
movw -6(%ebp), %ax; movb %al, (framebuffer + 16)
movw %ax, (framebuffer + 4)
movl $TARGET_WIDTH, (framebuffer + 8)
movl $TARGET_HEIGHT, (framebuffer + 12)
movb $TARGET_BPP, (framebuffer + 16)
movb $1, (framebuffer + 17)
movw %cx, (vesa_target_mode)
jmp .vesa_find_video_mode_loop_modes_done
@ -140,8 +81,10 @@ vesa_find_video_mode:
jmp .vesa_find_video_mode_loop_modes
.vesa_find_video_mode_loop_modes_done:
leavel
popal
popl %esi
popw %di
popw %cx
popw %ax
ret
.vesa_unsupported:
@ -155,37 +98,33 @@ vesa_find_video_mode:
jmp print_and_halt
# scan for video mode in kernel memory and set the correct one.
# when video mode is not found or does not exists,
# set it to 80x25 text mode to clear the screen.
.global vesa_set_video_mode
vesa_set_video_mode:
# set mode found from vesa_find_video_mode. if no mode
# was found, set it to 80x25 text mode to clear the screen.
.global vesa_set_target_mode
vesa_set_target_mode:
pushw %ax
pushw %bx
call vesa_find_video_mode
movw (vesa_target_mode), %bx
testw %bx, %bx
jz .vesa_set_target_mode_generic
jz .vesa_set_target_mode_generic
movw $0x4F02, %ax
orw $0x4000, %bx
pushl %ebp; int $0x10; popl %ebp # BOCHS doesn't seem to reserve ebp
int $0x10
jmp .set_video_done
.vesa_set_target_mode_generic:
movb $0x03, %al
movb $0x00, %ah
pushl %ebp; int $0x10; popl %ebp # BOCHS doesn't seem to reserve ebp
int $0x10
.set_video_done:
popw %bx
popw %ax
ret
.section .data
vesa_error_msg:
.asciz "VESA error"
@ -208,7 +147,6 @@ vesa_target_mode:
.skip 2
.global framebuffer
.align 8
framebuffer:
.skip 4 # address
.skip 4 # pitch

View File

@ -8,10 +8,8 @@ SECTIONS
. = ALIGN(512);
stage2_start = .;
.stage2 : { *(.stage2) }
. = ALIGN(512);
.data : { *(.data) }
stage2_end = .;
. = ALIGN(512);
.bss : { *(.bss) }
}
}

View File

@ -114,7 +114,6 @@ print_memory_map:
ret
.section .data
memory_map_msg:
.asciz "memmap:"

View File

@ -1,5 +1,3 @@
.include "common.S"
.set SCREEN_WIDTH, 80
.set SCREEN_HEIGHT, 25
@ -275,127 +273,6 @@ isprint:
movb $0, %al
ret
# memset with 32 bit registers
# edi: destination address
# ecx: bytes count
# al: value to set
# return:
# edi: destination address + bytes count
# ecx: 0
# other: preserved
.global memset32
memset32:
testl %ecx, %ecx
jz .memset32_done
pushf; cli
pushw %es
pushl %eax
pushl %ebx
pushl %edx
movl %cr0, %ebx
orb $1, %bl
movl %ebx, %cr0
ljmpl $GDT_CODE32, $.memset32_pmode32
.code32
.memset32_pmode32:
movw $GDT_DATA32, %dx
movw %dx, %es
movl %ecx, %edx
andl $3, %ecx
rep stosb %es:(%edi)
movl %edx, %ecx
shrl $2, %ecx
movb %al, %ah
movw %ax, %dx
shll $16, %eax
movw %dx, %ax
rep stosl %es:(%edi)
ljmpl $GDT_CODE16, $.memset32_pmode16
.code16
.memset32_pmode16:
andb $0xFE, %bl
movl %ebx, %cr0
ljmpl $0x00, $.memset32_rmode16
.memset32_rmode16:
popl %edx
popl %ebx
popl %eax
popw %es
popf
.memset32_done:
ret
# memcpy with 32 bit registers
# esi: source address
# edi: destination address
# ecx: bytes count
# return:
# esi: source address + bytes count
# edi: destination address + bytes count
# ecx: 0
# other: preserved
.global memcpy32
memcpy32:
testl %ecx, %ecx
jz .memcpy32_done
pushf; cli
pushw %ds
pushw %es
pushl %ebx
pushl %edx
movl %cr0, %ebx
orb $1, %bl
movl %ebx, %cr0
ljmpl $GDT_CODE32, $.memcpy32_pmode32
.code32
.memcpy32_pmode32:
movw $GDT_DATA32, %dx
movw %dx, %ds
movw %dx, %es
movl %ecx, %edx
andl $3, %ecx
rep movsb %ds:(%esi), %es:(%edi)
movl %edx, %ecx
shrl $2, %ecx
rep movsl %ds:(%esi), %es:(%edi)
ljmpl $GDT_CODE16, $.memcpy32_pmode16
.code16
.memcpy32_pmode16:
andb $0xFE, %bl
movl %ebx, %cr0
ljmpl $0x00, $.memcpy32_rmode16
.memcpy32_rmode16:
popl %edx
popl %ebx
popw %es
popw %ds
popf
.memcpy32_done:
ret
.section .bss
# enough for base 2 printing

View File

@ -1,11 +1,6 @@
cmake_minimum_required(VERSION 3.26)
if (NOT DEFINED ENV{BANAN_ARCH})
message(FATAL_ERROR "environment variable BANAN_ARCH not defined")
endif ()
set(BANAN_ARCH $ENV{BANAN_ARCH})
project(banan_os-bootloader-installer CXX)
project(x86_64-banan_os-bootloader-installer CXX)
set(SOURCES
crc32.cpp
@ -15,8 +10,8 @@ set(SOURCES
main.cpp
)
add_executable(banan_os-bootloader-installer ${SOURCES})
target_compile_options(banan_os-bootloader-installer PRIVATE -O2 -std=c++20)
target_compile_definitions(banan_os-bootloader-installer PRIVATE __arch=${BANAN_ARCH})
target_include_directories(banan_os-bootloader-installer PRIVATE ${CMAKE_SOURCE_DIR}/../../userspace/libraries/LibELF/include)
target_include_directories(banan_os-bootloader-installer PRIVATE ${CMAKE_SOURCE_DIR}/../../kernel/include)
add_executable(x86_64-banan_os-bootloader-installer ${SOURCES})
target_compile_options(x86_64-banan_os-bootloader-installer PRIVATE -O2 -std=c++20)
target_compile_definitions(x86_64-banan_os-bootloader-installer PRIVATE __arch=x86_64)
target_include_directories(x86_64-banan_os-bootloader-installer PRIVATE ${CMAKE_SOURCE_DIR}/../../LibELF/include)
target_include_directories(x86_64-banan_os-bootloader-installer PRIVATE ${CMAKE_SOURCE_DIR}/../../kernel/include)

View File

@ -81,7 +81,7 @@ bool ELFFile::validate_elf_header() const
#if ARCH(x86_64)
if (elf_header.e_ident[EI_CLASS] != ELFCLASS64)
#elif ARCH(i686)
#elif ARCH(i386)
if (elf_header.e_ident[EI_CLASS] != ELFCLASS32)
#endif
{

View File

@ -99,33 +99,33 @@ bool GPTFile::install_stage1(std::span<const uint8_t> stage1)
return true;
}
bool GPTFile::install_stage2(std::span<const uint8_t> stage2, std::span<const uint8_t> data, const GUID& root_partition_guid)
bool GPTFile::install_stage2(std::span<const uint8_t> stage2, const GUID& root_partition_guid)
{
if (data.size() < 16)
if (stage2.size() < 16)
{
std::cerr << m_path << ": contains invalid .data section, too small for patches" << std::endl;
std::cerr << m_path << ": contains invalid .stage2 section, too small for patches" << std::endl;
return false;
}
// find GUID patch offsets
std::size_t disk_guid_offset(-1);
std::size_t part_guid_offset(-1);
for (std::size_t i = 0; i < data.size() - 16; i++)
for (std::size_t i = 0; i < stage2.size() - 16; i++)
{
if (memcmp(data.data() + i, "root disk guid ", 16) == 0)
if (memcmp(stage2.data() + i, "root disk guid ", 16) == 0)
{
if (disk_guid_offset != std::size_t(-1))
{
std::cerr << m_path << ": contains invalid .data section, multiple patchable disk guids" << std::endl;
std::cerr << m_path << ": contains invalid .stage2 section, multiple patchable disk guids" << std::endl;
return false;
}
disk_guid_offset = i;
}
if (memcmp(data.data() + i, "root part guid ", 16) == 0)
if (memcmp(stage2.data() + i, "root part guid ", 16) == 0)
{
if (part_guid_offset != std::size_t(-1))
{
std::cerr << m_path << ": contains invalid .data section, multiple patchable partition guids" << std::endl;
std::cerr << m_path << ": contains invalid .stage2 section, multiple patchable partition guids" << std::endl;
return false;
}
part_guid_offset = i;
@ -133,14 +133,15 @@ bool GPTFile::install_stage2(std::span<const uint8_t> stage2, std::span<const ui
}
if (disk_guid_offset == std::size_t(-1))
{
std::cerr << m_path << ": contains invalid .data section, no patchable disk guid" << std::endl;
std::cerr << m_path << ": contains invalid .stage2 section, no patchable disk guid" << std::endl;
return false;
}
if (part_guid_offset == std::size_t(-1))
{
std::cerr << m_path << ": contains invalid .data section, no patchable partition guid" << std::endl;
std::cerr << m_path << ": contains invalid .stage2 section, no patchable partition guid" << std::endl;
return false;
}
auto partition = find_partition_with_type(bios_boot_guid);
if (!partition.has_value())
@ -151,28 +152,23 @@ bool GPTFile::install_stage2(std::span<const uint8_t> stage2, std::span<const ui
const std::size_t partition_size = (partition->ending_lba - partition->starting_lba + 1) * SECTOR_SIZE;
std::size_t data_offset = stage2.size();
if (std::size_t rem = data_offset % 512)
data_offset += 512 - rem;
if (data_offset + data.size() > partition_size)
if (stage2.size() > partition_size)
{
std::cerr << m_path << ": can't fit " << stage2.size() + data.size() << " bytes of data to partition of size " << partition_size << std::endl;
std::cerr << m_path << ": can't fit " << stage2.size() << " bytes of data to partition of size " << partition_size << std::endl;
return false;
}
uint8_t* partition_start = m_mmap + partition->starting_lba * SECTOR_SIZE;
memcpy(partition_start, stage2.data(), stage2.size());
memcpy(partition_start + data_offset, data.data(), data.size());
// patch GUIDs
*reinterpret_cast<GUID*>(partition_start + data_offset + disk_guid_offset) = gpt_header().disk_guid;
*reinterpret_cast<GUID*>(partition_start + data_offset + part_guid_offset) = root_partition_guid;
*reinterpret_cast<GUID*>(partition_start + disk_guid_offset) = gpt_header().disk_guid;
*reinterpret_cast<GUID*>(partition_start + part_guid_offset) = root_partition_guid;
return true;
}
bool GPTFile::install_bootloader(std::span<const uint8_t> stage1, std::span<const uint8_t> stage2, std::span<const uint8_t> data, const GUID& root_partition_guid)
bool GPTFile::install_bootloader(std::span<const uint8_t> stage1, std::span<const uint8_t> stage2, const GUID& root_partition_guid)
{
if (!find_partition_with_guid(root_partition_guid).has_value())
{
@ -181,7 +177,7 @@ bool GPTFile::install_bootloader(std::span<const uint8_t> stage1, std::span<cons
}
if (!install_stage1(stage1))
return false;
if (!install_stage2(stage2, data, root_partition_guid))
if (!install_stage2(stage2, root_partition_guid))
return false;
return true;
}

View File

@ -65,7 +65,7 @@ public:
GPTFile(std::string_view path);
~GPTFile();
bool install_bootloader(std::span<const uint8_t> stage1, std::span<const uint8_t> stage2, std::span<const uint8_t> data, const GUID& root_partition_guid);
bool install_bootloader(std::span<const uint8_t> stage1, std::span<const uint8_t> stage2, const GUID& root_partition_guid);
const GPTHeader& gpt_header() const;
@ -80,7 +80,7 @@ private:
std::optional<GPTPartitionEntry> find_partition_with_type(const GUID& type_guid) const;
bool install_stage1(std::span<const uint8_t> stage1);
bool install_stage2(std::span<const uint8_t> stage2, std::span<const uint8_t> data, const GUID& root_partition_guid);
bool install_stage2(std::span<const uint8_t> stage2, const GUID& root_partition_guid);
private:
const std::string m_path;

3
bootloader/installer/build.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
g++ -O2 -std=c++20 main.cpp crc32.cpp ELF.cpp GPT.cpp GUID.cpp -o install-bootloader

View File

@ -26,10 +26,9 @@ int main(int argc, char** argv)
auto stage1 = bootloader.find_section(".stage1"sv);
auto stage2 = bootloader.find_section(".stage2"sv);
auto data = bootloader.find_section(".data"sv);
if (!stage1.has_value() || !stage2.has_value() || !data.has_value())
if (!stage1.has_value() || !stage2.has_value())
{
std::cerr << bootloader.path() << " doesn't contain .stage1, .stage2 and .data sections" << std::endl;
std::cerr << bootloader.path() << " doesn't contain .stage1 and .stage2 sections" << std::endl;
return 1;
}
@ -37,9 +36,9 @@ int main(int argc, char** argv)
if (!disk_image.success())
return 1;
if (!disk_image.install_bootloader(*stage1, *stage2, *data, *root_partition_guid))
if (!disk_image.install_bootloader(*stage1, *stage2, *root_partition_guid))
return 1;
std::cout << "bootloader installed" << std::endl;
return 0;
}
}

View File

@ -1,30 +1,28 @@
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/ACPI.cpp
kernel/ACPI/AML.cpp
kernel/ACPI/AML/Field.cpp
kernel/ACPI/AML/NamedObject.cpp
kernel/ACPI/AML/Namespace.cpp
kernel/ACPI/AML/Node.cpp
kernel/ACPI/AML/Package.cpp
kernel/ACPI/AML/Scope.cpp
kernel/ACPI.cpp
kernel/APIC.cpp
kernel/BootInfo.cpp
kernel/CPUID.cpp
kernel/Credentials.cpp
kernel/Debug.cpp
kernel/Device/DebugDevice.cpp
kernel/Device/Device.cpp
kernel/Device/FramebufferDevice.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/FAT/FileSystem.cpp
kernel/FS/FAT/Inode.cpp
kernel/FS/FileSystem.cpp
kernel/FS/Inode.cpp
kernel/FS/Pipe.cpp
kernel/FS/ProcFS/FileSystem.cpp
@ -32,14 +30,9 @@ set(KERNEL_SOURCES
kernel/FS/TmpFS/FileSystem.cpp
kernel/FS/TmpFS/Inode.cpp
kernel/FS/VirtualFileSystem.cpp
kernel/GDT.cpp
kernel/IDT.cpp
kernel/Input/PS2/Controller.cpp
kernel/Input/PS2/Device.cpp
kernel/Input/PS2/Keyboard.cpp
kernel/Input/PS2/Keymap.cpp
kernel/Input/PS2/Mouse.cpp
kernel/Interruptable.cpp
kernel/Input/PS2Controller.cpp
kernel/Input/PS2Keyboard.cpp
kernel/Input/PS2Keymap.cpp
kernel/InterruptController.cpp
kernel/kernel.cpp
kernel/Memory/DMARegion.cpp
@ -49,28 +42,16 @@ set(KERNEL_SOURCES
kernel/Memory/MemoryBackedRegion.cpp
kernel/Memory/MemoryRegion.cpp
kernel/Memory/PhysicalRange.cpp
kernel/Memory/SharedMemoryObject.cpp
kernel/Memory/VirtualRange.cpp
kernel/Networking/ARPTable.cpp
kernel/Networking/E1000/E1000.cpp
kernel/Networking/E1000/E1000E.cpp
kernel/Networking/IPv4Layer.cpp
kernel/Networking/NetworkInterface.cpp
kernel/Networking/NetworkLayer.cpp
kernel/Networking/NetworkManager.cpp
kernel/Networking/NetworkSocket.cpp
kernel/Networking/TCPSocket.cpp
kernel/Networking/UDPSocket.cpp
kernel/Networking/UNIX/Socket.cpp
kernel/Networking/E1000.cpp
kernel/OpenFileDescriptorSet.cpp
kernel/Panic.cpp
kernel/PCI.cpp
kernel/PIC.cpp
kernel/Process.cpp
kernel/Processor.cpp
kernel/Random.cpp
kernel/Scheduler.cpp
kernel/Semaphore.cpp
kernel/SpinLock.cpp
kernel/SSP.cpp
kernel/Storage/ATA/AHCI/Controller.cpp
kernel/Storage/ATA/AHCI/Device.cpp
@ -78,15 +59,12 @@ set(KERNEL_SOURCES
kernel/Storage/ATA/ATAController.cpp
kernel/Storage/ATA/ATADevice.cpp
kernel/Storage/DiskCache.cpp
kernel/Storage/NVMe/Controller.cpp
kernel/Storage/NVMe/Namespace.cpp
kernel/Storage/NVMe/Queue.cpp
kernel/Storage/Partition.cpp
kernel/Storage/StorageDevice.cpp
kernel/Syscall.cpp
kernel/Terminal/FramebufferTerminal.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
@ -96,7 +74,7 @@ set(KERNEL_SOURCES
icxxabi.cpp
)
set(ENABLE_KERNEL_UBSAN False)
#set(ENABLE_KERNEL_UBSAN True)
if(ENABLE_KERNEL_UBSAN)
set(KERNEL_SOURCES ${KERNEL_SOURCES} ubsan.cpp)
@ -106,62 +84,61 @@ 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/Syscall.S
arch/x86_64/Thread.S
)
elseif("${BANAN_ARCH}" STREQUAL "i686")
elseif("${BANAN_ARCH}" STREQUAL "i386")
set(KERNEL_SOURCES
${KERNEL_SOURCES}
arch/i686/boot.S
arch/i686/interrupts.S
arch/i686/PageTable.cpp
arch/i686/Signal.S
arch/i686/Syscall.S
arch/i686/Thread.S
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/Assert.cpp
../BAN/BAN/New.cpp
../BAN/BAN/String.cpp
../BAN/BAN/StringView.cpp
../BAN/BAN/Time.cpp
)
set(KLIBC_SOURCES
klibc/ctype.cpp
klibc/string.cpp
set(LIBC_SOURCES
../libc/ctype.cpp
../libc/string.cpp
)
set(LIBELF_SOURCES
../userspace/libraries/LibELF/LibELF/LoadableELF.cpp
)
set(LIBFONT_SOURCES
../userspace/libraries/LibFont/Font.cpp
../userspace/libraries/LibFont/PSF.cpp
)
set(LIBINPUT_SOURCE
../userspace/libraries/LibInput/KeyboardLayout.cpp
../userspace/libraries/LibInput/KeyEvent.cpp
../LibELF/LibELF/LoadableELF.cpp
)
set(KERNEL_SOURCES
${KERNEL_SOURCES}
${LAI_SOURCES}
${BAN_SOURCES}
${KLIBC_SOURCES}
${LIBC_SOURCES}
${LIBELF_SOURCES}
${LIBFONT_SOURCES}
${LIBINPUT_SOURCE}
)
add_executable(kernel ${KERNEL_SOURCES})
add_dependencies(kernel headers)
target_compile_definitions(kernel PUBLIC __is_kernel)
target_compile_definitions(kernel PUBLIC __arch=${BANAN_ARCH})
@ -169,7 +146,7 @@ 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 -Wextra -Werror -Wstack-usage=1024 -fno-omit-frame-pointer -mgeneral-regs-only)
target_compile_options(kernel PUBLIC -fstack-protector -ffreestanding -Wall -Werror=return-type -Wstack-usage=1024 -fno-omit-frame-pointer -mgeneral-regs-only)
# This might not work with other toolchains
target_compile_options(kernel PUBLIC $<$<COMPILE_LANGUAGE:CXX>:-Wno-invalid-offsetof>)
@ -179,15 +156,26 @@ if(ENABLE_KERNEL_UBSAN)
endif()
if("${BANAN_ARCH}" STREQUAL "x86_64")
target_compile_options(kernel PUBLIC -mcmodel=kernel -mno-red-zone)
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 "i686")
target_link_options(kernel PUBLIC LINKER:-T,${CMAKE_CURRENT_SOURCE_DIR}/arch/i686/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(kernel-headers
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CMAKE_CURRENT_SOURCE_DIR}/include/ ${BANAN_INCLUDE}/
COMMAND ${CMAKE_COMMAND} -E copy_directory_if_different ${CMAKE_CURRENT_SOURCE_DIR}/lai/include/ ${BANAN_INCLUDE}/
DEPENDS sysroot
)
add_custom_target(kernel-install
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_BINARY_DIR}/kernel ${BANAN_BOOT}/banan-os.kernel
DEPENDS kernel
)
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)
@ -204,22 +192,6 @@ add_custom_command(
# COMMAND x86_64-banan_os-strip ${CMAKE_CURRENT_BINARY_DIR}/kernel
#)
banan_include_headers(kernel ban)
banan_include_headers(kernel libc)
banan_include_headers(kernel libfont)
banan_include_headers(kernel libelf)
banan_include_headers(kernel libinput)
banan_install_headers(kernel)
set_target_properties(kernel PROPERTIES OUTPUT_NAME banan-os.kernel)
install(TARGETS kernel DESTINATION ${BANAN_BOOT} OPTIONAL)
if("${BANAN_ARCH}" STREQUAL "x86_64")
set(ELF_FORMAT elf64-x86-64)
elseif("${BANAN_ARCH}" STREQUAL "i686")
set(ELF_FORMAT elf32-i386)
endif()
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

147
kernel/arch/i386/GDT.cpp Normal file
View File

@ -0,0 +1,147 @@
#include <BAN/Assert.h>
#include <kernel/GDT.h>
#include <string.h>
extern "C" uintptr_t g_boot_stack_top[0];
namespace Kernel::GDT
{
struct TaskStateSegment
{
uint16_t link;
uint16_t reserved1;
uint32_t esp0;
uint16_t ss0;
uint16_t reserved2;
uint32_t esp1;
uint16_t ss1;
uint16_t reserved3;
uint32_t esp2;
uint16_t ss2;
uint16_t reserved4;
uint32_t cr3;
uint32_t eip;
uint32_t eflags;
uint32_t eax;
uint32_t ecx;
uint32_t edx;
uint32_t ebx;
uint32_t esp;
uint32_t ebp;
uint32_t esi;
uint32_t edi;
uint16_t es;
uint16_t reserved5;
uint16_t cs;
uint16_t reserved6;
uint16_t ss;
uint16_t reserved7;
uint16_t ds;
uint16_t reserved8;
uint16_t fs;
uint16_t reserved9;
uint16_t gs;
uint16_t reserved10;
uint16_t ldtr;
uint16_t reserved11;
uint16_t reserved12;
uint16_t iopb;
uint32_t ssp;
} __attribute__((packed));
union SegmentDescriptor
{
struct
{
uint16_t limit1;
uint16_t base1;
uint8_t base2;
uint8_t access;
uint8_t limit2 : 4;
uint8_t flags : 4;
uint8_t base3;
} __attribute__((packed));
struct
{
uint32_t low;
uint32_t high;
} __attribute__((packed));
} __attribute__((packed));
struct GDTR
{
uint16_t size;
uint32_t address;
} __attribute__((packed));
static TaskStateSegment* s_tss = nullptr;
static SegmentDescriptor* s_gdt = nullptr;
static GDTR s_gdtr;
static void write_entry(uint8_t offset, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags)
{
SegmentDescriptor& desc = *(SegmentDescriptor*)((uintptr_t)s_gdt + offset);
desc.base1 = base;
desc.base2 = base >> 16;
desc.base3 = base >> 24;
desc.limit1 = limit;
desc.limit2 = limit >> 16;
desc.access = access;
desc.flags = flags;
}
static void write_tss(uint8_t offset)
{
s_tss = new TaskStateSegment();
ASSERT(s_tss);
memset(s_tss, 0x00, sizeof(TaskStateSegment));
s_tss->ss0 = 0x10;
s_tss->esp0 = (uintptr_t)g_boot_stack_top;
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));
}
extern "C" void flush_tss(uint16_t offset)
{
asm volatile("ltr %0" :: "m"(offset));
}
void initialize()
{
constexpr uint32_t descriptor_count = 6;
s_gdt = new SegmentDescriptor[descriptor_count];
ASSERT(s_gdt);
s_gdtr.address = (uint64_t)s_gdt;
s_gdtr.size = descriptor_count * sizeof(SegmentDescriptor) - 1;
write_entry(0x00, 0x00000000, 0x00000, 0x00, 0x0); // null
write_entry(0x08, 0x00000000, 0xFFFFF, 0x9A, 0xC); // kernel code
write_entry(0x10, 0x00000000, 0xFFFFF, 0x92, 0xC); // kernel data
write_entry(0x18, 0x00000000, 0xFFFFF, 0xFA, 0xC); // user code
write_entry(0x20, 0x00000000, 0xFFFFF, 0xF2, 0xC); // user data
write_tss(0x28);
flush_gdt();
flush_tss(0x28);
}
}

270
kernel/arch/i386/IDT.cpp Normal file
View File

@ -0,0 +1,270 @@
#include <BAN/Errors.h>
#include <kernel/IDT.h>
#include <kernel/InterruptController.h>
#include <kernel/Memory/kmalloc.h>
#include <kernel/Panic.h>
#include <kernel/Scheduler.h>
#define INTERRUPT_HANDLER____(i, msg) \
static void interrupt ## i () \
{ \
uint32_t eax, ebx, ecx, edx; \
uint32_t esp, ebp; \
uint32_t cr0, cr2, cr3, cr4; \
asm volatile("":"=a"(eax),"=b"(ebx),"=c"(ecx),"=d"(edx)); \
asm volatile("movl %%esp, %%eax":"=a"(esp)); \
asm volatile("movl %%ebp, %%eax":"=a"(ebp)); \
asm volatile("movl %%cr0, %%eax":"=a"(cr0)); \
asm volatile("movl %%cr2, %%eax":"=a"(cr2)); \
asm volatile("movl %%cr3, %%eax":"=a"(cr3)); \
asm volatile("movl %%cr4, %%eax":"=a"(cr4)); \
Kernel::panic(msg "\r\nRegister dump\r\n" \
"eax=0x{8H}, ebx=0x{8H}, ecx=0x{8H}, edx=0x{8H}\r\n" \
"esp=0x{8H}, ebp=0x{8H}\r\n" \
"CR0=0x{8H}, CR2=0x{8H}, CR3=0x{8H}, CR4=0x{8H}\r\n", \
eax, ebx, ecx, edx, esp, ebp, cr0, cr2, cr3, cr4); \
}
#define INTERRUPT_HANDLER_ERR(i, msg) \
static void interrupt ## i () \
{ \
uint32_t eax, ebx, ecx, edx; \
uint32_t esp, ebp; \
uint32_t cr0, cr2, cr3, cr4; \
uint32_t error_code; \
asm volatile("":"=a"(eax),"=b"(ebx),"=c"(ecx),"=d"(edx)); \
asm volatile("movl %%esp, %%eax":"=a"(esp)); \
asm volatile("movl %%ebp, %%eax":"=a"(ebp)); \
asm volatile("movl %%cr0, %%eax":"=a"(cr0)); \
asm volatile("movl %%cr2, %%eax":"=a"(cr2)); \
asm volatile("movl %%cr3, %%eax":"=a"(cr3)); \
asm volatile("movl %%cr4, %%eax":"=a"(cr4)); \
asm volatile("popl %%eax":"=a"(error_code)); \
Kernel::panic(msg " (error code: 0x{8H})\r\n" \
"Register dump\r\n" \
"eax=0x{8H}, ebx=0x{8H}, ecx=0x{8H}, edx=0x{8H}\r\n" \
"esp=0x{8H}, ebp=0x{8H}\r\n" \
"CR0=0x{8H}, CR2=0x{8H}, CR3=0x{8H}, CR4=0x{8H}\r\n", \
eax, ebx, ecx, edx, esp, ebp, cr0, cr2, cr3, cr4, error_code); \
}
#define REGISTER_HANDLER(i) register_interrupt_handler(i, interrupt ## i)
namespace IDT
{
struct GateDescriptor
{
uint16_t offset1;
uint16_t selector;
uint8_t reserved : 5;
uint8_t zero1 : 3;
uint8_t type : 4;
uint8_t zero2 : 1;
uint8_t DPL : 2;
uint8_t present : 1;
uint16_t offset2;
} __attribute__((packed));
struct IDTR
{
uint16_t size;
void* offset;
} __attribute((packed));
static IDTR s_idtr;
static GateDescriptor* s_idt = nullptr;
static void(*s_irq_handlers[16])() { nullptr };
INTERRUPT_HANDLER____(0x00, "Division Error")
INTERRUPT_HANDLER____(0x01, "Debug")
INTERRUPT_HANDLER____(0x02, "Non-maskable Interrupt")
INTERRUPT_HANDLER____(0x03, "Breakpoint")
INTERRUPT_HANDLER____(0x04, "Overflow")
INTERRUPT_HANDLER____(0x05, "Bound Range Exception")
INTERRUPT_HANDLER____(0x06, "Invalid Opcode")
INTERRUPT_HANDLER____(0x07, "Device Not Available")
INTERRUPT_HANDLER_ERR(0x08, "Double Fault")
INTERRUPT_HANDLER____(0x09, "Coprocessor Segment Overrun")
INTERRUPT_HANDLER_ERR(0x0A, "Invalid TSS")
INTERRUPT_HANDLER_ERR(0x0B, "Segment Not Present")
INTERRUPT_HANDLER_ERR(0x0C, "Stack-Segment Fault")
INTERRUPT_HANDLER_ERR(0x0D, "General Protection Fault")
INTERRUPT_HANDLER_ERR(0x0E, "Page Fault")
INTERRUPT_HANDLER____(0x0F, "Unknown Exception 0x0F")
INTERRUPT_HANDLER____(0x10, "x87 Floating-Point Exception")
INTERRUPT_HANDLER_ERR(0x11, "Alignment Check")
INTERRUPT_HANDLER____(0x12, "Machine Check")
INTERRUPT_HANDLER____(0x13, "SIMD Floating-Point Exception")
INTERRUPT_HANDLER____(0x14, "Virtualization Exception")
INTERRUPT_HANDLER_ERR(0x15, "Control Protection Exception")
INTERRUPT_HANDLER____(0x16, "Unknown Exception 0x16")
INTERRUPT_HANDLER____(0x17, "Unknown Exception 0x17")
INTERRUPT_HANDLER____(0x18, "Unknown Exception 0x18")
INTERRUPT_HANDLER____(0x19, "Unknown Exception 0x19")
INTERRUPT_HANDLER____(0x1A, "Unknown Exception 0x1A")
INTERRUPT_HANDLER____(0x1B, "Unknown Exception 0x1B")
INTERRUPT_HANDLER____(0x1C, "Hypervisor Injection Exception")
INTERRUPT_HANDLER_ERR(0x1D, "VMM Communication Exception")
INTERRUPT_HANDLER_ERR(0x1E, "Security Exception")
INTERRUPT_HANDLER____(0x1F, "Unkown Exception 0x1F")
extern "C" void handle_irq()
{
uint8_t irq;
for (uint32_t i = 0; i < 16; i++)
{
if (InterruptController::get().is_in_service(i))
{
irq = i;
goto found;
}
}
dprintln("Spurious irq");
return;
found:
if (s_irq_handlers[irq])
s_irq_handlers[irq]();
else
dprintln("no handler for irq 0x{2H}\n", irq);
// 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();
asm(
".globl handle_irq_common;"
"handle_irq_common:"
"pusha;"
"pushw %ds;"
"pushw %es;"
"pushw %ss;"
"pushw %ss;"
"popw %ds;"
"popw %es;"
"call handle_irq;"
"popw %es;"
"popw %ds;"
"popa;"
"iret;"
);
extern "C" void syscall_asm();
asm(
".global syscall_asm;"
"syscall_asm:"
"pusha;"
"pushw %ds;"
"pushw %es;"
"pushw %ss;"
"pushw %ss;"
"popw %ds;"
"popw %es;"
"pushl %edx;"
"pushl %ecx;"
"pushl %ebx;"
"pushl %eax;"
"call cpp_syscall_handler;"
"addl $16, %esp;"
"popw %es;"
"popw %ds;"
// 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;"
);
static void flush_idt()
{
asm volatile("lidt %0"::"m"(s_idtr));
}
static void register_interrupt_handler(uint8_t index, void(*f)())
{
GateDescriptor& descriptor = s_idt[index];
descriptor.offset1 = (uint32_t)f & 0xFFFF;
descriptor.selector = 0x08;
descriptor.type = 0xE;
descriptor.DPL = 0;
descriptor.present = 1;
descriptor.offset2 = (uint32_t)f >> 16;
}
void register_irq_handler(uint8_t irq, void(*f)())
{
s_irq_handlers[irq] = f;
register_interrupt_handler(IRQ_VECTOR_BASE + irq, handle_irq_common);
flush_idt();
}
void register_syscall_handler(uint8_t offset, void(*handler)())
{
register_interrupt_handler(offset, handler);
s_idt[offset].DPL = 3;
}
void initialize()
{
constexpr size_t idt_size = 0x100 * sizeof(GateDescriptor);
s_idt = (GateDescriptor*)kmalloc(idt_size);
ASSERT(s_idt);
memset(s_idt, 0x00, idt_size);
s_idtr.offset = s_idt;
s_idtr.size = idt_size - 1;
REGISTER_HANDLER(0x00);
REGISTER_HANDLER(0x01);
REGISTER_HANDLER(0x02);
REGISTER_HANDLER(0x03);
REGISTER_HANDLER(0x04);
REGISTER_HANDLER(0x05);
REGISTER_HANDLER(0x06);
REGISTER_HANDLER(0x07);
REGISTER_HANDLER(0x08);
REGISTER_HANDLER(0x09);
REGISTER_HANDLER(0x0A);
REGISTER_HANDLER(0x0B);
REGISTER_HANDLER(0x0C);
REGISTER_HANDLER(0x0D);
REGISTER_HANDLER(0x0E);
REGISTER_HANDLER(0x0F);
REGISTER_HANDLER(0x10);
REGISTER_HANDLER(0x11);
REGISTER_HANDLER(0x12);
REGISTER_HANDLER(0x13);
REGISTER_HANDLER(0x14);
REGISTER_HANDLER(0x15);
REGISTER_HANDLER(0x16);
REGISTER_HANDLER(0x17);
REGISTER_HANDLER(0x18);
REGISTER_HANDLER(0x19);
REGISTER_HANDLER(0x1A);
REGISTER_HANDLER(0x1B);
REGISTER_HANDLER(0x1C);
REGISTER_HANDLER(0x1D);
REGISTER_HANDLER(0x1E);
REGISTER_HANDLER(0x1F);
register_syscall_handler(0x80, syscall_asm);
flush_idt();
}
}

227
kernel/arch/i386/MMU.cpp Normal file
View File

@ -0,0 +1,227 @@
#include <BAN/Errors.h>
#include <kernel/Debug.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 FLAGS_MASK 0x00000fff
namespace Kernel
{
static MMU* s_instance = nullptr;
void MMU::initialize()
{
ASSERT(s_instance == nullptr);
s_instance = new MMU();
ASSERT(s_instance);
s_instance->initialize_kernel();
s_instance->load();
}
MMU& MMU::get()
{
ASSERT(s_instance);
return *s_instance;
}
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;
}
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;
}
}

View File

@ -0,0 +1,19 @@
.global spinlock_lock_asm
spinlock_lock_asm:
movl 4(%esp), %eax
lock; btsl $0, (%eax)
jnc .done
.retry:
pause
testl $1, (%eax)
jne .retry
lock; btsl $0, (%eax)
jc .retry
.done:
ret
.global spinlock_unlock_asm
spinlock_unlock_asm:
movl 4(%esp), %eax
movl $0, (%eax)
ret

47
kernel/arch/i386/Thread.S Normal file
View File

@ -0,0 +1,47 @@
# uint32_t read_rip()
.global read_rip
read_rip:
popl %eax
jmp *%eax
exit_thread_trampoline:
addl $4, %esp
pushl (%esp)
ret
# void start_thread(uint32_t esp, uint32_t eip)
.global start_thread
start_thread:
movl 8(%esp), %ecx
movl 4(%esp), %esp
movl $0, %ebp
pushl $exit_thread_trampoline
sti
jmp *%ecx
# void continue_thread(uint32_t rsp, uint32_t rip)
.global continue_thread
continue_thread:
movl 8(%esp), %ecx
movl 4(%esp), %esp
movl $0, %eax
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

182
kernel/arch/i386/boot.S Normal file
View File

@ -0,0 +1,182 @@
# Declare constants for the multiboot header
.set ALIGN, 1<<0 # align loaded modules on page boundaries
.set MEMINFO, 1<<1 # provide memory map
.set VIDEOINFO, 1<<2 # provide video info
.set MB_FLAGS, ALIGN | MEMINFO | VIDEOINFO # this is the Multiboot 'flag' field
.set MB_MAGIC, 0x1BADB002 # 'magic number' lets bootloader find the header
.set MB_CHECKSUM, -(MB_MAGIC + MB_FLAGS) #checksum of above, to prove we are multiboot
# Multiboot header
.section .multiboot, "aw"
.align 4
.long MB_MAGIC
.long MB_FLAGS
.long MB_CHECKSUM
.skip 20
.long 0
.long 800
.long 600
.long 32
.section .bss, "aw", @nobits
# Create stack
.global g_boot_stack_bottom
g_boot_stack_bottom:
.skip 16384
.global g_boot_stack_top
g_boot_stack_top:
# 0 MiB -> 1 MiB: bootloader stuff
# 1 MiB -> : kernel
.align 32
boot_page_directory_pointer_table:
.skip 4 * 8
.align 4096
boot_page_directory1:
.skip 512 * 8
.global g_kernel_cmdline
g_kernel_cmdline:
.skip 4096
.global g_multiboot_info
g_multiboot_info:
.skip 4
.global g_multiboot_magic
g_multiboot_magic:
.skip 4
.section .text
boot_gdt:
.quad 0x0000000000000000 # null
.quad 0x00CF9A000000FFFF # kernel code
.quad 0x00CF92000000FFFF # kernel data
boot_gdtr:
.short . - boot_gdt - 1
.long boot_gdt
has_cpuid:
pushfl
pushfl
xorl $0x00200000, (%esp)
popfl
pushfl
popl %eax
xorl (%esp), %eax
popfl
testl $0x00200000, %eax
ret
has_pae:
movl $0, %eax
cpuid
testl $(1 << 6), %edx
ret
has_sse:
movl $1, %eax
cpuid
testl $(1 << 25), %edx
ret
check_requirements:
call has_cpuid
jz .exit
call has_pae
jz .exit
call has_sse
jz .exit
ret
.exit:
jmp system_halt
copy_kernel_commandline:
pushl %esi
pushl %edi
movl g_multiboot_info, %esi
addl $16, %esi
movl (%esi), %esi
movl $1024, %ecx
movl $g_kernel_cmdline, %edi
rep movsl
popl %edi
popl %esi
ret
enable_sse:
movl %cr0, %eax
andw $0xFFFB, %ax
orw $0x0002, %ax
movl %eax, %cr0
movl %cr4, %eax
orw $0x0600, %ax
movl %eax, %cr4
ret
initialize_paging:
# identity map first 6 MiB
movl $(0x00000000 + 0x83), boot_page_directory1 + 0
movl $(0x00200000 + 0x83), boot_page_directory1 + 8
movl $(0x00400000 + 0x83), boot_page_directory1 + 16
movl $(boot_page_directory1 + 0x01), boot_page_directory_pointer_table
# enable PAE
movl %cr4, %ecx
orl $0x20, %ecx
movl %ecx, %cr4
# set address of paging structures
movl $boot_page_directory_pointer_table, %ecx
movl %ecx, %cr3
# enable paging
movl %cr0, %ecx
orl $0x80000000, %ecx
movl %ecx, %cr0
ret
initialize_gdt:
lgdt boot_gdtr
# flush gdt
movw $0x10, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw %ax, %ss
jmp $0x08, $flush
flush:
ret
.global _start
.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
call copy_kernel_commandline
call check_requirements
call enable_sse
call initialize_paging
call initialize_gdt
call _init
# call to the kernel itself (clear ebp for stacktrace)
xorl %ebp, %ebp
call kernel_main
call _fini
system_halt:
xchgw %bx, %bx
cli
1: hlt
jmp 1b

View File

@ -0,0 +1,28 @@
ENTRY (_start)
SECTIONS
{
. = 0x00100000;
g_kernel_start = .;
.text BLOCK(4K) : ALIGN(4K)
{
*(.multiboot)
*(.text)
}
.rodata BLOCK(4K) : ALIGN(4K)
{
*(.rodata.*)
}
.data BLOCK(4K) : ALIGN(4K)
{
*(.data)
}
.bss BLOCK(4K) : ALIGN(4K)
{
*(COMMON)
*(.bss)
}
g_kernel_end = .;
}

View File

@ -1,620 +0,0 @@
#include <kernel/CPUID.h>
#include <kernel/Lock/SpinLock.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
{
SpinLock PageTable::s_fast_page_lock;
static PageTable* s_kernel = nullptr;
static bool s_has_nxe = false;
static bool s_has_pge = false;
static paddr_t s_global_pdpte = 0;
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())
s_has_nxe = true;
if (CPUID::has_pge())
s_has_pge = true;
ASSERT(s_kernel == nullptr);
s_kernel = new PageTable();
ASSERT(s_kernel);
s_kernel->initialize_kernel();
s_kernel->initial_load();
}
void PageTable::initial_load()
{
if (s_has_nxe)
{
asm volatile(
"movl $0xC0000080, %%ecx;"
"rdmsr;"
"orl $0x800, %%eax;"
"wrmsr"
::: "eax", "ecx", "edx", "memory"
);
}
if (s_has_pge)
{
asm volatile(
"movl %%cr4, %%eax;"
"orl $0x80, %%eax;"
"movl %%eax, %%cr4;"
::: "eax"
);
}
// enable write protect
asm volatile(
"movl %%cr0, %%eax;"
"orl $0x10000, %%eax;"
"movl %%eax, %%cr0;"
::: "rax"
);
load();
}
PageTable& PageTable::kernel()
{
ASSERT(s_kernel);
return *s_kernel;
}
bool PageTable::is_valid_pointer(uintptr_t)
{
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_pdpte == 0);
s_global_pdpte = V2P(allocate_zeroed_page_aligned_page());
map_kernel_memory();
prepare_fast_page();
// Map main bios area below 1 MiB
map_range_at(
0x000E0000,
P2V(0x000E0000),
0x00100000 - 0x000E0000,
PageTable::Flags::Present
);
// Map (phys_kernel_start -> phys_kernel_end) to (virt_kernel_start -> virt_kernel_end)
ASSERT((vaddr_t)g_kernel_start % PAGE_SIZE == 0);
map_range_at(
V2P(g_kernel_start),
(vaddr_t)g_kernel_start,
g_kernel_end - g_kernel_start,
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
);
}
void PageTable::prepare_fast_page()
{
constexpr uint64_t pdpte = (fast_page() >> 30) & 0x1FF;
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
ASSERT(pdpt[pdpte] & Flags::Present);
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte]) & PAGE_ADDR_MASK);
ASSERT(!(pd[pde] & Flags::Present));
pd[pde] = V2P(allocate_zeroed_page_aligned_page()) | Flags::ReadWrite | Flags::Present;
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde]) & PAGE_ADDR_MASK);
ASSERT(!(pt[pte] & Flags::Present));
pt[pte] = V2P(allocate_zeroed_page_aligned_page());
}
void PageTable::map_fast_page(paddr_t paddr)
{
ASSERT(s_kernel);
ASSERT(paddr);
ASSERT(s_fast_page_lock.current_processor_has_lock());
constexpr uint64_t pdpte = (fast_page() >> 30) & 0x1FF;
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(s_kernel->m_highest_paging_struct));
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK));
ASSERT(!(pt[pte] & Flags::Present));
pt[pte] = paddr | Flags::ReadWrite | Flags::Present;
invalidate(fast_page());
}
void PageTable::unmap_fast_page()
{
ASSERT(s_kernel);
ASSERT(s_fast_page_lock.current_processor_has_lock());
constexpr uint64_t pdpte = (fast_page() >> 30) & 0x1FF;
constexpr uint64_t pde = (fast_page() >> 21) & 0x1FF;
constexpr uint64_t pte = (fast_page() >> 12) & 0x1FF;
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(s_kernel->m_highest_paging_struct));
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
uint64_t* pt = reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK));
ASSERT(pt[pte] & Flags::Present);
pt[pte] = 0;
invalidate(fast_page());
}
BAN::ErrorOr<PageTable*> PageTable::create_userspace()
{
SpinLockGuard _(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_pdpte);
ASSERT(m_highest_paging_struct == 0);
m_highest_paging_struct = V2P(kmalloc(32, 32, true));
ASSERT(m_highest_paging_struct);
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
pdpt[0] = 0;
pdpt[1] = 0;
pdpt[2] = 0;
pdpt[3] = s_global_pdpte | Flags::Present;
static_assert(KERNEL_OFFSET == 0xC0000000);
}
PageTable::~PageTable()
{
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
for (uint32_t pdpte = 0; pdpte < 3; pdpte++)
{
if (!(pdpt[pdpte] & Flags::Present))
continue;
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
for (uint32_t pde = 0; pde < 512; pde++)
{
if (!(pd[pde] & Flags::Present))
continue;
kfree(reinterpret_cast<uint64_t*>(P2V(pd[pde] & PAGE_ADDR_MASK)));
}
kfree(pd);
}
kfree(pdpt);
}
void PageTable::load()
{
SpinLockGuard _(m_lock);
ASSERT(m_highest_paging_struct < 0x100000000);
const uint32_t pdpt_lo = m_highest_paging_struct;
asm volatile("movl %0, %%cr3" :: "r"(pdpt_lo));
Processor::set_current_page_table(this);
}
void PageTable::invalidate(vaddr_t vaddr)
{
ASSERT(vaddr % PAGE_SIZE == 0);
asm volatile("invlpg (%0)" :: "r"(vaddr) : "memory");
}
void PageTable::unmap_page(vaddr_t vaddr)
{
ASSERT(vaddr);
ASSERT(vaddr % PAGE_SIZE == 0);
ASSERT(vaddr != fast_page());
if (vaddr >= KERNEL_OFFSET)
ASSERT(vaddr >= (vaddr_t)g_kernel_start);
if ((vaddr >= KERNEL_OFFSET) != (this == s_kernel))
Kernel::panic("unmapping {8H}, kernel: {}", vaddr, this == s_kernel);
const uint64_t pdpte = (vaddr >> 30) & 0x1FF;
const uint64_t pde = (vaddr >> 21) & 0x1FF;
const uint64_t pte = (vaddr >> 12) & 0x1FF;
SpinLockGuard _(m_lock);
if (is_page_free(vaddr))
{
dwarnln("unmapping unmapped page {8H}", vaddr);
return;
}
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
uint64_t* pt = reinterpret_cast<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);
SpinLockGuard _(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)
{
ASSERT(vaddr);
ASSERT(vaddr != fast_page());
if ((vaddr >= KERNEL_OFFSET) != (this == s_kernel))
Kernel::panic("mapping {8H} to {8H}, kernel: {}", paddr, vaddr, this == s_kernel);
ASSERT(paddr % PAGE_SIZE == 0);
ASSERT(vaddr % PAGE_SIZE == 0);
ASSERT(flags & Flags::Used);
const uint64_t pdpte = (vaddr >> 30) & 0x1FF;
const uint64_t pde = (vaddr >> 21) & 0x1FF;
const uint64_t pte = (vaddr >> 12) & 0x1FF;
uint64_t extra_flags = 0;
if (s_has_pge && vaddr >= KERNEL_OFFSET) // 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;
SpinLockGuard _(m_lock);
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
if (!(pdpt[pdpte] & Flags::Present))
pdpt[pdpte] = V2P(allocate_zeroed_page_aligned_page()) | Flags::Present;
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
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 = reinterpret_cast<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(vaddr);
ASSERT(paddr % PAGE_SIZE == 0);
ASSERT(vaddr % PAGE_SIZE == 0);
size_t page_count = range_page_count(vaddr, size);
SpinLockGuard _(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(vaddr % PAGE_SIZE == 0);
const uint64_t pdpte = (vaddr >> 30) & 0x1FF;
const uint64_t pde = (vaddr >> 21) & 0x1FF;
const uint64_t pte = (vaddr >> 12) & 0x1FF;
SpinLockGuard _(m_lock);
uint64_t* pdpt = (uint64_t*)P2V(m_highest_paging_struct);
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 vaddr) const
{
return parse_flags(get_page_data(vaddr));
}
paddr_t PageTable::physical_address_of(vaddr_t vaddr) const
{
uint64_t page_data = get_page_data(vaddr);
return (page_data & PAGE_ADDR_MASK) & ~(1ull << 63);
}
bool PageTable::is_page_free(vaddr_t vaddr) const
{
ASSERT(vaddr % PAGE_SIZE == 0);
return !(get_page_flags(vaddr) & 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);
SpinLockGuard _(m_lock);
for (vaddr_t page = s_page; page < e_page; page++)
if (!is_page_free(page * PAGE_SIZE))
return false;
return true;
}
bool PageTable::reserve_page(vaddr_t vaddr, bool only_free)
{
SpinLockGuard _(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);
SpinLockGuard _(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 (first_address >= KERNEL_OFFSET && first_address < (vaddr_t)g_kernel_end)
first_address = (vaddr_t)g_kernel_end;
if (size_t rem = first_address % PAGE_SIZE)
first_address += PAGE_SIZE - rem;
if (size_t rem = last_address % PAGE_SIZE)
last_address -= rem;
const uint32_t s_pdpte = (first_address >> 30) & 0x1FF;
const uint32_t s_pde = (first_address >> 21) & 0x1FF;
const uint32_t s_pte = (first_address >> 12) & 0x1FF;
const uint32_t e_pdpte = (last_address >> 30) & 0x1FF;
const uint32_t e_pde = (last_address >> 21) & 0x1FF;
const uint32_t e_pte = (last_address >> 12) & 0x1FF;
SpinLockGuard _(m_lock);
// Try to find free page that can be mapped without
// allocations (page table with unused entries)
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
for (uint32_t pdpte = s_pdpte; pdpte < 4; pdpte++)
{
if (pdpte > e_pdpte)
break;
if (!(pdpt[pdpte] & Flags::Present))
continue;
uint64_t* pd = reinterpret_cast<uint64_t*>(P2V(pdpt[pdpte] & PAGE_ADDR_MASK));
for (uint32_t pde = s_pde; pde < 512; pde++)
{
if (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 (uint32_t pte = s_pte; pte < 512; pte++)
{
if (pdpte == e_pdpte && pde == e_pde && pte >= e_pte)
break;
if (!(pt[pte] & Flags::Used))
{
vaddr_t vaddr = 0;
vaddr |= (vaddr_t)pdpte << 30;
vaddr |= (vaddr_t)pde << 21;
vaddr |= (vaddr_t)pte << 12;
ASSERT(reserve_page(vaddr));
return vaddr;
}
}
}
}
// Find any free page
for (vaddr_t vaddr = first_address; vaddr < last_address; vaddr += PAGE_SIZE)
{
if (is_page_free(vaddr))
{
ASSERT(reserve_page(vaddr));
return vaddr;
}
}
ASSERT_NOT_REACHED();
}
vaddr_t PageTable::reserve_free_contiguous_pages(size_t page_count, vaddr_t first_address, vaddr_t last_address)
{
if (first_address >= KERNEL_OFFSET && first_address < (vaddr_t)g_kernel_start)
first_address = (vaddr_t)g_kernel_start;
if (size_t rem = first_address % PAGE_SIZE)
first_address += PAGE_SIZE - rem;
if (size_t rem = last_address % PAGE_SIZE)
last_address -= rem;
SpinLockGuard _(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_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();
}
static void dump_range(vaddr_t start, vaddr_t end, PageTable::flags_t flags)
{
if (start == 0)
return;
dprintln("{}-{}: {}{}{}{}",
(void*)(start), (void*)(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()
{
SpinLockGuard _(m_lock);
flags_t flags = 0;
vaddr_t start = 0;
uint64_t* pdpt = reinterpret_cast<uint64_t*>(P2V(m_highest_paging_struct));
for (uint32_t pdpte = 0; pdpte < 4; pdpte++)
{
if (!(pdpt[pdpte] & Flags::Present))
{
dump_range(start, (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, (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, (pdpte << 30) | (pde << 21) | (pte << 12), flags);
start = 0;
}
if (!(pt[pte] & Flags::Used))
continue;
if (start == 0)
{
flags = parse_flags(pt[pte]);
start = (pdpte << 30) | (pde << 21) | (pte << 12);
}
}
}
}
}
}

View File

@ -1,35 +0,0 @@
.section .userspace, "aw"
// stack contains
// return address
// signal number
// signal handler
.global signal_trampoline
signal_trampoline:
pushl %ebp
movl %esp, %ebp
pusha
movl 40(%esp), %edi
movl 36(%esp), %eax
// align stack to 16 bytes
movl %esp, %ebx
andl $0x0F, %ebx
subl %ebx, %esp
subl $12, %esp
pushl %edi
call *%eax
addl $16, %esp
// restore stack
addl %ebx, %esp
popa
leave
addl $8, %esp
ret

View File

@ -1,85 +0,0 @@
// arguments in EAX, EBX, ECX, EDX, ESI, EDI
.global asm_syscall_handler
asm_syscall_handler:
# save segment registers
pushw %ds
pushw %es
pushw %fs
pushw %gs
# save general purpose registers
pushl %ebx
pushl %ecx
pushl %edx
pushl %edi
pushl %esi
pushl %ebp
# align stack and push arguments
pushl %esp
addl $32, (%esp)
pushl %edi
pushl %esi
pushl %edx
pushl %ecx
pushl %ebx
pushl %eax
# load kernel segments
movw $0x10, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw $0x28, %ax
movw %ax, %gs
call cpp_syscall_handler
addl $28, %esp
# restore general purpose registers
popl %ebp
popl %esi
popl %edi
popl %edx
popl %ecx
popl %ebx
# restore segment registers
popw %gs
popw %fs
popw %es
popw %ds
iret
.global sys_fork_trampoline
sys_fork_trampoline:
pushl %ebp
pushl %ebx
pushl %esi
pushl %edi
call read_ip
testl %eax, %eax
jz .reload_stack
movl %esp, %ebx
subl $8, %esp
pushl %eax
pushl %ebx
call sys_fork
addl $16, %esp
.done:
popl %edi
popl %esi
popl %ebx
popl %ebp
ret
.reload_stack:
call get_thread_start_sp
movl %eax, %esp
xorl %eax, %eax
jmp .done

View File

@ -1,68 +0,0 @@
# uint32_t read_ip()
.global read_ip
read_ip:
popl %eax
jmp *%eax
# void start_kernel_thread()
.global start_kernel_thread
start_kernel_thread:
call get_thread_start_sp
movl %eax, %esp
# STACK LAYOUT
# on_exit arg
# on_exit func
# entry arg
# entry func
movl 4(%esp), %edi
movl 0(%esp), %esi
subl $12, %esp
pushl %edi
sti
call *%esi
addl $16, %esp
movl 12(%esp), %edi
movl 8(%esp), %esi
subl $12, %esp
pushl %edi
call *%esi
addl $16, %esp
.global start_userspace_thread
start_userspace_thread:
call get_thread_start_sp
movl %eax, %esp
# STACK LAYOUT
# entry
# argc
# argv
# envp
# userspace stack
call get_userspace_thread_stack_top
movw $(0x20 | 3), %bx
movw %bx, %ds
movw %bx, %es
movw %bx, %fs
movw %bx, %gs
xorw %bx, %bx
popl %edx
popl %esi
popl %edi
popl %ecx
pushl $(0x20 | 3)
pushl %eax
pushl $0x202
pushl $(0x18 | 3)
pushl %ecx
iret

View File

@ -1,305 +0,0 @@
.set PG_PRESENT, 1<<0
.set PG_READ_WRITE, 1<<1
.set PG_PAGE_SIZE, 1<<7
.set FB_WIDTH, 800
.set FB_HEIGHT, 600
.set FB_BPP, 32
#define KERNEL_OFFSET 0xC0000000
#define V2P(vaddr) ((vaddr) - KERNEL_OFFSET)
.code32
# multiboot2 header
.section .multiboot, "aw"
.align 8
multiboot2_start:
.long 0xE85250D6
.long 0
.long multiboot2_end - multiboot2_start
.long -(0xE85250D6 + (multiboot2_end - multiboot2_start))
# framebuffer tag
.align 8
.short 5
.short 0
.long 20
.long FB_WIDTH
.long FB_HEIGHT
.long FB_BPP
# legacy start
.align 8
.short 3
.short 0
.long 12
.long V2P(_start)
.align 8
.short 0
.short 0
.long 8
multiboot2_end:
.section .bananboot, "aw"
.align 8
bananboot_start:
.long 0xBABAB007
.long -(0xBABAB007 + FB_WIDTH + FB_HEIGHT + FB_BPP)
.long FB_WIDTH
.long FB_HEIGHT
.long FB_BPP
bananboot_end:
.section .bss, "aw", @nobits
.align 4096
boot_stack_bottom:
.skip 4096 * 4
boot_stack_top:
.global g_kernel_cmdline
g_kernel_cmdline:
.skip 4096
bootloader_magic:
.skip 8
bootloader_info:
.skip 8
.section .data
# Map first GiB to 0x00000000 and 0xC0000000
.align 32
boot_pdpt:
.long V2P(boot_pd) + (PG_PRESENT)
.long 0
.quad 0
.quad 0
.long V2P(boot_pd) + (PG_PRESENT)
.long 0
.align 4096
boot_pd:
.set i, 0
.rept 512
.long V2P(boot_pts) + i + (PG_READ_WRITE | PG_PRESENT)
.long 0
.set i, i + 0x1000
.endr
boot_pts:
.set i, 0
.rept 512
.rept 512
.long i + (PG_READ_WRITE | PG_PRESENT)
.long 0
.set i, i + 0x1000
.endr
.endr
boot_gdt:
.quad 0x0000000000000000 # null descriptor
.quad 0x00CF9A000000FFFF # kernel code
.quad 0x00CF92000000FFFF # kernel data
boot_gdtr:
.short . - boot_gdt - 1
.long V2P(boot_gdt)
.global g_ap_startup_done
g_ap_startup_done:
.byte 0
.global g_ap_running_count
g_ap_running_count:
.byte 0
.global g_ap_stack_loaded
g_ap_stack_loaded:
.byte 0
.section .text
has_cpuid:
pushfl
pushfl
xorl $0x00200000, (%esp)
popfl
pushfl
popl %eax
xorl (%esp), %eax
popfl
testl $0x00200000, %eax
ret
has_pae:
movl $0, %eax
cpuid
testl $(1 << 6), %edx
ret
has_sse:
movl $1, %eax
cpuid
testl $(1 << 25), %edx
ret
check_requirements:
call has_cpuid
jz .exit
call has_pae
jz .exit
call has_sse
jz .exit
ret
.exit:
jmp system_halt
enable_sse:
movl %cr0, %eax
andw $0xFFFB, %ax
orw $0x0002, %ax
movl %eax, %cr0
movl %cr4, %eax
orw $0x0600, %ax
movl %eax, %cr4
ret
initialize_paging:
# enable PAE
movl %cr4, %ecx
orl $(1 << 5), %ecx
movl %ecx, %cr4
# load page tables
movl $V2P(boot_pdpt), %ecx
movl %ecx, %cr3
# enable paging
movl %cr0, %ecx
orl $(1 << 31), %ecx
movl %ecx, %cr0
ret
.global _start
.type _start, @function
_start:
cli; cld
# save bootloader magic and info
movl %eax, V2P(bootloader_magic)
movl %ebx, V2P(bootloader_info)
# load boot stack
movl $V2P(boot_stack_top), %esp
# load boot GDT
lgdt V2P(boot_gdtr)
ljmpl $0x08, $V2P(gdt_flush)
gdt_flush:
# set correct segment registers
movw $0x10, %ax
movw %ax, %ds
movw %ax, %ss
movw %ax, %es
# do processor initialization
call check_requirements
call enable_sse
call initialize_paging
# load higher half stack pointer
movl $boot_stack_top, %esp
# jump to higher half
leal higher_half, %ecx
jmp *%ecx
higher_half:
# call global constuctors
call _init
# call to the kernel itself (clear ebp for stacktrace)
xorl %ebp, %ebp
subl $8, %esp
pushl bootloader_info
pushl bootloader_magic
call kernel_main
addl $16, %esp
# call global destructors
call _fini
system_halt:
xchgw %bx, %bx
cli
1: hlt
jmp 1b
.section .ap_init, "ax"
.code16
.global ap_trampoline
ap_trampoline:
jmp 1f
.align 8
ap_stack_ptr:
.skip 4
1:
cli; cld
ljmpl $0x00, $ap_cs_clear
ap_cs_clear:
# load ap gdt and enter protected mode
lgdt ap_gdtr
movl %cr0, %eax
orb $1, %al
movl %eax, %cr0
ljmpl $0x08, $ap_protected_mode
.code32
ap_protected_mode:
movw $0x10, %ax
movw %ax, %ds
movw %ax, %ss
movw %ax, %es
movl ap_stack_ptr, %esp
movb $1, V2P(g_ap_stack_loaded)
call V2P(enable_sse)
call V2P(initialize_paging)
# load boot gdt and enter long mode
lgdt V2P(boot_gdtr)
ljmpl $0x08, $ap_flush_gdt
ap_flush_gdt:
# move stack pointer to higher half
movl %esp, %esp
addl $KERNEL_OFFSET, %esp
# jump to higher half
leal ap_higher_half, %ecx
jmp *%ecx
ap_higher_half:
# clear rbp for stacktrace
xorl %ebp, %ebp
1: pause
cmpb $0, g_ap_startup_done
jz 1b
lock incb g_ap_running_count
call ap_main
jmp system_halt
ap_gdt:
.quad 0x0000000000000000 # null descriptor
.quad 0x00CF9A000000FFFF # 32 bit code
.quad 0x00CF92000000FFFF # 32 bit data
ap_gdtr:
.short . - ap_gdt - 1
.long ap_gdt

View File

@ -1,173 +0,0 @@
.macro push_userspace
pushw %gs
pushw %fs
pushw %es
pushw %ds
pushal
.endm
.macro load_kernel_segments
movw $0x10, %ax
movw %ax, %ds
movw %ax, %es
movw %ax, %fs
movw $0x28, %ax
movw %ax, %gs
.endm
.macro pop_userspace
popal
popw %ds
popw %es
popw %fs
popw %gs
.endm
isr_stub:
push_userspace
load_kernel_segments
movl %cr0, %eax; pushl %eax
movl %cr2, %eax; pushl %eax
movl %cr3, %eax; pushl %eax
movl %cr4, %eax; pushl %eax
movl %esp, %eax // register ptr
leal 64(%esp), %ebx // interrupt stack ptr
movl 60(%esp), %ecx // error code
movl 56(%esp), %edx // isr number
subl $12, %esp
pushl %eax
pushl %ebx
pushl %ecx
pushl %edx
call cpp_isr_handler
addl $44, %esp
pop_userspace
addl $8, %esp
iret
irq_stub:
push_userspace
load_kernel_segments
movl 40(%esp), %eax # interrupt number
subl $12, %esp
pushl %eax
call cpp_irq_handler
addl $16, %esp
pop_userspace
addl $8, %esp
iret
.global asm_yield_handler
asm_yield_handler:
# This can only be called from kernel, so no segment saving is needed
pushal
movl %esp, %eax # interrupt registers ptr
leal 32(%esp), %ebx # interrupt stack ptr
subl $4, %esp
pushl %eax
pushl %ebx
call cpp_yield_handler
addl $12, %esp
popal
iret
.macro isr n
.global isr\n
isr\n:
pushl $0
pushl $\n
jmp isr_stub
.endm
.macro isr_err n
.global isr\n
isr\n:
pushl $\n
jmp isr_stub
.endm
.macro irq n
.global irq\n
irq\n:
pushl $0
pushl $\n
jmp irq_stub
.endm
isr 0
isr 1
isr 2
isr 3
isr 4
isr 5
isr 6
isr 7
isr_err 8
isr 9
isr_err 10
isr_err 11
isr_err 12
isr_err 13
isr_err 14
isr 15
isr 16
isr_err 17
isr 18
isr 19
isr 20
isr 21
isr 22
isr 23
isr 24
isr 25
isr 26
isr 27
isr 28
isr 29
isr 30
isr 31
irq 0
irq 1
irq 2
irq 3
irq 4
irq 5
irq 6
irq 7
irq 8
irq 9
irq 10
irq 11
irq 12
irq 13
irq 14
irq 15
irq 16
irq 17
irq 18
irq 19
irq 20
irq 21
irq 22
irq 23
irq 24
irq 25
irq 26
irq 27
irq 28
irq 29
irq 30
irq 31
irq 32

View File

@ -1,45 +0,0 @@
ENTRY (_start)
KERNEL_OFFSET = 0xC0000000;
SECTIONS
{
. = 0xF000;
.ap_init ALIGN(4K) : AT(ADDR(.ap_init))
{
g_ap_init_addr = .;
*(.ap_init)
}
. = 0x00100000 + KERNEL_OFFSET;
g_kernel_start = .;
.text ALIGN(4K) : AT(ADDR(.text) - KERNEL_OFFSET)
{
g_kernel_execute_start = .;
*(.multiboot)
*(.bananboot)
*(.text.*)
}
.userspace ALIGN(4K) : AT(ADDR(.userspace) - KERNEL_OFFSET)
{
g_userspace_start = .;
*(.userspace)
g_userspace_end = .;
g_kernel_execute_end = .;
}
.rodata ALIGN(4K) : AT(ADDR(.rodata) - KERNEL_OFFSET)
{
*(.rodata.*)
}
.data ALIGN(4K) : AT(ADDR(.data) - KERNEL_OFFSET)
{
*(.data)
}
.bss ALIGN(4K) : AT(ADDR(.bss) - KERNEL_OFFSET)
{
*(COMMON)
*(.bss)
}
g_kernel_end = .;
}

125
kernel/arch/x86_64/GDT.cpp Normal file
View File

@ -0,0 +1,125 @@
#include <BAN/Array.h>
#include <kernel/GDT.h>
#include <string.h>
extern "C" uintptr_t g_boot_stack_top[0];
namespace Kernel::GDT
{
struct TaskStateSegment
{
uint32_t reserved1;
uint64_t rsp0;
uint64_t rsp1;
uint64_t rsp2;
uint64_t reserved2;
uint64_t ist1;
uint64_t ist2;
uint64_t ist3;
uint64_t ist4;
uint64_t ist5;
uint64_t ist6;
uint64_t ist7;
uint64_t reserved3;
uint16_t reserved4;
uint16_t iopb;
} __attribute__((packed));
union SegmentDescriptor
{
struct
{
uint16_t limit1;
uint16_t base1;
uint8_t base2;
uint8_t access;
uint8_t limit2 : 4;
uint8_t flags : 4;
uint8_t base3;
} __attribute__((packed));
struct
{
uint32_t low;
uint32_t high;
} __attribute__((packed));
} __attribute__((packed));
struct GDTR
{
uint16_t size;
uint64_t address;
} __attribute__((packed));
static constexpr uint16_t s_tss_offset = 0x28;
static TaskStateSegment s_tss;
static BAN::Array<SegmentDescriptor, 7> s_gdt; // null, kernel code, kernel data, user code, user data, tss low, tss high
static GDTR s_gdtr;
static void write_entry(uint8_t offset, uint32_t base, uint32_t limit, uint8_t access, uint8_t flags)
{
ASSERT(offset % sizeof(SegmentDescriptor) == 0);
SegmentDescriptor& desc = s_gdt[offset / sizeof(SegmentDescriptor)];
desc.base1 = (base >> 0) & 0xFFFF;
desc.base2 = (base >> 16) & 0xFF;
desc.base3 = (base >> 24) & 0xFF;
desc.limit1 = (limit >> 0) & 0xFFFF;
desc.limit2 = (limit >> 16) & 0x0F;
desc.access = access & 0xFF;
desc.flags = flags & 0x0F;
}
static void write_tss()
{
memset(&s_tss, 0x00, sizeof(TaskStateSegment));
s_tss.iopb = sizeof(TaskStateSegment);
uint64_t base = (uint64_t)&s_tss;
write_entry(s_tss_offset, (uint32_t)base, sizeof(TaskStateSegment), 0x89, 0x0);
SegmentDescriptor& desc = s_gdt[s_tss_offset / sizeof(SegmentDescriptor) + 1];
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));
}
static void flush_tss()
{
asm volatile("ltr %0" :: "m"(s_tss_offset));
}
void initialize()
{
s_gdtr.address = (uint64_t)&s_gdt;
s_gdtr.size = s_gdt.size() * sizeof(SegmentDescriptor) - 1;
write_entry(0x00, 0x00000000, 0x00000, 0x00, 0x0); // null
write_entry(0x08, 0x00000000, 0xFFFFF, 0x9A, 0xA); // kernel code
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();
flush_gdt();
flush_tss();
}
}

View File

@ -10,14 +10,16 @@
#include <kernel/Timer/PIT.h>
#define ISR_LIST_X X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31)
#define IRQ_LIST_X X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31) X(32)
#define IRQ_LIST_X X(0) X(1) X(2) X(3) X(4) X(5) X(6) X(7) X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) X(18) X(19) X(20) X(21) X(22) X(23) X(24) X(25) X(26) X(27) X(28) X(29) X(30) X(31)
namespace Kernel
namespace Kernel::IDT
{
#if ARCH(x86_64)
struct Registers
{
uint64_t rsp;
uint64_t rip;
uint64_t rflags;
uint64_t cr4;
uint64_t cr3;
uint64_t cr2;
@ -31,33 +33,34 @@ namespace Kernel
uint64_t r10;
uint64_t r9;
uint64_t r8;
uint64_t rdi;
uint64_t rsi;
uint64_t rdi;
uint64_t rbp;
uint64_t rbx;
uint64_t rdx;
uint64_t rcx;
uint64_t rbx;
uint64_t rax;
};
#elif ARCH(i686)
struct Registers
{
uint32_t cr4;
uint32_t cr3;
uint32_t cr2;
uint32_t cr0;
uint32_t edi;
uint32_t esi;
uint32_t ebp;
uint32_t unused;
uint32_t ebx;
uint32_t edx;
uint32_t ecx;
uint32_t eax;
};
#endif
struct GateDescriptor
{
uint16_t offset1;
uint16_t selector;
uint8_t IST;
uint8_t flags;
uint16_t offset2;
uint32_t offset3;
uint32_t reserved;
} __attribute__((packed));
struct IDTR
{
uint16_t size;
uint64_t offset;
} __attribute__((packed));
static IDTR s_idtr;
static GateDescriptor* s_idt = nullptr;
#define X(num) 1 +
static BAN::Array<Interruptable*, IRQ_LIST_X 0> s_interruptables;
@ -118,7 +121,7 @@ namespace Kernel
uint32_t reserved2 : 16;
};
};
};
static_assert(sizeof(PageFaultError) == 4);
@ -158,98 +161,68 @@ namespace Kernel
"Unkown Exception 0x1F",
};
extern "C" void cpp_isr_handler(uint32_t isr, uint32_t error, InterruptStack* interrupt_stack, const Registers* regs)
extern "C" void cpp_isr_handler(uint64_t isr, uint64_t error, InterruptStack& interrupt_stack, const Registers* regs)
{
if (g_paniced)
{
dprintln("Processor {} halted", Processor::current_id());
if (InterruptController::is_initialized())
InterruptController::get().broadcast_ipi();
asm volatile("cli; 1: hlt; jmp 1b");
}
#if __enable_sse
bool from_userspace = (interrupt_stack.cs & 0b11) == 0b11;
if (from_userspace)
Thread::current().save_sse();
#endif
pid_t tid = Scheduler::current_tid();
pid_t pid = tid ? Process::current().pid() : 0;
if (tid)
{
Thread::current().set_return_rsp(interrupt_stack.rsp);
Thread::current().set_return_rip(interrupt_stack.rip);
if (isr == ISR::PageFault)
{
// Check if stack is OOB
auto& thread = Thread::current();
if (thread.userspace_stack_bottom() < interrupt_stack->sp && interrupt_stack->sp <= thread.userspace_stack_top())
; // using userspace stack
else if (thread.kernel_stack_bottom() < interrupt_stack->sp && interrupt_stack->sp <= thread.kernel_stack_top())
; // using kernel stack
auto& stack = Thread::current().stack();
auto& istack = Thread::current().interrupt_stack();
if (stack.vaddr() < interrupt_stack.rsp && interrupt_stack.rsp <= stack.vaddr() + stack.size())
; // using normal stack
else if (istack.vaddr() < interrupt_stack.rsp && interrupt_stack.rsp <= istack.vaddr() + istack.size())
; // using interrupt stack
else
{
derrorln("Stack pointer out of bounds!");
derrorln("rip {H}", interrupt_stack->ip);
derrorln("rsp {H}, userspace stack {H}->{H}, kernel stack {H}->{H}",
interrupt_stack->sp,
thread.userspace_stack_bottom(), thread.userspace_stack_top(),
thread.kernel_stack_bottom(), thread.kernel_stack_top()
derrorln("rsp {H}, stack {H}->{H}, istack {H}->{H}",
interrupt_stack.rsp,
stack.vaddr(), stack.vaddr() + stack.size(),
istack.vaddr(), istack.vaddr() + istack.size()
);
Thread::current().handle_signal(SIGKILL);
goto done;
}
// Demand paging is only supported in userspace
if (thread.is_userspace())
// Try demand paging on non present pages
PageFaultError page_fault_error;
page_fault_error.raw = error;
if (!page_fault_error.present)
{
// Try demand paging on non present pages
PageFaultError page_fault_error;
page_fault_error.raw = error;
if (!page_fault_error.present)
asm volatile("sti");
auto result = Process::current().allocate_page_for_demand_paging(regs->cr2);
asm volatile("cli");
if (!result.is_error() && result.value())
goto done;
if (result.is_error())
{
Processor::set_interrupt_state(InterruptState::Enabled);
auto result = Process::current().allocate_page_for_demand_paging(regs->cr2);
Processor::set_interrupt_state(InterruptState::Disabled);
if (!result.is_error() && result.value())
goto done;
if (result.is_error())
{
dwarnln("Demand paging: {}", result.error());
Thread::current().handle_signal(SIGKILL);
goto done;
}
dwarnln("Demand paging: {}", result.error());
Thread::current().handle_signal(SIGKILL);
goto done;
}
}
}
#if __enable_sse
else if (isr == ISR::DeviceNotAvailable)
{
#if ARCH(x86_64)
asm volatile(
"movq %cr0, %rax;"
"andq $~(1 << 3), %rax;"
"movq %rax, %cr0;"
);
#elif ARCH(i686)
asm volatile(
"movl %cr0, %eax;"
"andl $~(1 << 3), %eax;"
"movl %eax, %cr0;"
);
#endif
if (auto* current = &Thread::current(); current != Thread::sse_thread())
{
if (auto* sse = Thread::sse_thread())
sse->save_sse();
current->load_sse();
}
goto done;
}
#endif
}
Debug::s_debug_lock.lock();
if (PageTable::current().get_page_flags(interrupt_stack->ip & PAGE_ADDR_MASK) & PageTable::Flags::Present)
if (PageTable::current().get_page_flags(interrupt_stack.rip & PAGE_ADDR_MASK) & PageTable::Flags::Present)
{
auto* machine_code = (const uint8_t*)interrupt_stack->ip;
auto* machine_code = (const uint8_t*)interrupt_stack.rip;
dwarnln("While executing: {2H}{2H}{2H}{2H}{2H}{2H}{2H}{2H}",
machine_code[0],
machine_code[1],
@ -262,9 +235,8 @@ namespace Kernel
);
}
#if ARCH(x86_64)
dwarnln(
"{} (error code: 0x{8H}), pid {}, tid {}\r\n"
"{} (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"
@ -272,31 +244,14 @@ namespace Kernel
"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,
interrupt_stack->sp, regs->rbp, regs->rdi, regs->rsi,
interrupt_stack->ip, interrupt_stack->flags,
regs->rsp, regs->rbp, regs->rdi, regs->rsi,
regs->rip, regs->rflags,
regs->cr0, regs->cr2, regs->cr3, regs->cr4
);
#elif ARCH(i686)
dwarnln(
"{} (error code: 0x{8H}), pid {}, tid {}\r\n"
"Register dump\r\n"
"eax=0x{8H}, ebx=0x{8H}, ecx=0x{8H}, edx=0x{8H}\r\n"
"esp=0x{8H}, ebp=0x{8H}, edi=0x{8H}, esi=0x{8H}\r\n"
"eip=0x{8H}, eflags=0x{8H}\r\n"
"cr0=0x{8H}, cr2=0x{8H}, cr3=0x{8H}, cr4=0x{8H}",
isr_exceptions[isr], error, pid, tid,
regs->eax, regs->ebx, regs->ecx, regs->edx,
interrupt_stack->sp, regs->ebp, regs->edi, regs->esi,
interrupt_stack->ip, interrupt_stack->flags,
regs->cr0, regs->cr2, regs->cr3, regs->cr4
);
#endif
if (isr == ISR::PageFault)
PageTable::current().debug_dump();
Debug::dump_stack_trace();
Debug::s_debug_lock.unlock(InterruptState::Disabled);
if (tid && Thread::current().is_userspace())
{
// TODO: Confirm and fix the exception to signal mappings
@ -304,6 +259,7 @@ namespace Kernel
int signal = 0;
switch (isr)
{
case ISR::DeviceNotAvailable:
case ISR::DivisionError:
case ISR::SIMDFloatingPointException:
case ISR::x87FloatingPointException:
@ -317,7 +273,7 @@ namespace Kernel
break;
case ISR::PageFault:
signal = SIGSEGV;
break;
break;
default:
dwarnln("Unhandled exception");
signal = SIGABRT;
@ -332,29 +288,30 @@ namespace Kernel
}
ASSERT(Thread::current().state() != Thread::State::Terminated);
done:
#if __enable_sse
if (from_userspace)
{
ASSERT(Thread::current().state() == Thread::State::Executing);
Thread::current().load_sse();
}
#endif
return;
}
extern "C" void cpp_yield_handler(InterruptStack* interrupt_stack, InterruptRegisters* interrupt_registers)
extern "C" void cpp_irq_handler(uint64_t irq, InterruptStack& interrupt_stack)
{
ASSERT(!InterruptController::get().is_in_service(IRQ_YIELD));
ASSERT(!GDT::is_user_segment(interrupt_stack->cs));
#if __enable_sse
bool from_userspace = (interrupt_stack.cs & 0b11) == 0b11;
if (from_userspace)
Thread::current().save_sse();
#endif
Processor::enter_interrupt(interrupt_stack, interrupt_registers);
Scheduler::get().irq_reschedule();
Processor::leave_interrupt();
}
extern "C" void cpp_irq_handler(uint32_t irq)
{
if (g_paniced)
if (Scheduler::current_tid())
{
dprintln("Processor {} halted", Processor::current_id());
if (InterruptController::is_initialized())
InterruptController::get().broadcast_ipi();
asm volatile("cli; 1: hlt; jmp 1b");
Thread::current().set_return_rsp(interrupt_stack.rsp);
Thread::current().set_return_rip(interrupt_stack.rip);
}
if (!InterruptController::get().is_in_service(irq))
@ -362,45 +319,49 @@ done:
else
{
InterruptController::get().eoi(irq);
if (auto* handler = s_interruptables[irq])
handler->handle_irq();
else if (irq == IRQ_IPI)
Scheduler::get().yield();
if (s_interruptables[irq])
s_interruptables[irq]->handle_irq();
else
dprintln("no handler for irq 0x{2H}", irq);
dprintln("no handler for irq 0x{2H}\n", irq);
}
auto& current_thread = Thread::current();
if (current_thread.can_add_signal_to_execute())
current_thread.handle_signal();
Scheduler::get().reschedule_if_idling();
ASSERT(Thread::current().state() != Thread::State::Terminated);
}
void IDT::register_interrupt_handler(uint8_t index, void (*handler)())
{
auto& desc = m_idt[index];
memset(&desc, 0, sizeof(GateDescriptor));
desc.offset0 = (uint16_t)((uintptr_t)handler >> 0);
desc.offset1 = (uint16_t)((uintptr_t)handler >> 16);
#if ARCH(x86_64)
desc.offset2 = (uint32_t)((uintptr_t)handler >> 32);
#if __enable_sse
if (from_userspace)
{
ASSERT(Thread::current().state() == Thread::State::Executing);
Thread::current().load_sse();
}
#endif
desc.selector = 0x08;
desc.flags = 0x8E;
}
void IDT::register_syscall_handler(uint8_t index, void (*handler)())
static void flush_idt()
{
asm volatile("lidt %0"::"m"(s_idtr));
}
static void register_interrupt_handler(uint8_t index, void(*handler)())
{
GateDescriptor& descriptor = s_idt[index];
descriptor.offset1 = (uint16_t)((uint64_t)handler >> 0);
descriptor.offset2 = (uint16_t)((uint64_t)handler >> 16);
descriptor.offset3 = (uint32_t)((uint64_t)handler >> 32);
descriptor.selector = 0x08;
descriptor.IST = 0;
descriptor.flags = 0x8E;
}
static void register_syscall_handler(uint8_t index, void(*handler)())
{
register_interrupt_handler(index, handler);
m_idt[index].flags = 0xEE;
s_idt[index].flags = 0xEE;
}
void IDT::register_irq_handler(uint8_t irq, Interruptable* interruptable)
void register_irq_handler(uint8_t irq, Interruptable* interruptable)
{
if (irq > s_interruptables.size())
Kernel::panic("Trying to assign handler for irq {} while only {} are supported", irq, s_interruptables.size());
@ -415,37 +376,36 @@ done:
IRQ_LIST_X
#undef X
extern "C" void asm_yield_handler();
extern "C" void asm_syscall_handler();
extern "C" void syscall_asm();
IDT* IDT::create()
void initialize()
{
auto* idt = new IDT();
ASSERT(idt);
s_idt = (GateDescriptor*)kmalloc(0x100 * sizeof(GateDescriptor));
ASSERT(s_idt);
memset(s_idt, 0x00, 0x100 * sizeof(GateDescriptor));
memset(idt->m_idt.data(), 0x00, 0x100 * sizeof(GateDescriptor));
s_idtr.offset = (uint64_t)s_idt;
s_idtr.size = 0x100 * sizeof(GateDescriptor) - 1;
#define X(num) idt->register_interrupt_handler(num, isr ## num);
#define X(num) register_interrupt_handler(num, isr ## num);
ISR_LIST_X
#undef X
#define X(num) idt->register_interrupt_handler(IRQ_VECTOR_BASE + num, irq ## num);
#define X(num) register_interrupt_handler(IRQ_VECTOR_BASE + num, irq ## num);
IRQ_LIST_X
#undef X
idt->register_interrupt_handler(IRQ_VECTOR_BASE + IRQ_YIELD, asm_yield_handler);
register_syscall_handler(0x80, syscall_asm);
idt->register_syscall_handler(0x80, asm_syscall_handler);
return idt;
flush_idt();
}
[[noreturn]] void IDT::force_triple_fault()
[[noreturn]] void force_triple_fault()
{
// load 0 sized IDT and trigger an interrupt to force triple fault
Processor::set_interrupt_state(InterruptState::Disabled);
Processor::idt().m_idtr.size = 0;
Processor::idt().load();
asm volatile("cli");
s_idtr.size = 0;
flush_idt();
asm volatile("int $0x00");
ASSERT_NOT_REACHED();
}

View File

@ -1,7 +1,7 @@
#include <kernel/Arch.h>
#include <kernel/CPUID.h>
#include <kernel/InterruptController.h>
#include <kernel/Lock/SpinLock.h>
#include <kernel/LockGuard.h>
#include <kernel/Memory/kmalloc.h>
#include <kernel/Memory/PageTable.h>
@ -17,9 +17,8 @@ extern uint8_t g_userspace_end[];
namespace Kernel
{
SpinLock PageTable::s_fast_page_lock;
static PageTable* s_kernel = nullptr;
static PageTable* s_current = nullptr;
static bool s_has_nxe = false;
static bool s_has_pge = false;
@ -70,51 +69,40 @@ namespace Kernel
void PageTable::initialize()
{
if (CPUID::has_nxe())
{
asm volatile(
"movl $0xC0000080, %ecx;"
"rdmsr;"
"orl $0x800, %eax;"
"wrmsr"
);
s_has_nxe = true;
}
if (CPUID::has_pge())
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;
}
// enable write protect to kernel
asm volatile(
"movq %cr0, %rax;"
"orq $0x10000, %rax;"
"movq %rax, %cr0;"
);
ASSERT(s_kernel == nullptr);
s_kernel = new PageTable();
ASSERT(s_kernel);
s_kernel->initialize_kernel();
s_kernel->initial_load();
}
void PageTable::initial_load()
{
if (s_has_nxe)
{
asm volatile(
"movl $0xC0000080, %%ecx;"
"rdmsr;"
"orl $0x800, %%eax;"
"wrmsr"
::: "eax", "ecx", "edx", "memory"
);
}
if (s_has_pge)
{
asm volatile(
"movq %%cr4, %%rax;"
"orq $0x80, %%rax;"
"movq %%rax, %%cr4;"
::: "rax"
);
}
// enable write protect
asm volatile(
"movq %%cr0, %%rax;"
"orq $0x10000, %%rax;"
"movq %%rax, %%cr0;"
::: "rax"
);
load();
s_kernel->load();
}
PageTable& PageTable::kernel()
@ -123,6 +111,12 @@ namespace 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))
@ -144,7 +138,7 @@ namespace Kernel
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;
@ -212,9 +206,8 @@ namespace Kernel
void PageTable::map_fast_page(paddr_t paddr)
{
ASSERT(s_kernel);
ASSERT(paddr);
ASSERT(s_fast_page_lock.current_processor_has_lock());
ASSERT_NEQ(paddr, 0);
ASSERT(!interrupts_enabled());
constexpr vaddr_t uc_vaddr = uncanonicalize(fast_page());
constexpr uint64_t pml4e = (uc_vaddr >> 39) & 0x1FF;
@ -236,8 +229,7 @@ namespace Kernel
void PageTable::unmap_fast_page()
{
ASSERT(s_kernel);
ASSERT(s_fast_page_lock.current_processor_has_lock());
ASSERT(!interrupts_enabled());
constexpr vaddr_t uc_vaddr = uncanonicalize(fast_page());
constexpr uint64_t pml4e = (uc_vaddr >> 39) & 0x1FF;
@ -258,7 +250,7 @@ namespace Kernel
BAN::ErrorOr<PageTable*> PageTable::create_userspace()
{
SpinLockGuard _(s_kernel->m_lock);
LockGuard _(s_kernel->m_lock);
PageTable* page_table = new PageTable;
if (page_table == nullptr)
return BAN::Error::from_errno(ENOMEM);
@ -310,9 +302,8 @@ namespace Kernel
void PageTable::load()
{
SpinLockGuard _(m_lock);
asm volatile("movq %0, %%cr3" :: "r"(m_highest_paging_struct));
Processor::set_current_page_table(this);
s_current = this;
}
void PageTable::invalidate(vaddr_t vaddr)
@ -326,7 +317,7 @@ namespace Kernel
ASSERT(vaddr);
ASSERT(vaddr != fast_page());
if (vaddr >= KERNEL_OFFSET)
ASSERT(vaddr >= (vaddr_t)g_kernel_start);
ASSERT_GTE(vaddr, (vaddr_t)g_kernel_start);
if ((vaddr >= KERNEL_OFFSET) != (this == s_kernel))
Kernel::panic("unmapping {8H}, kernel: {}", vaddr, this == s_kernel);
@ -340,7 +331,7 @@ namespace Kernel
uint64_t pde = (uc_vaddr >> 21) & 0x1FF;
uint64_t pte = (uc_vaddr >> 12) & 0x1FF;
SpinLockGuard _(m_lock);
LockGuard _(m_lock);
if (is_page_free(vaddr))
{
@ -362,7 +353,7 @@ namespace Kernel
vaddr_t s_page = vaddr / PAGE_SIZE;
vaddr_t e_page = BAN::Math::div_round_up<vaddr_t>(vaddr + size, PAGE_SIZE);
SpinLockGuard _(m_lock);
LockGuard _(m_lock);
for (vaddr_t page = s_page; page < e_page; page++)
unmap_page(page * PAGE_SIZE);
}
@ -371,6 +362,8 @@ namespace Kernel
{
ASSERT(vaddr);
ASSERT(vaddr != fast_page());
if (vaddr >= KERNEL_OFFSET && s_current)
ASSERT_GTE(vaddr, (vaddr_t)g_kernel_start);
if ((vaddr >= KERNEL_OFFSET) != (this == s_kernel))
Kernel::panic("mapping {8H} to {8H}, kernel: {}", paddr, vaddr, this == s_kernel);
@ -399,7 +392,7 @@ namespace Kernel
// 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;
SpinLockGuard _(m_lock);
LockGuard _(m_lock);
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
if ((pml4[pml4e] & uwr_flags) != uwr_flags)
@ -443,8 +436,8 @@ namespace Kernel
ASSERT(vaddr % PAGE_SIZE == 0);
size_t page_count = range_page_count(vaddr, size);
SpinLockGuard _(m_lock);
LockGuard _(m_lock);
for (size_t page = 0; page < page_count; page++)
map_page_at(paddr + page * PAGE_SIZE, vaddr + page * PAGE_SIZE, flags);
}
@ -460,8 +453,8 @@ namespace Kernel
uint64_t pdpte = (uc_vaddr >> 30) & 0x1FF;
uint64_t pde = (uc_vaddr >> 21) & 0x1FF;
uint64_t pte = (uc_vaddr >> 12) & 0x1FF;
SpinLockGuard _(m_lock);
LockGuard _(m_lock);
uint64_t* pml4 = (uint64_t*)P2V(m_highest_paging_struct);
if (!(pml4[pml4e] & Flags::Present))
@ -495,7 +488,7 @@ namespace Kernel
bool PageTable::reserve_page(vaddr_t vaddr, bool only_free)
{
SpinLockGuard _(m_lock);
LockGuard _(m_lock);
ASSERT(vaddr % PAGE_SIZE == 0);
if (only_free && !is_page_free(vaddr))
return false;
@ -509,7 +502,7 @@ namespace Kernel
bytes += PAGE_SIZE - rem;
ASSERT(vaddr % PAGE_SIZE == 0);
SpinLockGuard _(m_lock);
LockGuard _(m_lock);
if (only_free && !is_range_free(vaddr, bytes))
return false;
for (size_t offset = 0; offset < bytes; offset += PAGE_SIZE)
@ -540,8 +533,8 @@ namespace Kernel
const uint16_t e_pdpte = (uc_vaddr_end >> 30) & 0x1FF;
const uint16_t e_pde = (uc_vaddr_end >> 21) & 0x1FF;
const uint16_t e_pte = (uc_vaddr_end >> 12) & 0x1FF;
SpinLockGuard _(m_lock);
LockGuard _(m_lock);
// Try to find free page that can be mapped without
// allocations (page table with unused entries)
@ -614,7 +607,7 @@ namespace Kernel
ASSERT(is_canonical(first_address));
ASSERT(is_canonical(last_address));
SpinLockGuard _(m_lock);
LockGuard _(m_lock);
for (vaddr_t vaddr = first_address; vaddr < last_address;)
{
@ -655,7 +648,7 @@ namespace Kernel
vaddr_t s_page = vaddr / PAGE_SIZE;
vaddr_t e_page = BAN::Math::div_round_up<vaddr_t>(vaddr + size, PAGE_SIZE);
SpinLockGuard _(m_lock);
LockGuard _(m_lock);
for (vaddr_t page = s_page; page < e_page; page++)
if (!is_page_free(page * PAGE_SIZE))
return false;
@ -678,7 +671,7 @@ namespace Kernel
void PageTable::debug_dump()
{
SpinLockGuard _(m_lock);
LockGuard _(m_lock);
flags_t flags = 0;
vaddr_t start = 0;
@ -721,7 +714,7 @@ namespace Kernel
if (!(pt[pte] & Flags::Used))
continue;
if (start == 0)
{
flags = parse_flags(pt[pte]);

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