├── .github └── workflows │ └── obos-build.yml ├── .gitignore ├── CMakeLists.txt ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── config ├── hyper.cfg ├── hyper_uefi_boot.bin └── hyper_uefi_boot_old.bin ├── dependencies ├── hyper.cmake └── uacpi.cmake ├── screenshots ├── 20240512_2114.png ├── 20240728_2338.png ├── 20240729_2257.png ├── 20240730_1559.png ├── 20240730_1639.png ├── 20240806_1401.png ├── 20240806_1612.png ├── 20240807_1158.png ├── 20240823_1544.png ├── 20241017_1948.png └── 20241230_1558.png ├── scripts ├── find_addr.sh ├── find_addr_m68k.sh ├── generate_initrd-x86_64.sh ├── launch_qemu-m68k.sh ├── launch_qemu.bat ├── launch_qemu.sh ├── make_bp.sh └── mangle.sh └── src ├── build ├── m68k │ ├── driver_link.ld │ ├── link.ld │ └── toolchain.cmake └── x86_64 │ ├── driver_link.ld │ ├── link.ld │ └── toolchain.cmake ├── drivers ├── generic │ ├── ahci │ │ ├── CMakeLists.txt │ │ ├── ahci_irq.c │ │ ├── ahci_irq.h │ │ ├── command.c │ │ ├── command.h │ │ ├── interface.c │ │ ├── main.c │ │ └── structs.h │ ├── initrd │ │ ├── CMakeLists.txt │ │ ├── main.c │ │ ├── name.h │ │ ├── parse.c │ │ ├── parse.h │ │ └── ustar_hdr.h │ ├── libps2 │ │ ├── CMakeLists.txt │ │ ├── controller.h │ │ ├── detect.c │ │ ├── detect.h │ │ ├── keyboard.c │ │ ├── keyboard.h │ │ ├── main.c │ │ └── scancode_tables.h │ ├── r8169 │ │ ├── CMakeLists.txt │ │ ├── device.c │ │ ├── main.c │ │ └── structs.h │ └── slowfat │ │ ├── CMakeLists.txt │ │ ├── alloc.h │ │ ├── cls_alloc.c │ │ ├── create.c │ │ ├── fat_irp.c │ │ ├── interface.c │ │ ├── io.c │ │ ├── lookup.c │ │ ├── main.c │ │ ├── probe.c │ │ └── structs.h ├── test_driver │ ├── CMakeLists.txt │ ├── fireworks.c │ ├── main.c │ ├── rand.c │ ├── rand.h │ └── sin_table.h └── x86 │ ├── bochs_vbe │ ├── CMakeLists.txt │ ├── io.c │ ├── io.h │ ├── main.c │ └── suspend.c │ ├── i8042 │ ├── CMakeLists.txt │ ├── ctlr.c │ ├── main.c │ ├── ps2_irql.h │ └── ps2_structs.h │ └── uart │ ├── CMakeLists.txt │ ├── main.c │ ├── serial_port.c │ └── serial_port.h ├── inc └── dev_prefix.h.in ├── init ├── CMakeLists.txt ├── main.c ├── motd.c └── x86_64-syscall.S ├── isogen └── CMakeLists.txt ├── oboskrnl ├── CMakeLists.txt ├── allocators │ ├── base.h │ ├── basic_allocator.c │ └── basic_allocator.h ├── arch │ ├── m68k │ │ ├── asm_helpers.S │ │ ├── asm_helpers.h │ │ ├── boot_info.h │ │ ├── cpu_local_arch.h │ │ ├── driver_loader.c │ │ ├── entry.c │ │ ├── exception_handlers.c │ │ ├── goldfish_pic.c │ │ ├── goldfish_pic.h │ │ ├── goldfish_rtc.c │ │ ├── interrupt_frame.h │ │ ├── irq.c │ │ ├── irql.c │ │ ├── isr.S │ │ ├── loader │ │ │ ├── Allocator.h │ │ │ ├── CMakeLists.txt │ │ │ ├── CppUtils.h │ │ │ ├── Elf.h │ │ │ ├── Elf32.h │ │ │ ├── Entry.S │ │ │ ├── LICENSE.txt │ │ │ ├── Limine.h │ │ │ ├── Linker.lds │ │ │ ├── List.h │ │ │ ├── Loader.cpp │ │ │ ├── Loader.h │ │ │ ├── Main.cpp │ │ │ ├── Maths.h │ │ │ ├── Memory.cpp │ │ │ ├── Memory.h │ │ │ ├── NanoPrintf.h │ │ │ ├── NativePtr.h │ │ │ ├── README.md │ │ │ ├── Syslib.cpp │ │ │ ├── Util.cpp │ │ │ ├── Util.h │ │ │ └── Vector.h │ │ ├── mmu.c │ │ ├── pmm.c │ │ ├── pmm.h │ │ ├── thread_ctx.S │ │ ├── thread_ctx.c │ │ └── thread_ctx.h │ └── x86_64 │ │ ├── asm_helpers.asm │ │ ├── asm_helpers.h │ │ ├── bgdt.asm │ │ ├── boot_info.h │ │ ├── cmos.c │ │ ├── cmos.h │ │ ├── cpu_local_arch.h │ │ ├── drv_loader.c │ │ ├── entry.asm │ │ ├── entry.c │ │ ├── except.c │ │ ├── execve.c │ │ ├── gdbstub │ │ ├── alloc.c │ │ ├── alloc.h │ │ ├── bp.c │ │ ├── bp.h │ │ ├── breakpoint.h │ │ ├── connection.c │ │ ├── connection.h │ │ ├── debug.c │ │ ├── debug.h │ │ ├── general_query.c │ │ ├── general_query.h │ │ ├── packet_dispatcher.c │ │ ├── packet_dispatcher.h │ │ ├── stop_reply.c │ │ └── stop_reply.h │ │ ├── hpet_table.h │ │ ├── idt.c │ │ ├── idt.h │ │ ├── interrupt_frame.h │ │ ├── ioapic.c │ │ ├── ioapic.h │ │ ├── irq_vector.h │ │ ├── isr.asm │ │ ├── lapic.c │ │ ├── lapic.h │ │ ├── lapic_timer_calibration.asm │ │ ├── madt.h │ │ ├── map.c │ │ ├── memmanip.asm │ │ ├── mtrr.c │ │ ├── mtrr.h │ │ ├── pci.c │ │ ├── pmm.c │ │ ├── pmm.h │ │ ├── sdt.h │ │ ├── smp.asm │ │ ├── smp.c │ │ ├── sse.c │ │ ├── sse.h │ │ ├── ssignal.c │ │ ├── syscall.asm │ │ ├── syscall.c │ │ ├── thread_ctx.asm │ │ ├── thread_ctx.h │ │ ├── timer.c │ │ ├── timer.h │ │ └── wake.c ├── cmdline.c ├── cmdline.h ├── driver_interface │ ├── driverId.h │ ├── drv_sys.c │ ├── drv_sys.h │ ├── header.h │ ├── loader.c │ ├── loader.h │ ├── pci.c │ ├── pci.h │ ├── pci_irq.c │ ├── pnp.c │ └── pnp.h ├── elf │ ├── elf.h │ ├── elf32.h │ ├── elf64.h │ ├── load.c │ └── load.h ├── error.h ├── execve.c ├── execve.h ├── external │ ├── fixedptc.h │ └── nanoprintf.h ├── font.h ├── gpt.c ├── gpt.h ├── handle.c ├── handle.h ├── init_proc.c ├── init_proc.h ├── int.h ├── irq │ ├── dpc.c │ ├── dpc.h │ ├── irq.c │ ├── irq.h │ ├── irql.c │ ├── irql.h │ ├── timer.c │ └── timer.h ├── klog.c ├── klog.h ├── locks │ ├── event.c │ ├── event.h │ ├── mutex.c │ ├── mutex.h │ ├── pushlock.c │ ├── pushlock.h │ ├── semaphore.c │ ├── semaphore.h │ ├── spinlock.c │ ├── spinlock.h │ ├── sys_futex.c │ ├── sys_futex.h │ ├── wait.c │ └── wait.h ├── mbr.c ├── mbr.h ├── memmanip.c ├── memmanip.h ├── mm │ ├── aging.c │ ├── alloc.c │ ├── alloc.h │ ├── bare_map.c │ ├── bare_map.h │ ├── context.c │ ├── context.h │ ├── disk_swap.c │ ├── disk_swap.h │ ├── fork.c │ ├── fork.h │ ├── handler.c │ ├── handler.h │ ├── init.c │ ├── init.h │ ├── initial_swap.c │ ├── initial_swap.h │ ├── mm_sys.c │ ├── mm_sys.h │ ├── page.h │ ├── page_table.h │ ├── pmm.c │ ├── pmm.h │ ├── swap.c │ └── swap.h ├── partition.c ├── partition.h ├── power │ ├── device.c │ ├── device.h │ ├── init.c │ ├── init.h │ ├── shutdown.c │ ├── shutdown.h │ ├── suspend.c │ └── suspend.h ├── scheduler │ ├── cpu_local.h │ ├── process.c │ ├── process.h │ ├── sched_sys.c │ ├── sched_sys.h │ ├── schedule.c │ ├── schedule.h │ ├── thread.c │ ├── thread.h │ └── thread_context_info.h ├── sig_sys.c ├── signal.c ├── signal.h ├── struct_packing.h ├── syscall.c ├── syscall.h ├── text.c ├── text.h ├── utils │ ├── hashmap.c │ ├── hashmap.h │ ├── list.h │ ├── shared_ptr.c │ ├── shared_ptr.h │ ├── string.c │ ├── string.h │ ├── tree.h │ ├── uuid.c │ └── uuid.h └── vfs │ ├── alloc.c │ ├── alloc.h │ ├── create.c │ ├── create.h │ ├── dirent.c │ ├── dirent.h │ ├── dummy_devices.c │ ├── fd.c │ ├── fd.h │ ├── fd_sys.c │ ├── fd_sys.h │ ├── init.c │ ├── init.h │ ├── irp.h │ ├── keycode.h │ ├── limits.h │ ├── mount.c │ ├── mount.h │ ├── namecache.h │ ├── pagecache.h │ ├── pipe.c │ ├── pipe.h │ ├── tty.c │ ├── tty.h │ └── vnode.h ├── sanitizers ├── CMakeLists.txt ├── asan.c ├── asan.h ├── asan_memory.c ├── prof.c ├── prof.h ├── stack.c └── ubsan.c ├── uACPI ├── CMakeLists.txt ├── ec.c ├── kernel_api.c ├── uacpi_arch_helpers.h └── uacpi_libc.h └── user_examples ├── CMakeLists.txt ├── fork_example.c ├── klog_level_example.c ├── mem_usage_example.c ├── mount_example.c ├── powerctl_example.c ├── umount_example.c └── x86_timeofday_example.c /.github/workflows/obos-build.yml: -------------------------------------------------------------------------------- 1 | # This starter workflow is for a CMake project running on multiple platforms. There is a different starter workflow if you just want a single platform. 2 | # See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-single-platform.yml 3 | name: Build OBOS. 4 | 5 | on: 6 | push: 7 | branches: [ "master" ] 8 | pull_request: 9 | branches: [ "master" ] 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v4 17 | 18 | - name: Set reusable strings 19 | # Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file. 20 | id: strings 21 | shell: bash 22 | run: | 23 | echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT" 24 | 25 | - name: Get libgcc binaries 26 | run: | 27 | git clone https://codeberg.org/osdev/libgcc-binaries 28 | 29 | - name: Install dependencies. 30 | run: | 31 | sudo apt-get update 32 | sudo apt-get install xorriso nasm llvm clang 33 | 34 | - name: Make empty initrd.tar file 35 | run: touch ${{ github.workspace }}/config/initrd.tar 36 | 37 | - name: Configure CMake 38 | run: > 39 | cmake -B ${{ steps.strings.outputs.build-output-dir }}/x86_64 40 | -DCMAKE_BUILD_TYPE=Release 41 | -DOBOS_USE_CLANG=ON 42 | -DOBOS_ENABLE_UBSAN=ON 43 | -DLIBGCC=`realpath libgcc-binaries/libgcc-x86_64-no-red-zone.a` 44 | --toolchain ${{ github.workspace }}/src/build/x86_64/toolchain.cmake 45 | -S ${{ github.workspace }} 46 | 47 | - name: Build 48 | working-directory: ${{ github.workspace }}/scripts 49 | run: | 50 | chmod +x ${{ github.workspace }}/dependencies/hyper/hyper_install-linux-x86_64 51 | cmake --build ${{ steps.strings.outputs.build-output-dir }}/x86_64 52 | ./generate_initrd-x86_64.sh 53 | cmake --build ${{ steps.strings.outputs.build-output-dir }}/x86_64 54 | - name: Archive code coverage results 55 | uses: actions/upload-artifact@v4 56 | with: 57 | name: obos.iso 58 | path: ${{ github.workspace }}/out/obos.iso 59 | # TODO: Tests 60 | # - name: Test 61 | # working-directory: ${{ steps.strings.outputs.build-output-dir }} 62 | # run: 63 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.vs 2 | /.vscode 3 | /CMakePresets.json 4 | /out 5 | /build 6 | /dependencies/hyper 7 | /dependencies/UltraProtocol 8 | /dependencies/uACPI 9 | /dependencies/include/ 10 | /dependencies/needs_download.cmake 11 | /qemu_log.txt 12 | /tar 13 | /src/oboskrnl/inc/* 14 | /.cache 15 | /.clangd 16 | /config/initrd.tar -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guide (If you care) 2 | ## Commits 3 | Make sure to make your commits with a couple changes each. 4 | Don't forget to describe said changes with a relatively-descriptive commit message. 5 | ## Pull Requests 6 | Any pull requests are welcome, as long as no Rust, or other Esoteric languages are included in the code, and they include a feature that actually matters. 7 | All commits should be made on a separate local branch, pushed onto the main repo. You should make a pull request describing your changes (unless they're self explanatory because of the branch name).
8 | ## Notes 9 | Please don't add backdoors to the kernel or other parts of the OS.
10 | Don't modify src/oboskrnl/int.h, unless absolutely neccessary (it will cause a rebuild for any other contributors). 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024-2025 Omar Berrow and contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /config/hyper.cfg: -------------------------------------------------------------------------------- 1 | default-entry = "OBOS" 2 | 3 | [OBOS] 4 | protocol=ultra 5 | higher-half-exclusive=true 6 | kernel-as-module=true 7 | video-mode=auto 8 | cmdline='-initrd-module=initrd -initrd-driver-module=initrd_driver --root-fs-partid initrd --working-set-cap=8388608 --load-modules=/libps2,/slowfat --initial-swap-size=67108864 --log-level=1 --init-args /usr/bin/bash --login' 9 | 10 | binary: 11 | path="/obos/oboskrnl" 12 | allocate-anywhere=true 13 | 14 | page-table: 15 | levels=4 16 | constraint=exactly 17 | null-guard=true 18 | 19 | module: 20 | type="file" 21 | path="/obos/initrd.tar" 22 | name="initrd" 23 | module: 24 | type="file" 25 | path="/obos/initrd" 26 | name="initrd_driver" 27 | -------------------------------------------------------------------------------- /config/hyper_uefi_boot.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OBOS-dev/obos/5ef388af87e2c9442ead5b552d2a7448f5f71eaa/config/hyper_uefi_boot.bin -------------------------------------------------------------------------------- /config/hyper_uefi_boot_old.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OBOS-dev/obos/5ef388af87e2c9442ead5b552d2a7448f5f71eaa/config/hyper_uefi_boot_old.bin -------------------------------------------------------------------------------- /dependencies/hyper.cmake: -------------------------------------------------------------------------------- 1 | # dependencies/hyper.cmake 2 | 3 | # Copyright (c) 2024 Omar Berrow 4 | 5 | include(FetchContent) 6 | 7 | file(MAKE_DIRECTORY "dependencies/include/UltraProtocol") 8 | file(DOWNLOAD 9 | https://github.com/UltraOS/Hyper/releases/download/v0.9.0/hyper_iso_boot 10 | ${CMAKE_SOURCE_DIR}/dependencies/hyper/hyper_iso_boot 11 | ) 12 | file(DOWNLOAD 13 | https://github.com/UltraOS/Hyper/releases/download/v0.9.0/BOOTX64.EFI 14 | ${CMAKE_SOURCE_DIR}/dependencies/hyper/BOOTX64.efi 15 | ) 16 | if (CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows") 17 | set (hyper_install ${CMAKE_SOURCE_DIR}/dependencies/hyper/hyper_install-win64.exe CACHE INTERNAL "The hyper install binary") 18 | file(DOWNLOAD 19 | https://github.com/UltraOS/Hyper/releases/download/v0.9.0/hyper_install-win64.exe 20 | ${hyper_install} 21 | ) 22 | elseif(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") 23 | set (hyper_install ${CMAKE_SOURCE_DIR}/dependencies/hyper/hyper_install-linux-x86_64 CACHE INTERNAL "The hyper install binary") 24 | file(DOWNLOAD 25 | https://github.com/UltraOS/Hyper/releases/download/v0.9.0/hyper_install-linux-x86_64 26 | ${hyper_install} 27 | ) 28 | else() 29 | message(FATAL_ERROR "You must be on windows or linux to compile OBOS.") 30 | endif() 31 | FetchContent_Declare(UltraProtocol 32 | GIT_REPOSITORY https://github.com/UltraOS/UltraProtocol.git 33 | GIT_TAG 69235d363c077a090a9b7a313ed8c6f73e4a4807 34 | SOURCE_DIR ${CMAKE_SOURCE_DIR}/dependencies/UltraProtocol 35 | ) 36 | FetchContent_MakeAvailable(UltraProtocol) 37 | file (COPY_FILE "dependencies/UltraProtocol/ultra_protocol.h" "dependencies/include/UltraProtocol/ultra_protocol.h") 38 | -------------------------------------------------------------------------------- /dependencies/uacpi.cmake: -------------------------------------------------------------------------------- 1 | # dependencies/uacpi.cmake 2 | 3 | # Copyright (c) 2024-2025 Omar Berrow 4 | 5 | if (OBOS_REFRESH_DEPENDENCIES) 6 | include(FetchContent) 7 | 8 | FetchContent_Declare(uACPI 9 | # In honor of the old uACPI link 10 | #GIT_REPOSITORY https://github.com/UltraOS/uACPI.git 11 | GIT_REPOSITORY https://github.com/uACPI/uACPI.git 12 | GIT_TAG 2.1.1 13 | SOURCE_DIR ${CMAKE_SOURCE_DIR}/dependencies/uACPI 14 | ) 15 | FetchContent_MakeAvailable(uACPI) 16 | 17 | file (COPY "${CMAKE_SOURCE_DIR}/dependencies/uACPI/include/uacpi" DESTINATION "${CMAKE_SOURCE_DIR}/dependencies/include/") 18 | endif() 19 | set (uacpi_cmake_file ${CMAKE_SOURCE_DIR}/dependencies/uACPI/uacpi.cmake CACHE INTERNAL "The uACPI CMake file.") 20 | -------------------------------------------------------------------------------- /screenshots/20240512_2114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OBOS-dev/obos/5ef388af87e2c9442ead5b552d2a7448f5f71eaa/screenshots/20240512_2114.png -------------------------------------------------------------------------------- /screenshots/20240728_2338.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OBOS-dev/obos/5ef388af87e2c9442ead5b552d2a7448f5f71eaa/screenshots/20240728_2338.png -------------------------------------------------------------------------------- /screenshots/20240729_2257.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OBOS-dev/obos/5ef388af87e2c9442ead5b552d2a7448f5f71eaa/screenshots/20240729_2257.png -------------------------------------------------------------------------------- /screenshots/20240730_1559.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OBOS-dev/obos/5ef388af87e2c9442ead5b552d2a7448f5f71eaa/screenshots/20240730_1559.png -------------------------------------------------------------------------------- /screenshots/20240730_1639.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OBOS-dev/obos/5ef388af87e2c9442ead5b552d2a7448f5f71eaa/screenshots/20240730_1639.png -------------------------------------------------------------------------------- /screenshots/20240806_1401.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OBOS-dev/obos/5ef388af87e2c9442ead5b552d2a7448f5f71eaa/screenshots/20240806_1401.png -------------------------------------------------------------------------------- /screenshots/20240806_1612.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OBOS-dev/obos/5ef388af87e2c9442ead5b552d2a7448f5f71eaa/screenshots/20240806_1612.png -------------------------------------------------------------------------------- /screenshots/20240807_1158.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OBOS-dev/obos/5ef388af87e2c9442ead5b552d2a7448f5f71eaa/screenshots/20240807_1158.png -------------------------------------------------------------------------------- /screenshots/20240823_1544.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OBOS-dev/obos/5ef388af87e2c9442ead5b552d2a7448f5f71eaa/screenshots/20240823_1544.png -------------------------------------------------------------------------------- /screenshots/20241017_1948.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OBOS-dev/obos/5ef388af87e2c9442ead5b552d2a7448f5f71eaa/screenshots/20241017_1948.png -------------------------------------------------------------------------------- /screenshots/20241230_1558.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OBOS-dev/obos/5ef388af87e2c9442ead5b552d2a7448f5f71eaa/screenshots/20241230_1558.png -------------------------------------------------------------------------------- /scripts/find_addr.sh: -------------------------------------------------------------------------------- 1 | cd .. 2 | export address=$1 3 | export exe=$2 4 | if [ -z "$exe" ] 5 | then 6 | export exe=out/oboskrnl 7 | fi 8 | addr2line -e $exe -Cfpira $address 9 | gdb "$exe" -batch -ex "set disassembly-flavor intel" -ex "disassemble/sr $address" | grep --color -i -C 10 -n $address 10 | # objdump -d $exe -C -M intel | grep --color -i -C 10 -n $address 11 | cd scripts 12 | -------------------------------------------------------------------------------- /scripts/find_addr_m68k.sh: -------------------------------------------------------------------------------- 1 | cd .. 2 | export address=$1 3 | export exe=$2 4 | if [ -z "$exe" ] 5 | then 6 | export exe=out/oboskrnl 7 | fi 8 | m68k-obos-addr2line -e $exe -Cfpira $address 9 | m68k-obos-gdb "$exe" -batch -ex "set disassembly-flavor intel" -ex "disassemble/sr $address" | grep --color -i -C 10 -n $address 10 | # objdump -d $exe -C -M intel | grep --color -i -C 10 -n $address 11 | cd scripts 12 | -------------------------------------------------------------------------------- /scripts/generate_initrd-x86_64.sh: -------------------------------------------------------------------------------- 1 | export old_pwd=$PWD 2 | cd $(git rev-parse --show-toplevel) 3 | if [[ ! -d tar ]] 4 | then 5 | mkdir tar 6 | fi 7 | cp out/uart tar 8 | cp out/ahci tar 9 | cp out/slowfat tar 10 | cp out/bochs_vbe tar 11 | cp out/r8169 tar 12 | cp out/i8042 tar 13 | cp out/libps2 tar 14 | cp out/init tar 15 | if [[ ! -d tar/dev ]] 16 | then 17 | mkdir tar/dev 18 | fi 19 | cd tar 20 | tar -H ustar -cf ../config/initrd.tar `ls -A` 21 | cd $old_pwd 22 | -------------------------------------------------------------------------------- /scripts/launch_qemu-m68k.sh: -------------------------------------------------------------------------------- 1 | cd ../ 2 | 3 | rm qemu_log.txt 4 | 5 | qemu-system-m68k \ 6 | -M virt \ 7 | -kernel out/m68k_bootloader \ 8 | -cpu m68040 \ 9 | -monitor stdio \ 10 | -s -S \ 11 | -m 512M \ 12 | -d int \ 13 | -D qemu_log.txt \ 14 | -serial file:/dev/stdout \ 15 | -append "--root-fs-uuid=initrd --log-level=0" \ 16 | -initrd "config/initrd.tar" 17 | 18 | cd scripts 19 | -------------------------------------------------------------------------------- /scripts/launch_qemu.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | cd ../ 4 | 5 | del qemu_log.txt 6 | 7 | qemu-system-x86_64 ^ 8 | -drive file=out/obos.iso,format=raw ^ 9 | -m 1G ^ 10 | -gdb tcp:0.0.0.0:1234 -S ^ 11 | -accel tcg ^ 12 | -cpu "Haswell" ^ 13 | -M q35 ^ 14 | -monitor stdio ^ 15 | -debugcon file:CON ^ 16 | -serial tcp:0.0.0.0:1534,server,nowait ^ 17 | -smp cores=4,threads=1,sockets=1 ^ 18 | -d int ^ 19 | -D qemu_log.txt 20 | rem -no-reboot ^ 21 | rem -no-shutdown ^ 22 | rem -drive if=pflash,format=raw,unit=1,file=ovmf/OVMF_VARS_4M.fd ^ 23 | rem -drive if=pflash,format=raw,unit=0,file=ovmf/OVMF_CODE_4M.fd,readonly=on ^ 24 | rem -drive id=disk2,file=disk.img,if=none,format=raw -device ide-hd,drive=disk2,bus=ahci1.1 ^ 25 | rem -M smm=off ^ 26 | 27 | cd scripts -------------------------------------------------------------------------------- /scripts/launch_qemu.sh: -------------------------------------------------------------------------------- 1 | cd ../ 2 | 3 | rm qemu_log.txt 4 | 5 | echo $@ 6 | qemu-system-x86_64 \ 7 | -drive format=raw,file=out/obos.iso,media=disk,index=0 \ 8 | -m 2G \ 9 | -gdb tcp:0.0.0.0:1234 -S \ 10 | -M q35 \ 11 | -cpu host \ 12 | -accel kvm \ 13 | -debugcon file:/dev/stdout \ 14 | -monitor stdio \ 15 | -serial tcp:0.0.0.0:1534,server,nowait \ 16 | -smp cores=1,threads=1,sockets=1 \ 17 | -d int \ 18 | -D qemu_log.txt "$@" 19 | 20 | # -nographic 21 | # -enable-kvm \ 22 | # -M smm=off \ 23 | # -no-reboot 24 | # -enable-kvm \ 25 | # -no-shutdown 26 | 27 | cd scripts 28 | -------------------------------------------------------------------------------- /scripts/make_bp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | out="for (volatile bool b = ($1); b; );" 3 | which -s xsel 4 | if [ $? -eq 0 ] 5 | then 6 | echo $out | xsel -ibo 7 | else 8 | echo $out 9 | fi 10 | -------------------------------------------------------------------------------- /scripts/mangle.sh: -------------------------------------------------------------------------------- 1 | echo -e $1 | x86_64-obos-g++ -ffreestanding -o /dev/stdout -xc++ -S - 2 | -------------------------------------------------------------------------------- /src/build/m68k/link.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT(elf32-m68k) 2 | 3 | ENTRY(Arch_KernelEntryBootstrap) 4 | 5 | PHDRS 6 | { 7 | text PT_LOAD FLAGS((1 << 0) | (1 << 2)) ; /* Execute + Read */ 8 | rodata PT_LOAD FLAGS((1 << 2)) ; /* Read only */ 9 | data PT_LOAD FLAGS((1 << 1) | (1 << 2)) ; /* Write + Read */ 10 | 11 | pageable_text PT_LOAD FLAGS((1 << 0) | (1 << 2)); /* Read + Execute */ 12 | pageable_data PT_LOAD FLAGS((1 << 1) | (1 << 2)); /* Read + Write */ 13 | pageable_rodata PT_LOAD FLAGS((1 << 2)); /* Read only */ 14 | } 15 | 16 | SECTIONS 17 | { 18 | . = 0xC0000000; 19 | KERNEL_BASE = .; 20 | 21 | .text : { 22 | *(.text .text.*) 23 | } :text 24 | 25 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 26 | 27 | 28 | .rodata : { 29 | *(.rodata .rodata.*) 30 | } :rodata 31 | 32 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 33 | 34 | .data : { 35 | *(.data .data.*) 36 | } :data 37 | 38 | .bss : { 39 | *(.bss .bss.*) 40 | *(COMMON) 41 | } :data 42 | 43 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 44 | 45 | MmS_MMPageableRangeStart = .; 46 | /* Functions */ 47 | .pageable.text : { 48 | *(.pageable.text) 49 | } :pageable_text 50 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 51 | /* RW Data. */ 52 | .pageable.data : { 53 | *(.pageable.data) 54 | } :pageable_data 55 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 56 | .pageable.bss : { 57 | *(.pageable.bss) 58 | } :pageable_data 59 | /* RO Data */ 60 | .pageable.rodata : { 61 | *(.pageable.rodata) 62 | } :pageable_rodata 63 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 64 | MmS_MMPageableRangeEnd = .; 65 | 66 | /DISCARD/ : { 67 | /* *(.eh_frame*) */ 68 | *(.note .note.*) 69 | *(.comment) 70 | } 71 | KERNEL_TOP = .; 72 | } -------------------------------------------------------------------------------- /src/build/x86_64/driver_link.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT(elf64-x86-64) 2 | OUTPUT_ARCH(i386:x86-64) 3 | 4 | ENTRY(OBOS_DriverEntry) 5 | 6 | PHDRS 7 | { 8 | headers PT_PHDR PHDRS; 9 | text PT_LOAD FILEHDR PHDRS FLAGS((1 << 0) | (1 << 2)) ; /* Execute + Read */ 10 | rodata PT_LOAD FLAGS((1 << 2)) ; /* Read only */ 11 | data PT_LOAD FLAGS((1 << 1) | (1 << 2)) ; /* Write + Read */ 12 | 13 | /* 0x00010000=PF_OBOS_PAGEABLE */ 14 | pageable_text PT_LOAD FLAGS((1 << 0) | (1 << 2) | 0x00010000); /* Read + Execute + Pageable */ 15 | pageable_data PT_LOAD FLAGS((1 << 1) | (1 << 2) | 0x00010000); /* Read + Write + Pageable */ 16 | pageable_rodata PT_LOAD FLAGS((1 << 2) | 0x00010000); /* Read only + Pageable */ 17 | 18 | dynamic PT_DYNAMIC; 19 | } 20 | 21 | 22 | SECTIONS 23 | { 24 | Drv_Base = .; 25 | . = 0x0000000000000000 + SIZEOF_HEADERS; 26 | 27 | .text : { 28 | *(.text .text.*) 29 | } :text 30 | 31 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 32 | 33 | .rodata : { 34 | *(.rodata .rodata.*) 35 | } :rodata 36 | 37 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 38 | 39 | .data : { 40 | *(.data .data.*) 41 | *(.driverheader) 42 | } :data 43 | 44 | .bss : { 45 | *(.bss .bss.*) 46 | *(COMMON) 47 | } :data 48 | 49 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 50 | 51 | /* Functions */ 52 | .pageable.text : { 53 | *(.pageable.text) 54 | } :pageable_text 55 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 56 | /* RW Data. */ 57 | .pageable.data : { 58 | *(.pageable.data) 59 | } :pageable_data 60 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 61 | .pageable.bss : { 62 | *(.pageable.bss) 63 | } :pageable_data 64 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 65 | /* RO Data */ 66 | .pageable.rodata : { 67 | *(.pageable.rodata) 68 | } :pageable_rodata 69 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 70 | 71 | /DISCARD/ : { 72 | *(.eh_frame) 73 | *(.note .note.*) 74 | *(.comment) 75 | } 76 | 77 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 78 | .dynamic : { 79 | *(.dynamic) 80 | } :data :dynamic 81 | 82 | Drv_Top = .; 83 | } 84 | -------------------------------------------------------------------------------- /src/build/x86_64/link.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT(elf64-x86-64) 2 | OUTPUT_ARCH(i386:x86-64) 3 | 4 | ENTRY(Arch_KernelEntryBootstrap) 5 | 6 | PHDRS 7 | { 8 | text PT_LOAD FLAGS((1 << 0) | (1 << 2)) ; /* Execute + Read */ 9 | rodata PT_LOAD FLAGS((1 << 2)) ; /* Read only */ 10 | data PT_LOAD FLAGS((1 << 1) | (1 << 2)) ; /* Write + Read */ 11 | 12 | pageable_text PT_LOAD FLAGS((1 << 0) | (1 << 2)); /* Read + Execute */ 13 | pageable_data PT_LOAD FLAGS((1 << 1) | (1 << 2)); /* Read + Write */ 14 | pageable_rodata PT_LOAD FLAGS((1 << 2)); /* Read only */ 15 | } 16 | 17 | SECTIONS 18 | { 19 | . = 0xffffffff80000000; 20 | KERNEL_BASE = .; 21 | 22 | MmS_MMPageableRangeStart = .; 23 | /* Functions */ 24 | .pageable.text : { 25 | *(.pageable.text) 26 | } :pageable_text 27 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 28 | /* RW Data. */ 29 | .pageable.data : { 30 | *(.pageable.data) 31 | } :pageable_data 32 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 33 | .pageable.bss : { 34 | *(.pageable.bss) 35 | } :pageable_data 36 | /* RO Data */ 37 | .pageable.rodata : { 38 | *(.pageable.rodata) 39 | } :pageable_rodata 40 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 41 | MmS_MMPageableRangeEnd = .; 42 | 43 | .text : { 44 | *(.text .text.*) 45 | } :text 46 | 47 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 48 | 49 | 50 | .rodata : { 51 | *(.rodata .rodata.*) 52 | } :rodata 53 | 54 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 55 | 56 | .data : { 57 | *(.data .data.*) 58 | } :data 59 | 60 | .bss : { 61 | *(.bss .bss.*) 62 | *(COMMON) 63 | } :data 64 | 65 | . = ALIGN(CONSTANT(MAXPAGESIZE)); 66 | 67 | /DISCARD/ : { 68 | *(.eh_frame) 69 | *(.note .note.*) 70 | *(.comment) 71 | } 72 | KERNEL_TOP = .; 73 | } 74 | -------------------------------------------------------------------------------- /src/drivers/generic/ahci/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # drivers/generic/ahci/CMakeLists.txt 2 | # 3 | # Copyright (c) 2024 Omar Berrow 4 | 5 | add_executable(ahci "main.c" "ahci_irq.c" "command.c" "interface.c") 6 | 7 | target_compile_options(ahci 8 | PRIVATE $<$:${TARGET_DRIVER_COMPILE_OPTIONS_C}> 9 | PRIVATE $<$:-ffreestanding> 10 | PRIVATE $<$:-Wall> 11 | PRIVATE $<$:-Wextra> 12 | PRIVATE $<$:-fstack-protector-all> 13 | PRIVATE $<$:-fno-builtin-memset> 14 | PRIVATE $<$:-fvisibility=hidden> 15 | PRIVATE $<$:-fPIC> 16 | ) 17 | 18 | set_property(TARGET ahci PROPERTY link_depends ${DRIVER_LINKER_SCRIPT}) 19 | 20 | target_include_directories(ahci 21 | PRIVATE "${CMAKE_SOURCE_DIR}/src/oboskrnl" 22 | PRIVATE ${OBOSKRNL_EXTERNAL_INCLUDES}) 23 | 24 | target_link_options(ahci 25 | PRIVATE "-nostdlib" 26 | PRIVATE "-fPIC" 27 | PRIVATE "-Wl,-shared" 28 | # PRIVATE "-Wl,--allow-shlib-undefined" 29 | PRIVATE "-T" PRIVATE ${DRIVER_LINKER_SCRIPT} 30 | PRIVATE ${TARGET_DRIVER_LINKER_OPTIONS} 31 | ) 32 | target_compile_definitions(ahci PRIVATE OBOS_DRIVER=1) 33 | -------------------------------------------------------------------------------- /src/drivers/generic/ahci/ahci_irq.h: -------------------------------------------------------------------------------- 1 | /* 2 | * drivers/generic/ahci/ahci_irq.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | bool ahci_irq_checker(struct irq* i, void* userdata); 17 | void ahci_irq_handler(struct irq* i, interrupt_frame* frame, void* userdata, irql oldIrql); 18 | extern pci_resource* PCIIrqResource; 19 | -------------------------------------------------------------------------------- /src/drivers/generic/ahci/command.h: -------------------------------------------------------------------------------- 1 | /* 2 | * drivers/generic/ahci/command.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include "structs.h" 15 | 16 | struct ahci_phys_region 17 | { 18 | uintptr_t phys; 19 | uint32_t sz : 22; 20 | }; 21 | enum { 22 | COMMAND_DIRECTION_READ, 23 | COMMAND_DIRECTION_WRITE, 24 | }; 25 | struct command_data 26 | { 27 | struct ahci_phys_region* phys_regions; 28 | uint16_t physRegionCount; 29 | uint8_t direction; 30 | uint8_t cmd; 31 | bool awaitingSignal; 32 | // Set when the command is done. 33 | event completionEvent; 34 | obos_status commandStatus; 35 | struct { 36 | uint8_t cmdSlot; 37 | } internal; 38 | }; 39 | obos_status SendCommand(Port* port, struct command_data* data, uint64_t lba, uint8_t device, uint16_t count); 40 | obos_status ClearCommand(Port* port, struct command_data* data); 41 | void StopCommandEngine(volatile HBA_PORT* port); 42 | void StartCommandEngine(volatile HBA_PORT* port); 43 | 44 | // Prevents any further transactions from happening. 45 | // This causes SendComamnd to return OBOS_STATUS_RETRY, thus making it's callers also return that. 46 | void HaltTranscations(); 47 | // Allows transactions to happen. 48 | void ResumeTranscations(); 49 | 50 | // Wait for transcations to complete. 51 | // If shutting down the ahci driver, or preparing to suspend, 52 | // then call this after halting transactions. 53 | void WaitForTranscations(); 54 | -------------------------------------------------------------------------------- /src/drivers/generic/initrd/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # drivers/generic/initrd/CMakeLists.txt 2 | # 3 | # Copyright (c) 2024 Omar Berrow 4 | 5 | add_executable(initrd "main.c" "parse.c") 6 | 7 | target_compile_options(initrd 8 | PRIVATE $<$:${TARGET_DRIVER_COMPILE_OPTIONS_C}> 9 | PRIVATE $<$:-ffreestanding> 10 | PRIVATE $<$:-Wall> 11 | PRIVATE $<$:-Wextra> 12 | PRIVATE $<$:-fstack-protector-all> 13 | PRIVATE $<$:-fno-builtin-memset> 14 | PRIVATE $<$:-fvisibility=hidden> 15 | PRIVATE $<$:-fPIC> 16 | ) 17 | 18 | set_property(TARGET initrd PROPERTY link_depends ${DRIVER_LINKER_SCRIPT}) 19 | 20 | target_include_directories(initrd 21 | PRIVATE "${CMAKE_SOURCE_DIR}/src/oboskrnl" 22 | PRIVATE ${OBOSKRNL_EXTERNAL_INCLUDES}) 23 | 24 | target_link_options(initrd 25 | PRIVATE "-nostdlib" 26 | PRIVATE "-fPIC" 27 | PRIVATE "-T${DRIVER_LINKER_SCRIPT}" 28 | PRIVATE "-Wl,-shared" 29 | # PRIVATE "-Wl,--allow-shlib-undefined" 30 | PRIVATE ${TARGET_DRIVER_LINKER_OPTIONS} 31 | ) 32 | target_compile_definitions(initrd PRIVATE OBOS_DRIVER=1) 33 | -------------------------------------------------------------------------------- /src/drivers/generic/initrd/name.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #define INITRD_DRIVER_NAME "Initial Ramdisk (InitRD) Driver" -------------------------------------------------------------------------------- /src/drivers/generic/initrd/parse.h: -------------------------------------------------------------------------------- 1 | /* 2 | * drivers/generic/initrd/parse.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include "ustar_hdr.h" 13 | 14 | extern initrd_inode* InitrdRoot; 15 | extern size_t CurrentInodeNumber; 16 | 17 | const ustar_hdr* GetFile(const char* path, obos_status* status); 18 | initrd_inode* DirentLookupFrom(const char* path, initrd_inode* root); 19 | inline static uint64_t oct2bin(const char* str, size_t size) 20 | { 21 | uint64_t n = 0; 22 | const char* c = str; 23 | while (size-- > 0) 24 | n = n * 8 + (uint64_t)(*c++ - '0'); 25 | return n; 26 | } 27 | void* malloc(size_t sz); 28 | void* realloc(void* buf, size_t sz); 29 | void free(void* buf); 30 | -------------------------------------------------------------------------------- /src/drivers/generic/initrd/ustar_hdr.h: -------------------------------------------------------------------------------- 1 | /* 2 | * drivers/generic/initrd/ustar_hdr.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | typedef struct ustar_hdr 15 | { 16 | char filename[100]; 17 | char filemode[8]; 18 | char owner_uid[8]; 19 | char group_uid[8]; 20 | char filesize[12]; // In octal! 21 | char last_mod[12]; // In octal! 22 | char chksum[8]; 23 | char type; 24 | char linked[100]; 25 | char magic[6]; // should be ustar\0 26 | char version[2]; 27 | char owner_uname[32]; 28 | char group_uname[32]; 29 | char unused[16]; 30 | char prefix[155]; 31 | } OBOS_PACK ustar_hdr; 32 | 33 | typedef struct initrd_inode { 34 | struct { 35 | struct initrd_inode *head, *tail; 36 | size_t nChildren; 37 | } children; 38 | struct initrd_inode *next, *prev, *parent; 39 | char* name; 40 | char* path; 41 | char* data; 42 | size_t filesize; 43 | size_t path_len; 44 | size_t path_size; 45 | size_t name_len; 46 | size_t name_size; 47 | file_type type; 48 | uint32_t ino; 49 | bool persistent : 1; 50 | driver_file_perm perm; 51 | } initrd_inode; 52 | 53 | enum { 54 | FILEMODE_EXEC = BIT(0), 55 | FILEMODE_WRITE = BIT(1), 56 | FILEMODE_READ = BIT(2), 57 | FILEMODE_OTHER_EXEC = FILEMODE_EXEC << 0, 58 | FILEMODE_OTHER_WRITE = FILEMODE_WRITE << 0, 59 | FILEMODE_OTHER_READ = FILEMODE_READ << 0, 60 | FILEMODE_GROUP_EXEC = FILEMODE_EXEC << 3, 61 | FILEMODE_GROUP_WRITE = FILEMODE_WRITE << 3, 62 | FILEMODE_GROUP_READ = FILEMODE_READ << 3, 63 | FILEMODE_OWNER_EXEC = FILEMODE_EXEC << 6, 64 | FILEMODE_OWNER_WRITE = FILEMODE_WRITE << 6, 65 | FILEMODE_OWNER_READ = FILEMODE_READ << 6, 66 | }; 67 | enum 68 | { 69 | AREGTYPE = '\0', 70 | REGTYPE = '0', 71 | LNKTYPE = '1', 72 | SYMTYPE = '2', 73 | CHRTYPE = '3', 74 | BLKTYPE = '4', 75 | DIRTYPE = '5', 76 | FIFOTYPE = '6', 77 | CONTYPE = '7', 78 | }; 79 | #define USTAR_MAGIC "ustar\0" -------------------------------------------------------------------------------- /src/drivers/generic/libps2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # drivers/generic/libps2/CMakeLists.txt 2 | 3 | # Copyright (c) 2025 Omar Berrow 4 | 5 | # The motive behind having this instead of directly intergrating PS/2 drivers 6 | # into a file is to allow PS/2 keyboard/mouse drivers to be shared between 7 | # platforms with different controllers. 8 | 9 | add_executable(libps2 "keyboard.c" "detect.c" "main.c") 10 | 11 | target_compile_options(libps2 12 | PRIVATE $<$:${TARGET_DRIVER_COMPILE_OPTIONS_C}> 13 | PRIVATE $<$:-ffreestanding> 14 | PRIVATE $<$:-Wall> 15 | PRIVATE $<$:-Wextra> 16 | PRIVATE $<$:-fstack-protector-all> 17 | PRIVATE $<$:-fno-builtin-memset> 18 | PRIVATE $<$:-fvisibility=hidden> 19 | PRIVATE $<$:-fPIC> 20 | ) 21 | 22 | set_property(TARGET libps2 PROPERTY link_depends ${DRIVER_LINKER_SCRIPT}) 23 | 24 | target_include_directories(libps2 25 | PRIVATE "${CMAKE_SOURCE_DIR}/src/oboskrnl" 26 | PRIVATE "${CMAKE_SOURCE_DIR}/src/drivers" 27 | PRIVATE ${OBOSKRNL_EXTERNAL_INCLUDES}) 28 | 29 | target_link_options(libps2 30 | PRIVATE "-nostdlib" 31 | PRIVATE "-fPIC" 32 | PRIVATE "-Wl,-shared" 33 | # PRIVATE "-Wl,--allow-shlib-undefined" 34 | PRIVATE "-T" PRIVATE ${DRIVER_LINKER_SCRIPT} 35 | PRIVATE ${TARGET_DRIVER_LINKER_OPTIONS} 36 | ) 37 | target_compile_definitions(libps2 PRIVATE OBOS_DRIVER=1) 38 | 39 | target_compile_definitions(libps2 40 | PRIVATE $<$:OBOS_DEBUG> 41 | PRIVATE $<$:OBOS_RELEASE> 42 | PRIVATE $<$:OBOS_RELEASE> 43 | PRIVATE $<$:OBOS_RELEASE> 44 | PUBLIC OBOS_DRIVER=1 45 | ) 46 | -------------------------------------------------------------------------------- /src/drivers/generic/libps2/controller.h: -------------------------------------------------------------------------------- 1 | /* 2 | * drivers/generic/libps2/controller.h 3 | * 4 | * Copyright (c) 2025 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | #if defined(__x86_64__) || defined(__i686__) 17 | # include 18 | #endif 19 | 20 | enum {PS2_PORT_MAGIC=0x1BADBEEF}; 21 | 22 | enum { 23 | PS2_DEV_TYPE_UNKNOWN = 'u', 24 | PS2_DEV_TYPE_KEYBOARD = 'k', 25 | PS2_DEV_TYPE_MOUSE = 'm', 26 | }; 27 | 28 | typedef struct ps2_port { 29 | union { 30 | uint64_t data; 31 | void* pdata; 32 | }; 33 | union { 34 | uint64_t udata; 35 | void* pudata; 36 | }; 37 | 38 | union { 39 | obos_status(*read_code)(void* handle, keycode* out, bool block); 40 | obos_status(*read_raw)(void* handle, void* buf, bool block); 41 | }; 42 | // Gets the amount of readable objects for that handle. 43 | obos_status(*get_readable_count)(void* handle, size_t* nReadable); 44 | obos_status(*make_handle)(struct ps2_port* port, void** handle); 45 | // To be set by the driver when there is at least one object ready to be read by read_* 46 | // Should be a 'EVENT_NOTIFICATION' 47 | event* data_ready_event; 48 | 49 | // NOTE: Remove this and make it correct when the net-stack branch is 50 | // merged, and add the (un)reference_interface callbacks. 51 | void* default_handle; 52 | 53 | struct irq* irq; 54 | void(*data_ready)(struct ps2_port* channel, uint8_t data); 55 | 56 | size_t blk_size; 57 | 58 | union { 59 | OBOS_PACK struct { 60 | char id[4]; 61 | uint8_t padding; 62 | }; 63 | char str_id[5]; 64 | }; 65 | 66 | uint32_t magic; 67 | uint32_t gsi; 68 | 69 | uint16_t model; 70 | 71 | char type; 72 | 73 | bool works : 1; 74 | bool suppress_irqs : 1; 75 | bool second : 1; 76 | } ps2_port; 77 | 78 | DRV_EXPORT void PS2_DeviceWrite(bool channel_two, uint8_t val); 79 | DRV_EXPORT uint8_t PS2_DeviceRead(uint32_t spin_timeout, obos_status* status); 80 | DRV_EXPORT obos_status PS2_EnableChannel(bool channel_two, bool status); 81 | DRV_EXPORT obos_status PS2_MaskChannelIRQs(bool channel_two, bool mask); 82 | DRV_EXPORT obos_status PS2_FlushInput(); 83 | DRV_EXPORT ps2_port* PS2_GetPort(bool channel_two); -------------------------------------------------------------------------------- /src/drivers/generic/libps2/detect.h: -------------------------------------------------------------------------------- 1 | /* 2 | * generic/libps2/detect.h 3 | * 4 | * Copyright (c) 2025 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #include "controller.h" 12 | 13 | void PS2_DetectDevice(ps2_port* port); 14 | 15 | uint8_t PS2_SendCommand(ps2_port* port, uint8_t cmd, size_t nArgs, ...); -------------------------------------------------------------------------------- /src/drivers/generic/libps2/keyboard.h: -------------------------------------------------------------------------------- 1 | /* 2 | * drivers/generic/libps2/keyboard.h 3 | * 4 | * Copyright (c) 2025 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | 18 | #include "controller.h" 19 | 20 | #define PS2_ACK 0xfa 21 | #define PS2_RESEND 0xfe 22 | #define PS2_INVALID_RESPONSE 0xff 23 | 24 | enum { 25 | PS2K_MAGIC_VALUE = 0xFEE1DEAD, 26 | PS2K_HND_MAGIC_VALUE = 0xFEE1DEAE 27 | }; 28 | 29 | typedef struct ps2k_ringbuffer 30 | { 31 | event e; 32 | union { 33 | void* buff; 34 | keycode* keycodes; 35 | }; 36 | size_t size; 37 | size_t nElements; 38 | size_t out_ptr; 39 | size_t handle_count; 40 | } ps2k_ringbuffer; 41 | 42 | typedef struct ps2k_handle { 43 | uint32_t magic; // PS2K_HND_MAGIC_VALUE 44 | ps2_port* port; 45 | size_t in_ptr; 46 | } ps2k_handle; 47 | 48 | obos_status PS2_RingbufferInitialize(ps2k_ringbuffer* buff); 49 | obos_status PS2_RingbufferAppend(ps2k_ringbuffer* buff, keycode code, bool signal); 50 | obos_status PS2_RingbufferFetch(const ps2k_ringbuffer* buff, size_t* in_ptr, keycode* code); 51 | obos_status PS2_RingbufferFree(ps2k_ringbuffer* buff); 52 | 53 | typedef struct ps2k_data { 54 | struct ps2k_ringbuffer input; 55 | ps2_port* port; 56 | uint32_t ps2k_magic; 57 | dpc dpc; 58 | uint8_t set; 59 | bool initialized : 1; 60 | bool processing_extended : 1; 61 | bool processing_release : 1; // only valid if set == 2 62 | bool super_key : 1; 63 | bool caps_lock : 1; 64 | bool num_lock : 1; 65 | bool ctrl : 1; 66 | bool shift : 1; 67 | bool alt : 1; 68 | bool fn : 1; 69 | } ps2k_data; 70 | 71 | void PS2_InitializeKeyboard(ps2_port* port); 72 | void PS2_FreeKeyboard(ps2_port* port); -------------------------------------------------------------------------------- /src/drivers/generic/r8169/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # drivers/generic/r8169/CMakeLists.txt 2 | # 3 | # Copyright (c) 2025 Omar Berrow 4 | 5 | add_executable(r8169 "main.c" "device.c") 6 | 7 | target_compile_options(r8169 8 | PRIVATE $<$:${TARGET_DRIVER_COMPILE_OPTIONS_C}> 9 | PRIVATE $<$:-ffreestanding> 10 | PRIVATE $<$:-Wall> 11 | PRIVATE $<$:-Wextra> 12 | PRIVATE $<$:-fstack-protector-all> 13 | PRIVATE $<$:-fno-builtin-memset> 14 | PRIVATE $<$:-fvisibility=hidden> 15 | PRIVATE $<$:-fPIC> 16 | ) 17 | 18 | set_property(TARGET r8169 PROPERTY link_depends ${DRIVER_LINKER_SCRIPT}) 19 | 20 | target_include_directories(r8169 21 | PRIVATE "${CMAKE_SOURCE_DIR}/src/oboskrnl" 22 | PRIVATE ${OBOSKRNL_EXTERNAL_INCLUDES}) 23 | 24 | target_link_options(r8169 25 | PRIVATE "-nostdlib" 26 | PRIVATE "-fPIC" 27 | PRIVATE "-Wl,-shared" 28 | # PRIVATE "-Wl,--allow-shlib-undefined" 29 | PRIVATE "-T" PRIVATE ${DRIVER_LINKER_SCRIPT} 30 | PRIVATE ${TARGET_DRIVER_LINKER_OPTIONS} 31 | ) 32 | target_compile_definitions(r8169 PRIVATE OBOS_DRIVER=1) 33 | -------------------------------------------------------------------------------- /src/drivers/generic/slowfat/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # drivers/generic/slowfat/CMakeLists.txt 2 | # 3 | # Copyright (c) 2024 Omar Berrow 4 | 5 | add_executable(slowfat "main.c" "probe.c" "lookup.c" "interface.c" 6 | "cls_alloc.c" "io.c" "create.c" "fat_irp.c" 7 | ) 8 | 9 | target_compile_options(slowfat 10 | PRIVATE $<$:${TARGET_DRIVER_COMPILE_OPTIONS_C}> 11 | PRIVATE $<$:-ffreestanding> 12 | PRIVATE $<$:-Wall> 13 | PRIVATE $<$:-Wextra> 14 | PRIVATE $<$:-fstack-protector-all> 15 | PRIVATE $<$:-fno-builtin-memset> 16 | PRIVATE $<$:-fvisibility=hidden> 17 | PRIVATE $<$:-fPIC> 18 | ) 19 | 20 | set_property(TARGET slowfat PROPERTY link_depends ${DRIVER_LINKER_SCRIPT}) 21 | 22 | target_include_directories(slowfat 23 | PRIVATE "${CMAKE_SOURCE_DIR}/src/oboskrnl" 24 | PRIVATE ${OBOSKRNL_EXTERNAL_INCLUDES}) 25 | 26 | target_link_options(slowfat 27 | PRIVATE "-nostdlib" 28 | PRIVATE "-fPIC" 29 | PRIVATE "-T${DRIVER_LINKER_SCRIPT}" 30 | PRIVATE "-Wl,-shared" 31 | # PRIVATE "-Wl,--allow-shlib-undefined" 32 | PRIVATE ${TARGET_DRIVER_LINKER_OPTIONS} 33 | ) 34 | target_compile_definitions(slowfat PRIVATE OBOS_DRIVER=1) 35 | -------------------------------------------------------------------------------- /src/drivers/generic/slowfat/alloc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * drivers/generic/slowfat/alloc.h 3 | * 4 | * Copyright (c) 2024-2025 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include "structs.h" 14 | 15 | // All functions in this file, unless otherwise specified, should take the fat lock in the fat_cache struct. 16 | // returns UINT32_MAX if no sector was found 17 | uint32_t AllocateClusters(fat_cache* volume, size_t nClusters); 18 | // Returns true if the cluster region was extended, otherwise you need to reallocate the clusters. 19 | bool ExtendClusters(fat_cache* volume, uint32_t cluster, size_t nClusters, size_t oldClusterCount); 20 | void TruncateClusters(fat_cache* volume, uint32_t cluster, size_t newClusterCount, size_t oldClusterCount); 21 | void FreeClusters(fat_cache* volume, uint32_t cluster, size_t nClusters); 22 | void InitializeCacheFreelist(fat_cache* volume); 23 | 24 | // if status is passed as OBOS_STATUS_SUCCESS, the cluster passed is valid. 25 | // if status is passed as OBOS_STATUS_EOF, the cluster passed is valid, and is the last cluster of the chain. 26 | // if status is passed as OBOS_STATUS_ABORTED, the cluster passed is not valid, as an error has occurred following the chain. 27 | typedef iterate_decision(*clus_chain_cb)(uint32_t cluster, obos_status status, void* userdata); 28 | obos_status NextCluster(fat_cache* cache, uint32_t cluster, uint8_t* sec_buf, uint32_t* ret); 29 | uint32_t ClusterSeek(fat_cache* cache, uint32_t cluster, uint32_t nClusters); 30 | void FollowClusterChain(fat_cache* volume, uint32_t clus, clus_chain_cb callback, void* userdata); -------------------------------------------------------------------------------- /src/drivers/test_driver/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # drivers/test_driver/CMakeLists.txt 2 | # 3 | # Copyright (c) 2024 Omar Berrow 4 | 5 | add_executable(test_driver "main.c" "fireworks.c" "rand.c") 6 | 7 | target_compile_options(test_driver 8 | PRIVATE $<$:${TARGET_DRIVER_COMPILE_OPTIONS_C}> 9 | PRIVATE $<$:-ffreestanding> 10 | PRIVATE $<$:-Wall> 11 | PRIVATE $<$:-Wextra> 12 | PRIVATE $<$:-fstack-protector-all> 13 | PRIVATE $<$:-fno-builtin-memset> 14 | PRIVATE $<$:-fvisibility=hidden> 15 | PRIVATE $<$:-fPIC> 16 | ) 17 | 18 | set_target_properties(test_driver PROPERTIES link_depends ${DRIVER_LINKER_SCRIPT}) 19 | 20 | target_include_directories(test_driver 21 | PRIVATE "${CMAKE_SOURCE_DIR}/src/oboskrnl" 22 | PRIVATE ${OBOSKRNL_EXTERNAL_INCLUDES}) 23 | 24 | target_link_options(test_driver 25 | PRIVATE "-nostdlib" 26 | PRIVATE "-fPIC" 27 | PRIVATE "-T${DRIVER_LINKER_SCRIPT}" 28 | PRIVATE "-Wl,-shared" 29 | # PRIVATE "-Wl,--allow-shlib-undefined" 30 | PRIVATE ${TARGET_DRIVER_LINKER_OPTIONS} 31 | ) 32 | 33 | target_compile_definitions(test_driver PRIVATE OBOS_DRIVER=1) 34 | -------------------------------------------------------------------------------- /src/drivers/test_driver/rand.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include "rand.h" 7 | 8 | // shamelessly stolen from https://osdev.wiki/wiki/Random_Number_Generator#Mersenne_Twister 9 | 10 | #if OBOS_ARCHITECTURE_BITS == 32 11 | #define STATE_SIZE 624 12 | #define MIDDLE 397 13 | #define INIT_SHIFT 30 14 | #define INIT_FACT 1812433253 15 | #define TWIST_MASK 0x9908b0df 16 | #define SHIFT1 11 17 | #define MASK1 0xffffffff 18 | #define SHIFT2 7 19 | #define MASK2 0x9d2c5680 20 | #define SHIFT3 15 21 | #define MASK3 0xefc60000 22 | #define SHIFT4 18 23 | #else 24 | #define STATE_SIZE 312 25 | #define MIDDLE 156 26 | #define INIT_SHIFT 62 27 | #define TWIST_MASK 0xb5026f5aa96619e9 28 | #define INIT_FACT 6364136223846793005 29 | #define SHIFT1 29 30 | #define MASK1 0x5555555555555555 31 | #define SHIFT2 17 32 | #define MASK2 0x71d67fffeda60000 33 | #define SHIFT3 37 34 | #define MASK3 0xfff7eee000000000 35 | #define SHIFT4 43 36 | #endif 37 | 38 | #define LOWER_MASK 0x7fffffff 39 | #define UPPER_MASK (~(uintptr_t)LOWER_MASK) 40 | static uintptr_t state[STATE_SIZE]; 41 | static size_t index = STATE_SIZE + 1; 42 | 43 | void mt_seed(uintptr_t s) 44 | { 45 | index = STATE_SIZE; 46 | state[0] = s; 47 | for (size_t i = 1; i < STATE_SIZE; i++) 48 | state[i] = (INIT_FACT * (state[i - 1] ^ (state[i - 1] >> INIT_SHIFT))) + i; 49 | } 50 | 51 | static void twist(void) 52 | { 53 | for (size_t i = 0; i < STATE_SIZE; i++) 54 | { 55 | uintptr_t x = (state[i] & UPPER_MASK) | (state[(i + 1) % STATE_SIZE] & LOWER_MASK); 56 | x = (x >> 1) ^ (x & 1? TWIST_MASK : 0); 57 | state[i] = state[(i + MIDDLE) % STATE_SIZE] ^ x; 58 | } 59 | index = 0; 60 | } 61 | 62 | uintptr_t mt_random(void) 63 | { 64 | if (index >= STATE_SIZE) 65 | { 66 | OBOS_ASSERT(index == STATE_SIZE || !"Generator never seeded"); 67 | twist(); 68 | } 69 | 70 | uintptr_t y = state[index]; 71 | y ^= (y >> SHIFT1) & MASK1; 72 | y ^= (y << SHIFT2) & MASK2; 73 | y ^= (y << SHIFT3) & MASK3; 74 | y ^= y >> SHIFT4; 75 | 76 | index++; 77 | return y; 78 | } 79 | 80 | OBOS_WEAK uintptr_t random_seed() 81 | { 82 | return CoreS_GetNativeTimerTick(); 83 | } -------------------------------------------------------------------------------- /src/drivers/test_driver/rand.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | uintptr_t mt_random(void); 6 | void mt_seed(uintptr_t seed); 7 | uintptr_t random_seed(); -------------------------------------------------------------------------------- /src/drivers/x86/bochs_vbe/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # drivers/x86/bochs_vbe/CMakeLists.txt 2 | # 3 | # Copyright (c) 2024 Omar Berrow 4 | 5 | add_executable(bochs_vbe "main.c" "suspend.c" "io.c") 6 | 7 | target_compile_options(bochs_vbe 8 | PRIVATE $<$:${TARGET_DRIVER_COMPILE_OPTIONS_C}> 9 | PRIVATE $<$:-ffreestanding> 10 | PRIVATE $<$:-Wall> 11 | PRIVATE $<$:-Wextra> 12 | PRIVATE $<$:-fstack-protector-all> 13 | PRIVATE $<$:-fno-builtin-memset> 14 | PRIVATE $<$:-fvisibility=hidden> 15 | PRIVATE $<$:-fPIC> 16 | ) 17 | 18 | set_property(TARGET bochs_vbe PROPERTY link_depends ${DRIVER_LINKER_SCRIPT}) 19 | 20 | target_include_directories(bochs_vbe 21 | PRIVATE "${CMAKE_SOURCE_DIR}/src/oboskrnl" 22 | PRIVATE ${OBOSKRNL_EXTERNAL_INCLUDES}) 23 | 24 | target_link_options(bochs_vbe 25 | PRIVATE "-nostdlib" 26 | PRIVATE "-fPIC" 27 | PRIVATE "-Wl,-shared" 28 | # PRIVATE "-Wl,--allow-shlib-undefined" 29 | PRIVATE "-T" PRIVATE ${DRIVER_LINKER_SCRIPT} 30 | PRIVATE ${TARGET_DRIVER_LINKER_OPTIONS} 31 | ) 32 | target_compile_definitions(bochs_vbe PRIVATE OBOS_DRIVER=1) 33 | -------------------------------------------------------------------------------- /src/drivers/x86/bochs_vbe/io.c: -------------------------------------------------------------------------------- 1 | /* 2 | * drivers/x86/bochs_vbe/io.c 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #include 8 | 9 | #include 10 | 11 | #include "io.h" 12 | 13 | #define INDEX_REG 0x1ce 14 | #define DATA_REG 0x1cf 15 | 16 | void WriteRegister(uint16_t index, uint16_t val) 17 | { 18 | outw(INDEX_REG, index); 19 | outw(DATA_REG, val); 20 | } 21 | uint16_t ReadRegister(uint16_t index) 22 | { 23 | outw(INDEX_REG, index); 24 | return inw(DATA_REG); 25 | } 26 | -------------------------------------------------------------------------------- /src/drivers/x86/bochs_vbe/io.h: -------------------------------------------------------------------------------- 1 | /* 2 | * drivers/x86/bochs_vbe/io.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #define INDEX_ID 0 12 | #define INDEX_XRES 1 13 | #define INDEX_YRES 2 14 | #define INDEX_BPP 3 15 | #define INDEX_ENABLE 4 16 | #define INDEX_BANK 5 17 | #define INDEX_VIRT_WIDTH 6 18 | #define INDEX_VIRT_HEIGHT 7 19 | #define INDEX_X_OFFSET 8 20 | #define INDEX_Y_OFFSET 9 21 | 22 | void WriteRegister(uint16_t index, uint16_t val); 23 | uint16_t ReadRegister(uint16_t index); 24 | -------------------------------------------------------------------------------- /src/drivers/x86/bochs_vbe/suspend.c: -------------------------------------------------------------------------------- 1 | /* 2 | * drivers/x86/bochs_vbe/suspend.c 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #include 8 | 9 | #include 10 | 11 | #include "io.h" 12 | 13 | /* 14 | * We need to save: 15 | * xres 16 | * yres 17 | * virtual width 18 | * virtual height 19 | * bpp 20 | * the bank 21 | * x offset 22 | * y offset 23 | * the value of the enable register 24 | */ 25 | 26 | struct { 27 | uint32_t xres, yres; 28 | uint32_t virt_width, virt_height; 29 | uint32_t bpp; 30 | uint32_t bank; 31 | uint32_t xoffset, yoffset; 32 | uint32_t enable; 33 | } saved_vals; 34 | 35 | void on_suspend() 36 | { 37 | saved_vals.xres = ReadRegister(INDEX_XRES); 38 | saved_vals.yres = ReadRegister(INDEX_YRES); 39 | saved_vals.virt_height = ReadRegister(INDEX_VIRT_HEIGHT); 40 | saved_vals.virt_width = ReadRegister(INDEX_VIRT_WIDTH); 41 | saved_vals.bpp = ReadRegister(INDEX_BPP); 42 | saved_vals.bank = ReadRegister(INDEX_BANK); 43 | saved_vals.xoffset = ReadRegister(INDEX_X_OFFSET); 44 | saved_vals.yoffset = ReadRegister(INDEX_Y_OFFSET); 45 | saved_vals.enable = ReadRegister(INDEX_ENABLE); 46 | } 47 | 48 | #define VGA_ATT_W 0x3C0 49 | #define VGA_MIS_W 0x3C2 50 | #define VGA_IS1_RC 0x3DA 51 | #define VGA_MIS_COLOR 0x01 52 | 53 | void on_wake() 54 | { 55 | // for (volatile bool b = true; b; ) 56 | // asm volatile ("" : :"r"(b) :"memory"); 57 | 58 | // NOTE: PCI stuff is already restored by now. 59 | 60 | outb(VGA_MIS_W, VGA_MIS_COLOR); 61 | inb(VGA_IS1_RC); 62 | outb(VGA_ATT_W, 0); 63 | 64 | WriteRegister(INDEX_ENABLE, 0); 65 | WriteRegister(INDEX_BPP, saved_vals.bpp); 66 | WriteRegister(INDEX_XRES, saved_vals.xres); 67 | WriteRegister(INDEX_YRES, saved_vals.yres); 68 | WriteRegister(INDEX_BANK, saved_vals.bank); 69 | WriteRegister(INDEX_VIRT_WIDTH, saved_vals.virt_width); 70 | WriteRegister(INDEX_VIRT_HEIGHT, saved_vals.virt_height); 71 | WriteRegister(INDEX_X_OFFSET, saved_vals.xoffset); 72 | WriteRegister(INDEX_Y_OFFSET, saved_vals.yoffset); 73 | WriteRegister(INDEX_ENABLE, saved_vals.enable | BIT(7)); 74 | 75 | outb(VGA_MIS_W, VGA_MIS_COLOR); 76 | inb(VGA_IS1_RC); 77 | outb(VGA_ATT_W, 0x20); 78 | } 79 | -------------------------------------------------------------------------------- /src/drivers/x86/i8042/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # drivers/x86/i8042/CMakeLists.txt 2 | # 3 | # Copyright (c) 2025 Omar Berrow 4 | 5 | add_executable(i8042 "main.c" "ctlr.c") 6 | 7 | target_compile_options(i8042 8 | PRIVATE $<$:${TARGET_DRIVER_COMPILE_OPTIONS_C}> 9 | PRIVATE $<$:-ffreestanding> 10 | PRIVATE $<$:-Wall> 11 | PRIVATE $<$:-Wextra> 12 | PRIVATE $<$:-fstack-protector-all> 13 | PRIVATE $<$:-fno-builtin-memset> 14 | PRIVATE $<$:-fvisibility=hidden> 15 | PRIVATE $<$:-fPIC> 16 | ) 17 | 18 | set_property(TARGET i8042 PROPERTY link_depends ${DRIVER_LINKER_SCRIPT}) 19 | 20 | target_include_directories(i8042 21 | PRIVATE "${CMAKE_SOURCE_DIR}/src/oboskrnl" 22 | PRIVATE "${CMAKE_SOURCE_DIR}/src/drivers" 23 | PRIVATE ${OBOSKRNL_EXTERNAL_INCLUDES}) 24 | 25 | target_link_options(i8042 26 | PRIVATE "-nostdlib" 27 | PRIVATE "-fPIC" 28 | PRIVATE "-Wl,-shared" 29 | # PRIVATE "-Wl,--allow-shlib-undefined" 30 | PRIVATE "-T" PRIVATE ${DRIVER_LINKER_SCRIPT} 31 | PRIVATE ${TARGET_DRIVER_LINKER_OPTIONS} 32 | ) 33 | target_compile_definitions(i8042 PRIVATE OBOS_DRIVER=1) 34 | -------------------------------------------------------------------------------- /src/drivers/x86/i8042/ps2_irql.h: -------------------------------------------------------------------------------- 1 | #ifndef IRQL_PS2 2 | # define IRQL_PS2 3 3 | #endif -------------------------------------------------------------------------------- /src/drivers/x86/i8042/ps2_structs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * drivers/x86/uart/ps2_structs.h 3 | * 4 | * Copyright (c) 2025 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | #define PS2_DATA 0x60 18 | #define PS2_CMD_STATUS 0x64 19 | 20 | enum { 21 | PS2_OUTPUT_BUFFER_FULL = BIT(0), 22 | PS2_INPUT_BUFFER_FULL = BIT(1), 23 | PS2_SYSTEM_FLAG = BIT(2), 24 | // "0 = data written to input buffer is data for PS/2 device, 1 = data written to input buffer is data for PS/2 controller command" 25 | PS2_CMD_DATA = BIT(3), 26 | PS2_TIMEOUT = BIT(6), 27 | PS2_PARITY_ERROR = BIT(7), 28 | }; 29 | 30 | #define PS2_CTLR_READ_RAM_CMD(n) (0x20+((n)&0x1f)) 31 | #define PS2_CTLR_WRITE_RAM_CMD(n) (0x60+((n)&0x1f)) 32 | #define PS2_CTLR_DISABLE_PORT_TWO 0xA7 33 | #define PS2_CTLR_ENABLE_PORT_TWO 0xA8 34 | #define PS2_CTLR_TEST_PORT_TWO 0xA9 35 | #define PS2_CTLR_TEST 0xAA 36 | #define PS2_CTLR_TEST_PORT_ONE 0xAB 37 | #define PS2_CTLR_DUMP_RAM 0xAC 38 | #define PS2_CTLR_DISABLE_PORT_ONE 0xAD 39 | #define PS2_CTLR_ENABLE_PORT_ONE 0xAE 40 | #define PS2_CTLR_READ_CTLR_OUT_BUFFER 0xD0 41 | #define PS2_CTLR_WRITE_CTLR_OUT_BUFFER 0xD1 42 | #define PS2_CTLR_WRITE_PORT_TWO 0xD4 43 | 44 | enum { 45 | PS2_CTLR_CONFIG_PORT_ONE_IRQ = BIT(0), 46 | PS2_CTLR_CONFIG_PORT_TWO_IRQ = BIT(1), 47 | PS2_CTLR_CONFIG_SYSTEM_FLAG = BIT(2), 48 | PS2_CTLR_CONFIG_PORT_ONE_CLOCK = BIT(4), 49 | PS2_CTLR_CONFIG_PORT_TWO_CLOCK = BIT(5), 50 | PS2_CTLR_CONFIG_PORT_ONE_TRANSLATION = BIT(6), 51 | }; 52 | 53 | #include 54 | 55 | extern struct ps2_ctlr_data { 56 | bool dual_channel : 1; 57 | ps2_port ports[2]; 58 | spinlock lock; 59 | } PS2_CtlrData; 60 | 61 | obos_status PS2_InitializeController(); -------------------------------------------------------------------------------- /src/drivers/x86/uart/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # drivers/x86/uart/CMakeLists.txt 2 | # 3 | # Copyright (c) 2024 Omar Berrow 4 | 5 | add_executable(uart "main.c" "serial_port.c") 6 | 7 | target_compile_options(uart 8 | PRIVATE $<$:${TARGET_DRIVER_COMPILE_OPTIONS_C}> 9 | PRIVATE $<$:-ffreestanding> 10 | PRIVATE $<$:-Wall> 11 | PRIVATE $<$:-Wextra> 12 | PRIVATE $<$:-fstack-protector-all> 13 | PRIVATE $<$:-fno-builtin-memset> 14 | PRIVATE $<$:-fvisibility=hidden> 15 | PRIVATE $<$:-fPIC> 16 | ) 17 | 18 | set_property(TARGET uart PROPERTY link_depends ${DRIVER_LINKER_SCRIPT}) 19 | 20 | target_include_directories(uart 21 | PRIVATE "${CMAKE_SOURCE_DIR}/src/oboskrnl" 22 | PRIVATE ${OBOSKRNL_EXTERNAL_INCLUDES}) 23 | 24 | target_link_options(uart 25 | PRIVATE "-nostdlib" 26 | PRIVATE "-fPIC" 27 | PRIVATE "-Wl,-shared" 28 | # PRIVATE "-Wl,--allow-shlib-undefined" 29 | PRIVATE "-T" PRIVATE ${DRIVER_LINKER_SCRIPT} 30 | PRIVATE ${TARGET_DRIVER_LINKER_OPTIONS} 31 | ) 32 | target_compile_definitions(uart PRIVATE OBOS_DRIVER=1) 33 | -------------------------------------------------------------------------------- /src/inc/dev_prefix.h.in: -------------------------------------------------------------------------------- 1 | #cmakedefine OBOS_DEV_PREFIX "@OBOS_DEV_PREFIX@" -------------------------------------------------------------------------------- /src/init/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # init/CMakeLists.txt 2 | # 3 | # Copyright (c) 2025 Omar Berrow 4 | 5 | if (${OBOS_ARCHITECTURE} STREQUAL "x86_64") 6 | add_library(syscall_invoke STATIC "x86_64-syscall.S") 7 | endif() 8 | 9 | if (OBOS_ENABLE_UBSAN) 10 | add_compile_options("-fno-sanitize=undefined") 11 | endif() 12 | if (OBOS_ENABLE_KASAN) 13 | add_compile_options("-fno-sanitize=address") 14 | endif() 15 | 16 | link_libraries(syscall_invoke) 17 | 18 | add_executable (init "main.c" "motd.c") 19 | -------------------------------------------------------------------------------- /src/init/motd.c: -------------------------------------------------------------------------------- 1 | /* 2 | * init/motd.c 3 | * 4 | * Copyright (c) 2025 Omar Berrow 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | int print_motd() 14 | { 15 | struct stat st = {}; 16 | if (stat("/etc/motd", &st) != 0) 17 | { 18 | perror("stat(\"/etc/motd\")"); 19 | return -1; 20 | } 21 | int motd_fd = open("/etc/motd", O_RDONLY); 22 | if (motd_fd < 0) 23 | { 24 | perror("open(\"/etc/motd\", O_RDONLY)"); 25 | return -1; 26 | } 27 | void* motd = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, motd_fd, 0); 28 | write(STDOUT_FILENO, motd, st.st_size); 29 | write(STDOUT_FILENO, "\n", 1); 30 | close(motd_fd); 31 | munmap(motd, st.st_size); 32 | } -------------------------------------------------------------------------------- /src/init/x86_64-syscall.S: -------------------------------------------------------------------------------- 1 | // This helper library allows one to use syscalln(...) in a user-program, since obos' 2 | // sysdep marks it as hidden 3 | 4 | .intel_syntax noprefix 5 | 6 | .global syscall 7 | 8 | syscall: 9 | push rbp 10 | mov rbp, rsp 11 | 12 | mov eax, edi 13 | mov rdi, rsi 14 | mov rsi, rdx 15 | mov rdx, rcx 16 | 17 | syscall 18 | 19 | leave 20 | ret 21 | 22 | .att_syntax prefix -------------------------------------------------------------------------------- /src/isogen/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # isogen/CMakeLists.txt 2 | 3 | # Copyright (c) 2024 Omar Berrow 4 | 5 | set (ISODIR ${CMAKE_SOURCE_DIR}/out/isodir/) 6 | 7 | if (OBOS_ARCHITECTURE STREQUAL "m68k") 8 | return() 9 | endif() 10 | 11 | if (NOT EXISTS ${ISODIR}) 12 | file (MAKE_DIRECTORY ${ISODIR}) 13 | endif() 14 | if (NOT EXISTS ${ISODIR}/obos) 15 | file (MAKE_DIRECTORY ${ISODIR}/obos) 16 | endif() 17 | if (NOT EXISTS ${CMAKE_SOURCE_DIR}/config/hyper.cfg) 18 | message(FATAL_ERROR "No hyper configuration file detected!") 19 | endif() 20 | 21 | if (CMAKE_HOST_WIN32) 22 | set(SUPPRESS_OUTPUT > NUL 2>&1) 23 | elseif(CMAKE_HOST_LINUX) 24 | set(SUPPRESS_OUTPUT > /dev/null 2>&1) 25 | endif() 26 | 27 | add_custom_target(isogen ALL 28 | COMMAND ${OBJCOPY} -g ${OUTPUT_DIR}/oboskrnl ${ISODIR}/obos/oboskrnl ${SUPPRESS_OUTPUT} 29 | COMMAND cmake -E copy ${CMAKE_SOURCE_DIR}/config/hyper.cfg ${ISODIR}/ ${SUPPRESS_OUTPUT} 30 | COMMAND cmake -E copy ${CMAKE_SOURCE_DIR}/dependencies/hyper/hyper_iso_boot ${ISODIR} ${SUPPRESS_OUTPUT} 31 | COMMAND cmake -E copy ${CMAKE_SOURCE_DIR}/config/hyper_uefi_boot.bin ${ISODIR} ${SUPPRESS_OUTPUT} 32 | COMMAND cmake -E copy ${CMAKE_SOURCE_DIR}/out/initrd ${ISODIR}/obos ${SUPPRESS_OUTPUT} 33 | COMMAND cmake -E copy ${CMAKE_SOURCE_DIR}/config/initrd.tar ${ISODIR}/obos ${SUPPRESS_OUTPUT} 34 | COMMAND xorriso -as mkisofs -b hyper_iso_boot -no-emul-boot -boot-load-size 4 -boot-info-table --efi-boot hyper_uefi_boot.bin -efi-boot-part --efi-boot-image --protective-msdos-label out/isodir -o ${OUTPUT_DIR}/obos.iso ${SUPPRESS_OUTPUT} 35 | COMMAND chmod +x ${hyper_install} 36 | COMMAND ${hyper_install} ${OUTPUT_DIR}/obos.iso ${SUPPRESS_OUTPUT} 37 | SOURCES ${CMAKE_SOURCE_DIR}/config/hyper.cfg ${CMAKE_SOURCE_DIR}/config/hyper_uefi_boot.bin ${CMAKE_SOURCE_DIR}/dependencies/hyper/hyper_iso_boot ${CMAKE_SOURCE_DIR}/config/initrd.tar 38 | BYPRODUCTS ${ISODIR}/hyper.cfg 39 | BYPRODUCTS ${ISODIR}/EFI/BOOT/BOOTX64.efi 40 | BYPRODUCTS ${ISODIR}/hyper_iso_boot 41 | BYPRODUCTS ${ISODIR}/obos/oboskrnl 42 | BYPRODUCTS ${ISODIR}/obos/initrd 43 | BYPRODUCTS ${ISODIR}/obos/initrd.tar 44 | BYPRODUCTS ${OUTPUT_DIR}/obos.iso 45 | WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} 46 | COMMENT "Generating ${OUTPUT_DIR}/obos.iso" 47 | ) 48 | add_dependencies(isogen oboskrnl) 49 | if (EXISTS initrd) 50 | add_dependencies(isogen initrd) 51 | endif() 52 | -------------------------------------------------------------------------------- /src/oboskrnl/allocators/basic_allocator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/allocators/basic_allocator.c 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | #define MEMBLOCK_MAGIC 0x6AB450AA 17 | #define PAGEBLOCK_MAGIC 0x768AADFC 18 | #define MEMBLOCK_DEAD 0x3D793CCD 19 | #define OBOS_BASIC_ALLOCATOR_MAGIC (0x7E046A92E7735) 20 | 21 | #define OBOS_NODE_ADDR(n) ((void*)(n + 1)) 22 | 23 | enum blockSource 24 | { 25 | BLOCK_SOURCE_INVALID = -1, // It is an error to get this. 26 | BLOCK_SOURCE_PHYSICAL_MEMORY, // See allocateBlock "if ((allocator_info*)This == Mm_Allocator)" 27 | BLOCK_SOURCE_BASICMM, // OBOS_BasicMMAllocatePages 28 | BLOCK_SOURCE_VMA, // Mm_AllocateVirtualMemory 29 | }; 30 | 31 | typedef struct freelist_node { 32 | struct freelist_node *next, *prev; 33 | } freelist_node; 34 | 35 | _Static_assert(sizeof(freelist_node) <= 16, "Internal bug, report this."); 36 | 37 | typedef struct freelist { 38 | freelist_node *head, *tail; 39 | size_t nNodes; 40 | } freelist; 41 | 42 | enum { 43 | REGION_MAGIC = 0xb49ad907c56c8 44 | }; 45 | 46 | typedef struct cache { 47 | freelist free; 48 | spinlock lock; 49 | } cache; 50 | 51 | typedef struct basic_allocator 52 | { 53 | allocator_info header; 54 | cache caches[28]; 55 | enum blockSource blkSource; 56 | } basic_allocator; 57 | 58 | obos_status OBOSH_ConstructBasicAllocator(basic_allocator* This); 59 | -------------------------------------------------------------------------------- /src/oboskrnl/arch/m68k/asm_helpers.S: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/m68k/asm_helpers.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | .cpu 68040 8 | 9 | // void setSR(uint32_t to); 10 | // uint32_t getSR(); 11 | .global setSR 12 | .global getSR 13 | .global pflush 14 | setSR: 15 | move.l (+4,%a7), %d0 16 | move.w %d0, %sr 17 | rts 18 | getSR: 19 | move.w %sr, %d0 20 | rts 21 | pflush: 22 | move.l (4, %sp), %a0 23 | pflush %a0 24 | rts -------------------------------------------------------------------------------- /src/oboskrnl/arch/m68k/asm_helpers.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/m68k/asm_helpers.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | void setSR(uint16_t to); 12 | uint16_t getSR(); 13 | void pflush(uintptr_t virt); 14 | // Calls the interrupt vector at 'vector' 15 | void Arch_SimulateIRQ(uint8_t vector); -------------------------------------------------------------------------------- /src/oboskrnl/arch/m68k/boot_info.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/m68k/boot_info.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | typedef enum BootInfoType 11 | { 12 | BootInfoType_Last = 0, 13 | BootInfoType_MachType = 1, 14 | BootInfoType_CpuType = 2, 15 | BootInfoType_FpuType = 3, 16 | BootInfoType_MmuType = 4, 17 | BootInfoType_MemChunk = 5, 18 | BootInfoType_InitRd = 6, 19 | BootInfoType_CommandLine = 7, 20 | BootInfoType_RngSeed = 8, 21 | 22 | BootInfoType_QemuVersion = 0x8000, 23 | BootInfoType_GoldfishPicBase = 0x8001, 24 | BootInfoType_GoldfishRtcBase = 0x8002, 25 | BootInfoType_GoldfishTtyBase = 0x8003, 26 | BootInfoType_VirtioBase = 0x8004, 27 | BootInfoType_ControlBase = 0x8005 28 | } BootInfoType; 29 | 30 | typedef struct BootDeviceBase 31 | { 32 | uint32_t base; 33 | uint32_t irq; 34 | } BootDeviceBase; 35 | typedef struct BootInfoTag 36 | { 37 | uint16_t type; 38 | uint16_t size; 39 | } OBOS_PACK BootInfoTag; 40 | 41 | OBOS_EXPORT BootInfoTag* Arch_GetBootInfo(BootInfoType type); 42 | OBOS_EXPORT BootInfoTag* Arch_GetBootInfoFrom(BootInfoType type, BootInfoTag* tag); -------------------------------------------------------------------------------- /src/oboskrnl/arch/m68k/cpu_local_arch.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/m68k/cpu_local_arch.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | // deferred irq 12 | typedef struct m68k_dirq 13 | { 14 | struct m68k_dirq *next, *prev; 15 | size_t nDefers; 16 | // Is called after the defer happens 17 | void(*on_defer_callback)(void* udata); // used by the PIC code. 18 | void* udata; 19 | uint8_t irql; 20 | } m68k_dirq; 21 | typedef struct m68k_dirq_list 22 | { 23 | m68k_dirq *head, *tail; 24 | size_t nNodes; 25 | } m68k_dirq_list; 26 | typedef struct cpu_local_arch 27 | { 28 | m68k_dirq irqs[256]; 29 | m68k_dirq_list deferred; 30 | } cpu_local_arch; -------------------------------------------------------------------------------- /src/oboskrnl/arch/m68k/exception_handlers.c: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/m68k/exception_handlers.c 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | 18 | // well technically it's an access fault but whatever 19 | void Arch_PageFaultHandler(interrupt_frame* frame) 20 | { 21 | uint32_t mm_ec = 0; 22 | if (frame->format_7.ssw.atc) 23 | mm_ec &= ~PF_EC_PRESENT; 24 | if (!frame->format_7.ssw.rw) 25 | mm_ec |= PF_EC_RW; 26 | if (!(frame->sr & (1<<13) /* Supervisor */)) 27 | mm_ec |= PF_EC_UM; 28 | if (Mm_IsInitialized()) 29 | { 30 | mm_ec &= ~PF_EC_PRESENT; 31 | page_info curr = {}; 32 | context* ctx = CoreS_GetCPULocalPtr()->currentContext; 33 | MmS_QueryPageInfo(ctx->pt, frame->format_7.fa & ~0xfff, &curr, nullptr); 34 | if (curr.prot.present) 35 | mm_ec |= PF_EC_PRESENT; 36 | obos_status status = Mm_HandlePageFault(ctx, frame->format_7.fa & ~0xfff, mm_ec); 37 | switch (status) 38 | { 39 | case OBOS_STATUS_SUCCESS: 40 | return; 41 | case OBOS_STATUS_UNHANDLED: 42 | break; 43 | default: 44 | { 45 | static const char format[] = "Handling page fault with error code 0x%x on address %p failed.\n"; 46 | OBOS_Warning(format, mm_ec, frame->format_7.fa); 47 | break; 48 | } 49 | } 50 | } 51 | OBOS_Panic(OBOS_PANIC_EXCEPTION, 52 | "Access fault in %s-mode at 0x%p while trying to %s the %spresent page at 0x%p.\nRegister dump:\n" 53 | "d0: 0x%p, d1: 0x%p, d2: 0x%p, d3: 0x%p\n" 54 | "d1: 0x%p, d5: 0x%p, d6: 0x%p, d7: 0x%p\n" 55 | "a0: 0x%p, a1: 0x%p, a2: 0x%p, a3: 0x%p\n" 56 | "a4: 0x%p, a5: 0x%p, a6: 0x%p, sp: 0x%p\n" 57 | "pc: 0x%p, sr: 0x%p\n", 58 | (mm_ec & PF_EC_UM) ? "user" : "kernel", 59 | frame->pc, 60 | (mm_ec & PF_EC_RW) ? "write" : "read", 61 | (mm_ec & PF_EC_PRESENT) ? "" : "non-", 62 | frame->format_7.fa, 63 | frame->d0, frame->d1, frame->d2, frame->d3, 64 | frame->d4, frame->d5, frame->d6, frame->d7, 65 | frame->a0, frame->a1, frame->a2, frame->a3, 66 | frame->a4, frame->a5, frame->a6, frame->usp, 67 | frame->pc, frame->sr 68 | ); 69 | } -------------------------------------------------------------------------------- /src/oboskrnl/arch/m68k/goldfish_pic.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/m68k/goldfish_pic.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #include 12 | 13 | typedef struct pic_irq { 14 | uint8_t vector; 15 | bool masked; 16 | } pic_irq; 17 | typedef struct pic 18 | { 19 | uintptr_t base; 20 | uintptr_t phys_base; 21 | pic_irq irqs[32]; 22 | } pic; 23 | extern pic* Arch_PICBases; 24 | extern size_t Arch_PICCount; 25 | void Arch_PICClearPending(pic* on); 26 | void Arch_PICDisable(pic*, uint32_t line); 27 | void Arch_PICEnable(pic*, uint32_t line); 28 | uint8_t Arch_PICGetPendingCount(pic*); 29 | uint32_t Arch_PICGetPending(pic*); 30 | void Arch_PICRegisterIRQ(uint32_t line, uint8_t irq); 31 | void Arch_PICMaskIRQ(uint32_t line, bool mask); 32 | void Arch_PICHandleIRQ(interrupt_frame*); 33 | void Arch_PICHandleSpurious(interrupt_frame*); -------------------------------------------------------------------------------- /src/oboskrnl/arch/m68k/interrupt_frame.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/m68k/interrupt_frame.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | struct OBOS_PACK ssw_68040 { 13 | uint16_t cp : 1; 14 | uint16_t cu : 1; 15 | uint16_t ct : 1; 16 | uint16_t cm : 1; 17 | uint16_t ma : 1; 18 | uint16_t atc : 1; 19 | uint16_t lk : 1; 20 | uint16_t rw : 1; 21 | uint16_t x : 1; 22 | uint16_t size : 2; 23 | uint16_t tt : 2; 24 | uint16_t tm : 3; 25 | }; 26 | typedef struct interrupt_frame 27 | { 28 | uint32_t intNumber; 29 | uint32_t vector; // intNumber-64 30 | uintptr_t usp; 31 | uintptr_t d0,d1,d2,d3,d4,d5,d6,d7; 32 | uintptr_t a0,a1,a2,a3,a4,a5,a6; 33 | uint16_t padding; 34 | uint16_t sr; 35 | uintptr_t pc; 36 | uint16_t unused; 37 | struct format_7 38 | { 39 | // Effective address (whatever that means) 40 | uint32_t ea; 41 | struct ssw_68040 ssw; 42 | uint16_t wb3s, wb2s, wb1s; 43 | // Fault address 44 | uint32_t fa; 45 | uint32_t wb3a, wb3d, wb2a, fb2d, wb1a, wb1d; 46 | uint32_t pd1, pd2, pd3; 47 | } OBOS_PACK format_7; 48 | } OBOS_PACK interrupt_frame; -------------------------------------------------------------------------------- /src/oboskrnl/arch/m68k/irq.c: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/m68k/irq.c 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | uint32_t vector_base[256]; 21 | uintptr_t Arch_IRQHandlers[256]; 22 | extern void isr_stub(); 23 | 24 | void Arch_InitializeVectorTable() 25 | { 26 | for (size_t i = 0; i < 256; i++) 27 | vector_base[i] = (uintptr_t)isr_stub; 28 | asm volatile("movec.l %0, %%vbr;" : :"r"(vector_base) :); 29 | } 30 | void Arch_RawRegisterInterrupt(uint8_t vec, uintptr_t f) 31 | { 32 | Arch_IRQHandlers[vec] = f; 33 | } 34 | obos_status CoreS_RegisterIRQHandler(irq_vector_id vector, void(*handler)(interrupt_frame* frame)) 35 | { 36 | obos_status s = OBOS_STATUS_SUCCESS; 37 | if ((s = CoreS_IsIRQVectorInUse(vector)) && handler) 38 | return s; 39 | if ((uintptr_t)handler < OBOS_KERNEL_ADDRESS_SPACE_BASE && handler) 40 | return OBOS_STATUS_INVALID_ARGUMENT; 41 | Arch_IRQHandlers[vector + 0x40] = (uintptr_t)handler; 42 | return OBOS_STATUS_SUCCESS; 43 | } 44 | OBOS_PAGEABLE_FUNCTION obos_status CoreS_IsIRQVectorInUse(irq_vector_id vector) 45 | { 46 | if (vector > OBOS_MAX_INTERRUPT_VECTORS) 47 | return OBOS_STATUS_INVALID_ARGUMENT; 48 | return Arch_IRQHandlers[vector+0x40] ? OBOS_STATUS_IN_USE : OBOS_STATUS_SUCCESS; 49 | } -------------------------------------------------------------------------------- /src/oboskrnl/arch/m68k/isr.S: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/m68k/isr.S 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | .global isr_stub 8 | .global Arch_SimulateIRQ 9 | .extern Arch_IrqHandlers 10 | 11 | isr_stub: 12 | .cfi_startproc simple 13 | .cfi_signal_frame 14 | 15 | // Disable IRQs 16 | or #0x700, %sr 17 | 18 | // Align the stack 19 | move.w #0, -(%sp) 20 | 21 | .cfi_def_cfa %sp, 0 22 | .cfi_offset %pc, 4 23 | 24 | // Push the GPRs d0-d7 and a0-a6. 25 | // Functionally equivalent to a pushad on x86 26 | movem.l %d0-%d7/%a0-%a6, %sp@- 27 | .cfi_adjust_cfa_offset 60 28 | 29 | // Push the user stack pointer 30 | move.l %usp, %a0 31 | move.l %a0, %sp@- 32 | .cfi_adjust_cfa_offset 4 33 | 34 | // Push 'vector' 35 | move.l #0, %d0 36 | move.l #0, %d1 37 | move.w (0x48,%sp), %d0 38 | and #0xfff, %d0 39 | divu #4, %d0 40 | move.w %d0, %d1 41 | sub.l #64, %d1 42 | move.l %d1, -(%sp) 43 | move.l %d0, -(%sp) 44 | .cfi_adjust_cfa_offset 8 45 | 46 | // Call the handler 47 | mulu #4, %d0 48 | move.l (%d0,Arch_IRQHandlers), %a0 49 | 50 | move.l %sp, -(%sp) 51 | .cfi_adjust_cfa_offset 4 52 | 53 | cmp #0, %a0 54 | beq .L1 55 | 56 | jsr (%a0) 57 | 58 | .L1: 59 | // Restore GPRs 60 | 61 | add #12, %sp 62 | .cfi_adjust_cfa_offset -12 63 | 64 | move.l %sp@+, %a0 65 | move.l %a0, %usp 66 | .cfi_adjust_cfa_offset -4 67 | 68 | movem.l %sp@+, %d0-%d7/%a0-%a6 69 | .cfi_adjust_cfa_offset -60 70 | 71 | add #2, %sp 72 | 73 | rte 74 | .cfi_endproc 75 | // Simulates an incoming IRQ on the vector passed. 76 | Arch_SimulateIRQ: 77 | // d0: Contains the VBR. 78 | // d1: Contains the vector. 79 | // a0: Contains the vector handler. 80 | move.l (4,%sp), %d1 81 | movec.l %vbr, %d0 82 | mulu #4, %d1 83 | move.l %d1, %a0 84 | move.w %d1, %sp@- 85 | move.l #ret, %sp@- 86 | move.w %sr, %sp@- 87 | adda.l %d0, %a0 88 | move.l (%a0), %a0 89 | jmp (%a0) 90 | ret: 91 | rts -------------------------------------------------------------------------------- /src/oboskrnl/arch/m68k/loader/Allocator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | extern "C" 6 | { 7 | void* malloc(size_t length); 8 | void free(void* ptr, size_t length); 9 | } 10 | 11 | namespace sl 12 | { 13 | struct DefaultAllocator 14 | { 15 | constexpr DefaultAllocator() 16 | {} 17 | 18 | [[nodiscard]] 19 | inline void* Allocate(size_t length) 20 | { 21 | return malloc(length); 22 | } 23 | 24 | inline void Deallocate(void* ptr, size_t length) 25 | { 26 | free(ptr, length); 27 | } 28 | }; 29 | } -------------------------------------------------------------------------------- /src/oboskrnl/arch/m68k/loader/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # oboskrnl/arch/m68k/loader/CMakeLists.txt 2 | # 3 | # Copyright (c) 2024 Omar Berrow 4 | 5 | # CMake file for the m68k loader "borrowed" from northport 6 | 7 | add_executable(m68k_bootloader) 8 | 9 | target_sources(m68k_bootloader PRIVATE 10 | "Entry.S" "Main.cpp" "Loader.cpp" "Memory.cpp" 11 | "Syslib.cpp" "Util.cpp") 12 | 13 | add_dependencies(m68k_bootloader oboskrnl) 14 | 15 | set_source_files_properties( 16 | "Loader.cpp" 17 | PROPERTIES 18 | OBJECT_DEPENDS "${OUTPUT_DIR}/oboskrnl" 19 | ) 20 | 21 | target_compile_options(m68k_bootloader 22 | PRIVATE "-w" 23 | PRIVATE "-fstack-protector-strong" 24 | PRIVATE "-ffreestanding" 25 | PRIVATE "-std=c++17" 26 | PRIVATE "-fno-rtti" 27 | PRIVATE "-fno-exceptions" 28 | PRIVATE "-fno-unwind-tables" 29 | PRIVATE "-fno-asynchronous-unwind-tables" 30 | PRIVATE "-g" 31 | PRIVATE "-m68040" 32 | ) 33 | target_link_options(m68k_bootloader 34 | PRIVATE "-nostdlib" 35 | PRIVATE "-static" 36 | PRIVATE "-T" PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/Linker.lds" 37 | ) 38 | target_compile_definitions(m68k_bootloader 39 | PRIVATE NPL_ENABLE_LOGGING=1 40 | ) 41 | 42 | target_include_directories(m68k_bootloader PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) -------------------------------------------------------------------------------- /src/oboskrnl/arch/m68k/loader/Elf.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if __SIZEOF_POINTER__ == 8 4 | # error what are you doing? how the hell did you end up here? 5 | #elif __SIZEOF_POINTER__ == 4 6 | #include 7 | 8 | #define Elf_Addr Elf32_addr 9 | #define Elf_Off Elf32_Off 10 | #define Elf_Half Elf32_Half 11 | #define Elf_Word Elf32_Word 12 | #define Elf_Sword Elf32_Sword 13 | #define Elf_Xword Elf32_Xword 14 | #define Elf_Sxword Elf32_Sxword 15 | #define Elf_UnsignedChar Elf32_UnsignedChar 16 | #define Elf_Ehdr Elf32_Ehdr 17 | #define Elf_Shdr Elf32_Shdr 18 | #define Elf_Sym Elf32_Sym 19 | #define Elf_Rel Elf32_Rel 20 | #define Elf_Rela Elf32_Rela 21 | #define Elf_Phdr Elf32_Phdr 22 | #define Elf_Dyn Elf32_Dyn 23 | 24 | #define ELF_ST_BIND ELF32_ST_BIND 25 | #define ELF_ST_TYPE ELF32_ST_TYPE 26 | #define ELF_ST_INFO ELF32_ST_INFO 27 | #define ELF_ST_VISIBILITY ELF32_ST_VISIBILITY 28 | #define ELF_R_TYPE ELF32_R_TYPE 29 | #define ELF_R_SYM ELF32_R_SYM 30 | #define ELF_R_INFO ELF32_R_INFO 31 | #else 32 | #error "Unsupported ELF spec" 33 | #endif 34 | #include 35 | 36 | namespace sl 37 | { 38 | bool ValidateElfHeader(const void* file, Elf_Half type); 39 | 40 | struct ComputedReloc 41 | { 42 | uintptr_t value; 43 | size_t length; 44 | bool usedSymbol; 45 | }; 46 | 47 | ComputedReloc ComputeRelocation(Elf_Word type, uintptr_t a, uintptr_t b, uintptr_t s, uintptr_t p); 48 | 49 | sl::Vector FindPhdrs(const Elf_Ehdr* hdr, Elf_Word type); 50 | const Elf_Shdr* FindShdr(const Elf_Ehdr* hdr, const char* name); 51 | sl::Vector FindShdrs(const Elf_Ehdr* hdr, Elf_Word type); 52 | } -------------------------------------------------------------------------------- /src/oboskrnl/arch/m68k/loader/Entry.S: -------------------------------------------------------------------------------- 1 | .global LoaderEntry 2 | .global LoaderExit 3 | 4 | .extern LoaderEntryNext 5 | 6 | LoaderEntry: 7 | lea StackTop, %a7 8 | jmp LoaderEntryNext 9 | 10 | # void LoaderExit(uintptr_t hhdmbase, uintptr_t jumpTarget) 11 | LoaderExit: 12 | move.l 8(%a7), %a0 13 | 14 | lea StackTop, %a1 15 | add.l 4(%a7), %a1 16 | exg %a1, %a7 17 | 18 | move.l #0, -(%a7) 19 | move.l #0, -(%a7) 20 | jmp (%a0) 21 | 22 | .section .bss 23 | .align 16 24 | StackBase: 25 | .zero 0x4000 26 | StackTop: 27 | -------------------------------------------------------------------------------- /src/oboskrnl/arch/m68k/loader/LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Dean T. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/oboskrnl/arch/m68k/loader/Linker.lds: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT(elf32-m68k) 2 | 3 | ENTRY(LoaderEntry) 4 | 5 | PHDRS 6 | { 7 | text PT_LOAD FLAGS((1 << 0) | (1 << 2)); 8 | rodata PT_LOAD FLAGS((1 << 2)); 9 | data PT_LOAD FLAGS((1 << 1) | (1 << 2)); 10 | } 11 | 12 | SECTIONS 13 | { 14 | . = 0x1000; 15 | 16 | LOADER_BLOB_BEGIN = .; 17 | .text : 18 | { 19 | *(.text) 20 | *(.text.*) 21 | } :text 22 | 23 | . += CONSTANT(MAXPAGESIZE); 24 | 25 | .rodata : 26 | { 27 | *(.rodata) 28 | *(.rodata.*) 29 | } :rodata 30 | 31 | . += CONSTANT(MAXPAGESIZE); 32 | 33 | .data : 34 | { 35 | *(.data) 36 | *(.data.*) 37 | } :data 38 | 39 | .bss : 40 | { 41 | *(COMMON) 42 | *(.bss) 43 | } :data 44 | 45 | /DISCARD/ : 46 | { 47 | *(.note) 48 | *(.note.*) 49 | } 50 | LOADER_BLOB_END = .; 51 | } 52 | -------------------------------------------------------------------------------- /src/oboskrnl/arch/m68k/loader/Loader.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace Npl 7 | { 8 | bool LoadKernel(); 9 | void ExecuteKernel(); 10 | void GetKernelBases(uint64_t* phys, uint64_t* virt); 11 | 12 | struct LbpRequest 13 | { 14 | uint64_t id[4]; 15 | uint64_t revision; 16 | union 17 | { 18 | uint64_t pad; 19 | void* response; 20 | }; 21 | }; 22 | 23 | LbpRequest* LbpNextRequest(LbpRequest* current = nullptr); 24 | } 25 | -------------------------------------------------------------------------------- /src/oboskrnl/arch/m68k/loader/Memory.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace Npl 7 | { 8 | constexpr uintptr_t DontCare = 0; 9 | constexpr uintptr_t HhdmBase = 0x8000'0000; 10 | 11 | enum class MemoryType 12 | { 13 | Usable, 14 | Reclaimable, 15 | KernelModules, 16 | }; 17 | 18 | void InitMemoryManager(); 19 | void EnableMmu(); 20 | size_t HhdmLimit(); 21 | size_t GenerateLbpMemoryMap(void* store, size_t count); 22 | 23 | uintptr_t AllocPages(size_t count, MemoryType type = MemoryType::Reclaimable); 24 | void* AllocGeneral(size_t size); 25 | void* MapMemory(size_t length, uintptr_t vaddr, uintptr_t paddr = DontCare); 26 | uintptr_t GetMap(uintptr_t vaddr); 27 | } 28 | 29 | // NOTE(oberrow): 30 | // Taken from https://github.com/DeanoBurrito/northport/blob/730f3c531f6190c238801f1abe180c1e0c8c61de/libs/np-syslib/include/Memory.h 31 | namespace sl 32 | { 33 | template 34 | void memsetT(void* const start, T value, size_t valueCount) 35 | { 36 | T* const si = reinterpret_cast(start); 37 | 38 | for (size_t i = 0; i < valueCount; i++) 39 | si[i] = value; 40 | } 41 | 42 | void* memset(void* const start, uint8_t val, size_t count); 43 | 44 | void* memcopy(const void* const source, void* const destination, size_t count); 45 | void* memcopy(const void* const source, size_t sourceOffset, void* const destination, size_t destOffset, size_t count); 46 | 47 | int memcmp(const void* const a, const void* const b, size_t count); 48 | int memcmp(const void* const a, size_t offsetA, const void* const b, size_t offsetB, size_t count); 49 | 50 | size_t memfirst(const void* const buff, uint8_t target, size_t upperLimit); 51 | size_t memfirst(const void* const buff, size_t offset, uint8_t target, size_t upperLimit); 52 | } 53 | 54 | //These MUST be provided by the program, we'll forward declare them here to make them available. 55 | extern "C" 56 | { 57 | void* malloc(size_t length); 58 | void free(void* ptr, size_t length); 59 | 60 | //clang requires these to exist for __builtin_xyz, while GCC provides its own. 61 | void* memcpy(void* dest, const void* src, size_t len); 62 | void* memset(void* dest, int value, size_t len); 63 | void* memmove(void* dest, const void* src, size_t len); 64 | } -------------------------------------------------------------------------------- /src/oboskrnl/arch/m68k/loader/Util.cpp: -------------------------------------------------------------------------------- 1 | #include "Util.h" 2 | #include 3 | 4 | #ifdef NPL_ENABLE_LOGGING 5 | #define NANOPRINTF_USE_FIELD_WIDTH_FORMAT_SPECIFIERS 1 6 | #define NANOPRINTF_USE_PRECISION_FORMAT_SPECIFIERS 1 7 | #define NANOPRINTF_USE_FLOAT_FORMAT_SPECIFIERS 0 8 | #define NANOPRINTF_USE_LARGE_FORMAT_SPECIFIERS 0 9 | #define NANOPRINTF_USE_BINARY_FORMAT_SPECIFIERS 0 10 | #define NANOPRINTF_USE_WRITEBACK_FORMAT_SPECIFIERS 0 11 | 12 | #define NANOPRINTF_IMPLEMENTATION 13 | #include 14 | #endif 15 | 16 | namespace Npl 17 | { 18 | void Panic(PanicReason r) 19 | { 20 | NPL_LOG("LOADER PANIC: %u", (unsigned)r); 21 | asm("clr %d1; add #0xDEAD, %d1"); 22 | asm("clr %d2; add #0xDEAD, %d2"); 23 | asm("clr %d3; add #0xDEAD, %d3"); 24 | while (true) 25 | asm("stop #0x2700"); 26 | __builtin_unreachable(); 27 | } 28 | 29 | sl::CNativePtr FindBootInfoTag(BootInfoType type, sl::CNativePtr begin) 30 | { 31 | constexpr size_t ReasonableSearchCount = 50; 32 | 33 | if (begin.ptr == nullptr) 34 | begin = sl::AlignUp((uintptr_t)LOADER_BLOB_END, 2); 35 | 36 | for (size_t i = 0; i < ReasonableSearchCount; i++) 37 | { 38 | auto tag = begin.As(); 39 | if (tag->type == BootInfoType::Last) 40 | return nullptr; 41 | if (tag->type == type) 42 | return begin; 43 | begin = begin.Offset(tag->size); 44 | } 45 | 46 | return nullptr; 47 | } 48 | 49 | #ifdef NPL_ENABLE_LOGGING 50 | sl::NativePtr uart = nullptr; 51 | 52 | void UartWrite(int c, void* ignored) 53 | { 54 | (void)ignored; 55 | if (uart.ptr != nullptr) 56 | uart.Write(c); //registers are 32-bits wide 57 | } 58 | #endif 59 | } 60 | -------------------------------------------------------------------------------- /src/oboskrnl/arch/m68k/loader/Util.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "NativePtr.h" 4 | #include 5 | 6 | extern "C" 7 | { 8 | extern char LOADER_BLOB_BEGIN[]; 9 | extern char LOADER_BLOB_END[]; 10 | extern char KERNEL_BLOB_BEGIN[]; 11 | extern char KERNEL_BLOB_END[]; 12 | } 13 | 14 | namespace Npl 15 | { 16 | constexpr size_t PageSize = 0x1000; 17 | 18 | enum class PanicReason 19 | { 20 | KernelReturned = 1, 21 | InternalAllocFailure = 2, 22 | LoadAllocFailure = 3, 23 | StackCheckFail = 4, 24 | HhdmSetupFail = 5, 25 | BadLbpRevision = 6, 26 | DeleteCalled = 7, 27 | }; 28 | 29 | enum class BootInfoType : uint16_t 30 | { 31 | Last = 0, 32 | MachType = 1, 33 | CpuType = 2, 34 | FpuType = 3, 35 | MmuType = 4, 36 | MemChunk = 5, 37 | InitRd = 6, 38 | CommandLine = 7, 39 | RngSeed = 8, 40 | 41 | QemuVersion = 0x8000, 42 | GoldfishPicBase = 0x8001, 43 | GoldfishRtcBase = 0x8002, 44 | GoldfishTtyBase = 0x8003, 45 | VirtioBase = 0x8004, 46 | ControlBase = 0x8005 47 | }; 48 | 49 | struct [[gnu::packed]] BootInfoTag 50 | { 51 | BootInfoType type; 52 | uint16_t size; 53 | }; 54 | 55 | struct [[gnu::packed]] BootInfoMemChunk 56 | { 57 | uint32_t addr; 58 | uint32_t size; 59 | }; 60 | 61 | void Panic(PanicReason reason); 62 | sl::CNativePtr FindBootInfoTag(BootInfoType type, sl::CNativePtr begin = nullptr); 63 | 64 | #ifdef NPL_ENABLE_LOGGING 65 | extern sl::NativePtr uart; 66 | 67 | void UartWrite(int c, void* ignored); 68 | 69 | #define NPL_LOG(...) npf_pprintf(UartWrite, nullptr, __VA_ARGS__) 70 | #else 71 | #define NPL_LOG(msg, ...) do {} while(false) 72 | #endif 73 | } 74 | -------------------------------------------------------------------------------- /src/oboskrnl/arch/m68k/pmm.c: -------------------------------------------------------------------------------- 1 | /* 2 | oboskrnl/arch/x86_64/pmm.c 3 | 4 | Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | extern volatile struct limine_memmap_request Arch_MemmapRequest; 18 | extern volatile struct limine_hhdm_request Arch_HHDMRequest; 19 | extern volatile struct limine_memmap_request Arch_MemmapRequest; 20 | extern volatile struct limine_hhdm_request Arch_HHDMRequest; 21 | obos_pmem_map_entry* MmS_GetFirstPMemMapEntry(uintptr_t* index) 22 | { 23 | *index = 0; 24 | return Arch_MemmapRequest.response->entries[0]; 25 | } 26 | // returns nullptr at the end of the list. 27 | obos_pmem_map_entry* MmS_GetNextPMemMapEntry(obos_pmem_map_entry* current, uintptr_t* index) 28 | { 29 | OBOS_UNUSED(current); 30 | size_t nEntries = (Arch_MemmapRequest.response->entry_count); 31 | if (!nEntries) 32 | OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "No memory map entries.\n"); 33 | if ((*index) > nEntries) 34 | return nullptr; 35 | return Arch_MemmapRequest.response->entries[++(*index)]; 36 | } 37 | #define MAP_TO_HHDM(addr, type) ((type*)((uintptr_t)Arch_HHDMRequest.response->offset + (uintptr_t)(addr))) 38 | #define UNMAP_FROM_HHDM(addr) ((uintptr_t)(addr) - (uintptr_t)Arch_HHDMRequest.response->offset) 39 | 40 | OBOS_NO_UBSAN OBOS_NO_KASAN void* Arch_MapToHHDM(uintptr_t phys) 41 | { 42 | return MAP_TO_HHDM(phys, void); 43 | } 44 | OBOS_NO_UBSAN OBOS_NO_KASAN uintptr_t Arch_UnmapFromHHDM(void* virt) 45 | { 46 | return UNMAP_FROM_HHDM(virt); 47 | } 48 | void* MmS_MapVirtFromPhys(uintptr_t addr) 49 | { 50 | return Arch_MapToHHDM(addr); 51 | } 52 | uintptr_t MmS_UnmapVirtFromPhys(void* virt) 53 | { 54 | return Arch_UnmapFromHHDM(virt); 55 | } -------------------------------------------------------------------------------- /src/oboskrnl/arch/m68k/pmm.h: -------------------------------------------------------------------------------- 1 | /* 2 | oboskrnl/arch/x86_64/pmm.h 3 | 4 | Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | typedef struct limine_memmap_entry obos_pmem_map_entry; 15 | #define pmem_map_base base 16 | #define pmem_map_size length 17 | #define pmem_map_type type 18 | #define PHYSICAL_MEMORY_TYPE_USABLE LIMINE_MEMMAP_USABLE 19 | #define PHYSICAL_MEMORY_TYPE_RECLAIMABLE LIMINE_MEMMAP_ACPI_RECLAIMABLE 20 | #define PHYSICAL_MEMORY_TYPE_LOADER_RECLAIMABLE LIMINE_MEMMAP_LOADER_RECLAIMABLE 21 | 22 | void* Arch_MapToHHDM(uintptr_t phys); 23 | uintptr_t Arch_UnmapFromHHDM(void* virt); -------------------------------------------------------------------------------- /src/oboskrnl/arch/m68k/thread_ctx.c: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/m68k/thread_ctx.c 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #include "error.h" 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | // Thread context manipulation functions. 14 | 15 | void CoreS_SetThreadIRQL(thread_ctx* ctx, irql newIRQL) 16 | { 17 | ctx->irql = newIRQL; 18 | } 19 | irql CoreS_GetThreadIRQL(const thread_ctx* ctx) 20 | { 21 | return ctx->irql; 22 | } 23 | void* CoreS_GetThreadStack(const thread_ctx* ctx) 24 | { 25 | return ctx->stackBase; 26 | } 27 | size_t CoreS_GetThreadStackSize(const thread_ctx* ctx) 28 | { 29 | return ctx->stackSize; 30 | } 31 | obos_status CoreS_SetupThreadContext(thread_ctx* ctx, uintptr_t entry, uintptr_t arg1, bool makeUserMode, void* stackBase, size_t stackSize) 32 | { 33 | if (!ctx) 34 | return OBOS_STATUS_INVALID_ARGUMENT; 35 | ctx->pc = entry; 36 | if (!makeUserMode) 37 | ctx->sr |= (1<<13); 38 | ctx->sp = (uintptr_t)stackBase+stackSize; 39 | ctx->sp -= 4; 40 | *(uintptr_t*)ctx->sp = arg1; 41 | ctx->sp -= 4; 42 | *(uintptr_t*)ctx->sp = 0; 43 | ctx->stackBase = stackBase; 44 | ctx->stackSize = stackSize; 45 | return OBOS_STATUS_SUCCESS; 46 | } 47 | obos_status CoreS_FreeThreadContext(thread_ctx* ctx) 48 | { 49 | OBOS_UNUSED(ctx); 50 | return OBOS_STATUS_SUCCESS; 51 | } 52 | void CoreS_SetThreadPageTable(thread_ctx* ctx, page_table pt) 53 | { 54 | if (!pt || !ctx) 55 | return; 56 | ctx->urp = pt; 57 | } 58 | 59 | void CoreS_SetKernelStack(void* stck) 60 | { 61 | // TODO: Set kernel stack 62 | OBOS_UNUSED(stck); 63 | } -------------------------------------------------------------------------------- /src/oboskrnl/arch/m68k/thread_ctx.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/m68k/thread_ctx.asm 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | struct thread_context_info 17 | { 18 | // 0x00 19 | uintptr_t urp; 20 | // 0x04 21 | uintptr_t sp; 22 | // 0x08,0x0C,0x10,0x14,0x18,0x2C,0x30,0x34 23 | uintptr_t d0,d1,d2,d3,d4,d5,d6,d7; 24 | // 0x38,0x3C,0x40,0x44,0x48,0x4C,0x50 25 | uintptr_t a0,a1,a2,a3,a4,a5,a6; 26 | // 0x54 27 | uint16_t padding; 28 | // 0x56 29 | uint16_t sr; 30 | // 0x58 31 | uintptr_t pc; 32 | // 0x5c 33 | uint16_t unused; 34 | // 0x5e 35 | irql irql; 36 | // 0x61 37 | void* stackBase; 38 | // 0x65 39 | size_t stackSize; 40 | } OBOS_ALIGN(8); -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/asm_helpers.h: -------------------------------------------------------------------------------- 1 | /* 2 | oboskrnl/arch/x86_64/asm_helpers.h 3 | 4 | Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | void outb(uint16_t port, uint8_t data); 12 | void outw(uint16_t port, uint16_t data); 13 | void outd(uint16_t port, uint32_t data); 14 | uint8_t inb(uint16_t port); 15 | uint16_t inw(uint16_t port); 16 | uint32_t ind(uint16_t port); 17 | 18 | uintptr_t getCR0(); 19 | uintptr_t getCR2(); 20 | uintptr_t getCR3(); 21 | uintptr_t getCR4(); 22 | uintptr_t getCR8(); 23 | uintptr_t getEFER(); 24 | 25 | uintptr_t getDR6(); 26 | 27 | uint64_t rdtsc(); 28 | 29 | void __cpuid__(uint64_t initialEax, uint64_t initialEcx, uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx); 30 | 31 | uint64_t rdmsr(uint32_t msr); 32 | void wrmsr(uint32_t msr, uint64_t val); 33 | 34 | void pause(); 35 | 36 | void invlpg(uintptr_t addr); 37 | void wbinvd(); 38 | 39 | void xsave(void* region); 40 | 41 | void cli(); 42 | void sti(); 43 | void hlt(); -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/bgdt.asm: -------------------------------------------------------------------------------- 1 | ; oboskrnl/arch/x86_64/bgdt.asm 2 | 3 | ; Copyright (c) 2024 Omar Berrow 4 | 5 | [BITS 64] 6 | 7 | section .bss 8 | Arch_InitialISTStack: 9 | resb 0x20000 10 | global Arch_InitialISTStack:data hidden 11 | section .data 12 | align 1 13 | TSS: 14 | .rsv1: dd 0 15 | .rsp0: dq 0 16 | .rsp1: dq 0 17 | .rsp2: dq 0 18 | .rsv2: dq 0 19 | .ist0: dq 0 20 | .ist1: dq 0 21 | .ist2: dq 0 22 | .ist3: dq 0 23 | .ist4: dq 0 24 | .ist5: dq 0 25 | .ist6: dq 0 26 | .ist7: dq 0 27 | .rsv3: dq 0 28 | .rsv4: dw 0 29 | .iopb: dw 103 30 | .end: 31 | TSS_Len equ TSS.end-TSS 32 | global GDT:data hidden 33 | GDT: 34 | .null: dq 0 35 | .kcode: dq 0x00af9b000000ffff 36 | .kdata: dq 0x00af93000000ffff 37 | .tss_limitLow: dw 0 38 | .tss_baseLow: dw 0 39 | .tss_baseMiddle1: db 0 40 | .tss_access: db 0x89 41 | .tss_gran: db 0x40 42 | .tss_baseMiddle2: db 0 43 | .tss_baseHigh: dd 0 44 | .tss_resv1: dd 0 45 | .end: 46 | GDTPtr: 47 | .len: dw GDT.end-GDT-1 48 | .base: dq GDT 49 | section .text 50 | 51 | global Arch_InitBootGDT:function hidden 52 | 53 | Arch_InitBootGDT: 54 | push rbp 55 | mov rbp, rsp 56 | sub rsp, 10 57 | 58 | mov rax, TSS 59 | mov word [GDT.tss_limitLow], TSS_Len 60 | mov [GDT.tss_baseLow], ax 61 | mov rdx, rax 62 | shr rdx, 16 63 | mov [GDT.tss_baseMiddle1], dl 64 | shr rdx, 8 65 | mov [GDT.tss_baseMiddle2], dl 66 | shr rdx, 8 67 | mov [GDT.tss_baseHigh], edx 68 | 69 | lea rax, [Arch_InitialISTStack+0x20000] 70 | mov [TSS.ist0], rax 71 | 72 | lgdt [GDTPtr] 73 | 74 | mov ax, 0x18 75 | ltr ax 76 | 77 | mov ax, 0x10 78 | mov ds, ax 79 | mov ss, ax 80 | mov es, ax 81 | mov fs, ax 82 | mov gs, ax 83 | 84 | leave 85 | pop rax 86 | push 0x8 87 | push rax 88 | retfq 89 | global Arch_FlushGDT:function hidden 90 | Arch_FlushGDT: 91 | push rbp 92 | mov rbp, rsp 93 | 94 | lgdt [rdi] 95 | 96 | mov ax, 0x10 97 | mov ds, ax 98 | mov ss, ax 99 | mov es, ax 100 | mov fs, ax 101 | mov gs, ax 102 | 103 | mov ax, 0x28 104 | ltr ax 105 | 106 | leave 107 | pop rax 108 | push 0x8 109 | push rax 110 | retfq 111 | -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/boot_info.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/x86_64/boot_info.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | extern volatile struct ultra_memory_map_attribute* Arch_MemoryMap; 12 | extern volatile struct ultra_platform_info_attribute* Arch_LdrPlatformInfo; 13 | extern volatile struct ultra_kernel_info_attribute* Arch_KernelInfo; 14 | extern volatile struct ultra_module_info_attribute* Arch_KernelBinary; 15 | extern volatile struct ultra_module_info_attribute* Arch_InitialSwapBuffer; 16 | extern volatile struct ultra_framebuffer* Arch_Framebuffer; 17 | extern volatile struct ultra_boot_context* Arch_BootContext; -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/cmos.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/x86_64/cmos.h 3 | * 4 | * Copyright (c) 2025 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | enum { 13 | CMOS_SELECT = 0x70, 14 | CMOS_DATA = 0x71, 15 | }; 16 | 17 | // Century register should be fetched from the FADT 18 | enum { 19 | // 1-byte, range 0-60 20 | CMOS_REGISTER_SECONDS = 0x00, 21 | // 1-byte, range 0-60 22 | CMOS_REGISTER_MINUTES = 0x02, 23 | // 1-byte, range 0-23 in 24-hour mode, 0-12 in 12-hour mode 24 | CMOS_REGISTER_HOURS = 0x04, 25 | // 1-byte, range 1-7 26 | CMOS_REGISTER_WEEKDAY = 0x06, 27 | // 1-byte, range 0-31 28 | CMOS_REGISTER_DAY_OF_MONTH = 0x07, 29 | // 1-byte, range 1-12 30 | CMOS_REGISTER_MONTH = 0x08, 31 | // 1-byte, range 0-99 32 | CMOS_REGISTER_YEAR = 0x09, 33 | // 1-byte 34 | CMOS_REGISTER_STATUS_A = 0x0A, 35 | // 1-byte 36 | CMOS_REGISTER_STATUS_B = 0x0B, 37 | }; 38 | 39 | enum { 40 | CMOS_SUNDAY = 1, 41 | CMOS_MONDAY, 42 | CMOS_TUESDAY, 43 | CMOS_WEDNESDAY, 44 | CMOS_THURSDAY, 45 | CMOS_FRIDAY, 46 | CMOS_SATURDAY, 47 | }; 48 | 49 | typedef struct cmos_timeofday 50 | { 51 | uint8_t seconds; 52 | uint8_t minutes; 53 | uint8_t hours; 54 | uint8_t day_of_month; 55 | uint8_t month; 56 | uint16_t year; 57 | } cmos_timeofday; 58 | 59 | obos_status Arch_CMOSInitialize(); 60 | obos_status Arch_CMOSGetTimeOfDay(cmos_timeofday* time); 61 | 62 | obos_status SysS_ClockGet(int clock, long *secs, long *nsecs); -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/cpu_local_arch.h: -------------------------------------------------------------------------------- 1 | /* 2 | oboskrnl/arch/x86_64/cpu_local_arch.h 3 | 4 | Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | 17 | typedef struct cpu_local_arch 18 | { 19 | uint64_t gdtEntries[7]; 20 | struct 21 | { 22 | uint32_t rsv1; 23 | uint64_t rsp0; 24 | uint64_t rsp1; 25 | uint64_t rsp2; 26 | uint64_t rsv2; 27 | uint64_t ist0; 28 | uint64_t ist1; 29 | uint64_t ist2; 30 | uint64_t ist3; 31 | uint64_t ist4; 32 | uint64_t ist5; 33 | uint64_t ist6; 34 | uint64_t ist7; 35 | uint64_t rsv3; 36 | uint16_t rsv4; 37 | uint16_t iopb; 38 | } OBOS_PACK tss; 39 | // Size: 0x20000 bytes, divided into the IST1 stack (offset 0 to 0x10000), and the cpu temp stack (offset 0x10000 to 0x20000) 40 | void* ist_stack; 41 | void* startup_stack; // Size: 0x4000 bytes, freed after smp initialization. 42 | bool initializedSchedulerTimer; 43 | bool pf_handler_running; 44 | gdb_ctx dbg_ctx; 45 | dpc dbg_dpc; 46 | uint64_t stack_check_guard; 47 | uint8_t lapicId; 48 | } cpu_local_arch; 49 | -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/entry.asm: -------------------------------------------------------------------------------- 1 | ; oboskrnl/arch/x86_64/entry.asm 2 | 3 | ; Copyright (c) 2024 Omar Berrow 4 | 5 | [BITS 64] 6 | 7 | default rel 8 | 9 | ; Bootstrap code to initialize the stack guard. 10 | 11 | extern __stack_chk_guard 12 | extern Arch_disablePIC 13 | extern Arch_KernelEntry 14 | global Arch_KernelEntryBootstrap:function hidden 15 | Arch_KernelEntryBootstrap: 16 | cmp rsi, 0x554c5442 17 | je .ok ; should triple fault on failure 18 | xor rax,rax 19 | jmp rax ; All hope is lost. 20 | .ok: 21 | push rdi 22 | push rsi 23 | ; Get a hardware-generated random value. 24 | ; If both methods are unsupported, it will fallback to using the default value used. 25 | .rdrand: 26 | mov eax, 1 27 | xor ecx,ecx 28 | cpuid 29 | bt ecx, 30 30 | jnc .rdseed 31 | rdrand rax 32 | jnc .rdrand 33 | jmp .move 34 | .rdseed: 35 | mov eax, 7 36 | xor ecx,ecx 37 | cpuid 38 | bt ebx, 18 39 | jnc .done 40 | rdseed rax 41 | jnc .rdseed 42 | .move: 43 | ; Move the (likely) random value into the stack guard variable. 44 | mov [__stack_chk_guard], rax 45 | .done: 46 | call Arch_disablePIC 47 | ; Turn on cr0.WP (write protect) 48 | mov rax, cr0 49 | or rax, (1<<16) ; WP 50 | mov cr0, rax 51 | ; Restore rdi and rsi 52 | pop rsi 53 | pop rdi 54 | ; Call into the kernel entry. 55 | push 0 ; Make sure if the kernel entry returns, it triple faults and doesn't do goofy things. 56 | jmp Arch_KernelEntry 57 | global Arch_IdleTask:function hidden 58 | section .data 59 | global Arch_MakeIdleTaskSleep:data hidden 60 | Arch_MakeIdleTaskSleep: db 0 61 | section .text 62 | Arch_IdleTask: 63 | hlt 64 | cmp byte [Arch_MakeIdleTaskSleep], 1 65 | jne Arch_IdleTask 66 | cli 67 | .slp: 68 | pause 69 | cmp byte [Arch_MakeIdleTaskSleep], 1 70 | je .slp 71 | sti 72 | jmp Arch_IdleTask 73 | -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/gdbstub/alloc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/x86_64/gdbstub/alloc.c 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | void* Kdbg_Malloc(size_t sz) 13 | { 14 | return Allocate(OBOS_NonPagedPoolAllocator, sz, nullptr); 15 | } 16 | void* Kdbg_Calloc(size_t nObjs, size_t szObj) 17 | { 18 | return ZeroAllocate(OBOS_NonPagedPoolAllocator, nObjs, szObj, nullptr); 19 | } 20 | void* Kdbg_Realloc(void* ptr, size_t newSz) 21 | { 22 | return Reallocate(OBOS_NonPagedPoolAllocator, ptr, newSz, nullptr); 23 | } 24 | void Kdbg_Free(void* ptr) 25 | { 26 | size_t sz = 0; 27 | QueryBlockSize(OBOS_NonPagedPoolAllocator, ptr, &sz); 28 | Free(OBOS_NonPagedPoolAllocator, ptr, sz); 29 | } -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/gdbstub/alloc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/x86_64/gdbstub/alloc.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | // All memory for the gdb stub is allocated using the non-paged pool allocator 13 | 14 | void* Kdbg_Malloc(size_t sz); 15 | void* Kdbg_Calloc(size_t nObjs, size_t szObj); 16 | void* Kdbg_Realloc(void* ptr, size_t newSz); 17 | void Kdbg_Free(void* ptr); -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/gdbstub/bp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/x86_64/gdbstub/bp.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | // Removes a software breakpoint. 15 | obos_status Kdbg_GDB_z0(gdb_connection* con, const char* arguments, size_t argumentsLen, gdb_ctx* dbg_ctx, void* userdata); 16 | // Adds a software breakpoint. 17 | obos_status Kdbg_GDB_Z0(gdb_connection* con, const char* arguments, size_t argumentsLen, gdb_ctx* dbg_ctx, void* userdata); -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/gdbstub/breakpoint.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/x86_64/gdbstub/breakpoint.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | typedef LIST_HEAD(sw_breakpoint_list, struct sw_breakpoint) sw_breakpoint_list; 15 | LIST_PROTOTYPE(sw_breakpoint_list, struct sw_breakpoint, node); 16 | 17 | typedef struct sw_breakpoint 18 | { 19 | uintptr_t addr; 20 | uint8_t at; // the byte at addr before setting it to a breakpoint instruction 21 | LIST_NODE(sw_breakpoint_list, struct sw_breakpoint) node; 22 | } sw_breakpoint; -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/gdbstub/connection.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/x86_64/gdbstub/connection.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include 18 | 19 | typedef struct gdb_connection 20 | { 21 | // Communication context 22 | const driver_ftable* pipe_interface; 23 | dev_desc pipe; 24 | uint32_t flags; 25 | bool connection_active; 26 | 27 | // Connection context. 28 | struct 29 | { 30 | bool received_first; 31 | thread_node* last_thread; 32 | } q_ThreadInfo_ctx; 33 | // bool swbreak_supported; 34 | // bool hwbreak_supported; 35 | // bool multiprocess_supported; 36 | // bool vCont_supported; 37 | // bool errormessage_supported; 38 | // Bitfield: 39 | // bit 0: swbreak 40 | // bit 1: hwbreak 41 | // bit 2: multiprocess 42 | // bit 3: vCont 43 | // bit 4: error-message 44 | uint32_t gdb_supported; 45 | sw_breakpoint_list sw_breakpoints; 46 | } gdb_connection; 47 | typedef struct gdb_ctx 48 | { 49 | thread* interrupted_thread; 50 | thread_ctx interrupt_ctx; 51 | bool wake; 52 | } gdb_ctx; 53 | extern OBOS_EXPORT gdb_connection* Kdbg_CurrentConnection; 54 | 55 | uintptr_t KdbgH_hex2bin(const char* str, unsigned size); 56 | 57 | // Must be a pipe-style driver, or stuff will go wrong. 58 | obos_status Kdbg_ConnectionInitialize(gdb_connection* conn, const driver_ftable* pipe_interface, dev_desc pipe); 59 | obos_status Kdbg_ConnectionSendPacket(gdb_connection* conn, const char* packet); 60 | // *packet is guaranteed to be nul-terminated. 61 | obos_status Kdbg_ConnectionRecvPacket(gdb_connection* conn, char** packet, size_t* szPacket); 62 | // NOTE: Does not send the packet to change the ack status 63 | // You must do that yourself. 64 | obos_status Kdbg_ConnectionSetAck(gdb_connection* conn, bool ack); 65 | 66 | char* KdbgH_FormatResponse(const char* format, ...); 67 | // size needs to be the exact size of the output, or bad things will happen. 68 | char* KdbgH_FormatResponseSized(size_t size, const char* format, ...); -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/gdbstub/debug.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/x86_64/gdbstub/debug.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | 18 | extern bool Kdbg_Paused; 19 | 20 | OBOS_EXPORT void Kdbg_Break(); 21 | 22 | void Kdbg_CallDebugExceptionHandler(interrupt_frame* frame, bool isSource); 23 | void Kdbg_NotifyGDB(gdb_connection* con, uint8_t signal); 24 | 25 | void Kdbg_int3_handler(interrupt_frame* frame); 26 | void Kdbg_int1_handler(interrupt_frame* frame); 27 | 28 | void Kdbg_GeneralDebugExceptionHandler(gdb_connection* conn, gdb_ctx* dbg_ctx, bool isSource); -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/gdbstub/general_query.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/x86_64/gdbstub/general_query.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | obos_status Kdbg_GDB_qC(gdb_connection* con, const char* arguments, size_t argumentsLen, gdb_ctx* ctx, void* userdata); 15 | obos_status Kdbg_GDB_q_ThreadInfo(gdb_connection* con, const char* arguments, size_t argumentsLen, gdb_ctx* ctx, void* userdata); 16 | obos_status Kdbg_GDB_QStartNoAckMode(gdb_connection* con, const char* arguments, size_t argumentsLen, gdb_ctx* ctx, void* userdata); 17 | obos_status Kdbg_GDB_qSupported(gdb_connection* con, const char* arguments, size_t argumentsLen, gdb_ctx* ctx, void* userdata); 18 | obos_status Kdbg_GDB_qAttached(gdb_connection* con, const char* arguments, size_t argumentsLen, gdb_ctx* ctx, void* userdata); 19 | obos_status Kdbg_GDB_qRcmd(gdb_connection* con, const char* arguments, size_t argumentsLen, gdb_ctx* ctx, void* userdata); 20 | obos_status Kdbg_GDB_vMustReplyEmpty(gdb_connection* con, const char* arguments, size_t argumentsLen, gdb_ctx* ctx, void* userdata); -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/gdbstub/packet_dispatcher.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/x86_64/gdbstub/packet_dispatcher.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | typedef obos_status(*packet_handler)(gdb_connection* con, const char* arguments, size_t argumentsLen, gdb_ctx* ctx, void* userdata); 15 | void Kdbg_AddPacketHandler(const char* name, packet_handler handler, void* userdata); 16 | // packet must be nul-terminated 17 | // or bad stuff might happen. 18 | obos_status Kdbg_DispatchPacket(gdb_connection* con, const char* packet, size_t packetLen, gdb_ctx* ctx); -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/gdbstub/stop_reply.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/x86_64/gdbstub/stop_reply.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | // '?' packet 15 | // Queries the stop reason. 16 | obos_status Kdbg_GDB_query_halt(gdb_connection* con, const char* arguments, size_t argumentsLen, gdb_ctx* ctx, void* userdata); 17 | // Read Registers 18 | obos_status Kdbg_GDB_g(gdb_connection* con, const char* arguments, size_t argumentsLen, gdb_ctx* ctx, void* userdata); 19 | // Write Registers 20 | obos_status Kdbg_GDB_G(gdb_connection* con, const char* arguments, size_t argumentsLen, gdb_ctx* ctx, void* userdata); 21 | // Kill the kernel (shutdown) 22 | obos_status Kdbg_GDB_k(gdb_connection* con, const char* arguments, size_t argumentsLen, gdb_ctx* ctx, void* userdata); 23 | // Detach from gdb. 24 | obos_status Kdbg_GDB_D(gdb_connection* con, const char* arguments, size_t argumentsLen, gdb_ctx* ctx, void* userdata); 25 | // Read Memory 26 | obos_status Kdbg_GDB_m(gdb_connection* con, const char* arguments, size_t argumentsLen, gdb_ctx* ctx, void* userdata); 27 | // Write Memory 28 | obos_status Kdbg_GDB_M(gdb_connection* con, const char* arguments, size_t argumentsLen, gdb_ctx* ctx, void* userdata); 29 | // Queries thread status. 30 | obos_status Kdbg_GDB_T(gdb_connection* con, const char* arguments, size_t argumentsLen, gdb_ctx* ctx, void* userdata); 31 | // Step 32 | obos_status Kdbg_GDB_s(gdb_connection* con, const char* arguments, size_t argumentsLen, gdb_ctx* ctx, void* userdata); 33 | // Continue [at address] 34 | obos_status Kdbg_GDB_c(gdb_connection* con, const char* arguments, size_t argumentsLen, gdb_ctx* ctx, void* userdata); 35 | obos_status Kdbg_GDB_C(gdb_connection* con, const char* arguments, size_t argumentsLen, gdb_ctx* dbg_ctx, void* userdata); 36 | // These packets: g,G,k,m,M 37 | // But multithreaded 38 | obos_status Kdbg_GDB_H(gdb_connection* con, const char* arguments, size_t argumentsLen, gdb_ctx* ctx, void* userdata); -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/hpet_table.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/x86_64/hpet_table.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | typedef struct OBOS_PACK HPET_Addr 15 | { 16 | uint8_t addressSpaceId; 17 | uint8_t registerBitWidth; 18 | uint8_t registerBitOffset; 19 | uint8_t resv; 20 | uintptr_t address; 21 | } HPET_Addr; 22 | typedef struct OBOS_PACK HPET_Table 23 | { 24 | ACPISDTHeader sdtHeader; 25 | uint32_t eventTimerBlockID; 26 | HPET_Addr baseAddress; 27 | uint8_t hpetNumber; 28 | uint16_t mainCounterMinimum; 29 | uint8_t pageProtectionAndOEMAttrib; 30 | } HPET_Table; 31 | typedef struct OBOS_PACK HPET_Timer 32 | { 33 | volatile uint64_t timerConfigAndCapabilities; 34 | volatile uint64_t timerComparatorValue; 35 | volatile struct 36 | { 37 | uint32_t fsbIntVal; 38 | uint32_t fsbIntAddr; 39 | } timerFSBInterruptRoute; 40 | const volatile uint64_t resv; 41 | } HPET_Timer; 42 | typedef struct OBOS_PACK HPET 43 | { 44 | volatile const struct { 45 | uint8_t revisionId; 46 | uint8_t numTimCap : 4; 47 | bool countSizeCap : 1; 48 | bool resv1 : 1; 49 | bool legRouteCap : 1; 50 | uint16_t vendorID; 51 | uint32_t counterCLKPeriod; 52 | } OBOS_PACK generalCapabilitiesAndID; 53 | volatile const uint64_t resv1; 54 | volatile uint64_t generalConfig; 55 | volatile const uint64_t resv2; 56 | volatile uint64_t generalInterruptStatus; 57 | volatile const uint64_t resv3[0x19]; 58 | volatile uint64_t mainCounterValue; 59 | volatile const uint64_t resv4; 60 | volatile HPET_Timer timer0, timer1, timer2; 61 | // 0x160-0x400 are for timers 0-31 62 | } HPET; 63 | extern HPET* Arch_HPETAddress; 64 | extern uint64_t Arch_HPETFrequency; 65 | -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/idt.h: -------------------------------------------------------------------------------- 1 | /* 2 | oboskrnl/arch/x86_64/idt.h 3 | 4 | Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #include 12 | 13 | struct idtEntry 14 | { 15 | uint16_t offset1; 16 | uint16_t selector; 17 | uint8_t ist; 18 | uint8_t typeAttributes; 19 | uint16_t offset2; 20 | uint32_t offset3; 21 | uint32_t resv1; 22 | }; 23 | 24 | void Arch_InitializeIDT(bool isBSP); 25 | void Arch_RawRegisterInterrupt(uint8_t vec, uintptr_t f); 26 | void Arch_PutInterruptOnIST(uint8_t vec, uint8_t ist); -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/interrupt_frame.h: -------------------------------------------------------------------------------- 1 | /* 2 | oboskrnl/arch/x86_64/interrupt_frame.h 3 | 4 | Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #define BITFIELD_FROM_BIT(n) (1< 10 | 11 | #include 12 | 13 | typedef uint8_t irq_vector_id; 14 | #define OBOS_IRQ_VECTOR_ID_MAX (224 /* 256 vectors - the 32 reserved vectors */) 15 | #define OBOS_IRQ_VECTOR_ID_TO_IRQL(x) ((irql)(((x)>>4)+2)) 16 | #define OBOS_IRQL_TO_IRQ_VECTOR_ID(x) ((irq_vector_id)(((x)<<4)-0x20)) 17 | #define OBOS_IRQ_VECTOR_ID_COUNT_PER_IRQL (16) -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/lapic_timer_calibration.asm: -------------------------------------------------------------------------------- 1 | ; oboskrnl/arch/x86_64/lapic_timer_calibration.asm 2 | ; 3 | ; Copyright (c) 2024 Omar Berrow 4 | 5 | [BITS 64] 6 | 7 | global Arch_FindCounter:function hidden 8 | extern Arch_LAPICAddress 9 | extern Arch_HPETAddress 10 | extern Arch_CalibrateHPET 11 | 12 | ; uint64_t Arch_FindCounter(uint64_t hz); 13 | ; (input) rdi: The expected frequency of the LAPIC count. 14 | ; (output) rax: The timer count for the LAPIC, assuming the divisor is LAPIC_TIMER_DIVISIOR_ONE (0b1101) 15 | Arch_FindCounter: 16 | push rbp 17 | mov rbp, rsp 18 | push r15 19 | push r13 20 | 21 | call Arch_CalibrateHPET 22 | mov r15, rax 23 | mov r13, [Arch_LAPICAddress] 24 | mov r11, [Arch_HPETAddress] 25 | 26 | mov r13, [Arch_LAPICAddress] 27 | mov dword [r13+0x3E0], 0xB ; DIVISOR_ONE 28 | mov dword [r13+0x380], 0xffffffff 29 | 30 | ; Start the HPET timer. 31 | mov rax, [r11+0x10] 32 | or rax, (1<<0) 33 | mov [r11+0x10], rax 34 | 35 | add r11, 0xf0 36 | 37 | .loop: 38 | mov r9, [r11] 39 | cmp r9, r15 40 | jnge .loop 41 | 42 | xor r9,r9 43 | mov r9d, [r13+0x390] 44 | mov dword [r13+0x380], 0 45 | mov rax, 0xffffffff 46 | sub rax, r9 47 | 48 | .end: 49 | pop r13 50 | pop r15 51 | leave 52 | ret -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/madt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/x86_64/irq/madt.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #include 12 | 13 | typedef struct OBOS_PACK MADTTable 14 | { 15 | ACPISDTHeader sdtHeader; 16 | uint32_t lapicAddress; 17 | uint32_t unwanted; 18 | // There are more entries. 19 | } MADTTable; 20 | typedef struct OBOS_PACK MADT_EntryHeader 21 | { 22 | uint8_t type; 23 | uint8_t length; 24 | } MADT_EntryHeader; 25 | typedef struct OBOS_PACK MADT_EntryType0 26 | { 27 | MADT_EntryHeader entryHeader; 28 | uint8_t processorID; 29 | uint8_t apicID; 30 | uint32_t flags; 31 | } MADT_EntryType0; 32 | typedef struct OBOS_PACK MADT_EntryType1 33 | { 34 | MADT_EntryHeader entryHeader; 35 | uint8_t ioApicID; 36 | uint8_t resv1; 37 | uint32_t ioapicAddress; 38 | uint32_t globalSystemInterruptBase; 39 | } MADT_EntryType1; 40 | typedef struct OBOS_PACK MADT_EntryType2 41 | { 42 | MADT_EntryHeader entryHeader; 43 | uint8_t busSource; 44 | uint8_t irqSource; 45 | uint32_t globalSystemInterrupt; 46 | uint16_t flags; 47 | } MADT_EntryType2; 48 | typedef struct OBOS_PACK MADT_EntryType3 49 | { 50 | MADT_EntryHeader entryHeader; 51 | uint8_t nmiSource; 52 | uint8_t resv; 53 | uint16_t flags; 54 | uint32_t globalSystemInterrupt; 55 | } MADT_EntryType3; 56 | typedef struct OBOS_PACK MADT_EntryType4 57 | { 58 | MADT_EntryHeader entryHeader; 59 | uint8_t processorID; 60 | uint16_t flags; 61 | uint8_t lINT; 62 | } MADT_EntryType4; 63 | typedef struct OBOS_PACK MADT_EntryType5 64 | { 65 | MADT_EntryHeader entryHeader; 66 | uint8_t resv1[2]; 67 | uintptr_t lapic_address; 68 | } MADT_EntryType5; 69 | typedef struct OBOS_PACK MADT_EntryType9 70 | { 71 | MADT_EntryHeader entryHeader; 72 | uint8_t resv1[2]; 73 | uint32_t x2APIC_ID; 74 | uint32_t flags; 75 | uint32_t acpiID; 76 | } MADT_EntryType9; -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/memmanip.asm: -------------------------------------------------------------------------------- 1 | ; oboskrnl/arch/x86_64/memmanip.asm 2 | ; 3 | ; Copyright (c) 2024 Omar Berrow 4 | 5 | [BITS 64] 6 | 7 | global memset:function default 8 | global memzero:function default 9 | global memcpy:function default 10 | global memcmp:function default 11 | global memcmp_b:function default 12 | global strcmp:function default 13 | global strlen:function default 14 | global strchr:function default 15 | 16 | section .text 17 | 18 | memset: 19 | push rbp 20 | mov rbp, rsp 21 | 22 | push rdi 23 | mov al, sil 24 | mov rcx, rdx 25 | rep stosb 26 | pop rax 27 | 28 | leave 29 | ret 30 | memzero: 31 | push rbp 32 | mov rbp, rsp 33 | 34 | push rdi 35 | xor eax, eax 36 | mov rcx, rsi 37 | rep stosb 38 | pop rax 39 | 40 | leave 41 | ret 42 | memcpy: 43 | push rbp 44 | mov rbp, rsp 45 | 46 | mov rax, rdi 47 | mov rcx, rdx 48 | rep movsb 49 | 50 | leave 51 | ret 52 | memcmp: 53 | push rbp 54 | mov rbp, rsp 55 | 56 | mov rcx, rdx 57 | repe cmpsb 58 | sete al 59 | 60 | leave 61 | ret 62 | memcmp_b: 63 | push rbp 64 | mov rbp, rsp 65 | 66 | mov al, sil 67 | mov rcx, rdx 68 | repe scasb 69 | sete al 70 | 71 | leave 72 | ret 73 | strcmp: 74 | push rbp 75 | mov rbp, rsp 76 | sub rsp, 0x8 77 | 78 | push rdi 79 | push rsi 80 | call strlen 81 | mov [rbp-8], rax 82 | mov rdi, rsi 83 | call strlen 84 | pop rsi 85 | pop rdi 86 | cmp rax, [rbp-8] 87 | sete al 88 | jne .end 89 | 90 | mov rdx, [rbp-8] 91 | call memcmp 92 | 93 | .end: 94 | leave 95 | ret 96 | strlen: 97 | push rbp 98 | mov rbp, rsp 99 | 100 | xor rcx, rcx 101 | not rcx 102 | xor eax,eax 103 | repne scasb 104 | sub rax, rcx 105 | sub rax, 2 106 | 107 | leave 108 | ret 109 | strchr: 110 | push rbp 111 | mov rbp, rsp 112 | 113 | push rdi 114 | call strlen 115 | pop rdi 116 | mov r8, rax 117 | cld 118 | mov rcx, rax 119 | mov rax, rsi 120 | repne scasb 121 | sub r8, rcx 122 | mov rax, r8 123 | 124 | leave 125 | ret 126 | -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/mtrr.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/x86_64/mtrr.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | // Only to be called once on the BSP 12 | void Arch_SaveMTRRs(); 13 | // Can be called on any CPU any amount of times. 14 | void Arch_RestoreMTRRs(); 15 | -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/pmm.c: -------------------------------------------------------------------------------- 1 | /* 2 | oboskrnl/arch/x86_64/pmm.c 3 | 4 | Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | extern struct ultra_memory_map_attribute* Arch_MemoryMap; 17 | extern struct ultra_platform_info_attribute* Arch_LdrPlatformInfo; 18 | obos_pmem_map_entry* MmS_GetFirstPMemMapEntry(uintptr_t* index) 19 | { 20 | *index = 0; 21 | return &Arch_MemoryMap->entries[0]; 22 | } 23 | // returns nullptr at the end of the list. 24 | obos_pmem_map_entry* MmS_GetNextPMemMapEntry(obos_pmem_map_entry* current, uintptr_t* index) 25 | { 26 | OBOS_UNUSED(current); 27 | size_t nEntries = (Arch_MemoryMap->header.size - sizeof(Arch_MemoryMap->header)) / sizeof(struct ultra_memory_map_entry); 28 | if (!nEntries) 29 | OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "No memory map entries.\n"); 30 | if ((*index) > nEntries) 31 | return nullptr; 32 | return &Arch_MemoryMap->entries[++(*index)]; 33 | } 34 | #define MAP_TO_HHDM(addr, type) ((type*)(Arch_LdrPlatformInfo->higher_half_base + (uintptr_t)(addr))) 35 | #define UNMAP_FROM_HHDM(addr) ((uintptr_t)(addr) - Arch_LdrPlatformInfo->higher_half_base) 36 | 37 | OBOS_NO_KASAN OBOS_NO_UBSAN __attribute__((no_instrument_function)) void* Arch_MapToHHDM(uintptr_t phys) 38 | { 39 | return MAP_TO_HHDM(phys, void); 40 | } 41 | OBOS_NO_KASAN OBOS_NO_UBSAN __attribute__((no_instrument_function)) uintptr_t Arch_UnmapFromHHDM(void* virt) 42 | { 43 | return UNMAP_FROM_HHDM(virt); 44 | } 45 | 46 | __attribute__((no_instrument_function)) OBOS_EXPORT void* MmS_MapVirtFromPhys(uintptr_t addr) 47 | { 48 | return Arch_MapToHHDM(addr); 49 | } 50 | 51 | __attribute__((no_instrument_function)) OBOS_EXPORT uintptr_t MmS_UnmapVirtFromPhys(void* virt) 52 | { 53 | return Arch_UnmapFromHHDM(virt); 54 | } 55 | -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/pmm.h: -------------------------------------------------------------------------------- 1 | /* 2 | oboskrnl/arch/x86_64/pmm.h 3 | 4 | Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | typedef struct ultra_memory_map_entry obos_pmem_map_entry; 15 | #define pmem_map_base physical_address 16 | #define pmem_map_size size 17 | #define pmem_map_type type 18 | #define PHYSICAL_MEMORY_TYPE_USABLE ULTRA_MEMORY_TYPE_FREE 19 | #define PHYSICAL_MEMORY_TYPE_RECLAIMABLE ULTRA_MEMORY_TYPE_RECLAIMABLE 20 | #define PHYSICAL_MEMORY_TYPE_LOADER_RECLAIMABLE ULTRA_MEMORY_TYPE_LOADER_RECLAIMABLE 21 | 22 | void* Arch_MapToHHDM(uintptr_t phys); 23 | uintptr_t Arch_UnmapFromHHDM(void* virt); -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/sdt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/x86_64/sdt.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | typedef struct OBOS_PACK ACPIRSDPHeader { 13 | char Signature[8]; 14 | uint8_t Checksum; 15 | char OEMID[6]; 16 | uint8_t Revision; 17 | uint32_t RsdtAddress; // Deprecated 18 | 19 | // Fields only valid if Revision != 0 20 | uint32_t Length; 21 | uint64_t XsdtAddress; 22 | uint8_t ExtendedChecksum; 23 | uint8_t reserved[3]; 24 | } ACPIRSDPHeader; 25 | typedef struct OBOS_PACK ACPISDTHeader { 26 | char Signature[4]; 27 | uint32_t Length; 28 | uint8_t Revision; 29 | uint8_t Checksum; 30 | char OEMID[6]; 31 | char OEMTableID[8]; 32 | uint32_t OEMRevision; 33 | uint32_t CreatorID; 34 | uint32_t CreatorRevision; 35 | } ACPISDTHeader; -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/sse.c: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/x86_64/sse.c 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | 14 | static size_t xsave_size = 512; 15 | bool Arch_HasXSAVE = false; 16 | 17 | void* Arch_AllocateXSAVERegion() 18 | { 19 | return ZeroAllocate(OBOS_NonPagedPoolAllocator, 1, xsave_size, nullptr); 20 | } 21 | 22 | void Arch_FreeXSAVERegion(void* buf) 23 | { 24 | Free(OBOS_NonPagedPoolAllocator, buf, xsave_size); 25 | } 26 | 27 | // Enables stuff such as XSAVE, SSE(2), AVX, AVX512, etc. 28 | __attribute__((target("xsave"))) void Arch_EnableSIMDFeatures() 29 | { 30 | // Enable SSE. 31 | 32 | // Clear CR0.EM, set CR0.MP 33 | asm ("mov %0, %%cr0" : :"r"(getCR0() & ~BIT(2))); 34 | asm ("mov %0, %%cr0" : :"r"(getCR0() | BIT(1))); 35 | // Set CR4.OSFXSR, CR4.OSXMMEXCPT 36 | asm ("mov %0, %%cr4" : :"r"(getCR4() | BIT(9) | BIT(10))); 37 | 38 | // Enable XSAVE, if supported 39 | uint32_t ecx = 0; 40 | __cpuid__(0x1, 0x0, nullptr, nullptr, &ecx, nullptr); 41 | if (ecx & BIT(26)) 42 | { 43 | asm ("mov %0, %%cr4" : :"r"(getCR4() | BIT(18))); 44 | Arch_HasXSAVE = true; 45 | __cpuid__(0xd, 0, nullptr, nullptr, (uint32_t*)&xsave_size, nullptr); 46 | } 47 | 48 | // Enable AVX. 49 | if (ecx & BIT(28)) 50 | __builtin_ia32_xsetbv(0, __builtin_ia32_xgetbv(0)|0b111); 51 | 52 | // Enable AVX512. 53 | uint32_t eax = 0; 54 | __cpuid__(0xd, 0, &eax, nullptr,nullptr,nullptr); 55 | if (eax & (0x7<<5)) 56 | __builtin_ia32_xsetbv(0, __builtin_ia32_xgetbv(0) | (0x7<<5)); 57 | } 58 | 59 | size_t Arch_GetXSaveRegionSize() 60 | {return xsave_size;} 61 | -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/sse.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/x86_64/sse.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | void* Arch_AllocateXSAVERegion(); 12 | void Arch_FreeXSAVERegion(void* reg); 13 | // Enables stuff such as XSAVE, SSE(2), AVX, AVX512, etc. 14 | void Arch_EnableSIMDFeatures(); 15 | size_t Arch_GetXSaveRegionSize(); 16 | 17 | // Set to false if the thread context code should fallback to fxsave/fxrstor, 18 | // otherwise, the thread context code can and should use xsave/xrstor 19 | extern bool Arch_HasXSAVE; 20 | -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/thread_ctx.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/x86_64/thread_ctx.asm 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | // Don't forget to update this in the assembly code (thread_ctx.asm) 15 | struct thread_context_info 16 | { 17 | void* extended_ctx_ptr; 18 | uint8_t irql; 19 | uintptr_t cr3; 20 | uint64_t gs_base, fs_base; 21 | interrupt_frame frame; 22 | void* stackBase; 23 | size_t stackSize; 24 | void* signal_extended_ctx_ptr; 25 | } OBOS_ALIGN(8); 26 | 27 | extern void Arch_UserYield(void* kstck); 28 | -------------------------------------------------------------------------------- /src/oboskrnl/arch/x86_64/timer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/arch/x86_64/timer.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | // NOTE: To be called at > IRQL_PASSIVE. 12 | void Arch_InitializeSchedulerTimer(); 13 | -------------------------------------------------------------------------------- /src/oboskrnl/cmdline.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/cmdline.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | extern OBOS_EXPORT const char* OBOS_KernelCmdLine; 12 | extern OBOS_EXPORT const char* volatile OBOS_InitrdBinary; 13 | extern OBOS_EXPORT size_t volatile OBOS_InitrdSize; 14 | extern OBOS_EXPORT char** OBOS_argv; 15 | extern OBOS_EXPORT size_t OBOS_argc; 16 | extern size_t OBOS_InitArgumentsStart; // if SIZE_MAX, assume it doesn't exist 17 | extern size_t OBOS_InitArgumentsCount; 18 | 19 | // Parses the command line into OBOS_argv and OBOS_argc 20 | void OBOS_ParseCMDLine(); 21 | // Gets the value of a string command line option. 22 | OBOS_EXPORT char* OBOS_GetOPTS(const char* opt); 23 | // Gets the value of an integer command line option. 24 | OBOS_EXPORT uint64_t OBOS_GetOPTD(const char* opt); 25 | OBOS_EXPORT uint64_t OBOS_GetOPTD_Ex(const char* opt, uint64_t default_value); 26 | // Gets the value of a flag command line option. 27 | // true if the flag was found on the command line, otherwise false. 28 | OBOS_EXPORT bool OBOS_GetOPTF(const char* opt); 29 | -------------------------------------------------------------------------------- /src/oboskrnl/driver_interface/drv_sys.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/driver_interface/drv_sys.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | handle Sys_LoadDriver(const void* file, size_t szFile, obos_status* status); 14 | obos_status Sys_StartDriver(handle driver, handle* mainThread); 15 | obos_status Sys_UnloadDriver(handle driver); 16 | 17 | obos_status Sys_PnpLoadDriversAt(handle dent, bool wait); 18 | 19 | // Finds a loaded driver by its name, and returns a handle to it. 20 | // If the calling process has insufficient permissions, HANDLE_INVALID is returned. 21 | handle Sys_FindDriverByName(const char* name /* assumed to be 64-bytes at max */); 22 | 23 | // Returns the next driver in the list 24 | // The handle 'curr' is not automatically closed. 25 | // If 'curr' is HANDLE_INVALID, the first item in the list is returned. 26 | // If the calling process has insufficient permissions, HANDLE_INVALID is returned. 27 | handle Sys_EnumerateLoadedDrivers(handle curr); 28 | 29 | // Queries the name of the driver in 'drv'. 30 | // sznamebuf shall never be NULL. 31 | // sznamebuf is the size of the buffer passed, and *sznamebuf is set to the actual length of the string. 32 | // When copying the buffer, MIN(*sznamebuf, strlen(driverName)) is chosen. 33 | obos_status Sys_QueryDriverName(handle drv, char* namebuf, size_t *sznamebuf /* need not be over 64 */); 34 | -------------------------------------------------------------------------------- /src/oboskrnl/driver_interface/loader.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/driver_interface/loader.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include 18 | 19 | // gets the driver header of an unloaded driver 20 | obos_status Drv_LoadDriverHeader(const void* file, size_t szFile, driver_header* header); 21 | driver_id *Drv_LoadDriver(const void* file, size_t szFile, obos_status* status); 22 | obos_status Drv_StartDriver(driver_id* driver, thread** mainThread); 23 | obos_status Drv_UnloadDriver(driver_id* driver); 24 | 25 | // returns the base of the elf. 26 | // if this resolves a symbol from a driver while relocating, then it must add the driver to the dependency list. 27 | OBOS_WEAK void* DrvS_LoadRelocatableElf(driver_id* driver, const void* file, size_t szFile, Elf_Sym** dynamicSymbolTable, size_t* nEntriesDynamicSymbolTable, const char** dynstrtab, void** top, obos_status* status); 28 | 29 | // if the value set at *driver is nullptr, then the symbol is from the kernel 30 | driver_symbol* DrvH_ResolveSymbol(const char* name, struct driver_id** driver); 31 | driver_symbol* DrvH_ResolveSymbolReverse(uintptr_t addr, struct driver_id** driver); -------------------------------------------------------------------------------- /src/oboskrnl/driver_interface/pnp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/driver_interface/pnp.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | // every driver header in 'toLoad' is one found in 'what' 18 | // nodes are allocated using the general purpose kernel allocator. 19 | obos_status Drv_PnpDetectDrivers(driver_header_list what, driver_header_list *toLoad); 20 | obos_status Drv_PnpLoadDriversAt(dirent* directory, bool wait); -------------------------------------------------------------------------------- /src/oboskrnl/elf/elf.h: -------------------------------------------------------------------------------- 1 | #if OBOS_ARCHITECTURE_BITS == 64 2 | # include 3 | #elif OBOS_ARCHITECTURE_BITS == 32 4 | # include 5 | #else 6 | # error Unsupported OBOS_ARCHITECTURE_BITS value for elf. 7 | #endif 8 | -------------------------------------------------------------------------------- /src/oboskrnl/elf/load.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/elf/load.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | typedef struct elf_info { 15 | void* base; 16 | uintptr_t entry; 17 | uintptr_t real_entry; 18 | } elf_info; 19 | 20 | // if dryRun is true, nothing is mapped, but checks are still made on the ELF. 21 | // noLdr should always be false unless you know what you're doing. 22 | obos_status OBOS_LoadELF(context* ctx, const void* file, size_t szFile, elf_info* info, bool dryRun, bool noLdr); 23 | -------------------------------------------------------------------------------- /src/oboskrnl/execve.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/execve.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | // envp can be nullptr 16 | // argv can be nullptr 17 | obos_status Sys_ExecVE(const char* path, char* const* argv, char* const* envp); 18 | 19 | struct exec_aux_values { 20 | elf_info elf; 21 | 22 | struct { 23 | void* ptr; 24 | size_t phnum; 25 | size_t phent; 26 | } phdr; 27 | 28 | // NOTE: Make sure to free the next fields after copying them to whereever the process expects them. 29 | // Guaranteed to be allocated with OBOS_KernelAllocator. 30 | 31 | char** argv; 32 | char** envp; 33 | size_t argc; 34 | size_t envpc; 35 | }; 36 | 37 | OBOS_NORETURN OBOS_WEAK void OBOSS_HandControlTo(struct context* ctx, struct exec_aux_values* aux); 38 | -------------------------------------------------------------------------------- /src/oboskrnl/gpt.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/gpt.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #define GPT_SIGNATURE 0x5452415020494645 17 | typedef struct gpt_header 18 | { 19 | uint64_t signature; 20 | uint32_t revision; 21 | uint32_t size; // must be 92...blksize 22 | uint32_t checksum; // CRC32 (without this field) 23 | uint32_t resv1; 24 | uint64_t this_lba; 25 | uint64_t alt_lba; 26 | uint64_t first_lba; 27 | uint64_t last_lba; 28 | char disk_uuid[16]; 29 | uint64_t part_table_lba; 30 | uint32_t part_entry_count; 31 | uint32_t sizeof_partiton_entry; 32 | uint32_t partition_entry_checksum; 33 | // rest of fields are reserved. 34 | } OBOS_PACK gpt_header; 35 | typedef uint64_t gpt_partition_attrib; 36 | #define GPT_ATTRIB_REQUIRED = BIT_TYPE(0, UL) 37 | #define GPT_NO_BLOCK_IO = BIT_TYPE(1, UL) 38 | #define GPT_LEGACY_BIOS_BOOTABLE = BIT_TYPE(2, UL) 39 | #define GPT_TYPE_UUID_START = BIT_TYPE(48, UL) 40 | #define GPT_TYPE_UUID_END = BIT_TYPE(63, UL) 41 | typedef struct gpt_partition_entry 42 | { 43 | char uuid[16]; 44 | char part_uuid[16]; 45 | uint64_t begin_lba; 46 | uint64_t end_lba; 47 | uint64_t attributes; 48 | uint16_t part_name[36]; 49 | } OBOS_PACK gpt_partition_entry; 50 | obos_status OBOS_IdentifyGPTPartitions(fd* desc, partition* partition_list, size_t* nPartitions, bool allow_checksum_fail); -------------------------------------------------------------------------------- /src/oboskrnl/init_proc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/init_proc.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | void OBOS_LoadInit(); 13 | 14 | OBOS_NORETURN OBOS_WEAK void OBOSS_HandOffToInit(struct exec_aux_values* info); 15 | -------------------------------------------------------------------------------- /src/oboskrnl/irq/dpc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/irq/dpc.c 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | #include 20 | 21 | #include 22 | 23 | LIST_GENERATE(dpc_queue, dpc, node); 24 | 25 | dpc* CoreH_AllocateDPC(obos_status* status) 26 | { 27 | if (!OBOS_NonPagedPoolAllocator) 28 | return ZeroAllocate(OBOS_KernelAllocator, 1, sizeof(dpc), status); 29 | return ZeroAllocate(OBOS_NonPagedPoolAllocator, 1, sizeof(dpc), status); 30 | } 31 | obos_status CoreH_InitializeDPC(dpc* dpc, void(*handler)(struct dpc* obj, void* userdata), thread_affinity affinity) 32 | { 33 | if (!dpc || !handler) 34 | return OBOS_STATUS_INVALID_ARGUMENT; 35 | if (dpc->cpu) 36 | return OBOS_STATUS_DPC_ALREADY_ENQUEUED; 37 | // if (LIST_IS_NODE_UNLINKED(dpc_queue, &dpc->cpu->dpcs, dpc)) 38 | affinity &= Core_DefaultThreadAffinity; 39 | if (!affinity) 40 | affinity = Core_DefaultThreadAffinity; 41 | dpc->handler = handler; 42 | cpu_local* target = nullptr; 43 | for (size_t i = 0; i < Core_CpuCount; i++) 44 | if ((!target || Core_CpuInfo[i].dpcs.nNodes < target->dpcs.nNodes)) 45 | target = (affinity & CoreH_CPUIdToAffinity(Core_CpuInfo[i].id)) ? &Core_CpuInfo[i] : nullptr; 46 | // If this fails, something stupid has happened. 47 | OBOS_ENSURE(target); 48 | dpc->cpu = target; 49 | irql oldIrql = Core_SpinlockAcquireExplicit(&target->dpc_queue_lock, IRQL_MASKED, false); 50 | LIST_PREPEND(dpc_queue, &target->dpcs, dpc); 51 | Core_SpinlockRelease(&target->dpc_queue_lock, oldIrql); 52 | return OBOS_STATUS_SUCCESS; 53 | } 54 | obos_status CoreH_FreeDPC(dpc* dpc, bool dealloc) 55 | { 56 | if (!dpc) 57 | return OBOS_STATUS_INVALID_ARGUMENT; 58 | if (!dpc->handler || !dpc->cpu) 59 | return OBOS_STATUS_UNINITIALIZED; 60 | if (!LIST_IS_NODE_UNLINKED(dpc_queue, &dpc->cpu->dpcs, dpc)) 61 | { 62 | irql oldIrql = Core_SpinlockAcquire(&dpc->cpu->dpc_queue_lock); 63 | LIST_REMOVE(dpc_queue, &dpc->cpu->dpcs, dpc); 64 | Core_SpinlockRelease(&dpc->cpu->dpc_queue_lock, oldIrql); 65 | dpc->cpu = nullptr; 66 | } 67 | return dealloc ? Free(OBOS_NonPagedPoolAllocator, dpc, sizeof(*dpc)) : OBOS_STATUS_SUCCESS; 68 | } 69 | -------------------------------------------------------------------------------- /src/oboskrnl/irq/dpc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/irq/dpc.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | typedef LIST_HEAD(dpc_queue, struct dpc) dpc_queue; 17 | LIST_PROTOTYPE(dpc_queue, struct dpc, node); 18 | 19 | typedef struct dpc 20 | { 21 | LIST_NODE(dpc_queue, struct dpc) node; 22 | // The handler mustn't ever lower the irql below IRQL_DISPATCH 23 | // This is called at IRQL_DISPATCH. 24 | void(*handler)(struct dpc* dpc, void* userdata); 25 | void* userdata; 26 | struct cpu_local* cpu; 27 | } dpc; 28 | 29 | OBOS_EXPORT dpc* CoreH_AllocateDPC(obos_status* status); 30 | OBOS_EXPORT obos_status CoreH_InitializeDPC(dpc* dpc, void(*handler)(struct dpc* obj, void* userdata), thread_affinity affinity); 31 | OBOS_EXPORT obos_status CoreH_FreeDPC(dpc* dpc, bool dealloc); 32 | -------------------------------------------------------------------------------- /src/oboskrnl/locks/event.c: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/locks/event.c 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | obos_status Core_EventPulse(event* event, bool boostWaitingThreadPriority) 21 | { 22 | if (!event) 23 | return OBOS_STATUS_INVALID_ARGUMENT; 24 | irql oldIrql = Core_RaiseIrql(IRQL_DISPATCH); 25 | event->signaled = true; 26 | CoreH_SignalWaitingThreads((struct waitable_header*)&event->hdr, !(event->type == EVENT_SYNC), boostWaitingThreadPriority); 27 | event->signaled = false; 28 | CoreH_ClearSignaledState((struct waitable_header*)&event->hdr); 29 | Core_LowerIrql(oldIrql); 30 | return OBOS_STATUS_SUCCESS; 31 | } 32 | bool Core_EventGetState(const event* event) 33 | { 34 | if (!event) 35 | return false; 36 | return event->signaled; 37 | } 38 | obos_status Core_EventReset(event* event) 39 | { 40 | if (!event) 41 | return OBOS_STATUS_INVALID_ARGUMENT; 42 | event->signaled = false; 43 | CoreH_ClearSignaledState((struct waitable_header*)&event->hdr); 44 | return OBOS_STATUS_SUCCESS; 45 | } 46 | obos_status Core_EventSet(event* event, bool boostWaitingThreadPriority) 47 | { 48 | if (!event) 49 | return OBOS_STATUS_INVALID_ARGUMENT; 50 | // irql oldIrql = Core_RaiseIrql(IRQL_DISPATCH); 51 | CoreH_SignalWaitingThreads((struct waitable_header*)&event->hdr, !(event->type == EVENT_SYNC), boostWaitingThreadPriority); 52 | event->signaled = true; 53 | // Core_LowerIrql(oldIrql); 54 | return OBOS_STATUS_SUCCESS; 55 | } 56 | obos_status Core_EventClear(event* event) 57 | { 58 | // NOTE(oberrow): Are these functions supposed to be implemented differently? 59 | return Core_EventReset(event); 60 | } -------------------------------------------------------------------------------- /src/oboskrnl/locks/event.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/locks/event.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | 18 | typedef enum event_type 19 | { 20 | EVENT_NOTIFICATION, 21 | EVENT_SYNC, 22 | } event_type; 23 | typedef volatile struct event { 24 | struct waitable_header hdr; 25 | atomic_bool signaled; 26 | event_type type; 27 | } event; 28 | 29 | #define EVENT_INITIALIZE(t) (event){ .hdr=WAITABLE_HEADER_INITIALIZE(false, true), .signaled=0, .type=(t) } 30 | 31 | OBOS_EXPORT obos_status Core_EventPulse(event* event, bool boostWaitingThreadPriority); 32 | OBOS_EXPORT bool Core_EventGetState(const event* event); 33 | OBOS_EXPORT obos_status Core_EventReset(event* event); 34 | OBOS_EXPORT obos_status Core_EventSet(event* event, bool boostWaitingThreadPriority); 35 | OBOS_EXPORT obos_status Core_EventClear(event* event); -------------------------------------------------------------------------------- /src/oboskrnl/locks/mutex.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/locks/mutex.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | 18 | typedef struct mutex { 19 | struct waitable_header hdr; 20 | // Whether the mutex is locked or not. 21 | atomic_flag lock; 22 | bool locked; 23 | // set this when freeing an object. 24 | bool ignoreAllAndBlowUp; 25 | // The thread that took the mutex. 26 | thread* who; 27 | // The last lock time, in nanoseconds. 28 | uint64_t lastLockTimeNS; 29 | } mutex; 30 | 31 | #define MUTEX_INITIALIZE() (mutex){ .hdr=WAITABLE_HEADER_INITIALIZE(true, false), .locked=false, .who=nullptr } 32 | 33 | OBOS_EXPORT obos_status Core_MutexAcquire(mutex* mut); 34 | OBOS_EXPORT obos_status Core_MutexTryAcquire(mutex* mut); 35 | OBOS_EXPORT obos_status Core_MutexRelease(mutex* mut); 36 | OBOS_EXPORT bool Core_MutexAcquired(mutex* mut); 37 | -------------------------------------------------------------------------------- /src/oboskrnl/locks/pushlock.c: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnk/locks/pushlock.c 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | obos_status Core_PushlockAcquire(pushlock* lock, bool reader /* false: writer, true: reader */) 18 | { 19 | if (!lock) 20 | return OBOS_STATUS_INVALID_ARGUMENT; 21 | if (reader) 22 | { 23 | if (lock->currWriter) 24 | { 25 | lock->nWaitingReaders++; 26 | while(lock->currWriter); 27 | lock->nWaitingReaders--; 28 | } 29 | lock->nReaders++; 30 | return OBOS_STATUS_SUCCESS; 31 | } 32 | // Hopefully this is right. 33 | // maybe a possible race condition. 34 | try_again: 35 | Core_WaitOnObject(&lock->hdr); 36 | CoreH_ClearSignaledState(&lock->hdr); 37 | if (lock->nWaitingReaders) 38 | goto try_again; 39 | lock->currWriter = Core_GetCurrentThread(); 40 | return OBOS_STATUS_SUCCESS; 41 | } 42 | obos_status Core_PushlockTryAcquire(pushlock* lock) 43 | { 44 | if (!lock) 45 | return OBOS_STATUS_INVALID_ARGUMENT; 46 | if (lock->nReaders) 47 | return OBOS_STATUS_IN_USE; 48 | return Core_PushlockAcquire(lock, false); 49 | } 50 | obos_status Core_PushlockRelease(pushlock* lock, bool reader) 51 | { 52 | if (!lock) 53 | return OBOS_STATUS_INVALID_ARGUMENT; 54 | if (reader) 55 | { 56 | if (lock->nReaders) 57 | lock->nReaders--; 58 | else 59 | return OBOS_STATUS_ABORTED; // bruh 60 | return OBOS_STATUS_SUCCESS; 61 | } 62 | lock->currWriter = nullptr; 63 | return lock->nWaitingReaders ? OBOS_STATUS_SUCCESS : CoreH_SignalWaitingThreads(&lock->hdr, false, true); 64 | } 65 | size_t Core_PushlockGetReaderCount(pushlock* lock) 66 | { 67 | if (!lock) 68 | return 0; 69 | return lock->nReaders; 70 | } 71 | thread* Core_PushlockGetWriter(const pushlock* lock) 72 | { 73 | if (!lock) 74 | return 0; 75 | return lock->currWriter; 76 | } 77 | -------------------------------------------------------------------------------- /src/oboskrnl/locks/pushlock.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnk/locks/pushlock.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | typedef struct pushlock 17 | { 18 | struct waitable_header hdr; // for writers 19 | _Atomic(size_t) nReaders; // if > 0, wait on hdr (if writer), when it gets to zero, signal hdr. 20 | _Atomic(size_t) nWaitingReaders; 21 | thread* currWriter; // if == nullptr, no one is writing 22 | } pushlock; 23 | 24 | #define PUSHLOCK_INITIALIZE() (pushlock){ .hdr=WAITABLE_HEADER_INITIALIZE(true, true), .nReaders=0, .currWriter=nullptr } 25 | 26 | OBOS_EXPORT obos_status Core_PushlockAcquire(pushlock* lock, bool reader /* false: writer, true: reader */); 27 | OBOS_EXPORT obos_status Core_PushlockTryAcquire(pushlock* lock); // Only for writers. 28 | OBOS_EXPORT obos_status Core_PushlockRelease(pushlock* lock, bool reader); 29 | OBOS_EXPORT size_t Core_PushlockGetReaderCount(pushlock* lock); 30 | OBOS_EXPORT thread* Core_PushlockGetWriter(const pushlock* lock); 31 | -------------------------------------------------------------------------------- /src/oboskrnl/locks/semaphore.c: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/locks/semaphore.c 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | #include 21 | 22 | obos_status Core_SemaphoreAcquire(semaphore* sem) 23 | { 24 | if (!sem) 25 | return OBOS_STATUS_INVALID_ARGUMENT; 26 | OBOS_ASSERT(Core_GetIrql() <= IRQL_DISPATCH); 27 | if (Core_GetIrql() > IRQL_DISPATCH) 28 | return OBOS_STATUS_INVALID_IRQL; 29 | irql oldIrql = Core_SpinlockAcquire(&sem->lock); 30 | if (sem->count) 31 | { 32 | sem->count--; 33 | Core_SpinlockRelease(&sem->lock, oldIrql); 34 | return OBOS_STATUS_SUCCESS; 35 | } 36 | Core_SpinlockRelease(&sem->lock, oldIrql); 37 | // Add the current thread to the waiting list. 38 | Core_WaitOnObject(&sem->hdr); 39 | oldIrql = Core_SpinlockAcquire(&sem->lock); 40 | sem->count--; 41 | Core_SpinlockRelease(&sem->lock, oldIrql); 42 | return OBOS_STATUS_SUCCESS; 43 | } 44 | obos_status Core_SemaphoreTryAcquire(semaphore* sem) 45 | { 46 | if (!sem) 47 | return OBOS_STATUS_INVALID_ARGUMENT; 48 | if (!sem->count) 49 | return OBOS_STATUS_IN_USE; 50 | return Core_SemaphoreAcquire(sem); 51 | } 52 | obos_status Core_SemaphoreRelease(semaphore* sem) 53 | { 54 | if (!sem) 55 | return OBOS_STATUS_INVALID_ARGUMENT; 56 | sem->count++; 57 | CoreH_SignalWaitingThreads(&sem->hdr, false, false); 58 | CoreH_ClearSignaledState(&sem->hdr); 59 | return OBOS_STATUS_SUCCESS; 60 | } 61 | size_t Core_SemaphoreGetValue(semaphore* sem) 62 | { 63 | return sem->count; 64 | } -------------------------------------------------------------------------------- /src/oboskrnl/locks/semaphore.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/locks/semaphore.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | 19 | typedef struct semaphore { 20 | struct waitable_header hdr; 21 | spinlock lock; 22 | size_t count; 23 | } semaphore; 24 | 25 | #define SEMAPHORE_INITIALIZE(cnt) (semaphore){ .hdr=WAITABLE_HEADER_INITIALIZE(true, false), .count=cnt } 26 | 27 | OBOS_EXPORT obos_status Core_SemaphoreAcquire(semaphore* sem); 28 | OBOS_EXPORT obos_status Core_SemaphoreTryAcquire(semaphore* sem); 29 | OBOS_EXPORT obos_status Core_SemaphoreRelease(semaphore* sem); 30 | OBOS_EXPORT size_t Core_SemaphoreGetValue(semaphore* sem); -------------------------------------------------------------------------------- /src/oboskrnl/locks/spinlock.h: -------------------------------------------------------------------------------- 1 | /* 2 | oboskrnl/locks/spinlock.h 3 | 4 | Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | typedef struct { 16 | OBOS_ALIGNAS(OBOS_ARCHITECTURE_BITS/8) atomic_flag val; 17 | OBOS_ALIGNAS(OBOS_ARCHITECTURE_BITS/8) bool locked; 18 | } spinlock; 19 | 20 | OBOS_EXPORT spinlock Core_SpinlockCreate(); 21 | OBOS_EXPORT irql Core_SpinlockAcquireExplicit(spinlock* const lock, irql minIrql, bool irqlNthrVariant); 22 | OBOS_EXPORT irql Core_SpinlockAcquire(spinlock* const lock); 23 | OBOS_EXPORT obos_status Core_SpinlockRelease(spinlock* const lock, irql oldIrql); 24 | OBOS_EXPORT bool Core_SpinlockAcquired(spinlock* const lock); 25 | -------------------------------------------------------------------------------- /src/oboskrnl/locks/sys_futex.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/locks/sys_futex.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | // NOTE: Because Linux, futex must be aligned to 4 bytes. 18 | 19 | obos_status Sys_FutexWait(uint32_t *futex, uint32_t cmp_with, uint64_t timeout); 20 | obos_status Sys_FutexWake(uint32_t *futex, uint32_t nWaiters); 21 | 22 | typedef RB_HEAD(futex_tree, futex) futex_tree; 23 | RB_PROTOTYPE(futex_tree, futex, node, cmp_futex); 24 | typedef struct futex 25 | { 26 | struct waitable_header wait_hdr; 27 | size_t refs; 28 | uint32_t *obj; 29 | struct context* ctx; 30 | RB_ENTRY(futex) node; 31 | } futex_object; 32 | 33 | inline static int cmp_futex(futex_object* lhs, futex_object* rhs) 34 | { 35 | if (lhs->ctx < rhs->ctx) 36 | return -1; 37 | if (lhs->ctx > rhs->ctx) 38 | return -1; 39 | if (lhs->obj < rhs->obj) 40 | return -1; 41 | if (lhs->obj > rhs->obj) 42 | return 1; 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /src/oboskrnl/locks/wait.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/locks/wait.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | 16 | struct waitable_header 17 | { 18 | thread_list waiting; 19 | spinlock lock; 20 | bool signaled : 1; 21 | bool use_signaled : 1; 22 | bool interrupted : 1; 23 | }; 24 | 25 | #define WAITABLE_HEADER_INITIALIZE(s, use) (struct waitable_header){ .waiting={}, .signaled=(s), .use_signaled=(use) } 26 | 27 | // obj must be a type with `struct waitable_header` as its first member 28 | // otherwise, this will not work, and will corrupt stuff. 29 | #define WAITABLE_OBJECT(obj) (struct waitable_header*)(&(obj)) 30 | 31 | OBOS_EXPORT obos_status Core_WaitOnObject(struct waitable_header* obj); 32 | // Waits until at least one object is signaled. 33 | OBOS_EXPORT obos_status Core_WaitOnObjects(size_t nObjects, struct waitable_header** objs, struct waitable_header** signaled); 34 | OBOS_EXPORT obos_status CoreH_SignalWaitingThreads(struct waitable_header* obj, bool all, bool boostPriority); 35 | OBOS_EXPORT void CoreH_ClearSignaledState(struct waitable_header* obj); 36 | OBOS_EXPORT obos_status CoreH_AbortWaitingThreads(struct waitable_header* obj); -------------------------------------------------------------------------------- /src/oboskrnl/mbr.c: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/mbr.c 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | obos_status OBOS_IdentifyMBRPartitions(fd* desc, partition* partition_list, size_t* nPartitions) 21 | { 22 | if (!desc || (!partition_list && !nPartitions)) 23 | return OBOS_STATUS_INVALID_ARGUMENT; 24 | mbr_t *mbr = ZeroAllocate(OBOS_KernelAllocator, 1, sizeof(mbr_t), nullptr); 25 | size_t nRead = 0; 26 | size_t filesize = desc->vn->filesize; 27 | if (filesize < sizeof(mbr_t)) 28 | return OBOS_STATUS_EOF; 29 | obos_status status = Vfs_FdRead(desc, mbr, sizeof(*mbr), &nRead); 30 | if (obos_is_error(status)) 31 | { 32 | Free(OBOS_KernelAllocator, mbr, sizeof(*mbr)); 33 | return status; 34 | } 35 | if (nRead != sizeof(*mbr)) 36 | { 37 | Free(OBOS_KernelAllocator, mbr, sizeof(*mbr)); 38 | return OBOS_STATUS_INTERNAL_ERROR; 39 | } 40 | if (mbr->signature != MBR_BOOT_SIGNATURE) 41 | { 42 | Free(OBOS_KernelAllocator, mbr, sizeof(*mbr)); 43 | return OBOS_STATUS_INVALID_FILE; 44 | } 45 | if (nPartitions) 46 | *nPartitions = 0; 47 | size_t blkSize = Vfs_FdGetBlkSz(desc); 48 | for (uint8_t i = 0; i < 4; i++) 49 | { 50 | mbr_partition* curr = &mbr->parts[i]; 51 | if (!curr->nSectors) 52 | break; 53 | if (nPartitions) 54 | (*nPartitions)++; 55 | // Sanity check. 56 | if (((blkSize * curr->lba) + (curr->nSectors * blkSize)) > filesize) 57 | { 58 | Free(OBOS_KernelAllocator, mbr, sizeof(*mbr)); 59 | if (nPartitions) 60 | *nPartitions = 0; 61 | return OBOS_STATUS_INVALID_FILE; 62 | } 63 | if (!partition_list) 64 | continue; 65 | partition_list[i].vn = desc->vn; 66 | partition_list[i].off = curr->lba * blkSize; 67 | partition_list[i].size = curr->nSectors * blkSize; 68 | partition_list[i].drive = desc->vn; 69 | partition_list[i].format = PARTITION_FORMAT_MBR; 70 | } 71 | Free(OBOS_KernelAllocator, mbr, sizeof(*mbr)); 72 | return OBOS_STATUS_SUCCESS; 73 | } 74 | -------------------------------------------------------------------------------- /src/oboskrnl/mbr.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/mbr.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | typedef enum mbr_partition_type 17 | { 18 | MBR_PARTITION_FAT12, 19 | MBR_PARTITION_XENIX_ROOT, 20 | MBR_PARTITION_XENIX_USR, 21 | MBR_PARTITION_FAT16, 22 | MBR_PARTITION_FAT16B = 0x6, 23 | MBR_PARTITION_IFS = 0x7, 24 | MBR_PARTITION_HPFS = 0x7, 25 | MBR_PARTITION_NTFS = 0x7, 26 | MBR_PARTITION_exFAT = 0x7, 27 | MBR_PARTITION_FAT32_CHS = 0xb, 28 | MBR_PARTITION_FAT32, 29 | MBR_PARTITION_FAT16B_LBA, 30 | } mbr_partition_type; 31 | typedef struct mbr_partition 32 | { 33 | uint8_t status; 34 | uint8_t chs_start[3]; 35 | uint8_t type; 36 | uint8_t chs_end[3]; 37 | uint32_t lba; 38 | uint32_t nSectors; 39 | } OBOS_PACK mbr_partition; 40 | typedef struct mbr 41 | { 42 | uint8_t boot_sector[446]; 43 | mbr_partition parts[4]; 44 | uint16_t signature; // 0xAA55 45 | } OBOS_PACK mbr_t; 46 | OBOS_STATIC_ASSERT(sizeof(mbr_t) == 512, "sizeof(mbr_t) is not 512 bytes!"); 47 | OBOS_STATIC_ASSERT(sizeof(mbr_partition) == 16, "sizeof(mbr_partition) is not 16 bytes!"); 48 | #define MBR_BOOT_SIGNATURE 0xAA55 49 | obos_status OBOS_IdentifyMBRPartitions(fd* desc, partition* partition_list, size_t* nPartitions); -------------------------------------------------------------------------------- /src/oboskrnl/memmanip.h: -------------------------------------------------------------------------------- 1 | /* 2 | oboskrnl/memmanip.h 3 | 4 | Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | OBOS_EXPORT void* memset(void* blk, int val, size_t count); 13 | OBOS_EXPORT void* memzero(void* blk, size_t count); 14 | OBOS_EXPORT void* memcpy(void* blk1, const void* blk2, size_t count); 15 | OBOS_EXPORT bool memcmp(const void* blk1, const void* blk2, size_t count); 16 | OBOS_EXPORT bool memcmp_b(const void* blk1, int against, size_t count); 17 | OBOS_EXPORT bool strcmp(const char* str1, const char* str2); 18 | OBOS_EXPORT size_t strlen(const char* str); 19 | OBOS_EXPORT size_t strnlen(const char* str, size_t maxcnt); 20 | OBOS_EXPORT size_t strchr(const char* str, char ch); 21 | 22 | obos_status memcpy_usr_to_k(void* k_dest, const void* usr_src, size_t count); 23 | obos_status memcpy_k_to_usr(void* usr_dest, const void* k_src, size_t count); 24 | -------------------------------------------------------------------------------- /src/oboskrnl/mm/disk_swap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/mm/disk_swap.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | // Defines the interface for setting up a swap device to swap out to disk (vnodes) 8 | 9 | #pragma once 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | typedef struct obos_swap_free_region 18 | { 19 | // In bytes from the beginning of the files. 20 | uint64_t next, prev; 21 | // MUST be < hdr.size 22 | uint64_t size; // size including sizeof_this 23 | uint64_t sizeof_this; 24 | // The region starts right after this header. 25 | // If the device being used is a block device, then it will be on the next block. 26 | } OBOS_PACK obos_swap_free_region; 27 | typedef struct obos_swap_header 28 | { 29 | // Must be from 128-sector size. 30 | // If the device is not a block device, it must be 128 31 | uint64_t header_size; 32 | // Must be filesize - header_size 33 | uint64_t size; 34 | struct { 35 | uint64_t head; // head in byte offset from the start of the vnode 36 | uint64_t tail; // tail in byte offset from the start of the vnode 37 | uint64_t nNodes; // the amount of free nodes. 38 | uint64_t freeBytes; // the amount of free bytes 39 | } OBOS_PACK freelist; 40 | uint32_t flags; 41 | uint32_t header_version; // current version is OBOS_SWAP_HEADER_VERSION 42 | uint32_t magic; // must be OBOS_SWAP_HEADER_MAGIC 43 | uint8_t resv[68]; // must be zero 44 | } OBOS_PACK obos_swap_header; 45 | OBOS_STATIC_ASSERT(sizeof(obos_swap_header) == 128, "Invalid swap header size!"); 46 | OBOS_STATIC_ASSERT(sizeof(obos_swap_free_region) == 32, "Invalid swap free region size!"); 47 | enum { 48 | OBOS_SWAP_HEADER_VERSION = 1, 49 | OBOS_SWAP_HEADER_MAGIC_x86_64 = 0x50A9DE61, 50 | OBOS_SWAP_HEADER_MAGIC_m68k = 0x50A9DE62, 51 | #if defined (__x86_64__) 52 | OBOS_SWAP_HEADER_MAGIC = OBOS_SWAP_HEADER_MAGIC_x86_64, 53 | #elif defined (__m68k__) 54 | OBOS_SWAP_HEADER_MAGIC = OBOS_SWAP_HEADER_MAGIC_m68k, 55 | #endif 56 | }; 57 | enum { 58 | // If set, the system didn't properly stop the swap device (possibly due to a power failure/forced shutdown). 59 | // If that is the case, then the system must reinitailize the freelist. 60 | OBOS_SWAP_HEADER_DIRTY = 0b1, 61 | }; 62 | 63 | obos_status MmH_InitializeDiskSwapDevice(swap_dev *dev, void* vnode); 64 | obos_status MmH_InitializeDiskSwap(void* vnode); -------------------------------------------------------------------------------- /src/oboskrnl/mm/fork.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/mm/fork.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | obos_status Mm_ForkContext(context* into, context* toFork); 15 | -------------------------------------------------------------------------------- /src/oboskrnl/mm/init.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/mm/init.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | void Mm_Initialize(); 12 | bool Mm_IsInitialized(); -------------------------------------------------------------------------------- /src/oboskrnl/mm/initial_swap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/mm/initial_swap.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | obos_status Mm_InitializeInitialSwapDevice(swap_dev* dev, size_t size); -------------------------------------------------------------------------------- /src/oboskrnl/mm/mm_sys.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/mm/mm_sys.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | struct vma_alloc_userspace_args 18 | { 19 | prot_flags prot; 20 | vma_flags flags; 21 | handle file; 22 | uintptr_t offset; 23 | }; 24 | void* Sys_VirtualMemoryAlloc(handle ctx, void* base, size_t size, struct vma_alloc_userspace_args* args, obos_status* status); 25 | obos_status Sys_VirtualMemoryFree(handle ctx, void* base, size_t size); 26 | obos_status Sys_VirtualMemoryProtect(handle ctx, void* base, size_t size, prot_flags newProt); 27 | obos_status Sys_VirtualMemoryLock(handle ctx, void* base, size_t size); 28 | obos_status Sys_VirtualMemoryUnlock(handle ctx, void* base, size_t size); 29 | 30 | handle Sys_MakeNewContext(size_t ws_capacity); 31 | obos_status Sys_ContextExpandWSCapacity(handle ctx, size_t ws_capacity); 32 | obos_status Sys_ContextGetStat(handle ctx, memstat* stat); 33 | 34 | size_t Sys_GetUsedPhysicalMemoryCount(); 35 | 36 | obos_status Sys_QueryPageInfo(handle ctx, void* base, page_info* info); 37 | 38 | void Sys_VMMContextClone(handle_desc *hnd, handle_desc *new); 39 | -------------------------------------------------------------------------------- /src/oboskrnl/mm/page_table.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #ifdef __x86_64__ 6 | typedef uintptr_t page_table; 7 | #elif __m68k__ 8 | typedef uintptr_t page_table; 9 | #else 10 | # error Unknown architecture 11 | #endif 12 | -------------------------------------------------------------------------------- /src/oboskrnl/mm/swap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/mm/swap.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | typedef struct swap_device 18 | { 19 | // *id needs to be aligned to OBOS_PAGE_SIZE if !huge_page, otherwise it needs to be aligned to OBOS_HUGE_PAGE_SIZE 20 | obos_status(* swap_resv)(struct swap_device* dev, uintptr_t* id, bool huge_page); 21 | obos_status(* swap_free)(struct swap_device* dev, uintptr_t id); 22 | obos_status(*swap_write)(struct swap_device* dev, uintptr_t id, page* pg); 23 | obos_status(* swap_read)(struct swap_device* dev, uintptr_t id, page* pg); 24 | obos_status(*deinit_dev)(struct swap_device* dev); 25 | void* metadata; 26 | } swap_dev; 27 | extern swap_dev* Mm_SwapProvider; 28 | 29 | obos_status Mm_SwapOut(uintptr_t virt, page_range* rng); 30 | obos_status Mm_SwapIn(page_info* page, fault_type* type); 31 | 32 | extern phys_page_list Mm_DirtyPageList; 33 | extern phys_page_list Mm_StandbyPageList; 34 | extern size_t Mm_DirtyPagesBytes; 35 | extern size_t Mm_DirtyPagesBytesThreshold; 36 | OBOS_EXPORT void Mm_MarkAsDirty(page_info* pg); 37 | OBOS_EXPORT void Mm_MarkAsStandby(page_info* pg); 38 | OBOS_EXPORT void Mm_MarkAsDirtyPhys(page* pg); 39 | OBOS_EXPORT void Mm_MarkAsStandbyPhys(page* pg); 40 | void Mm_InitializePageWriter(); 41 | // Wakes up the page writer to free up memory 42 | // Set 'wait' to true to wait for the page writer to release 43 | void Mm_WakePageWriter(bool wait); 44 | irql Mm_TakeSwapLock(); 45 | void Mm_ReleaseSwapLock(irql oldIrql); 46 | 47 | obos_status Mm_ChangeSwapProvider(swap_dev* to); 48 | -------------------------------------------------------------------------------- /src/oboskrnl/partition.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/partition.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | // #include 16 | 17 | #include 18 | #include 19 | 20 | typedef enum partition_format 21 | { 22 | PARTITION_FORMAT_MBR, 23 | PARTITION_FORMAT_GPT, 24 | PARTITION_FORMAT_RAW, 25 | } partition_format; 26 | typedef struct partition 27 | { 28 | dirent* ent; 29 | struct vnode* vn; 30 | struct vnode* drive; 31 | uoff_t off; 32 | size_t size; 33 | partition_format format; 34 | struct driver_id* fs_driver; 35 | uuid part_uuid; // invalid when format != GPT 36 | string part_name; // optional 37 | string partid; 38 | } partition; 39 | void OBOS_PartProbeAllDrives(bool check_checksum); 40 | obos_status OBOS_PartProbeDrive(struct dirent* ent, bool check_checksum); 41 | -------------------------------------------------------------------------------- /src/oboskrnl/power/device.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/power/device.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | * 6 | * D state helpers. 7 | */ 8 | 9 | #pragma once 10 | 11 | #include 12 | #include 13 | 14 | #if OBOS_ARCHITECTURE_HAS_ACPI 15 | # include 16 | # include 17 | #endif 18 | 19 | typedef enum d_state { 20 | DSTATE_INVALID = -1, 21 | DSTATE_0, 22 | DSTATE_1, 23 | DSTATE_2, 24 | DSTATE_3HOT, 25 | DSTATE_3COLD, 26 | DSTATE_MAX = DSTATE_3COLD, 27 | } d_state; 28 | 29 | // if dry_run is true, then the function does not actually put the device into the state, 30 | // but only checks if it would be able to and returns an apprioriate status. 31 | 32 | #if OBOS_ARCHITECTURE_HAS_ACPI 33 | 34 | OBOS_EXPORT obos_status OBOS_DeviceSetDState(uacpi_namespace_node* dev, d_state new_state, bool dry_run); 35 | OBOS_EXPORT obos_status OBOS_DeviceHasDState(uacpi_namespace_node* dev, d_state state); 36 | 37 | // Makes the device wake capable from sleep state 'state' 38 | // state must be > S0 and < S5 39 | OBOS_EXPORT obos_status OBOS_DeviceMakeWakeCapable(uacpi_namespace_node* dev, uacpi_sleep_state state, bool registerGPEOnly); 40 | 41 | // Returns DSTATE_INVALID on error, or if the device does not need to be moved in another 42 | // D state to wake us. 43 | // Always check status to make sure. 44 | OBOS_EXPORT d_state OBOS_DeviceGetDStateForWake(uacpi_namespace_node* dev, uacpi_sleep_state state, obos_status* status); 45 | 46 | #else 47 | 48 | // Always returns UNIMPLEMENTED 49 | OBOS_EXPORT obos_status OBOS_DeviceSetDState(void* dev, d_state new_state, bool dry_run); 50 | 51 | // Always returns UNIMPLEMENTED 52 | OBOS_EXPORT obos_status OBOS_DeviceHasDState(void* dev, d_state state); 53 | 54 | // Always returns UNIMPLEMENTED 55 | OBOS_EXPORT obos_status OBOS_DeviceMakeWakeCapable(void* dev, int state, bool registerGPEOnly); 56 | 57 | // Returns DSTATE_INVALID, and status is set to UNIMPLEMENTED, if status is non-null 58 | OBOS_EXPORT d_state OBOS_DeviceGetDStateForWake(void* dev, int state, obos_status* status); 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /src/oboskrnl/power/init.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/power/init.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | void OBOS_SetupEarlyTableAccess(); 12 | void OBOS_InitializeUACPI(); 13 | 14 | void OBOS_InitializeECFromECDT(); 15 | void OBOS_InitializeECFromNamespace(); 16 | void OBOS_ECSetGPEs(); 17 | -------------------------------------------------------------------------------- /src/oboskrnl/power/shutdown.c: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/power/shutdown.c 3 | * 4 | * Copyright (c) 2024-2025 Omar Berrow 5 | */ 6 | 7 | #if OBOS_ARCHITECTURE_HAS_ACPI 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | 17 | #include 18 | 19 | #include 20 | #include 21 | 22 | OBOS_NORETURN void OBOS_Shutdown() 23 | { 24 | irql oldIrql = Core_RaiseIrql(IRQL_DISPATCH); 25 | OBOS_UNUSED(oldIrql); 26 | Core_SuspendScheduler(true); 27 | Core_WaitForSchedulerSuspend(); 28 | OBOS_Log("oboskrnl: Shutdown requested.\n"); 29 | // We're at IRQL_DISPATCH which should probably be enough for prepare for sleep state. 30 | uacpi_prepare_for_sleep_state(UACPI_SLEEP_STATE_S5); 31 | UACPI_ARCH_DISABLE_INTERRUPTS(); 32 | uacpi_enter_sleep_state(UACPI_SLEEP_STATE_S5); 33 | while(1) 34 | asm volatile(""); 35 | } 36 | OBOS_NORETURN void OBOS_Reboot() 37 | { 38 | Core_SuspendScheduler(true); 39 | Core_WaitForSchedulerSuspend(); 40 | uacpi_reboot(); 41 | #ifdef __x86_64__ 42 | UACPI_ARCH_DISABLE_INTERRUPTS(); 43 | // Try triple faulting. 44 | struct { 45 | uint16_t limit; 46 | uint64_t base; 47 | } OBOS_PACK gdtr = {.limit=0x18-1}; 48 | asm volatile ("lgdt (%0); mov $0x8, %%ax; mov %%ax, %%ss; push $0;" : :"r"(&gdtr) :"memory"); 49 | // We should not be here anymore. 50 | OBOS_UNREACHABLE; 51 | #endif 52 | while(1) 53 | asm volatile(""); 54 | } 55 | #else 56 | 57 | #include 58 | #include 59 | 60 | OBOS_NORETURN void OBOS_Shutdown() 61 | { 62 | OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "Shutting down is unsupported\n"); 63 | } 64 | OBOS_NORETURN void OBOS_Reboot() 65 | { 66 | OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "Rebooting is unsupported\n"); 67 | } 68 | 69 | #endif 70 | -------------------------------------------------------------------------------- /src/oboskrnl/power/shutdown.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/power/shutdown.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | OBOS_NORETURN void OBOS_Shutdown(); 12 | OBOS_NORETURN void OBOS_Reboot(); 13 | -------------------------------------------------------------------------------- /src/oboskrnl/power/suspend.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/power/suspend.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | // NOTE: Only currently supports S3 13 | 14 | // NOTE: This thread will always be at IRQL_DISPATCH, even at entry. 15 | // After the architecture reinitializes itself after wake-from-suspend, it should just blindly switch to this thread's context. 16 | // Example: 17 | /* 18 | // do stuff 19 | // NOTE: Since we are on the BSP, which the suspend worker thread is guaranteed to be on, we can just switch to the thread without changing 20 | // anything in the cpu_local struct 21 | OBOS_WokeFromSuspend = true; 22 | CoreS_SwitchToThreadContext(&OBOS_SuspendWorkerThread->ctx); 23 | */ 24 | extern struct thread* OBOS_SuspendWorkerThread; 25 | // NOTE: Set to false automatically. 26 | extern bool OBOS_WokeFromSuspend; 27 | 28 | // NOTE: The operation is aborted if there is already someone trying to suspend us. 29 | obos_status OBOS_Suspend(); 30 | 31 | void OBOS_InitWakeGPEs(); 32 | 33 | extern uint32_t OBOSS_WakeVector; 34 | 35 | extern OBOS_WEAK obos_status OBOSS_PrepareWakeVector(); 36 | 37 | void OBOSS_SuspendSavePlatformState(); 38 | 39 | // Saves EC state before entering S3. 40 | void OBOS_ECSave(); 41 | // Restores previously saved EC state before entering S3. 42 | void OBOS_ECResume(); 43 | -------------------------------------------------------------------------------- /src/oboskrnl/scheduler/cpu_local.h: -------------------------------------------------------------------------------- 1 | /* 2 | oboskrnl/scheduler/cpu_local.h 3 | 4 | Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | #ifdef __x86_64__ 19 | # include 20 | #elif defined(__m68k__) 21 | # include 22 | #endif 23 | 24 | typedef struct cpu_local 25 | { 26 | uint32_t id; 27 | bool isBSP; 28 | struct thread* currentThread; 29 | struct thread* idleThread; 30 | struct context* currentContext; 31 | cpu_local_arch arch_specific; 32 | // Only threads that are ready can go in one of these thread lists. 33 | thread_priority_list priorityLists[THREAD_PRIORITY_MAX_VALUE + 1]; 34 | thread_priority_list* currentPriorityList; 35 | spinlock schedulerLock; 36 | uint64_t schedulerTicks; 37 | irql currentIrql; 38 | bool initialized; 39 | dpc_queue dpcs; 40 | spinlock dpc_queue_lock; 41 | void* currentKernelStack; // size: 0x10000 42 | 43 | struct cpu_local* curr; 44 | } cpu_local; 45 | extern DRV_EXPORT cpu_local* Core_CpuInfo; 46 | extern DRV_EXPORT size_t Core_CpuCount; 47 | 48 | #ifdef OBOS_KERNEL 49 | OBOS_WEAK cpu_local* CoreS_GetCPULocalPtr(); 50 | #elif defined(OBOS_DRIVER) 51 | OBOS_EXPORT cpu_local* CoreS_GetCPULocalPtr(); 52 | #endif 53 | -------------------------------------------------------------------------------- /src/oboskrnl/scheduler/process.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/scheduler/process.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | typedef struct process 23 | { 24 | // Processes waiting for a status update. 25 | struct waitable_header waiting_threads; 26 | 27 | // If pid==0, this is the kernel process. 28 | uint32_t pid; 29 | thread_list threads; 30 | struct context* ctx; 31 | handle_table handles; 32 | _Atomic(size_t) refcount; 33 | 34 | uid currentUID; 35 | gid currentGID; 36 | uint32_t exitCode; 37 | bool dead; 38 | 39 | struct process* parent; 40 | struct { 41 | struct process *head, *tail; 42 | size_t nChildren; 43 | } children; 44 | spinlock children_lock; 45 | struct process *next, *prev; 46 | 47 | dirent* cwd; 48 | const char* cwd_str; 49 | 50 | tty* controlling_tty; 51 | } process; 52 | extern uint32_t Core_NextPID; 53 | 54 | // The first thread in this process must be the kernel main thread, until the thread exits. 55 | extern OBOS_EXPORT process* OBOS_KernelProcess; 56 | /// 57 | /// Allocates a process object. 58 | /// 59 | /// [out,opt] The status of the function. 60 | /// The object. 61 | OBOS_EXPORT process* Core_ProcessAllocate(obos_status* status); 62 | /// 63 | /// Starts a process. Readies the mainThread passed. 64 | /// 65 | /// A pointer to the process object. 66 | /// The main thread of the process. Must be initialized, but not readied. 67 | /// The status of the function. 68 | OBOS_EXPORT obos_status Core_ProcessStart(process* proc, thread* mainThread); 69 | /// 70 | /// Appends a thread to a process. Does not ready the thread passed to it. 71 | /// 72 | /// The process. 73 | /// The thread. 74 | /// The status of the function. 75 | OBOS_EXPORT obos_status Core_ProcessAppendThread(process* proc, thread* thread); 76 | /// 77 | /// Terminates the current process. 78 | /// 79 | /// The exit code of the process. 80 | OBOS_NORETURN void Core_ExitCurrentProcess(uint32_t code); 81 | 82 | process* Core_LookupProc(uint64_t pid); -------------------------------------------------------------------------------- /src/oboskrnl/scheduler/sched_sys.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/scheduler/sched_sys.h 3 | * 4 | * Copyright (c) 2024-2025 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include 16 | 17 | // internal 18 | typedef struct thread_ctx_handle 19 | { 20 | // NOTE: When the thread context is finally used in a thread creation, ctx gets freed, 21 | // canFree is set to false, then ctx is set to &thread->context. 22 | struct thread_context_info* ctx; 23 | pushlock lock; 24 | // If false, this thread context cannot be used in a new thread creation. 25 | bool canFree; 26 | 27 | struct context* vmm_ctx; 28 | } thread_ctx_handle; 29 | 30 | // scheduler/thread_context_info.h 31 | 32 | handle Sys_ThreadContextCreate(uintptr_t entry, uintptr_t arg1, void* stack, size_t stack_size, handle vmm_context); 33 | 34 | // scheduler/thread.h 35 | 36 | handle Sys_ThreadOpen(handle proc, uint64_t tid); 37 | handle Sys_ThreadCreate(thread_priority priority, thread_affinity affinity, handle thread_context); 38 | obos_status Sys_ThreadReady(handle thread); 39 | obos_status Sys_ThreadBlock(handle thread); 40 | obos_status Sys_ThreadBoostPriority(handle thread, int reserved /* ignored as of now */); 41 | obos_status Sys_ThreadPriority(handle thread, const thread_priority *new, thread_priority* old); 42 | obos_status Sys_ThreadAffinity(handle thread, const thread_affinity *new, thread_affinity* old); 43 | // Can only be called once per thread-object, and must be called before readying a thread. 44 | obos_status Sys_ThreadSetOwner(handle thr, handle process); 45 | uint64_t Sys_ThreadGetTid(handle thr); 46 | 47 | // locks/wait.h 48 | 49 | obos_status Sys_WaitOnObject(handle object /* must be a waitable handle */); 50 | 51 | // scheduler/process.h 52 | 53 | handle Sys_ProcessOpen(uint64_t pid); 54 | handle Sys_ProcessStart(handle mainThread /* optional, set to HANDLE_INVALID if unwanted */, handle vmm_context, bool is_fork); 55 | uint32_t Sys_ProcessGetStatus(handle process); 56 | uint64_t Sys_ProcessGetPID(handle process); 57 | uint64_t Sys_ProcessGetPPID(handle process); 58 | // Gets a handle to any arbitrary child process. 59 | handle Sys_ProcessGetChildHandle(); 60 | 61 | #define WNOHANG 1 62 | #define WSTOPPED 2 63 | #define WEXITED 4 64 | #define WCONTINUED 8 65 | 66 | // If HANDLE_ANY to make it choose an arbitrary child process. 67 | obos_status Sys_WaitProcess(handle proc, int* status, int options, uint32_t* ret_pid); 68 | -------------------------------------------------------------------------------- /src/oboskrnl/scheduler/schedule.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/scheduler/schedule.h 3 | * 4 | * Copyright (c) 2024-2025 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | /// 17 | /// Gets the current thread. 18 | /// 19 | /// The current thread. 20 | OBOS_EXPORT thread* Core_GetCurrentThread(); 21 | /// 22 | /// Schedules a thread. 23 | /// Only provided for documentation purposes, never call directly without saving the current thread's context first 24 | /// 25 | void Core_Schedule(); 26 | /// 27 | /// Yields the current thread. This will save the current thread context, then call Core_Schedule after raising the IRQL (if needed). 28 | /// 29 | OBOS_EXPORT void Core_Yield(); 30 | 31 | /// 32 | /// Suspends or unsuspends the scheduler. 33 | /// This causes it to hang indefinitely on yield. This is used so that we can save thread contexts 34 | /// of all CPUs' threads before suspending the system. 35 | /// 36 | /// Whether to suspend (true) or unsuspend (false) the scheduler.. 37 | OBOS_EXPORT void Core_SuspendScheduler(bool suspended); 38 | /// 39 | /// Waits for all CPUs (but the current CPU) to suspend their scheduler, 40 | /// 41 | OBOS_EXPORT void Core_WaitForSchedulerSuspend(); 42 | 43 | extern OBOS_EXPORT size_t Core_ReadyThreadCount; 44 | extern struct irq* Core_SchedulerIRQ; 45 | extern OBOS_EXPORT uint64_t Core_SchedulerTimerFrequency; 46 | extern spinlock Core_SchedulerLock; 47 | -------------------------------------------------------------------------------- /src/oboskrnl/struct_packing.h: -------------------------------------------------------------------------------- 1 | #if defined(__GNUC__) 2 | #define OBOS_PACK __attribute__((packed)) 3 | #define OBOS_ALIGN(n) __attribute__((aligned(n))) 4 | #elif defined(_MSC_VER) 5 | #define OBOS_PACK __declspec(align(1)) 6 | #define OBOS_ALIGN(n) __declspec(align(n)) 7 | #endif -------------------------------------------------------------------------------- /src/oboskrnl/syscall.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/syscall.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | // All syscall number ranges outside this are reserved. 14 | #define SYSCALL_BEGIN (0) 15 | #define SYSCALL_END (0x10000) 16 | #define ARCH_SYSCALL_BEGIN (0x80000000) 17 | #define ARCH_SYSCALL_END (0x80010000) 18 | 19 | #define IS_ARCH_SYSCALL(n) ((n) >= ARCH_SYSCALL_BEGIN) 20 | 21 | extern OBOS_EXPORT uintptr_t OBOS_SyscallTable[SYSCALL_END-SYSCALL_BEGIN]; 22 | extern OBOS_EXPORT uintptr_t OBOS_ArchSyscallTable[ARCH_SYSCALL_END-ARCH_SYSCALL_BEGIN]; 23 | 24 | typedef uint64_t syscall_ret_t; 25 | 26 | // NOTE (for kernel devs): Syscalls can have a max of 5 parameters, any more paramters must be passed through a memory buffer. 27 | 28 | // Note: entry can return a max of syscall_ret_t, and can take a max of 5 arguments. 29 | inline static void OBOS_RegisterSyscall(uint32_t num, uintptr_t entry) 30 | { 31 | if (IS_ARCH_SYSCALL(num)) 32 | OBOS_ArchSyscallTable[num-ARCH_SYSCALL_BEGIN] = entry; 33 | else 34 | OBOS_SyscallTable[num-SYSCALL_BEGIN] = entry; 35 | } 36 | void OBOSS_InitializeSyscallInterface(); 37 | 38 | // if buf and sz_buf are nullptr, the function silently fails 39 | // if ustr is nullptr, OBOS_STATUS_INVALID_ARGUMENT is returned 40 | // if a page fault occurs reading the string, then OBOS_STATUS_PAGE_FAULT is returned 41 | // if all goes well, you get a string and its size back, and OBOS_STATUS_SUCCESS 42 | obos_status OBOSH_ReadUserString(const char* ustr, char* buf, size_t* sz_buf); 43 | -------------------------------------------------------------------------------- /src/oboskrnl/text.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/text.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | // Makeshift text renderer. 13 | 14 | #define OBOS_FB_FORMAT_RGB888 1 15 | #define OBOS_FB_FORMAT_BGR888 2 16 | #define OBOS_FB_FORMAT_RGBX8888 3 17 | #define OBOS_FB_FORMAT_XRGB8888 4 18 | 19 | #define OBOS_TEXT_BACKGROUND 0x1b1c1b00 20 | 21 | #define get_line_bitmap_size(height) (height/512+((height%512 == 0) ? 0 : 1)) 22 | typedef struct 23 | { 24 | uint32_t column; 25 | uint32_t row; 26 | const void* font; // Must be 8x16 font. 27 | struct 28 | { 29 | void* base; 30 | void* backbuffer_base; 31 | // Size is height/512 32 | // Only is valid if backbuffer_base is non-null. 33 | uint32_t* modified_line_bitmap; 34 | uint32_t pitch; 35 | uint32_t width; 36 | uint32_t height; 37 | uint16_t format; 38 | uint8_t bpp; 39 | } fb; 40 | uint32_t fg_color; // rgbx 41 | bool paused; 42 | } text_renderer_state; 43 | extern OBOS_EXPORT text_renderer_state OBOS_TextRendererState; 44 | // Plots a pixel at fb. fbFmt is of OBOS_FB_FORMAT_* 45 | // Colour is RGBX 46 | OBOS_EXPORT void OBOS_PlotPixel(uint32_t colour, uint8_t* fb, uint16_t fbFmt); 47 | void OBOS_FlushBuffers(text_renderer_state* state); 48 | obos_status OBOS_WriteCharacter(text_renderer_state* state, char ch); 49 | obos_status OBOS_WriteCharacterAt(text_renderer_state* state, char ch, uint32_t column, uint32_t row); 50 | -------------------------------------------------------------------------------- /src/oboskrnl/utils/shared_ptr.c: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/utils/shared_ptr.c 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | 14 | shared_ptr* OBOS_SharedPtrConstructSz(shared_ptr* ptr, void* obj, size_t sz) 15 | { 16 | ptr->obj = obj; 17 | ptr->szObj = sz; 18 | ptr->refs = 0; 19 | ptr->free = nullptr; 20 | ptr->freeUdata = nullptr; 21 | ptr->onDeref = ptr->onRef = nullptr; 22 | return ptr; 23 | } 24 | 25 | void OBOS_SharedPtrRef(shared_ptr* ptr) 26 | { 27 | OBOS_ASSERT(ptr); 28 | if (!ptr) 29 | return; 30 | ptr->refs++; 31 | if (ptr->onRef) 32 | ptr->onRef(ptr); 33 | } 34 | 35 | void OBOS_SharedPtrUnref(shared_ptr* ptr) 36 | { 37 | OBOS_ASSERT(ptr); 38 | if (!ptr) 39 | return; 40 | OBOS_ASSERT(ptr->refs); 41 | if (ptr->onDeref) 42 | ptr->onDeref(ptr); 43 | if (!(--ptr->refs)) 44 | ptr->free(ptr->freeUdata, ptr); 45 | } 46 | 47 | void OBOS_SharedPtrAssertRefs(shared_ptr* ptr) 48 | { 49 | OBOS_ASSERT(ptr->refs); 50 | } 51 | 52 | void OBOS_SharedPtrDefaultFree(void* udata, shared_ptr* ptr) 53 | { 54 | struct allocator_info* alloc = udata ? udata : OBOS_KernelAllocator; 55 | alloc->Free(alloc, ptr->obj, ptr->szObj); 56 | } 57 | -------------------------------------------------------------------------------- /src/oboskrnl/utils/shared_ptr.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/utils/shared_ptr.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | typedef struct shared_ptr 12 | { 13 | _Atomic(size_t) refs; 14 | void* obj; 15 | size_t szObj; 16 | // Can be nullptr 17 | // Frees obj. 18 | void(*free)(void* udata, struct shared_ptr*); 19 | void* freeUdata; 20 | // Can be nullptr 21 | // Called before the ref count is decreased. 22 | void(*onDeref)(struct shared_ptr*); 23 | // Can be nullptr 24 | // Called after the ref count is increased. 25 | void(*onRef)(struct shared_ptr*); 26 | } shared_ptr; 27 | 28 | shared_ptr* OBOS_SharedPtrConstructSz(shared_ptr* ptr, void* obj, size_t sz); 29 | #define OBOS_SharedPtrConstruct(ptr, obj_ptr) ({ typeof(obj_ptr) _a = (obj_ptr); OBOS_SharedPtrConstructSz((ptr), _a, sizeof(*_a)); }) 30 | void OBOS_SharedPtrRef(shared_ptr* ptr); 31 | void OBOS_SharedPtrUnref(shared_ptr* ptr); 32 | // udata is the struct allocator_info* used to allocate the object. 33 | // if udata is nullptr, OBOS_KernelAllocator is assumed 34 | void OBOS_SharedPtrDefaultFree(void* udata, shared_ptr* ptr); 35 | void OBOS_SharedPtrAssertRefs(shared_ptr* ptr); 36 | #define OBOS_SharedPtrGet(type, ptr_) ({ typeof(ptr_) _a = (ptr_); OBOS_SharedPtrAssertRefs(_a); (type*)(_a->obj); }) 37 | -------------------------------------------------------------------------------- /src/oboskrnl/utils/string.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/utils/string.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | * 6 | * String manipulation routines. 7 | */ 8 | 9 | #pragma once 10 | 11 | #include 12 | 13 | typedef struct string 14 | { 15 | // small string optimization. 16 | // this buffer is used when cap < 32 17 | char sso[33]; 18 | char *ls; 19 | size_t len, cap; 20 | struct allocator_info* allocator; 21 | } string; 22 | 23 | OBOS_EXPORT void OBOS_StringSetAllocator(string* obj, struct allocator_info* allocator); 24 | OBOS_EXPORT void OBOS_InitString(string* obj, const char* str); 25 | OBOS_EXPORT void OBOS_InitStringLen(string* obj, const char* str, size_t len); 26 | OBOS_EXPORT void OBOS_AppendStringC(string* obj, const char* str); 27 | OBOS_EXPORT void OBOS_AppendStringS(string* obj, string* str); 28 | OBOS_EXPORT void OBOS_ResizeString(string* obj, size_t len); 29 | OBOS_EXPORT void OBOS_SetCapacityString(string* obj, size_t cap); 30 | OBOS_EXPORT size_t OBOS_GetStringCapacity(const string* obj); 31 | OBOS_EXPORT size_t OBOS_GetStringSize(const string* obj); 32 | OBOS_EXPORT char* OBOS_GetStringPtr(string* obj); 33 | OBOS_EXPORT const char* OBOS_GetStringCPtr(const string* obj); 34 | OBOS_EXPORT void OBOS_FreeString(string* obj); 35 | OBOS_EXPORT bool OBOS_CompareStringS(const string* str1, const string* str2); 36 | OBOS_EXPORT bool OBOS_CompareStringC(const string* str1, const char* str2); 37 | OBOS_EXPORT bool OBOS_CompareStringNC(const string* str1, const char* str2, size_t str2len); -------------------------------------------------------------------------------- /src/oboskrnl/utils/uuid.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/utils/uuid.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #include 12 | 13 | typedef uint32_t uuid[4]; 14 | OBOS_STATIC_ASSERT(sizeof(uuid) == 16, "The size of a UUID is not 16 bytes (128-bits)!"); 15 | 16 | // str is a pointer to a newly zeroed string object 17 | OBOS_EXPORT void OBOS_UUIDToString(const uuid* const uuid, string* str); 18 | OBOS_EXPORT void OBOS_StringToUUID(const string* const str, uuid* uuid); 19 | // TODO: Generate UUID? -------------------------------------------------------------------------------- /src/oboskrnl/vfs/alloc.c: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/vfs/alloc.c 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | allocator_info* Vfs_Allocator; 15 | 16 | struct allocation_hdr { 17 | size_t sz; 18 | }; 19 | 20 | static basic_allocator alloc; 21 | void* Vfs_Malloc(size_t cnt) 22 | { 23 | if (!Vfs_Allocator) 24 | { 25 | OBOSH_ConstructBasicAllocator(&alloc); 26 | Vfs_Allocator = (allocator_info*)&alloc; 27 | } 28 | cnt += sizeof(struct allocation_hdr); 29 | struct allocation_hdr *hdr = Vfs_Allocator->ZeroAllocate(Vfs_Allocator, 1, cnt, nullptr); 30 | hdr->sz = cnt-sizeof(struct allocation_hdr); 31 | return hdr+1; 32 | } 33 | 34 | void* Vfs_Calloc(size_t nObjs, size_t szObj) 35 | { 36 | if (!Vfs_Allocator) 37 | { 38 | OBOSH_ConstructBasicAllocator(&alloc); 39 | Vfs_Allocator = (allocator_info*)&alloc; 40 | } 41 | return Vfs_Malloc(nObjs*szObj); 42 | } 43 | 44 | void* Vfs_Realloc(void* what, size_t cnt) 45 | { 46 | if (!Vfs_Allocator) 47 | return nullptr; 48 | struct allocation_hdr* hdr = what; 49 | hdr--; 50 | hdr->sz += cnt; 51 | hdr = Vfs_Allocator->Reallocate(Vfs_Allocator, hdr, cnt, hdr->sz-cnt, nullptr); 52 | return hdr+1; 53 | } 54 | 55 | void Vfs_Free(void* what) 56 | { 57 | if (!Vfs_Allocator) 58 | return; 59 | struct allocation_hdr* hdr = what; 60 | hdr--; 61 | Vfs_Allocator->Free(Vfs_Allocator, hdr, hdr->sz); 62 | } 63 | -------------------------------------------------------------------------------- /src/oboskrnl/vfs/alloc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/vfs/alloc.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #include 12 | 13 | extern allocator_info* Vfs_Allocator; 14 | 15 | void* Vfs_Malloc(size_t cnt); 16 | void* Vfs_Calloc(size_t nObjs, size_t szObj); 17 | void* Vfs_Realloc(void* what, size_t cnt); 18 | void Vfs_Free(void* what); -------------------------------------------------------------------------------- /src/oboskrnl/vfs/create.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/vfs/create.h 3 | * 4 | * Copyright (c) 2025 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | // obos_status VfsH_CreateNodeP(const char* parent, const char* name, uint32_t vtype, file_perm mode); 18 | #define VfsH_CreateNodeP(parent, name, vtype, mode) ({\ 19 | struct dirent* _parent = VfsH_DirentLookup(parent);\ 20 | obos_status _status = OBOS_STATUS_SUCCESS;\ 21 | if (!(_parent))\ 22 | _status = (OBOS_STATUS_NOT_FOUND);\ 23 | else\ 24 | _status = Vfzs_CreateNode(_parent, (name), (vtype), (mode));\ 25 | (_status);\ 26 | }) 27 | 28 | obos_status Vfs_CreateNode(dirent* parent, const char* name, uint32_t vtype, file_perm mode); -------------------------------------------------------------------------------- /src/oboskrnl/vfs/dirent.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/vfs/dirent.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | 17 | typedef LIST_HEAD(dirent_list, struct dirent) dirent_list; 18 | typedef struct dirent 19 | { 20 | struct 21 | { 22 | struct dirent* parent; 23 | struct 24 | { 25 | struct dirent* head; 26 | struct dirent* tail; 27 | size_t nChildren; 28 | } children; 29 | struct dirent* next_child; 30 | struct dirent* prev_child; 31 | } tree_info; 32 | struct vnode* vnode; 33 | string name; 34 | LIST_NODE(dirent_list, struct dirent) node; 35 | } dirent; 36 | LIST_PROTOTYPE(dirent_list, dirent, node); 37 | #define d_children tree_info.children 38 | #define d_next_child tree_info.next_child 39 | #define d_prev_child tree_info.prev_child 40 | #define d_parent tree_info.parent 41 | void VfsH_DirentAppendChild(dirent* parent, dirent* child); 42 | void VfsH_DirentRemoveChild(dirent* parent, dirent* what); 43 | // path shouldn't have unneeded slashes, this way, there is a higher chance of a name cache hit, thus speeding up 44 | // the lookup 45 | dirent* VfsH_DirentLookup(const char* path); 46 | dirent* VfsH_DirentLookupFrom(const char* path, dirent* root); 47 | obos_status VfsH_Chdir(void* /* struct process */ target, const char *path); 48 | obos_status VfsH_ChdirEnt(void* /* struct process */ target, dirent* ent); 49 | 50 | OBOS_EXPORT dirent* Drv_RegisterVNode(struct vnode* vn, const char* const dev_name); 51 | 52 | // solely for mlibc support 53 | obos_status Vfs_ReadEntries(dirent* dent, void* buffer, size_t szBuf, dirent** last, size_t* nRead); 54 | -------------------------------------------------------------------------------- /src/oboskrnl/vfs/fd.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/vfs/fd.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include 18 | 19 | #include 20 | 21 | typedef LIST_HEAD(fd_list, struct fd) fd_list; 22 | LIST_PROTOTYPE(fd_list, struct fd, node); 23 | enum 24 | { 25 | FD_FLAGS_OPEN = 1, 26 | FD_FLAGS_READ = 2, 27 | FD_FLAGS_WRITE = 4, 28 | FD_FLAGS_UNCACHED = 8, 29 | FD_FLAGS_NOEXEC = 16, 30 | }; 31 | enum 32 | { 33 | FD_OFLAGS_READ = 1, 34 | FD_OFLAGS_WRITE = 2, 35 | FD_OFLAGS_UNCACHED = 4, 36 | FD_OFLAGS_NOEXEC = 8, 37 | // NOTE: Only handled in syscalls, and is ignored in Vfs_FdOpen*. 38 | FD_OFLAGS_CREATE = 16, 39 | }; 40 | typedef struct fd 41 | { 42 | struct vnode* vn; 43 | uint32_t flags; 44 | uoff_t offset; 45 | dev_desc desc; 46 | LIST_NODE(fd_list, struct fd) node; 47 | } fd; 48 | OBOS_EXPORT obos_status Vfs_FdOpen(fd* const desc, const char* path, uint32_t oflags); 49 | OBOS_EXPORT obos_status Vfs_FdOpenDirent(fd* const desc, dirent* ent, uint32_t oflags); 50 | OBOS_EXPORT obos_status Vfs_FdOpenVnode(fd* const desc, void* vn, uint32_t oflags); 51 | OBOS_EXPORT obos_status Vfs_FdWrite(fd* desc, const void* buf, size_t nBytes, size_t* nWritten); 52 | OBOS_EXPORT obos_status Vfs_FdRead(fd* desc, void* buf, size_t nBytes, size_t* nRead); 53 | OBOS_EXPORT obos_status Vfs_FdSeek(fd* desc, off_t off, whence_t whence); 54 | OBOS_EXPORT uoff_t Vfs_FdTellOff(const fd* desc); 55 | OBOS_EXPORT size_t Vfs_FdGetBlkSz(const fd* desc); 56 | OBOS_EXPORT obos_status Vfs_FdEOF(const fd* desc); 57 | OBOS_EXPORT struct vnode* Vfs_FdGetVnode(fd* desc); 58 | OBOS_EXPORT obos_status Vfs_FdIoctl(fd* desc, uint64_t request, void* argp); 59 | OBOS_EXPORT obos_status Vfs_FdFlush(fd* desc); 60 | OBOS_EXPORT obos_status Vfs_FdClose(fd* desc); 61 | -------------------------------------------------------------------------------- /src/oboskrnl/vfs/init.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/vfs/init.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | // Initializes the VFS. 12 | // After this is called, the root is set to the InitRD. 13 | void Vfs_Initialize(); 14 | // Finalizes VFS initialization. 15 | // To be called after fs drivers and disk drivers are done being loaded. 16 | // This mainly mounts the root fs as was specified in the kernel cmd line. 17 | // This also makes the special files: 18 | // /dev/null 19 | // /dev/zero 20 | // /dev/full 21 | void Vfs_FinalizeInitialization(); 22 | void Vfs_InitDummyDevices(); 23 | -------------------------------------------------------------------------------- /src/oboskrnl/vfs/limits.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/vfs/limits.h 3 | * 4 | * Copyright (c) 2024-2025 Omar Berrow 5 | * 6 | * Defines limits for the VFS. 7 | */ 8 | 9 | #pragma once 10 | 11 | #include 12 | 13 | #define MAX_FILENAME_LEN 256UL /* In bytes */ 14 | 15 | typedef int64_t off_t; 16 | typedef uint64_t uoff_t; 17 | #define OFF_T_MIN INT64_MIN 18 | #define OFF_T_MAX INT64_MAX 19 | #define UOFF_T_MIN UINT64_MIN 20 | #define UOFF_T_MAX UINT64_MAX 21 | typedef enum whence_t 22 | { 23 | SEEK_SET, 24 | SEEK_CUR, 25 | SEEK_END, 26 | } whence_t; 27 | -------------------------------------------------------------------------------- /src/oboskrnl/vfs/mount.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/vfs/mount.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include 19 | 20 | typedef LIST_HEAD(mount_list, struct mount) mount_list; 21 | LIST_PROTOTYPE(mount_list, struct mount, node); 22 | typedef struct mount 23 | { 24 | LIST_NODE(mount_list, struct mount) node; 25 | mutex lock; 26 | dirent* root; 27 | vdev* fs_driver; 28 | vnode* device; // the block device the filesystem is situated on. 29 | vnode* mounted_on; 30 | namecache nc; 31 | dirent_list dirent_list; 32 | atomic_size_t nWaiting; 33 | bool awaitingFree; 34 | } mount; 35 | extern struct dirent* Vfs_Root; 36 | extern mount_list Vfs_Mounted; 37 | 38 | // returns true if the operation succeeded. 39 | bool VfsH_LockMountpoint(mount* point); 40 | // returns true if the operation succeeded. 41 | bool VfsH_UnlockMountpoint(mount* point); 42 | 43 | obos_status Vfs_Mount(const char* at, vnode* on, vdev* fs_driver, mount** mountpoint); 44 | obos_status Vfs_Unmount(mount* what); 45 | obos_status Vfs_UnmountP(const char* at); 46 | 47 | obos_status Vfs_StatFSInfo(struct vnode* vn, struct drv_fs_info* out); 48 | -------------------------------------------------------------------------------- /src/oboskrnl/vfs/namecache.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/vfs/namecache.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | typedef RB_HEAD(namecache, namecache_ent) namecache; 18 | typedef LIST_HEAD(namecache_list, struct namecache_ent) namecache_list; 19 | 20 | typedef struct namecache_ent 21 | { 22 | RB_ENTRY(namecache_ent) rb_cache; 23 | LIST_NODE(namecache_list, struct namecache_ent) list_node; 24 | struct vnode* ref; 25 | struct dirent* ent; 26 | string path; // path relative to the mount point root. 27 | } namecache_ent; 28 | 29 | inline static int cmp_namecache_ent(const struct namecache_ent* a, const struct namecache_ent* b) 30 | { 31 | return uacpi_strcmp(OBOS_GetStringCPtr(&a->path), OBOS_GetStringCPtr(&b->path)); 32 | } 33 | RB_PROTOTYPE(namecache, namecache_ent, rb_cache, cmp_namecache_ent); 34 | LIST_PROTOTYPE(namecache_list, struct namecache_ent, list_node); -------------------------------------------------------------------------------- /src/oboskrnl/vfs/pipe.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/vfs/pipe.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | 18 | // fds is an array of 2 file descriptors 19 | obos_status Vfs_CreatePipe(fd* fds, size_t pipesize); 20 | obos_status Vfs_CreateNamedPipe(file_perm perm, gid group_uid, uid owner_uid, const char* parentpath, const char* name, size_t pipesize); 21 | 22 | // Called in Vfs_Initialize. 23 | void Vfs_InitializePipeInterface(); 24 | 25 | // !O_NONBLOCK, n <= PIPE_BUF: Atomic writes, block if no room 26 | // O_NONBLOCK, n <= PIPE_BUF: Atomic writes, return OBOS_STATUS_TRY_AGAIN if no room. 27 | // !O_NONBLOCK, n > PIPE_BUF: Unatomic writes, blocks until data is written (which includes blocking until the pipe is full). 28 | // O_NONBLOCK, n > PIPE_BUF: Unatomic writes, return OBOS_STATUS_TRY_AGAIN if no room. Note: Partial writes are possible (check nWritten). 29 | #define PIPE_BUF (512 /* minimum specified by POSIX */) 30 | 31 | typedef struct pipe_desc 32 | { 33 | struct waitable_header wait_hdr; 34 | vnode *vn; 35 | void* buf; 36 | size_t pipe_size; 37 | _Atomic(uintptr_t) offset; 38 | pushlock lock; 39 | } pipe_desc; 40 | -------------------------------------------------------------------------------- /src/sanitizers/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # uACPI/CMakeLists.txt 2 | 3 | # Copyright (c) 2024 Omar Berrow 4 | 5 | add_library(sanitizers STATIC "asan.c" "stack.c" "ubsan.c" "prof.c" "asan_memory.c") 6 | 7 | target_compile_options(sanitizers 8 | PRIVATE $<$:${TARGET_COMPILE_OPTIONS_C}> 9 | PRIVATE $<$:-ffreestanding> 10 | PRIVATE $<$:-Wall> 11 | PRIVATE $<$:-Wextra> 12 | PRIVATE $<$:-fstack-protector-all> 13 | PRIVATE $<$:-fno-builtin-memset> 14 | # PRIVATE $<$:-g0> 15 | PRIVATE $<$:-fvisibility=default> # We should have all symbols exported 16 | ) 17 | 18 | target_include_directories(sanitizers PRIVATE "${CMAKE_SOURCE_DIR}/src/oboskrnl") 19 | target_include_directories(sanitizers PRIVATE "${CMAKE_SOURCE_DIR}/src/sanitizers") 20 | target_include_directories(sanitizers PRIVATE ${OBOSKRNL_EXTERNAL_INCLUDES}) 21 | target_include_directories(sanitizers PUBLIC "${CMAKE_SOURCE_DIR}/src/uACPI") 22 | 23 | target_link_libraries(sanitizers PRIVATE ${LIBGCC}) 24 | 25 | target_compile_definitions(sanitizers 26 | PRIVATE $<$:OBOS_DEBUG> 27 | PRIVATE $<$:OBOS_RELEASE> 28 | PRIVATE $<$:OBOS_RELEASE> 29 | PRIVATE $<$:OBOS_RELEASE> 30 | PUBLIC UACPI_OVERRIDE_LIBC=1 31 | PUBLIC UACPI_OVERRIDE_ARCH_HELPERS=1 32 | PUBLIC UACPI_FORMATTED_LOGGING=1 33 | PUBLIC OBOS_KERNEL=1 34 | PUBLIC IS_UACPI_BUILD=1 35 | PRIVATE OBOS_ARCHITECTURE_HAS_ACPI=${OBOS_ARCHITECTURE_HAS_ACPI} 36 | ) 37 | target_link_options(sanitizers 38 | PRIVATE "-nostdlib" 39 | ) 40 | -------------------------------------------------------------------------------- /src/sanitizers/asan.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sanitizers/asan.h 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #define OBOS_CROSSES_PAGE_BOUNDARY(base, size) (((uintptr_t)(base) & ~(OBOS_PAGE_SIZE-1)) == ((((uintptr_t)(base) + (size)) & ~(OBOS_PAGE_SIZE-1)))) 16 | 17 | typedef enum 18 | { 19 | ASAN_InvalidType = 0, 20 | ASAN_InvalidAccess, 21 | ASAN_ShadowSpaceAccess, 22 | ASAN_UseAfterFree, 23 | ASAN_UninitMemory, 24 | ASAN_AllocatorMismatch, 25 | } asan_violation_type; 26 | // Used to index into OBOS_ASANPoisonValues. 27 | enum 28 | { 29 | ASAN_POISON_ALLOCATED, 30 | ASAN_POISON_FREED, 31 | ASAN_POISON_ANON_PAGE_UNINITED, 32 | ASAN_POISON_MAX = ASAN_POISON_ANON_PAGE_UNINITED, 33 | }; 34 | 35 | void OBOS_ASANReport(uintptr_t ip, uintptr_t addr, size_t sz, asan_violation_type type, bool rw); 36 | extern const uint8_t OBOS_ASANPoisonValues[ASAN_POISON_MAX + 1]; 37 | // Note: Still exists without KASAN. 38 | bool KASAN_IsAllocated(uintptr_t base, size_t size, bool rw); 39 | -------------------------------------------------------------------------------- /src/sanitizers/asan_memory.c: -------------------------------------------------------------------------------- 1 | /* 2 | * oboskrnl/sanitizers/asan_memory.c 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #ifdef __x86_64__ 11 | #include 12 | uintptr_t Arch_GetPML4Entry(uintptr_t pml4Base, uintptr_t addr); 13 | uintptr_t Arch_GetPML3Entry(uintptr_t pml4Base, uintptr_t addr); 14 | uintptr_t Arch_GetPML2Entry(uintptr_t pml4Base, uintptr_t addr); 15 | uintptr_t Arch_GetPML1Entry(uintptr_t pml4Base, uintptr_t addr); 16 | uintptr_t* Arch_AllocatePageMapAt(uintptr_t pml4Base, uintptr_t at, uintptr_t cpuFlags, uint8_t depth); 17 | bool Arch_FreePageMapAt(uintptr_t pml4Base, uintptr_t at, uint8_t maxDepth); 18 | obos_status Arch_MapPage(uintptr_t cr3, void* at_, uintptr_t phys, uintptr_t flags); 19 | obos_status Arch_MapHugePage(uintptr_t cr3, void* at_, uintptr_t phys, uintptr_t flags); 20 | #elif defined(__m68k__) 21 | #include 22 | obos_status Arch_GetPagePTE(page_table pt_root, uintptr_t virt, uint32_t* out); 23 | #endif 24 | 25 | OBOS_NO_KASAN bool KASAN_IsAllocated(uintptr_t base, size_t size, bool rw) 26 | { 27 | #ifdef __x86_64__ 28 | base &= ~0xfff; 29 | size += (0x1000 - (size & 0xfff)); 30 | uintptr_t flags = 1; 31 | if (rw) 32 | flags |= 2; 33 | for (uintptr_t addr = base; addr < (base + size); addr += 0x1000) 34 | { 35 | // First check if this is a huge page. 36 | uintptr_t entry = Arch_GetPML2Entry(getCR3(), addr); 37 | if (!(entry & flags)) 38 | return false; 39 | if (entry & (1 << 7)) 40 | goto check; 41 | entry = Arch_GetPML1Entry(getCR3(), addr); 42 | check: 43 | if (!(entry & flags)) 44 | return false; 45 | } 46 | #elif defined(__m68k__) 47 | obos_status Arch_GetPagePTE(page_table pt_root, uintptr_t virt, uint32_t* out); 48 | uintptr_t flags = 0b11|(0b1 << 7); 49 | if (!rw) 50 | flags |= (0b1 << 2); 51 | uintptr_t pt_root = 0; 52 | asm("movec.l %%srp, %0" :"=r"(pt_root) :); 53 | for (uintptr_t addr = base; addr < (base + size); addr += 0x1000) 54 | { 55 | uintptr_t entry = 0; 56 | Arch_GetPagePTE(pt_root, addr, &entry); 57 | if (!(entry & flags)) 58 | return false; 59 | } 60 | #else 61 | # error Unknown architecture! 62 | #endif 63 | return true; 64 | } 65 | -------------------------------------------------------------------------------- /src/sanitizers/prof.h: -------------------------------------------------------------------------------- 1 | #if OBOS_ENABLE_PROFILING 2 | 3 | // This file, and prof.c were found at 4 | // https://gist.github.com/monkuous/5752282d03995080e99671ecb9969b3f 5 | // with minor additions 6 | 7 | #ifndef HYDROGEN_UTIL_PROF_H 8 | #define HYDROGEN_UTIL_PROF_H 9 | 10 | #include 11 | 12 | typedef struct { 13 | void *fn; // function 14 | void *site; // call site 15 | uint64_t start; // tsc value when the function was called 16 | uint64_t ptime; // total time spent in profiler code across the entire call stack below this function, subtracted from runtime when adding to records 17 | } call_frame_t; 18 | 19 | #define MAX_FRAMES 64 20 | 21 | void prof_start(void); 22 | 23 | void prof_stop(void); 24 | 25 | void prof_reset(void); 26 | 27 | void prof_show(const char *name); 28 | 29 | #endif // HYDROGEN_UTIL_PROF_H 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /src/sanitizers/stack.c: -------------------------------------------------------------------------------- 1 | /* 2 | * sanitizers/stack.c 3 | * 4 | * Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | // Should be randomly set by kernel entry, but a default value will be provided anyway. 11 | #if UINTPTR_MAX == UINT64_MAX 12 | OBOS_EXPORT uint64_t __stack_chk_guard = 124770532977999; 13 | #elif UINT32_MAX == UINTPTR_MAX 14 | OBOS_EXPORT uint32_t __stack_chk_guard = 373612817; 15 | #endif 16 | 17 | OBOS_NORETURN OBOS_EXPORT void __stack_chk_fail() 18 | { 19 | OBOS_Panic(OBOS_PANIC_STACK_CORRUPTION, "Stack corruption detected at IP=0x%p (overwrite of stack canary).\n", __builtin_extract_return_addr(__builtin_return_address(0))); 20 | } 21 | -------------------------------------------------------------------------------- /src/uACPI/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # uACPI/CMakeLists.txt 2 | 3 | # Copyright (c) 2024 Omar Berrow 4 | 5 | if (OBOS_ARCHITECTURE_HAS_ACPI) 6 | include (${uacpi_cmake_file}) 7 | endif() 8 | 9 | add_library(uacpi STATIC ${UACPI_SOURCES} "kernel_api.c" "ec.c") 10 | 11 | target_compile_options(uacpi 12 | PRIVATE $<$:${TARGET_COMPILE_OPTIONS_C}> 13 | PRIVATE $<$:-ffreestanding> 14 | PRIVATE $<$:-Wall> 15 | PRIVATE $<$:-Wextra> 16 | PRIVATE $<$:-fstack-protector-all> 17 | PRIVATE $<$:-fno-builtin-memset> 18 | # PRIVATE $<$:-g0> 19 | PRIVATE $<$:-fvisibility=default> # uACPI should have all its symbols exported 20 | ) 21 | 22 | if (OBOS_ENABLE_PROFILER) 23 | target_compile_options(uacpi PRIVATE $<$:-finstrument-functions>) 24 | endif() 25 | 26 | # All symbols exported, except for the kernel api of course. 27 | set_source_files_properties("kernel_api.c" PROPERTIES COMPILE_OPTIONS "-fvisibility=hidden") 28 | 29 | target_include_directories(uacpi PRIVATE "${CMAKE_SOURCE_DIR}/src/oboskrnl") 30 | target_include_directories(uacpi PRIVATE "${CMAKE_SOURCE_DIR}/src/sanitizers") 31 | target_include_directories(uacpi PRIVATE ${OBOSKRNL_EXTERNAL_INCLUDES}) 32 | target_include_directories(uacpi PUBLIC "${CMAKE_SOURCE_DIR}/src/uACPI") 33 | 34 | target_link_libraries(uacpi PRIVATE ${LIBGCC} PRIVATE sanitizers) 35 | 36 | target_compile_definitions(uacpi 37 | PRIVATE $<$:OBOS_DEBUG> 38 | PRIVATE $<$:OBOS_RELEASE> 39 | PRIVATE $<$:OBOS_RELEASE> 40 | PRIVATE $<$:OBOS_RELEASE> 41 | PUBLIC UACPI_OVERRIDE_LIBC=1 42 | PUBLIC UACPI_OVERRIDE_ARCH_HELPERS=1 43 | PUBLIC UACPI_NATIVE_ALLOC_ZEROED=1 44 | PUBLIC UACPI_SIZED_FREES=1 45 | PUBLIC UACPI_FORMATTED_LOGGING=1 46 | PUBLIC UACPI_USE_BUILTIN_STRING=1 47 | PUBLIC OBOS_KERNEL=1 48 | PUBLIC IS_UACPI_BUILD=1 49 | PRIVATE OBOS_ARCHITECTURE_HAS_ACPI=${OBOS_ARCHITECTURE_HAS_ACPI} 50 | ) 51 | target_link_options(uacpi 52 | PRIVATE "-nostdlib" 53 | ) 54 | -------------------------------------------------------------------------------- /src/uACPI/uacpi_arch_helpers.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #if OBOS_ARCHITECTURE_HAS_ACPI 6 | # ifdef __x86_64__ 7 | # define UACPI_ARCH_FLUSH_CPU_CACHE() asm volatile ("wbinvd") 8 | # define UACPI_ARCH_DISABLE_INTERRUPTS() asm volatile ("cli") 9 | # define UACPI_ARCH_ENABLE_INTERRUPTS() asm volatile ("sti") /* not actually used by uacpi */ 10 | # else 11 | # error Invalid architecture. 12 | # endif 13 | # ifndef UACPI_ATOMIC_LOAD_THREAD_ID 14 | # define UACPI_ATOMIC_LOAD_THREAD_ID(ptr) ((uacpi_thread_id)uacpi_atomic_load_ptr(ptr)) 15 | # endif 16 | 17 | # ifndef UACPI_ATOMIC_STORE_THREAD_ID 18 | # define UACPI_ATOMIC_STORE_THREAD_ID(ptr, value) uacpi_atomic_store_ptr(ptr, value) 19 | # endif 20 | 21 | # include 22 | 23 | # ifndef UACPI_THREAD_ID_NONE 24 | # define UACPI_THREAD_ID_NONE ((uacpi_thread_id)-1) 25 | # endif 26 | 27 | typedef uint8_t uacpi_cpu_flags; 28 | typedef uintptr_t uacpi_thread_id; 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/uACPI/uacpi_libc.h: -------------------------------------------------------------------------------- 1 | /* 2 | libs/uACPI/uacpi_stdlib.h 3 | 4 | Copyright (c) 2024 Omar Berrow 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | // Now handled somewhere else 12 | // #define UACPI_PRIx64 "lx" 13 | // #define UACPI_PRIX64 "lX" 14 | // #define UACPI_PRIu64 "lu" 15 | 16 | // #define PRIx64 UACPI_PRIx64 17 | // #define PRIX64 UACPI_PRIX64 18 | // #define PRIu64 UACPI_PRIu64 19 | 20 | // #define uacpi_offsetof(t, m) ((uintptr_t)(&((t*)0)->m)) 21 | 22 | #ifdef __cplusplus 23 | extern "C" { 24 | #endif 25 | OBOS_EXPORT void *uacpi_memcpy(void *dest, const void* src, size_t sz); 26 | OBOS_EXPORT void *uacpi_memset(void *dest, int src, size_t cnt); 27 | OBOS_EXPORT int uacpi_memcmp(const void *src1, const void *src2, size_t cnt); 28 | OBOS_EXPORT int uacpi_strncmp(const char *src1, const char *src2, size_t maxcnt); 29 | OBOS_EXPORT int uacpi_strcmp(const char *src1, const char *src2); 30 | OBOS_EXPORT void *uacpi_memmove(void *dest, const void* src, size_t sz); 31 | OBOS_EXPORT size_t uacpi_strnlen(const char *src, size_t maxcnt); 32 | OBOS_EXPORT size_t uacpi_strlen(const char *src); 33 | OBOS_EXPORT int uacpi_snprintf(char* dest, size_t n, const char* format, ...); 34 | #ifdef __cplusplus 35 | } 36 | #endif 37 | #define uacpi_memcpy uacpi_memcpy 38 | #define uacpi_memset uacpi_memset 39 | #define uacpi_memmove uacpi_memmove 40 | #define uacpi_memcmp uacpi_memcmp 41 | #define uacpi_strcmp uacpi_strcmp 42 | #define uacpi_strncmp uacpi_strncmp 43 | #define uacpi_strnlen uacpi_strnlen 44 | #define uacpi_strlen uacpi_strlen 45 | #define uacpi_snprintf uacpi_snprintf -------------------------------------------------------------------------------- /src/user_examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # user_examples/CMakeLists.txt 2 | # 3 | # Copyright (c) 2025 Omar Berrow 4 | 5 | if (OBOS_ENABLE_UBSAN) 6 | add_compile_options("-fno-sanitize=undefined") 7 | endif() 8 | if (OBOS_ENABLE_KASAN) 9 | add_compile_options("-fno-sanitize=address") 10 | endif() 11 | 12 | link_libraries(syscall_invoke) 13 | 14 | add_executable (powerctl "powerctl_example.c") 15 | add_executable (klog-level "klog_level_example.c") 16 | add_executable (fork-test "fork_example.c") 17 | add_executable (mem-usage "mem_usage_example.c") 18 | add_executable (mount "mount_example.c") 19 | add_executable (umount "umount_example.c") 20 | 21 | if (${OBOS_ARCHITECTURE} STREQUAL "x86_64") 22 | add_executable(obos-gettime "x86_timeofday_example.c") 23 | endif() -------------------------------------------------------------------------------- /src/user_examples/fork_example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main(int argc, char** argv, char** envp) 6 | { 7 | printf("testing fork\n"); 8 | pid_t pid = fork(); 9 | if (pid == 0) 10 | printf("in child, we are %d\n", getpid()); 11 | else if (pid > 0) 12 | printf("in parent, child is %d\n", pid); 13 | else 14 | printf("error\n"); 15 | return 0; 16 | } 17 | -------------------------------------------------------------------------------- /src/user_examples/klog_level_example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char** argv) 8 | { 9 | if (argc < 2) 10 | { 11 | printf("%s level\n", argv[0]); 12 | return -1; 13 | } 14 | int level = strtol(argv[1], NULL, 0); 15 | if (level == LONG_MAX) 16 | { 17 | perror("strtol"); 18 | return -1; 19 | } 20 | if (level < 0 || level > 4) 21 | { 22 | errno = EINVAL; 23 | perror("Sys_SetKLogLevel"); 24 | return -1; 25 | } 26 | syscall1(Sys_SetKLogLevel, level); 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /src/user_examples/mount_example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | static int parse_file_status(obos_status status) 11 | { 12 | switch (status) 13 | { 14 | case OBOS_STATUS_SUCCESS: return 0; 15 | case OBOS_STATUS_NOT_FOUND: return ENOENT; 16 | case OBOS_STATUS_INVALID_ARGUMENT: return EINVAL; 17 | case OBOS_STATUS_PAGE_FAULT: return EFAULT; 18 | case OBOS_STATUS_NOT_A_FILE: return EISDIR; 19 | case OBOS_STATUS_UNINITIALIZED: return EBADF; 20 | case OBOS_STATUS_EOF: return EIO; 21 | case OBOS_STATUS_ACCESS_DENIED: return EACCES; 22 | case OBOS_STATUS_NO_SYSCALL: return ENOSYS; 23 | case OBOS_STATUS_NOT_ENOUGH_MEMORY: return ENOSPC; 24 | case OBOS_STATUS_PIPE_CLOSED: return EPIPE; 25 | default: abort(); 26 | } 27 | } 28 | 29 | int main(int argc, char** argv) 30 | { 31 | if (argc < 3) 32 | { 33 | printf("Usage: %s device target\n", argv[0]); 34 | return -1; 35 | } 36 | char* target = argv[2]; 37 | char* device = argv[1]; 38 | obos_status st = syscall2(Sys_Mount, target, device); 39 | if (obos_is_error(st)) 40 | { 41 | errno = parse_file_status(st); 42 | perror("Sys_Mount"); 43 | return -1; 44 | } 45 | 46 | return 0; 47 | } -------------------------------------------------------------------------------- /src/user_examples/powerctl_example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | static char obos_getchar() 7 | { 8 | char ch[2] = {}; 9 | syscall4(Sys_FdRead, 0, &ch, 2, NULL); 10 | return ch[0]; 11 | } 12 | #define confirm() do \ 13 | {\ 14 | fputs("Continue? y/n ", stderr);\ 15 | char c = 0;\ 16 | do {\ 17 | c = obos_getchar();\ 18 | switch (c)\ 19 | {\ 20 | case 'y': break;\ 21 | case 'n': puts("Abort"); return 1;\ 22 | case '\n': c = 'y'; break;\ 23 | default: fputs("Please put y/n ", stderr); break;\ 24 | }\ 25 | } while(c != 'y');\ 26 | } while(0) 27 | 28 | int main(int argc, char** argv) 29 | { 30 | const char* option = argv[1] ? argv[1] : "shutdown"; 31 | if (strcasecmp(option, "suspend") == 0) 32 | { 33 | puts("Suspending..."); 34 | confirm(); 35 | syscall0(Sys_Suspend); 36 | } 37 | else if (strcasecmp(option, "reboot") == 0) 38 | { 39 | puts("Rebooting..."); 40 | confirm(); 41 | syscall0(Sys_Reboot); 42 | } 43 | else 44 | { 45 | puts("Shutting down..."); 46 | confirm(); 47 | syscall0(Sys_Shutdown); 48 | } 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /src/user_examples/umount_example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | static int parse_file_status(obos_status status) 11 | { 12 | switch (status) 13 | { 14 | case OBOS_STATUS_SUCCESS: return 0; 15 | case OBOS_STATUS_NOT_FOUND: return ENOENT; 16 | case OBOS_STATUS_INVALID_ARGUMENT: return EINVAL; 17 | case OBOS_STATUS_PAGE_FAULT: return EFAULT; 18 | case OBOS_STATUS_NOT_A_FILE: return EISDIR; 19 | case OBOS_STATUS_UNINITIALIZED: return EBADF; 20 | case OBOS_STATUS_EOF: return EIO; 21 | case OBOS_STATUS_ACCESS_DENIED: return EACCES; 22 | case OBOS_STATUS_NO_SYSCALL: return ENOSYS; 23 | case OBOS_STATUS_NOT_ENOUGH_MEMORY: return ENOSPC; 24 | case OBOS_STATUS_PIPE_CLOSED: return EPIPE; 25 | default: abort(); 26 | } 27 | } 28 | 29 | int main(int argc, char** argv) 30 | { 31 | if (argc < 3) 32 | { 33 | printf("Usage: %s target\n", argv[0]); 34 | return -1; 35 | } 36 | char* target = argv[2]; 37 | char* device = argv[1]; 38 | obos_status st = syscall1(Sys_Unmount, target); 39 | if (obos_is_error(st)) 40 | { 41 | errno = parse_file_status(st); 42 | perror("Sys_Unmount"); 43 | return -1; 44 | } 45 | 46 | return 0; 47 | } -------------------------------------------------------------------------------- /src/user_examples/x86_timeofday_example.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define SysS_ClockGet 0x80000002 6 | 7 | int main() 8 | { 9 | long secs = 0; 10 | long nsecs = 0; 11 | syscall3(SysS_ClockGet, 0, &secs, &nsecs); 12 | struct tm* time = localtime(&secs); 13 | printf("%d-%02d-%02d %02d:%02d:%02d\n", time->tm_year+1900, time->tm_mon+1, time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec); 14 | return 0; 15 | } --------------------------------------------------------------------------------