diff --git a/.gitignore b/.gitignore index 02e2a916..b4dcf36d 100644 --- a/.gitignore +++ b/.gitignore @@ -8,9 +8,9 @@ /dependencies/uACPI /dependencies/uHDA /dependencies/flanterm/ -/dependencies/freebsd-e1000/ -/dependencies/include/ /dependencies/freebsd-e1000 +/dependencies/limine +/dependencies/include/ /dependencies/needs_download.cmake /qemu_log.txt /tar diff --git a/CMakeLists.txt b/CMakeLists.txt index a52ad865..478be4ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,7 @@ option (OBOS_LAZY_IRQL "Enables lazy IRQL. Recommended if the main target of the option (OBOS_USE_OBOS_GCC "Uses arch-obos-gcc instead of obos-elf-gcc. Ignored if OBOS_USE_CLANG is true.") option (OBOS_COMPILE_USER_UTILS "Compiles user examples" ${OBOS_USE_OBOS_GCC}) option (OBOS_ONLY_COMPILE_USER_UTILS "Only compile user utilities" OFF) +option (OBOS_USE_LIMINE "Use Limine instead of Hyper on supported architectures" OFF) option (OBOS_ENABLE_UHDA "Whether to include uHDA" ON) set (OBOS_LAZY_IRQL OFF) @@ -87,6 +88,10 @@ if (OBOS_REFRESH_DEPENDENCIES) message("Fetching Hyper.") include("dependencies/hyper.cmake") endif() + if (OBOS_USE_LIMINE) + message("Fetching Limine.") + include("dependencies/limine.cmake") + endif() message("Fetching uACPI.") include ("dependencies/uacpi.cmake") message("Fetching flanterm.") @@ -105,6 +110,9 @@ else() if (NOT EXISTS hyper_install AND OBOS_ARCHITECTURE STREQUAL "x86_64") include("dependencies/hyper.cmake") endif() + if (OBOS_USE_LIMINE AND NOT EXISTS limine_exe) + include("dependencies/limine.cmake") + endif() if (NOT EXISTS uacpi_cmake_file) include("dependencies/uacpi.cmake") endif() @@ -129,7 +137,14 @@ if (OBOS_LAZY_IRQL) else() set (OBOS_LAZY_IRQL "0") endif() + add_compile_definitions(OBOS_LAZY_IRQL=${OBOS_LAZY_IRQL}) +if (OBOS_USE_LIMINE) + set (OBOS_USE_LIMINE "1") +else() + set (OBOS_USE_LIMINE "0") +endif() +add_compile_definitions(OBOS_USE_LIMINE=${OBOS_USE_LIMINE}) if (OBOS_ENABLE_LOCK_PROFILING) set (OBOS_ENABLE_LOCK_PROFILING "1") diff --git a/README.md b/README.md index e7c12566..0a6c9d60 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,7 @@ # OBOS OBOS uses ***✨ state of the art technology ✨*** to do ***✨ almost nothing ✨*** ## Downloads -- ISO Downloads can currently be found at http://obos-dev.ddns.net/images/ -- An XBPS binary package repository exists at http://obos-dev.ddns.net/current for x86_64-obos **only**. +- The obos file server can be found at http://obos-dev.ddns.net/ ## Building ### Prerequisites - (For an x86-64 build) NASM @@ -63,9 +62,6 @@ call launch_qemu.bat - x86_64-obos: Working, not all ported programs work - m68k-obos: Userspace is unstable, but the port works otherwise - For information on ported programs, go to the obos-pkgs repository -## Credits -- My friend [@LemurLord16](https://github.com/LemurLord16) (@sigsbeedrive on discord) for listening to me yap about new features. -- My cousin Ali because why not. ## License Notice Most code in this repository is licensed under the MIT license.
Any code from other projects that require a license notice will be put below. diff --git a/config/hyper.cfg b/config/hyper.cfg index 86eda3ec..5bbf11b7 100644 --- a/config/hyper.cfg +++ b/config/hyper.cfg @@ -28,3 +28,7 @@ module: type="memory" name="FLANTERM_BUFF" size=16777216 +module: + type="memory" + name="BUMP_REGION" + size=16777216 diff --git a/config/limine.conf b/config/limine.conf new file mode 100644 index 00000000..2282dd43 --- /dev/null +++ b/config/limine.conf @@ -0,0 +1,32 @@ +timeout: 5 + +/OBOS + protocol: limine + comment: OBOS + + paging_mode: 4level + module_path: boot():/obos/initrd.tar + module_string: initrd + module_path: boot():/obos/initrd + module_string: initrd_driver + module_path: boot():/obos/flanterm_buff + module_string: FLANTERM_BUFF + module_path: boot():/obos/flanterm_buff + module_string: BUMP_REGION + path: boot():/obos/oboskrnl + cmdline: initrd-module=initrd initrd-driver-module=initrd_driver root-fs-partid initrd load-modules=/libps2,/extfs initial-swap-size=67108864 log-level=1 init-args /usr/bin/bash --login +/OBOS (Login) + protocol: limine + comment: OBOS (Login Prompt) + + paging_mode: 4level + module_path: boot():/obos/initrd.tar + module_string: initrd + module_path: boot():/obos/initrd + module_string: initrd_driver + module_path: boot():/obos/flanterm_buff + module_string: FLANTERM_BUFF + module_path: boot():/obos/flanterm_buff + module_string: BUMP_REGION + path: boot():/obos/oboskrnl + cmdline: initrd-module=initrd initrd-driver-module=initrd_driver root-fs-partid initrd load-modules=/libps2,/extfs initial-swap-size=67108864 log-level=1 init-args /usr/bin/bash --login -c login \ No newline at end of file diff --git a/dependencies/limine.cmake b/dependencies/limine.cmake new file mode 100644 index 00000000..7efdd0a6 --- /dev/null +++ b/dependencies/limine.cmake @@ -0,0 +1,26 @@ +# dependencies/limine.cmake + +# Copyright (c) 2025 Omar Berrow + +include(FetchContent) + +if (OBOS_REFRESH_DEPENDENCIES) + FetchContent_Declare(Limine + GIT_REPOSITORY https://github.com/limine-bootloader/limine.git + GIT_TAG v10.3.0-binary + SOURCE_DIR ${CMAKE_SOURCE_DIR}/dependencies/limine + ) + FetchContent_MakeAvailable(Limine) + file (COPY_FILE "${CMAKE_SOURCE_DIR}/dependencies/limine/limine.h" "${CMAKE_SOURCE_DIR}/dependencies/include/limine.h") +endif() +if(CMAKE_HOST_SYSTEM_NAME STREQUAL "Linux") + execute_process( + COMMAND "make" + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/dependencies/limine + ) + set (limine_exe ${CMAKE_SOURCE_DIR}/dependencies/limine/limine CACHE INTERNAL "x") + # elseif (CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows" OR CMAKE_HOST_SYSTEM_NAME STREQUAL "MSYS") + # set (limine_exe ${CMAKE_SOURCE_DIR}/dependencies/limine/limine.exe CACHE INTERNAL "x") +else() + message(FATAL_ERROR "You must be on to compile OBOS with Limine.") +endif() diff --git a/dependencies/uacpi.cmake b/dependencies/uacpi.cmake index 7a026d32..88627c79 100644 --- a/dependencies/uacpi.cmake +++ b/dependencies/uacpi.cmake @@ -9,7 +9,7 @@ if (OBOS_REFRESH_DEPENDENCIES) # In honor of the old uACPI link #GIT_REPOSITORY https://github.com/UltraOS/uACPI.git GIT_REPOSITORY https://github.com/uACPI/uACPI.git - GIT_TAG 3.0.0 + GIT_TAG 3.2.0 SOURCE_DIR ${CMAKE_SOURCE_DIR}/dependencies/uACPI ) FetchContent_MakeAvailable(uACPI) diff --git a/screenshots/20251202_0930.png b/screenshots/20251202_0930.png new file mode 100644 index 00000000..fa9682cd Binary files /dev/null and b/screenshots/20251202_0930.png differ diff --git a/scripts/launch_qemu.sh b/scripts/launch_qemu.sh index b178d690..bfe11054 100755 --- a/scripts/launch_qemu.sh +++ b/scripts/launch_qemu.sh @@ -13,7 +13,6 @@ qemu-system-x86_64 \ -debugcon file:/dev/stdout \ -monitor stdio \ -serial tcp:0.0.0.0:1534,server,nowait \ --smp cores=1,threads=1,sockets=1 \ -d int \ -D qemu_log.txt "$@" diff --git a/scripts/launch_qemu.tcg.sh b/scripts/launch_qemu.tcg.sh new file mode 100755 index 00000000..2635452c --- /dev/null +++ b/scripts/launch_qemu.tcg.sh @@ -0,0 +1,26 @@ +cd ../ + +rm qemu_log.txt + +echo $@ +qemu-system-x86_64 \ +-drive format=raw,file=out/obos.iso,media=disk,index=0 \ +-m 2G \ +-gdb tcp:0.0.0.0:1234 -S \ +-M q35 \ +-cpu Haswell \ +-accel tcg \ +-debugcon file:/dev/stdout \ +-monitor stdio \ +-serial tcp:0.0.0.0:1534,server,nowait \ +-d int \ +-D qemu_log.txt "$@" + +# -nographic +# -enable-kvm \ +# -M smm=off \ +# -no-reboot +# -enable-kvm \ +# -no-shutdown + +cd scripts diff --git a/src/drivers/generic/ahci/command.c b/src/drivers/generic/ahci/command.c index 8796aaef..e5e0bd04 100644 --- a/src/drivers/generic/ahci/command.c +++ b/src/drivers/generic/ahci/command.c @@ -14,7 +14,8 @@ #include -#include "locks/wait.h" +#include + #include "structs.h" #include "command.h" @@ -159,6 +160,9 @@ void WaitForTranscations() Port* port = Ports + i; for (size_t j = 0; j < 32; j++) if (port->CommandBitmask & BIT(j) && port->PendingCommands[j]) - Core_WaitOnObject(WAITABLE_OBJECT(port->PendingCommands[j]->completionEvent)); + { + obos_status status = Core_WaitOnObject(WAITABLE_OBJECT(port->PendingCommands[j]->completionEvent)); + OBOS_UNUSED(status); + } } } diff --git a/src/drivers/generic/ahci/interface.c b/src/drivers/generic/ahci/interface.c index 08c6996c..a1352513 100644 --- a/src/drivers/generic/ahci/interface.c +++ b/src/drivers/generic/ahci/interface.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -63,7 +64,7 @@ static obos_status populate_physical_regions(uintptr_t base, size_t size, struct base &= ~1; const size_t MAX_PRDT_COUNT = sizeof(((HBA_CMD_TBL*)nullptr))->prdt_entry/sizeof(HBA_PRDT_ENTRY); /* - data->phys_regions = Mm_Allocator->Reallocate(Mm_Allocator, data->phys_regions, ++data->physRegionCount*sizeof(struct ahci_phys_region), nullptr); + data->phys_regions = Reallocate(Mm_Allocator, data->phys_regions, ++data->physRegionCount*sizeof(struct ahci_phys_region), nullptr); struct ahci_phys_region* reg = &data->phys_regions[data->physRegionCount - 1]; */ long bytesLeft = size; @@ -83,17 +84,25 @@ static obos_status populate_physical_regions(uintptr_t base, size_t size, struct { if (data->physRegionCount >= MAX_PRDT_COUNT) return OBOS_STATUS_INTERNAL_ERROR; + + Mm_HandlePageFault(ctx, addr, (data->direction == COMMAND_DIRECTION_WRITE ? 0 : PF_EC_RW) | (ctx == &Mm_KernelContext ? 0 : PF_EC_UM)); + page_info info = {}; MmS_QueryPageInfo(ctx->pt, addr, &info, nullptr); + page key = {.phys=info.phys}; page* pg = RB_FIND(phys_page_tree, &Mm_PhysicalPages, &key); + OBOS_ENSURE(pg != Mm_AnonPage); + OBOS_ENSURE(pg != Mm_UserAnonPage); + MmH_RefPage(pg); + if ((lastPhys + pgSize) != info.phys) { if (addr != base) { size_t old_sz = data->physRegionCount*sizeof(struct ahci_phys_region); - data->phys_regions = Mm_Allocator->Reallocate(Mm_Allocator, data->phys_regions, ++data->physRegionCount*sizeof(struct ahci_phys_region), old_sz, nullptr); + data->phys_regions = Reallocate(Mm_Allocator, data->phys_regions, ++data->physRegionCount*sizeof(struct ahci_phys_region), old_sz, nullptr); struct ahci_phys_region* reg = &data->phys_regions[data->physRegionCount - 1]; *reg = curr; wroteback = true; @@ -116,7 +125,7 @@ static obos_status populate_physical_regions(uintptr_t base, size_t size, struct if (!wroteback && curr.phys) { size_t old_sz = data->physRegionCount*sizeof(struct ahci_phys_region); - data->phys_regions = Mm_Allocator->Reallocate(Mm_Allocator, data->phys_regions, ++data->physRegionCount*sizeof(struct ahci_phys_region), old_sz, nullptr); + data->phys_regions = Reallocate(Mm_Allocator, data->phys_regions, ++data->physRegionCount*sizeof(struct ahci_phys_region), old_sz, nullptr); struct ahci_phys_region* reg = &data->phys_regions[data->physRegionCount - 1]; *reg = curr; } @@ -145,7 +154,7 @@ static obos_status unpopulate_physical_regions(uintptr_t base, size_t size, stru MmH_DerefPage(pg); pgSize = info.prot.huge_page ? OBOS_HUGE_PAGE_SIZE : OBOS_PAGE_SIZE; } - Mm_Allocator->Free(Mm_Allocator, data->phys_regions, data->physRegionCount*sizeof(struct ahci_phys_region)); + Free(Mm_Allocator, data->phys_regions, data->physRegionCount*sizeof(struct ahci_phys_region)); return OBOS_STATUS_SUCCESS; } // #pragma GCC pop_options @@ -215,7 +224,12 @@ obos_status read_sync(dev_desc desc, void* buf, size_t blkCount, size_t blkOffse // irql oldIrql = Core_RaiseIrql(IRQL_AHCI); SendCommand(port, &data, blkOffset, 0x40, blkCount == 0x10000 ? 0 : blkCount); // Core_LowerIrql(oldIrql); - Core_WaitOnObject(WAITABLE_OBJECT(data.completionEvent)); + if (obos_is_error(status = Core_WaitOnObject(WAITABLE_OBJECT(data.completionEvent)))) + { + Core_SemaphoreRelease(&port->lock); + unpopulate_physical_regions((uintptr_t)buf, blkCount*port->sectorSize, &data); + break; + } Core_EventClear(&data.completionEvent); if (!port->works) { @@ -275,7 +289,12 @@ obos_status write_sync(dev_desc desc, const void* buf, size_t blkCount, size_t b { SendCommand(port, &data, blkOffset, 0x40, blkCount == 0x10000 ? 0 : blkCount); HBA->ghc |= BIT(1) /* GhcIE */; - Core_WaitOnObject(WAITABLE_OBJECT(data.completionEvent)); + if (obos_is_error(status = Core_WaitOnObject(WAITABLE_OBJECT(data.completionEvent)))) + { + Core_SemaphoreRelease(&port->lock); + unpopulate_physical_regions((uintptr_t)buf, blkCount*port->sectorSize, &data); + break; + } Core_EventClear(&data.completionEvent); if (!port->works) { diff --git a/src/drivers/generic/ahci/main.c b/src/drivers/generic/ahci/main.c index 61f635b2..515b9fea 100644 --- a/src/drivers/generic/ahci/main.c +++ b/src/drivers/generic/ahci/main.c @@ -158,6 +158,7 @@ static void* map_registers(uintptr_t phys, size_t size, bool uc) page.phys = phys+offset; MmS_SetPageMapping(Mm_KernelContext.pt, &page, phys + offset, false); } + Drv_TLBShootdown(Mm_KernelContext.pt, (uintptr_t)virt, size); return virt+phys_page_offset; } diff --git a/src/drivers/generic/extfs/helper.c b/src/drivers/generic/extfs/helper.c index caa19c38..aa6da2ab 100644 --- a/src/drivers/generic/extfs/helper.c +++ b/src/drivers/generic/extfs/helper.c @@ -213,8 +213,7 @@ void ext_ino_foreach_block(ext_cache* cache, } struct read_block_packet { - void* buffer; - size_t buffer_offset; + uint32_t* blocks; size_t count; size_t start_offset; size_t current_offset; @@ -233,18 +232,7 @@ static iterate_decision read_cb(ext_cache* cache, ext_inode* inode, uint32_t *bl decision = ITERATE_DECISION_STOP; goto out1; } - void* const buff = (void*)((uintptr_t)packet->buffer + packet->buffer_offset); - if (!block) - memzero(buff, cache->block_size); // sparse block - else - { - page* pg = nullptr; - void* data = ext_read_block(cache, *block, &pg); - MmH_RefPage(pg); - memcpy(buff, data, OBOS_MIN(packet->count - packet->buffer_offset, cache->block_size)); - MmH_DerefPage(pg); - } - packet->buffer_offset += cache->block_size; + packet->blocks[(packet->current_offset - packet->start_offset) / cache->block_size] = block ? *block : UINT32_MAX; out1: packet->current_offset += cache->block_size; @@ -262,11 +250,97 @@ obos_status ext_ino_read_blocks(ext_cache* cache, uint32_t ino, size_t offset, s return OBOS_STATUS_INVALID_ARGUMENT; if ((offset + count) > inode->blocks*512) count = (offset + count) - inode->blocks*512; - struct read_block_packet userdata = {.buffer=buffer,.start_offset=offset,.count=count,.buffer_offset=0}; + uint32_t nBlocks = count /= cache->block_size; + uint32_t* blocks = ZeroAllocate(OBOS_KernelAllocator, nBlocks, sizeof(uint32_t), nullptr); + struct read_block_packet userdata = {.blocks=blocks,.start_offset=offset,.count=count}; ext_ino_foreach_block(cache, ino, read_cb, &userdata); MmH_DerefPage(pg); + uint32_t current_block_base = 0; + uint32_t current_block_index = 0; + uint32_t current_block_count = 0; + bool read_current = false; + irp** irps = nullptr; + size_t nIrps = 0; + bool refresh_next = true; + for (uint32_t i = 0; i < nBlocks; i++) + { + if (blocks[i] == UINT32_MAX) + { + // TODO: Make that asynchronous? + memzero((void*)((uintptr_t)buffer + i*cache->block_size), cache->block_size); + refresh_next = true; + continue; + } + if (refresh_next) + { + read_current = false; + refresh_next = false; + current_block_base = blocks[i]; + ++current_block_count; + current_block_index = i; + continue; + } + if (blocks[i] == (current_block_base + current_block_count)) + { + read_current = false; + ++current_block_count; + continue; + } + irp* req = VfsH_IRPAllocate(); + VfsH_IRPBytesToBlockCount(cache->vn, current_block_count*cache->block_size, &req->blkCount); + VfsH_IRPBytesToBlockCount(cache->vn, current_block_base*cache->block_size, &req->blkOffset); + req->vn = cache->vn; + req->buff = (void*)((uintptr_t)buffer + current_block_index*cache->block_size); + req->op = IRP_READ; + VfsH_IRPSubmit(req, nullptr); + read_current = true; + if (req->evnt && !Core_EventGetState(req->evnt)) + { + size_t oldsize = nIrps*sizeof(irp*); + nIrps++; + irps = Reallocate(OBOS_KernelAllocator, irps, nIrps*sizeof(irp*), oldsize, nullptr); + irps[nIrps-1] = req; + } + if (blocks[i] == UINT32_MAX) + continue; + current_block_index = i; + current_block_base = blocks[i]; + current_block_count++; + } + if (!read_current) + { + irp* req = VfsH_IRPAllocate(); + VfsH_IRPBytesToBlockCount(cache->vn, current_block_count*cache->block_size, &req->blkCount); + VfsH_IRPBytesToBlockCount(cache->vn, current_block_base*cache->block_size, &req->blkOffset); + req->vn = cache->vn; + req->buff = (void*)((uintptr_t)buffer + current_block_index*cache->block_size); + req->op = IRP_READ; + VfsH_IRPSubmit(req, nullptr); + read_current = true; + if (req->evnt && !Core_EventGetState(req->evnt)) + { + size_t oldsize = nIrps*sizeof(irp*); + nIrps++; + irps = Reallocate(OBOS_KernelAllocator, irps, nIrps*sizeof(irp*), oldsize, nullptr); + irps[nIrps-1] = req; + } + else + { + VfsH_IRPWait(req); + VfsH_IRPUnref(req); + } + } + for (size_t i = 0; i < nIrps; i++) + { + VfsH_IRPWait(irps[i]); + VfsH_IRPUnref(irps[i]); + irps[i] = nullptr; + } + Free(OBOS_KernelAllocator, irps, nIrps*sizeof(irp*)); + + Free(OBOS_KernelAllocator, blocks, nBlocks*sizeof(uint32_t)); if (nRead) - *nRead = userdata.buffer_offset; + *nRead = count; return userdata.status; } @@ -628,6 +702,7 @@ uint32_t allocate_bmp(ext_cache* cache, const uint32_t* block_group_ptr, int wha buffer = ext_read_block(cache, block, &pg); MmH_RefPage(pg); } + OBOS_ENSURE(buffer); if (buffer[i] != 0xff) { uint8_t bit = __builtin_ctz(~buffer[i]); @@ -663,7 +738,13 @@ uint32_t allocate_bmp(ext_cache* cache, const uint32_t* block_group_ptr, int wha uint32_t ext_ino_allocate(ext_cache* cache, const uint32_t* block_group_ptr) { - return allocate_bmp(cache, block_group_ptr, ALLOC_INODE); + uint32_t ret = allocate_bmp(cache, block_group_ptr, ALLOC_INODE); + ext_bgd* bgd = &cache->bgdt[ext_ino_get_block_group(cache, ret)]; + bgd->free_inodes--; + cache->superblock.free_inode_count--; + ext_writeback_sb(cache); + ext_writeback_bgd(cache, ext_ino_get_block_group(cache, ret)); + return ret; } void ext_ino_free(ext_cache* cache, uint32_t ino) @@ -706,7 +787,13 @@ void ext_ino_free(ext_cache* cache, uint32_t ino) uint32_t ext_blk_allocate(ext_cache* cache, const uint32_t* block_group_ptr) { - return allocate_bmp(cache, block_group_ptr, ALLOC_BLOCK); + uint32_t blk = allocate_bmp(cache, block_group_ptr, ALLOC_BLOCK); + ext_bgd* bgd = &cache->bgdt[blk/cache->blocks_per_group]; + bgd->free_blocks--; + cache->superblock.free_block_count--; + ext_writeback_sb(cache); + ext_writeback_bgd(cache, blk/cache->blocks_per_group); + return blk; } void ext_blk_free(ext_cache* cache, uint32_t blk) diff --git a/src/drivers/generic/extfs/interface.c b/src/drivers/generic/extfs/interface.c index f3a453e0..6b5d232b 100644 --- a/src/drivers/generic/extfs/interface.c +++ b/src/drivers/generic/extfs/interface.c @@ -210,6 +210,7 @@ obos_status vnode_search(void** vn_found, dev_desc desc, void* dev_vn) ext_inode_handle* hnd = (void*)desc; cache = hnd->cache; ino = hnd->ino; + OBOS_ENSURE(cache); } *vn_found = ext_make_vnode(cache, ino, nullptr); @@ -322,11 +323,14 @@ static void on_match(ext_inode** const inode, ext_cache* const cache) { uint32_t ino = dent->ino; - size_t old_size = *nToRead; - *nToRead = le32_to_host((*inode)->blocks) * 512; - *buffer = Reallocate(EXT_Allocator, *buffer, *nToRead, old_size, nullptr); - ext_ino_read_blocks(cache, ino, 0, *nToRead, *buffer, nullptr); - *offset = 0; + if (dent->file_type == EXT2_FT_DIR) + { + size_t old_size = *nToRead; + *nToRead = le32_to_host((*inode)->blocks) * 512; + *buffer = Reallocate(EXT_Allocator, *buffer, *nToRead, old_size, nullptr); + ext_ino_read_blocks(cache, ino, 0, *nToRead, *buffer, nullptr); + *offset = 0; + } MmH_DerefPage(*pg); *inode = ext_read_inode_pg(cache, ino, pg); MmH_RefPage(*pg); @@ -334,7 +338,7 @@ static void on_match(ext_inode** const inode, obos_status path_search(dev_desc* found, void* vn, const char* path, dev_desc parent) { - if (!found || !vn || !path) + if (!found || (!vn && parent == UINTPTR_MAX) || !path) return OBOS_STATUS_INVALID_ARGUMENT; uint32_t parent_ino = 0; @@ -410,7 +414,10 @@ obos_status path_search(dev_desc* found, void* vn, const char* path, dev_desc pa { get_next_tok(); if (tok == (path + path_len)) + { *found = get_desc(cache, ent->ino); + break; + } on_match(&inode, &pg, &buffer, @@ -418,10 +425,6 @@ obos_status path_search(dev_desc* found, void* vn, const char* path, dev_desc pa &offset, ent, cache); - if (!(*found)) - continue; - else - break; } } diff --git a/src/drivers/generic/extfs/probe.c b/src/drivers/generic/extfs/probe.c index f9cfcfa2..898fe9f5 100644 --- a/src/drivers/generic/extfs/probe.c +++ b/src/drivers/generic/extfs/probe.c @@ -140,7 +140,10 @@ vnode* ext_make_vnode(ext_cache* cache, uint32_t ino, mount* mnt) } ext_inode* inode = ext_read_inode(cache, ino); - + OBOS_ASSERT(inode); + if (!inode) + return nullptr; + uint32_t vtype = 0; if (ext_ino_test_type(inode, EXT2_S_IFDIR)) vtype = VNODE_TYPE_DIR; @@ -163,8 +166,8 @@ vnode* ext_make_vnode(ext_cache* cache, uint32_t ino, mount* mnt) vn->desc = (dev_desc)handle; vn->vtype = vtype; vn->blkSize = 1; - vn->owner_uid = inode->uid; - vn->group_uid = inode->gid; + vn->uid = inode->uid; + vn->gid = inode->gid; vn->filesize = (uint64_t)inode->size | (ext_sb_supports_64bit_filesize ? (uint64_t)inode->dir_acl << 32 : 0); vn->times.access = inode->access_time; vn->times.birth = inode->creation_time; diff --git a/src/drivers/generic/freebsd-e1000/CMakeLists.txt b/src/drivers/generic/freebsd-e1000/CMakeLists.txt index 4d2655c4..f5c7fa8e 100644 --- a/src/drivers/generic/freebsd-e1000/CMakeLists.txt +++ b/src/drivers/generic/freebsd-e1000/CMakeLists.txt @@ -17,6 +17,10 @@ target_compile_options(e1000 PRIVATE $<$:-Wno-error> ) +if (OBOS_ENABLE_FANALYZER) + target_compile_options(e1000 PRIVATE "-fno-analyzer") +endif() + set_property(TARGET e1000 PROPERTY link_depends ${DRIVER_LINKER_SCRIPT}) target_include_directories(e1000 diff --git a/src/drivers/generic/freebsd-e1000/dev.h b/src/drivers/generic/freebsd-e1000/dev.h index 7ff1f103..c7b3f6f7 100644 --- a/src/drivers/generic/freebsd-e1000/dev.h +++ b/src/drivers/generic/freebsd-e1000/dev.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include @@ -19,7 +20,8 @@ #include #define RX_QUEUE_SIZE (32) -#define TX_QUEUE_SIZE (8) +#define TX_QUEUE_SIZE (32) +#define TX_BUFFER_PAGES (4) typedef struct e1000_frame { void* buff; @@ -51,6 +53,7 @@ typedef struct e1000_device { page* tx_ring_phys_pg; size_t tx_index; event tx_done_evnt; + uintptr_t tx_buffers[TX_QUEUE_SIZE]; size_t refs; @@ -80,7 +83,7 @@ typedef struct e1000_handle { void e1000_init_rx(e1000_device* dev); void e1000_init_tx(e1000_device* dev); -event* e1000_tx_packet(e1000_device* dev, const void* buffer, size_t size, bool dry); +event* e1000_tx_packet(e1000_device* dev, const void* buffer, size_t size, bool dry, obos_status* status); void e1000_irq_handler(struct irq* i, interrupt_frame* frame, void* userdata, irql oldIrql); bool e1000_check_irq_callback(struct irq* i, void* userdata); \ No newline at end of file diff --git a/src/drivers/generic/freebsd-e1000/io.c b/src/drivers/generic/freebsd-e1000/io.c index feaba376..a3b1e90e 100644 --- a/src/drivers/generic/freebsd-e1000/io.c +++ b/src/drivers/generic/freebsd-e1000/io.c @@ -7,6 +7,7 @@ */ #include +#include #include @@ -17,6 +18,7 @@ #include #include +#include #include @@ -24,8 +26,11 @@ #include +#include + #include "dev.h" + LIST_GENERATE(e1000_frame_list, e1000_frame, node); #define EM_RADV 64 @@ -191,13 +196,6 @@ void e1000_init_tx(e1000_device* dev) { dev->tx_ring_phys_pg = MmH_PgAllocatePhysical(false, false); dev->tx_ring = dev->tx_ring_phys_pg->phys; - struct e1000_tx_desc* desc = ((struct e1000_tx_desc*)MmS_MapVirtFromPhys(dev->tx_ring)); - for (size_t i = 0; i < TX_QUEUE_SIZE; i++) - { - desc[i].buffer_addr = 0; - desc[i].lower.data = 0; - desc[i].upper.fields.status = E1000_TXD_STAT_DD; - } // Copied from managarm E1000_WRITE_REG(&dev->hw, E1000_TDLEN(0), TX_QUEUE_SIZE * sizeof(struct e1000_tx_desc)); @@ -205,8 +203,8 @@ void e1000_init_tx(e1000_device* dev) E1000_WRITE_REG(&dev->hw, E1000_TDBAL(0), (u32)dev->tx_ring); /* Init the HEAD/TAIL indices */ - E1000_WRITE_REG(&dev->hw, E1000_TDT(0), 0); E1000_WRITE_REG(&dev->hw, E1000_TDH(0), 0); + E1000_WRITE_REG(&dev->hw, E1000_TDT(0), 0); u32 txdctl = 0; /* clear txdctl */ txdctl |= 0x1f; /* PTHRESH */ @@ -273,7 +271,7 @@ void e1000_init_tx(e1000_device* dev) /* Program the Transmit Control Register */ u32 tctl = E1000_READ_REG(&dev->hw, E1000_TCTL); tctl &= ~E1000_TCTL_CT; - tctl |= (E1000_TCTL_RTLC | E1000_TCTL_EN | (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT)); + tctl |= (E1000_TCTL_RTLC | E1000_TCTL_EN | E1000_TCTL_PSP | (E1000_COLLISION_THRESHOLD << E1000_CT_SHIFT)); if (dev->hw.mac.type >= e1000_82571) tctl |= E1000_TCTL_MULR; @@ -293,14 +291,24 @@ void e1000_init_tx(e1000_device* dev) reg |= E1000_TARC0_CB_MULTIQ_2_REQ; E1000_WRITE_REG(&dev->hw, E1000_TARC(0), reg); } + + struct e1000_tx_desc* desc = ((struct e1000_tx_desc*)MmS_MapVirtFromPhys(dev->tx_ring)); + for (size_t i = 0; i < TX_QUEUE_SIZE; i++) + { + dev->tx_buffers[i] = Mm_AllocatePhysicalPages(TX_BUFFER_PAGES, 1, nullptr); + desc[i].buffer_addr = dev->tx_buffers[i]; + desc[i].lower.data = 0; + desc[i].upper.data = 0; + } + OBOS_ENSURE(memcmp_b(desc, 0, sizeof(*desc)*TX_QUEUE_SIZE) == false); } void e1000_tx_reap(e1000_device* dev); -event* e1000_tx_packet(e1000_device* dev, const void* buffer, size_t size, bool dry) +event* e1000_tx_packet(e1000_device* dev, const void* buffer, size_t size, bool dry, obos_status* status) { e1000_tx_reap(dev); - struct e1000_tx_desc* desc = &((struct e1000_tx_desc*)MmS_MapVirtFromPhys(dev->tx_ring))[dev->tx_index % TX_QUEUE_SIZE]; + volatile struct e1000_tx_desc* desc = &((volatile struct e1000_tx_desc*)MmS_MapVirtFromPhys(dev->tx_ring))[dev->tx_index % TX_QUEUE_SIZE]; if (dry) return nullptr; irql oldIrql = Core_RaiseIrql(IRQL_E1000); @@ -308,18 +316,24 @@ event* e1000_tx_packet(e1000_device* dev, const void* buffer, size_t size, bool size_t nPages = size / OBOS_PAGE_SIZE; if (size % OBOS_PAGE_SIZE) nPages++; - uintptr_t buff = Mm_AllocatePhysicalPages(nPages, 1, nullptr); + if (nPages > TX_BUFFER_PAGES) + return nullptr; + uintptr_t buff = dev->tx_buffers[dev->tx_index % TX_QUEUE_SIZE]; memcpy(MmS_MapVirtFromPhys(buff), buffer, size); desc->buffer_addr = buff; desc->upper.data = 0; desc->lower.data = size | E1000_TXD_CMD_EOP | E1000_TXD_CMD_RS; + E1000_WRITE_REG(&dev->hw, E1000_TDBAH(0), (u32)(dev->tx_ring >> 32)); + E1000_WRITE_REG(&dev->hw, E1000_TDBAL(0), (u32)dev->tx_ring); E1000_WRITE_REG(&dev->hw, E1000_TDT(0), ++dev->tx_index % TX_QUEUE_SIZE); - - while (~desc->upper.data & E1000_TXD_STAT_DD) - continue; - // printf("ret from %s, upper.data=0x%x, lower.data=0x%x, buffer=0x%p\n", __func__, desc->upper.data, desc->lower.data, desc->buffer_addr); - + Core_LowerIrql(oldIrql); + + uintptr_t deadline = CoreS_GetTimerTick() + CoreH_TimeFrameToTick(1*1000*1000); + while (~desc->upper.data & E1000_TXD_STAT_DD && CoreS_GetTimerTick() < deadline) + Core_Yield(); + if (~desc->upper.data & E1000_TXD_STAT_DD) + *status = OBOS_STATUS_TIMED_OUT; return nullptr; } @@ -373,15 +387,16 @@ static void tx_event_set_dpc(dpc* d, void* udata) } void e1000_tx_reap(e1000_device* dev) { - struct e1000_tx_desc* desc = &((struct e1000_tx_desc*)MmS_MapVirtFromPhys(dev->tx_ring))[0]; + volatile struct e1000_tx_desc* desc = &((struct e1000_tx_desc*)MmS_MapVirtFromPhys(dev->tx_ring))[0]; size_t i = dev->tx_index; for (; ; ) { - if (~desc[i].upper.fields.status & E1000_TXD_STAT_DD) + if (~desc[i].upper.data & E1000_TXD_STAT_DD) break; desc[i].upper.fields.status = 0; - desc[i].lower.data = 0; - desc[i].buffer_addr = 0; + desc[i].lower.data = 0; + desc[i].buffer_addr = 0; + i++; } dev->tx_index = i; } diff --git a/src/drivers/generic/freebsd-e1000/main.c b/src/drivers/generic/freebsd-e1000/main.c index 6d531ee6..61ceaf47 100644 --- a/src/drivers/generic/freebsd-e1000/main.c +++ b/src/drivers/generic/freebsd-e1000/main.c @@ -6,6 +6,7 @@ #include #include +#include #include @@ -29,6 +30,7 @@ #include #include "dev.h" +#include "e1000/e1000_defines.h" OBOS_PAGEABLE_FUNCTION obos_status get_blk_size(dev_desc desc, size_t* blkSize) { @@ -124,9 +126,11 @@ static void irp_on_tx_event_set(irp* req) e1000_handle* hnd = (void*)req->desc; if (req->evnt) Core_EventClear(req->evnt); - req->evnt = e1000_tx_packet(hnd->dev, req->cbuff,req->blkCount, req->dryOp); + req->status = OBOS_STATUS_SUCCESS; + req->evnt = e1000_tx_packet(hnd->dev, req->cbuff,req->blkCount, req->dryOp, &req->status); req->on_event_set = nullptr; - req->status = req->evnt ? OBOS_STATUS_IRP_RETRY : OBOS_STATUS_SUCCESS; + if (obos_is_success(req->status)) + req->status = req->evnt ? OBOS_STATUS_IRP_RETRY : OBOS_STATUS_SUCCESS; if (req->status) req->nBlkWritten = req->blkCount; } @@ -152,9 +156,9 @@ obos_status submit_irp(void* request) } else { - req->evnt = e1000_tx_packet(hnd->dev, req->cbuff, req->blkCount, req->dryOp); + req->status = OBOS_STATUS_SUCCESS; + req->evnt = e1000_tx_packet(hnd->dev, req->cbuff, req->blkCount, req->dryOp, &req->status); req->on_event_set = irp_on_tx_event_set; - req->status = req->evnt ? OBOS_STATUS_IRP_RETRY : OBOS_STATUS_SUCCESS; if (obos_is_success(req->status)) req->nBlkWritten = req->blkCount; } @@ -272,6 +276,7 @@ static void* map_registers(uintptr_t phys, size_t size, bool uc, bool mmio, bool MmH_RefPage(pg); MmS_SetPageMapping(Mm_KernelContext.pt, &page, phys + offset, false); } + Drv_TLBShootdown(Mm_KernelContext.pt, (uintptr_t)virt, size); return virt+phys_page_offset; } @@ -326,7 +331,10 @@ static void search_bus(pci_bus* bus) Devices = OBOS_NonPagedPoolAllocator->Reallocate(OBOS_NonPagedPoolAllocator, Devices, nDevices*sizeof(e1000_device), (nDevices-1)*sizeof(e1000_device), nullptr); memzero(&Devices[nDevices-1], sizeof(Devices[nDevices-1])); - dev->resource_cmd_register->cmd_register |= 0x7; // io space + memspace + bus master + // for (volatile bool b = true; b;) + // OBOSS_SpinlockHint(); + + dev->resource_cmd_register->cmd_register |= 0x7; Drv_PCISetResource(dev->resource_cmd_register); Devices[nDevices-1].hw.back = &Devices[nDevices-1].osdep; @@ -393,16 +401,6 @@ static void search_bus(pci_bus* bus) e1000_get_bus_info(&Devices[nDevices-1].hw); - if (e1000_reset_hw(&Devices[nDevices-1].hw) != E1000_SUCCESS) - { - Mm_VirtualMemoryFree(&Mm_KernelContext, (void*)Devices[nDevices-1].osdep.membase, bar0->bar->size); - nDevices--; - Devices = Reallocate(OBOS_NonPagedPoolAllocator, Devices, nDevices*sizeof(e1000_device), (nDevices+1)*sizeof(e1000_device), nullptr); - OBOS_Warning("%02x:%02x:%02x: Bogus E1000 PCI node.", dev->location.bus, dev->location.slot, dev->location.function); - dev = LIST_GET_NEXT(pci_device_list, &bus->devices, dev); - continue; - } - Devices[nDevices-1].hw.mac.autoneg = 1; Devices[nDevices-1].hw.phy.autoneg_wait_to_complete = false; Devices[nDevices-1].hw.phy.autoneg_advertised = (ADVERTISE_10_HALF | ADVERTISE_10_FULL | ADVERTISE_100_HALF | ADVERTISE_100_FULL | ADVERTISE_1000_FULL); @@ -414,6 +412,27 @@ static void search_bus(pci_bus* bus) } Devices[nDevices-1].hw.mac.report_tx_early = true; + + if (e1000_reset_hw(&Devices[nDevices-1].hw) != E1000_SUCCESS) + { + Mm_VirtualMemoryFree(&Mm_KernelContext, (void*)Devices[nDevices-1].osdep.membase, bar0->bar->size); + nDevices--; + Devices = Reallocate(OBOS_NonPagedPoolAllocator, Devices, nDevices*sizeof(e1000_device), (nDevices+1)*sizeof(e1000_device), nullptr); + OBOS_Warning("%02x:%02x:%02x: Bogus E1000 PCI node.", dev->location.bus, dev->location.slot, dev->location.function); + dev = LIST_GET_NEXT(pci_device_list, &bus->devices, dev); + continue; + } + e1000_power_up_phy(&Devices[nDevices-1].hw); + + if (e1000_validate_nvm_checksum(&Devices[nDevices-1].hw) != E1000_SUCCESS) + { + Mm_VirtualMemoryFree(&Mm_KernelContext, (void*)Devices[nDevices-1].osdep.membase, bar0->bar->size); + nDevices--; + Devices = Reallocate(OBOS_NonPagedPoolAllocator, Devices, nDevices*sizeof(e1000_device), (nDevices+1)*sizeof(e1000_device), nullptr); + OBOS_Warning("%02x:%02x:%02x: Bogus E1000 PCI node.", dev->location.bus, dev->location.slot, dev->location.function); + dev = LIST_GET_NEXT(pci_device_list, &bus->devices, dev); + continue; + } // if (e1000_init_hw(&Devices[nDevices-1].hw) != E1000_SUCCESS) // { @@ -425,7 +444,6 @@ static void search_bus(pci_bus* bus) // continue; // } - e1000_power_up_phy(&Devices[nDevices-1].hw); e1000_disable_ulp_lpt_lp(&Devices[nDevices-1].hw, true); Devices[nDevices-1].rx_evnt = EVENT_INITIALIZE(EVENT_NOTIFICATION); @@ -444,8 +462,8 @@ static void search_bus(pci_bus* bus) Devices[nDevices-1].irq.irqCheckerUserdata = Devices + nDevices - 1; Devices[nDevices-1].irq.handlerUserdata = Devices + nDevices - 1; - e1000_init_tx(&Devices[nDevices-1]); e1000_init_rx(&Devices[nDevices-1]); + e1000_init_tx(&Devices[nDevices-1]); e1000_clear_hw_cntrs_base_generic(&Devices[nDevices-1].hw); E1000_WRITE_REG(&Devices[nDevices-1].hw, E1000_IMS, IMS_ENABLE_MASK); diff --git a/src/drivers/generic/initrd/main.c b/src/drivers/generic/initrd/main.c index 0932982c..a94981d0 100644 --- a/src/drivers/generic/initrd/main.c +++ b/src/drivers/generic/initrd/main.c @@ -177,7 +177,6 @@ static int64_t strrfind(const char* str, char ch) initrd_inode* create_inode_boot(const ustar_hdr* hdr) { initrd_inode* ino = ZeroAllocate(OBOS_KernelAllocator, 1, sizeof(initrd_inode), nullptr); - ino->ino = CurrentInodeNumber++; bool path_needs_slash = hdr->filename[0] != '/' && (*hdr->prefix && hdr->prefix[strnlen(hdr->prefix, 155)-1] != '/'); ino->path_len = strnlen(hdr->filename, 100) + strnlen(hdr->prefix, 155) + path_needs_slash; @@ -201,8 +200,6 @@ initrd_inode* create_inode_boot(const ustar_hdr* hdr) ino->name = Allocate(OBOS_KernelAllocator, ino->name_len+1, nullptr); memcpy(ino->name, ino->path+index, ino->name_len); ino->name[ino->name_len] = 0; - ino->filesize = oct2bin(hdr->filesize, strnlen(hdr->filesize, 12)); - ino->data = (char*)hdr + 512; // ino->data = Allocate(OBOS_NonPagedPoolAllocator, ino->filesize, nullptr); // if (!ino->data) // { @@ -213,6 +210,7 @@ initrd_inode* create_inode_boot(const ustar_hdr* hdr) // return nullptr; // } // memcpy(ino->data, (char*)hdr + 512, ino->filesize); + back: switch (hdr->type) { case AREGTYPE: case REGTYPE: @@ -221,13 +219,29 @@ initrd_inode* create_inode_boot(const ustar_hdr* hdr) case DIRTYPE: ino->type = FILE_TYPE_DIRECTORY; break; - case LNKTYPE: case SYMTYPE: ino->type = FILE_TYPE_SYMBOLIC_LINK; break; + case LNKTYPE: + { + obos_status status = OBOS_STATUS_SUCCESS; + hdr = GetFile(hdr->linked, &status); + if (obos_is_error(status)) + { + Free(OBOS_KernelAllocator, ino->name, ino->name_size); + Free(OBOS_KernelAllocator, ino->path, ino->path_size); + Free(OBOS_KernelAllocator, ino, sizeof(*ino)); + return nullptr; + } + goto back; + break; + } default: OBOS_ENSURE(!"Unrecognized header type"); } + ino->filesize = oct2bin(hdr->filesize, strnlen(hdr->filesize, 12)); + ino->data = (char*)hdr + 512; + uint16_t filemode = oct2bin(hdr->filemode, strnlen(hdr->filemode, 8)); ino->perm.group_read = filemode & FILEMODE_GROUP_READ; ino->perm.owner_read = filemode & FILEMODE_OWNER_READ; @@ -242,13 +256,12 @@ initrd_inode* create_inode_boot(const ustar_hdr* hdr) ino->perm.set_gid = filemode & 02000; ino->linked_path = hdr->linked; - ino->vnode = Vfs_Calloc(1, sizeof(vnode)); ino->vnode->desc = (uintptr_t)ino; ino->vnode->filesize = ino->filesize; ino->vnode->blkSize = 1; - ino->vnode->owner_uid = 0; - ino->vnode->group_uid = 0; + ino->vnode->uid = 0; + ino->vnode->gid = 0; ino->vnode->inode = ino->ino; ino->vnode->perm = ino->perm; ino->vnode->times.change = oct2bin(hdr->last_mod, strnlen(hdr->last_mod, 12)); @@ -270,6 +283,8 @@ initrd_inode* create_inode_boot(const ustar_hdr* hdr) } ino->hdr = hdr; + ino->ino = CurrentInodeNumber++; + return ino; } driver_init_status OBOS_DriverEntry(driver_id* this) @@ -315,6 +330,8 @@ driver_init_status OBOS_DriverEntry(driver_id* this) goto down; initrd_inode* ino = create_inode_boot(hdr); + if (!ino) + return (driver_init_status){.status=OBOS_STATUS_INTERNAL_ERROR,.fatal=false}; ino->parent = InitrdRoot; if (!ino->parent->children.head) ino->parent->children.head = ino; @@ -472,6 +489,8 @@ initrd_inode* create_inode_with_parents(const char* path, const ustar_hdr* hdr) return nullptr; initrd_inode* ino = create_inode_boot(hdr); + if (!ino) + return nullptr; // Get our parent. int64_t index = strrfind(ino->path, '/'); if (index == -1) @@ -508,6 +527,13 @@ initrd_inode* create_inode_with_parents(const char* path, const ustar_hdr* hdr) goto down; initrd_inode* sub_ino = create_inode_boot(sub_hdr); + if (!sub_ino) + { + Free(OBOS_KernelAllocator, ino->name, ino->name_size); + Free(OBOS_KernelAllocator, ino->path, ino->path_size); + Free(OBOS_KernelAllocator, ino, sizeof(*ino)); + return nullptr; + } sub_ino->parent = ino->parent; // printf("%s %s\n", iter, sub_ino->parent->name); if (!sub_ino->parent->children.head) @@ -618,7 +644,7 @@ OBOS_PAGEABLE_FUNCTION obos_status list_dir(dev_desc dir_, void* unused, iterate initrd_inode *ino = DirentLookupFrom(hdr_path, dir); if (!ino) ino = create_inode_with_parents(hdr_path, hdr); - if (ino->dead) + if (!ino || ino->dead) goto down; if (cb((dev_desc)ino, 1, ino->filesize, userdata, ino->name) == ITERATE_DECISION_STOP) { diff --git a/src/drivers/generic/libps2/keyboard.c b/src/drivers/generic/libps2/keyboard.c index 02822840..cef6ad7b 100644 --- a/src/drivers/generic/libps2/keyboard.c +++ b/src/drivers/generic/libps2/keyboard.c @@ -155,7 +155,9 @@ static obos_status read_code(void* handle, keycode* out, bool block) if (!Core_EventGetState(port->data_ready_event) && !block) return OBOS_STATUS_WOULD_BLOCK; - Core_WaitOnObject(WAITABLE_OBJECT(*port->data_ready_event)); + obos_status status = Core_WaitOnObject(WAITABLE_OBJECT(*port->data_ready_event)); + if (obos_is_error(status)) + return status; } return PS2_RingbufferFetchKeycode(&data->input, &hnd->in_ptr, out); @@ -282,10 +284,9 @@ OBOS_PAGEABLE_FUNCTION void PS2_InitializeKeyboard(ps2_port* port) // 'true' is not an error, see PS2_StartKeyboard port->suppress_irqs = true; - - data->set = set; + data->input.e = EVENT_INITIALIZE(EVENT_NOTIFICATION); port->data_ready_event = &data->input.e; port->read_code = read_code; port->make_handle = make_handle; diff --git a/src/drivers/generic/libps2/mouse.c b/src/drivers/generic/libps2/mouse.c index 29b197a8..5c3768bc 100644 --- a/src/drivers/generic/libps2/mouse.c +++ b/src/drivers/generic/libps2/mouse.c @@ -36,7 +36,9 @@ static obos_status read_pckt(void* handle, mouse_packet* out, bool block) if (!Core_EventGetState(port->data_ready_event) && !block) return OBOS_STATUS_WOULD_BLOCK; - Core_WaitOnObject(WAITABLE_OBJECT(*port->data_ready_event)); + obos_status status = Core_WaitOnObject(WAITABLE_OBJECT(*port->data_ready_event)); + if (obos_is_error(status)) + return status; } return PS2_RingbufferFetchMousePacket(&data->packets, &hnd->in_ptr, out); diff --git a/src/drivers/generic/r8169/device.c b/src/drivers/generic/r8169/device.c index 17a549be..ebd72b27 100644 --- a/src/drivers/generic/r8169/device.c +++ b/src/drivers/generic/r8169/device.c @@ -385,6 +385,7 @@ static void* map_registers(uintptr_t phys, size_t size, bool uc, bool mmio, bool MmH_RefPage(pg); MmS_SetPageMapping(Mm_KernelContext.pt, &page, phys + offset, false); } + Drv_TLBShootdown(Mm_KernelContext.pt, (uintptr_t)virt, size); return virt+phys_page_offset; } diff --git a/src/drivers/test_driver/fireworks.c b/src/drivers/test_driver/fireworks.c index ed3b4c1e..7e099a39 100644 --- a/src/drivers/test_driver/fireworks.c +++ b/src/drivers/test_driver/fireworks.c @@ -290,7 +290,7 @@ void particle_handler(void* udata) udata[3] = t.lastTimeTicked; if (obos_is_error(status)) goto die; - Core_WaitOnObject(WAITABLE_OBJECT(e)); + status = Core_WaitOnObject(WAITABLE_OBJECT(e)); goto die; } int t = 0; diff --git a/src/init/main.c b/src/init/main.c index 339db47a..16d945a6 100644 --- a/src/init/main.c +++ b/src/init/main.c @@ -144,13 +144,13 @@ int main(int argc, char** argv) setenv("PATH", "/usr/bin:/bin:/usr/sbin:/sbin", 1); + nm_initialize_hostname(); + nm_initialize_interfaces("/etc/interfaces.json"); + int ret = print_motd(); if (ret != 0) return ret; - nm_initialize_hostname(); - nm_initialize_interfaces("/etc/interfaces.json"); - syscall1(Sys_SetKLogLevel, final_log_level); // Start a shell, I guess. @@ -179,7 +179,7 @@ int main(int argc, char** argv) top: waitpid(pid, &status, 0); if (WIFSIGNALED(status)) - printf("Child exitted due to signal %d\n", WTERMSIG(status)); + printf("Handoff process exited due to signal %d\n", WTERMSIG(status)); if (!WIFEXITED(status) && !WIFSIGNALED(status)) goto top; sigchld_handler(SIGCHLD); diff --git a/src/init/nm.c b/src/init/nm.c index 3b6ea998..9a2546d4 100644 --- a/src/init/nm.c +++ b/src/init/nm.c @@ -146,6 +146,8 @@ bool nm_initialize_interface(cJSON* top_level) pid_t pid = 0; if ((pid = fork()) == 0) { + setpgrp(); + tcsetpgrp(0, getpgrp()); char *argv[3] = { "obos_dhcpc", (char*)interface_name, @@ -189,19 +191,37 @@ bool nm_initialize_interface(cJSON* top_level) for (size_t i = 0; i < ip_table_len; i++) { if (ip_table[i].address.addr && ip_table[i].broadcast.addr && ip_table[i].subnet) - ioctl(fd, IOCTL_IFACE_ADD_IP_TABLE_ENTRY, &ip_table[i]); + { + if (ioctl(fd, IOCTL_IFACE_ADD_IP_TABLE_ENTRY, &ip_table[i]) != 0) + { + fprintf(stderr, "ioctl(IOCTL_IFACE_ADD_IP_TABLE_ENTRY): %s\nIs the interface already configured?\n", strerror(errno)); + return false; + } + } else fprintf(stderr, "NM: %s: Skipping invalid ip table entry\n", interface_name); } for (size_t i = 0; i < nGateways; i++) { if (gateways[i].src.addr && gateways[i].dest.addr) - ioctl(fd, IOCTL_IFACE_ADD_ROUTING_TABLE_ENTRY, &gateways[i]); + { + if (ioctl(fd, IOCTL_IFACE_ADD_ROUTING_TABLE_ENTRY, &gateways[i]) != 0) + { + fprintf(stderr, "ioctl(IOCTL_IFACE_ADD_ROUTING_TABLE_ENTRY): %s\nIs the router up, or is the interface already configured?\n", strerror(errno)); + return false; + } + } else fprintf(stderr, "NM: %s: Skipping invalid static route\n", interface_name); } if (default_gateway.addr) - ioctl(fd, IOCTL_IFACE_SET_DEFAULT_GATEWAY, &default_gateway); + { + if (ioctl(fd, IOCTL_IFACE_SET_DEFAULT_GATEWAY, &default_gateway) != 0) + { + fprintf(stderr, "ioctl(IOCTL_IFACE_SET_DEFAULT_GATEWAY): %s\nIs the router up, or is the interface already configured?\n", strerror(errno)); + return false; + } + } else fprintf(stderr, "NM: %s: Skipping default gateway\n", interface_name); @@ -264,7 +284,7 @@ void nm_initialize_interfaces(const char* config_file) if (nm_initialize_interface(obj)) nInterfacesInitialized++; } - printf("NM: Initialized %ld interfaces (%ld failed)\n", nInterfacesInitialized, nInterfaces-nInterfacesInitialized); + printf("NM: Initialized %ld interfaces (%ld failed)\n\n", nInterfacesInitialized, nInterfaces-nInterfacesInitialized); cJSON_Delete(top_level); } diff --git a/src/isogen/isogen.cmake b/src/isogen/isogen.cmake index da04ffbe..85027121 100644 --- a/src/isogen/isogen.cmake +++ b/src/isogen/isogen.cmake @@ -14,9 +14,6 @@ endif() if (NOT EXISTS ${ISODIR}/obos) file (MAKE_DIRECTORY ${ISODIR}/obos) endif() -if (NOT EXISTS ${CMAKE_SOURCE_DIR}/config/hyper.cfg) - message(FATAL_ERROR "No hyper configuration file detected!") -endif() if (CMAKE_HOST_WIN32) set(SUPPRESS_OUTPUT > NUL 2>&1) @@ -24,24 +21,48 @@ elseif(CMAKE_HOST_LINUX) set(SUPPRESS_OUTPUT > /dev/null 2>&1) endif() +if (OBOS_USE_LIMINE) + set (LIMINE_ENABLED "true") + set (LIMINE_NOT_ENABLED "false") + set(BIOS_INSTALL ${limine_exe} bios-install ${OUTPUT_DIR}/obos.iso ${SUPPRESS_OUTPUT}) + set(BIOS_PRE_XORRISO fallocate -l16M ${ISODIR}/obos/flanterm_buff && cmake -E make_directory ${ISODIR}/limine/ && cmake -E copy ${CMAKE_SOURCE_DIR}/dependencies/limine/limine-bios.sys ${ISODIR}/limine/) + set(BTLDR_CONF "limine.conf") + set(xorriso_bios_cd_path "dependencies/limine/limine-bios-cd.bin") + set(xorriso_uefi_cd_path "dependencies/limine/limine-uefi-cd.bin") + set(xorriso_uefi_cd_name "limine-uefi-cd.bin") + set(xorriso_bios_cd_name "limine-bios-cd.bin") +else() + set(BIOS_INSTALL ${hyper_install} ${OUTPUT_DIR}/obos.iso ${SUPPRESS_OUTPUT}) + set(BIOS_PRE_XORRISO true) + set(BTLDR_CONF "hyper.cfg") + set(xorriso_bios_cd_path "dependencies/hyper/hyper_iso_boot") + set(xorriso_uefi_cd_path "config/hyper_uefi_boot.bin") + set(xorriso_uefi_cd_name "hyper_uefi_boot.bin") + set(xorriso_bios_cd_name "hyper_iso_boot") +endif() + +if (NOT EXISTS ${CMAKE_SOURCE_DIR}/config/${BTLDR_CONF}) + message(FATAL_ERROR "No bootloader configuration file detected!") +endif() + add_custom_command(OUTPUT ${OUTPUT_DIR}/obos.iso COMMAND ${OBJCOPY} -g ${OUTPUT_DIR}/oboskrnl ${ISODIR}/obos/oboskrnl ${SUPPRESS_OUTPUT} - COMMAND cmake -E copy ${CMAKE_SOURCE_DIR}/config/hyper.cfg ${ISODIR}/ ${SUPPRESS_OUTPUT} - COMMAND cmake -E copy ${CMAKE_SOURCE_DIR}/dependencies/hyper/hyper_iso_boot ${ISODIR} ${SUPPRESS_OUTPUT} - COMMAND cmake -E copy ${CMAKE_SOURCE_DIR}/config/hyper_uefi_boot.bin ${ISODIR} ${SUPPRESS_OUTPUT} + COMMAND cmake -E copy ${CMAKE_SOURCE_DIR}/config/${BTLDR_CONF} ${ISODIR}/ ${SUPPRESS_OUTPUT} + COMMAND cmake -E copy ${CMAKE_SOURCE_DIR}/${xorriso_bios_cd_path} ${ISODIR} ${SUPPRESS_OUTPUT} + COMMAND cmake -E copy ${CMAKE_SOURCE_DIR}/${xorriso_uefi_cd_path} ${ISODIR} ${SUPPRESS_OUTPUT} COMMAND cmake -E copy ${CMAKE_SOURCE_DIR}/out/initrd ${ISODIR}/obos ${SUPPRESS_OUTPUT} COMMAND cmake -E copy ${CMAKE_SOURCE_DIR}/config/initrd.tar ${ISODIR}/obos ${SUPPRESS_OUTPUT} - 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} - COMMAND chmod +x ${hyper_install} - COMMAND ${hyper_install} ${OUTPUT_DIR}/obos.iso ${SUPPRESS_OUTPUT} - BYPRODUCTS ${ISODIR}/hyper.cfg - ${ISODIR}/hyper_iso_boot - ${ISODIR}/hyper_uefi_boot.bin + COMMAND ${BIOS_PRE_XORRISO} + COMMAND xorriso -as mkisofs -b ${xorriso_bios_cd_name} -no-emul-boot -boot-load-size 4 -boot-info-table --efi-boot ${xorriso_uefi_cd_name} -efi-boot-part --efi-boot-image --protective-msdos-label out/isodir -o ${OUTPUT_DIR}/obos.iso ${SUPPRESS_OUTPUT} + COMMAND ${BIOS_INSTALL} + BYPRODUCTS ${ISODIR}/${BTLDR_CONF} + ${ISODIR}/${xorriso_bios_cd_name} + ${ISODIR}/${xorriso_uefi_cd_name} ${ISODIR}/obos/oboskrnl ${ISODIR}/obos/initrd ${ISODIR}/obos/initrd.tar WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} - DEPENDS ${CMAKE_SOURCE_DIR}/config/initrd.tar ${CMAKE_SOURCE_DIR}/config/hyper.cfg oboskrnl initrd + DEPENDS ${CMAKE_SOURCE_DIR}/config/initrd.tar ${CMAKE_SOURCE_DIR}/config/${BTLDR_CONF} oboskrnl initrd ) add_custom_target (isogen ALL DEPENDS oboskrnl initrd ${OUTPUT_DIR}/obos.iso diff --git a/src/oboskrnl/allocators/base.h b/src/oboskrnl/allocators/base.h index 45cc6002..4645996f 100644 --- a/src/oboskrnl/allocators/base.h +++ b/src/oboskrnl/allocators/base.h @@ -66,8 +66,8 @@ typedef struct allocator_info OBOS_EXPORT obos_status Free(struct allocator_info* This, void* base, size_t nBytes); #ifndef __clang__ -OBOS_EXPORT __attribute__((malloc, malloc(Free, 2))) void* Allocate(struct allocator_info* This, size_t nBytes, obos_status* status); -OBOS_EXPORT __attribute__((malloc, malloc(Free, 2))) void* ZeroAllocate(struct allocator_info* This, size_t nObjects, size_t bytesPerObject, obos_status* status); +OBOS_EXPORT __attribute__((malloc, malloc(Free, 2), returns_nonnull)) void* Allocate(struct allocator_info* This, size_t nBytes, obos_status* status); +OBOS_EXPORT __attribute__((malloc, malloc(Free, 2), returns_nonnull)) void* ZeroAllocate(struct allocator_info* This, size_t nObjects, size_t bytesPerObject, obos_status* status); #else OBOS_EXPORT void* Allocate(struct allocator_info* This, size_t nBytes, obos_status* status); OBOS_EXPORT void* ZeroAllocate(struct allocator_info* This, size_t nObjects, size_t bytesPerObject, obos_status* status); diff --git a/src/oboskrnl/arch/m68k/entry.c b/src/oboskrnl/arch/m68k/entry.c index 01d6aa2e..baea8904 100644 --- a/src/oboskrnl/arch/m68k/entry.c +++ b/src/oboskrnl/arch/m68k/entry.c @@ -175,6 +175,7 @@ void Arch_KernelEntryBootstrap() CoreH_ThreadInitialize(&idle_thread, THREAD_PRIORITY_IDLE, Core_DefaultThreadAffinity, &ctx); CoreH_ThreadReadyNode(&kmain_thread, &kmain_node); CoreH_ThreadReadyNode(&idle_thread, &idle_thread_node); + bsp_cpu.nReadyThreads--; Core_LowerIrql(oldIrql); // Finally, yield. diff --git a/src/oboskrnl/arch/m68k/gf_tty.c b/src/oboskrnl/arch/m68k/gf_tty.c index c9783f97..8ba91c72 100644 --- a/src/oboskrnl/arch/m68k/gf_tty.c +++ b/src/oboskrnl/arch/m68k/gf_tty.c @@ -4,6 +4,7 @@ * Copyright (c) 2025 Omar Berrow */ +#include "error.h" #include #include @@ -92,7 +93,8 @@ static void poll_gf_tty(struct gf_tty_iface* iface) // struct gf_tty* dev = (void*)Arch_TTYBase; while (1) { - Core_WaitOnObject(WAITABLE_OBJECT(iface->data_ready_evnt)); + if (obos_is_error(Core_WaitOnObject(WAITABLE_OBJECT(iface->data_ready_evnt)))) + continue; irql oldIrql = Core_RaiseIrql(IRQL_DISPATCH); if (iface->data_ready) { diff --git a/src/oboskrnl/arch/m68k/syscall.c b/src/oboskrnl/arch/m68k/syscall.c index 4ce9df1c..859f9ce2 100644 --- a/src/oboskrnl/arch/m68k/syscall.c +++ b/src/oboskrnl/arch/m68k/syscall.c @@ -160,6 +160,14 @@ const char *syscall_to_string[] = { "Sys_UMask", "Sys_RenameAt", "Sys_UTimeNSAt", + "Sys_ThreadGetStack", + "Sys_SetRESUid", + "Sys_SetRESGid", + "Sys_GetRESUid", + "Sys_GetRESGid", + "Sys_SigPending", + "Sys_SetGroups", + "Sys_GetGroups", }; const char* status_to_string[] = { diff --git a/src/oboskrnl/arch/x86_64/boot_info.h b/src/oboskrnl/arch/x86_64/boot_info.h index 4bc49dcd..eebfe263 100644 --- a/src/oboskrnl/arch/x86_64/boot_info.h +++ b/src/oboskrnl/arch/x86_64/boot_info.h @@ -6,6 +6,8 @@ #pragma once +#if !OBOS_USE_LIMINE + #include extern volatile struct ultra_memory_map_attribute* Arch_MemoryMap; @@ -14,4 +16,21 @@ extern volatile struct ultra_kernel_info_attribute* Arch_KernelInfo; extern volatile struct ultra_module_info_attribute* Arch_KernelBinary; extern volatile struct ultra_module_info_attribute* Arch_InitialSwapBuffer; extern volatile struct ultra_framebuffer* Arch_Framebuffer; -extern volatile struct ultra_boot_context* Arch_BootContext; \ No newline at end of file +extern volatile struct ultra_boot_context* Arch_BootContext; +#else + +#include +#include + +extern volatile struct limine_framebuffer_request Arch_LimineFBRequest; +extern volatile struct limine_memmap_request Arch_LimineMemmapRequest; +extern volatile struct limine_module_request Arch_LimineModuleRequest; +extern volatile struct limine_hhdm_request Arch_LimineHHDMRequest; +extern volatile struct limine_executable_file_request Arch_LimineKernelInfoRequest; +extern volatile struct limine_executable_address_request Arch_LimineKernelAddressRequest; +extern volatile struct limine_executable_cmdline_request Arch_LimineKernelCmdlineRequest; +extern volatile struct limine_bootloader_info_request Arch_LimineBtldrInfoRequest; +extern volatile struct ultra_framebuffer* Arch_Framebuffer; // Artificially created +extern struct limine_file* Arch_KernelBinary; +#endif +extern uintptr_t Arch_RSDPBase; \ No newline at end of file diff --git a/src/oboskrnl/arch/x86_64/cpu_local_arch.h b/src/oboskrnl/arch/x86_64/cpu_local_arch.h index 910e089b..ccc7b479 100644 --- a/src/oboskrnl/arch/x86_64/cpu_local_arch.h +++ b/src/oboskrnl/arch/x86_64/cpu_local_arch.h @@ -1,7 +1,7 @@ /* - oboskrnl/arch/x86_64/cpu_local_arch.h - - Copyright (c) 2024 Omar Berrow + * oboskrnl/arch/x86_64/cpu_local_arch.h + * + * Copyright (c) 2024 Omar Berrow */ #pragma once @@ -14,6 +14,8 @@ #include +#include + typedef struct cpu_local_arch { uint64_t gdtEntries[7]; @@ -45,4 +47,5 @@ typedef struct cpu_local_arch dpc dbg_dpc; uint64_t stack_check_guard; uint8_t lapicId; + struct tlb_shootdown_packet* curr_pckt; } cpu_local_arch; diff --git a/src/oboskrnl/arch/x86_64/entry.asm b/src/oboskrnl/arch/x86_64/entry.asm index 18a50d06..79176293 100644 --- a/src/oboskrnl/arch/x86_64/entry.asm +++ b/src/oboskrnl/arch/x86_64/entry.asm @@ -14,10 +14,12 @@ extern Arch_disablePIC extern Arch_KernelEntry global Arch_KernelEntryBootstrap:function hidden Arch_KernelEntryBootstrap: +%if !OBOS_USE_LIMINE cmp rsi, 0x554c5442 je .ok ; should triple fault on failure xor rax,rax jmp rax ; All hope is lost. +%endif .ok: push rdi push rsi diff --git a/src/oboskrnl/arch/x86_64/entry.c b/src/oboskrnl/arch/x86_64/entry.c index d5d7b948..aec4cae1 100644 --- a/src/oboskrnl/arch/x86_64/entry.c +++ b/src/oboskrnl/arch/x86_64/entry.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #define FLANTERM_IN_FLANTERM @@ -47,12 +49,16 @@ #include #include -#include "gdbstub/connection.h" -#include "gdbstub/gdb_udp_backend.h" -#include "gdbstub/debug.h" - #include +#include + +#include + +#if OBOS_USE_LIMINE +# include +#endif + extern void Arch_InitBootGDT(); static char thr_stack[0x4000]; @@ -168,15 +174,16 @@ static void init_flanterm_backend() OBOS_AddLogSource(&backend); } -static struct ultra_module_info_attribute* Arch_FlantermBumpAllocator; +static struct { + uintptr_t address; + uintptr_t size; +} Arch_FlantermBumpAllocator = {}; static void *flanterm_malloc(size_t sz) { - if (!Arch_FlantermBumpAllocator) - return nullptr; static size_t bump_off = 0; - if ((bump_off + sz) > Arch_FlantermBumpAllocator->size) + if ((bump_off + sz) > Arch_FlantermBumpAllocator.size) return nullptr; - void* ret = (void*)(Arch_FlantermBumpAllocator->address + bump_off); + void* ret = (void*)(Arch_FlantermBumpAllocator.address + bump_off); bump_off += sz; return ret; } @@ -186,7 +193,55 @@ static void flanterm_free(void* blk, size_t sz) return; } +#if OBOS_USE_LIMINE +volatile struct limine_framebuffer_request Arch_LimineFBRequest = { + .id = LIMINE_FRAMEBUFFER_REQUEST_ID, + .revision = 1, +}; +volatile struct limine_memmap_request Arch_LimineMemmapRequest = { + .id = LIMINE_MEMMAP_REQUEST_ID, + .revision = 0, +}; +volatile struct limine_module_request Arch_LimineModuleRequest = { + .id = LIMINE_MODULE_REQUEST_ID, + .revision = 1, +}; +volatile struct limine_hhdm_request Arch_LimineHHDMRequest = { + .id = LIMINE_HHDM_REQUEST_ID, + .revision = 0, +}; +volatile struct limine_executable_file_request Arch_LimineKernelInfoRequest = { + .id = LIMINE_EXECUTABLE_FILE_REQUEST_ID, + .revision = 0, +}; +volatile struct limine_executable_address_request Arch_LimineKernelAddressRequest = { + .id = LIMINE_EXECUTABLE_ADDRESS_REQUEST_ID, + .revision = 0, +}; +volatile struct limine_executable_cmdline_request Arch_LimineKernelCmdlineRequest = { + .id = LIMINE_EXECUTABLE_CMDLINE_REQUEST_ID, + .revision = 0, +}; +volatile struct limine_rsdp_request Arch_LimineRSDPRequest = { + .id = LIMINE_RSDP_REQUEST_ID, + .revision = 0, +}; +volatile struct limine_bootloader_info_request Arch_LimineBtldrInfoRequest = { + .id = LIMINE_BOOTLOADER_INFO_REQUEST_ID, + .revision = 0, +}; +volatile struct ultra_framebuffer limine_fb0 = {}; +volatile struct ultra_framebuffer* Arch_Framebuffer = &limine_fb0; +struct limine_file* Arch_KernelBinary = nullptr; +#endif + +uintptr_t Arch_RSDPBase = 0; + +#if !OBOS_USE_LIMINE OBOS_PAGEABLE_FUNCTION void __attribute__((no_stack_protector)) Arch_KernelEntry(struct ultra_boot_context* bcontext) +#else +OBOS_PAGEABLE_FUNCTION void __attribute__((no_stack_protector)) Arch_KernelEntry() +#endif { bsp_cpu.id = 0; bsp_cpu.isBSP = true; @@ -200,18 +255,6 @@ OBOS_PAGEABLE_FUNCTION void __attribute__((no_stack_protector)) Arch_KernelEntry wrmsr(0xC0000101, (uintptr_t)&Core_CpuInfo[0]); - ParseBootContext(bcontext); - Arch_BootContext = bcontext; - OBOS_ParseCMDLine(); - asm("sti"); - - uint64_t log_level = OBOS_GetOPTD_Ex("log-level", LOG_LEVEL_LOG); - if (log_level > 4) - log_level = LOG_LEVEL_DEBUG; - OBOS_SetLogLevel(log_level); - extern uint64_t Arch_KernelCR3; - Arch_KernelCR3 = getCR3(); - #if !OBOS_ENABLE_PROFILING { uint32_t ecx = 0; @@ -225,30 +268,71 @@ OBOS_PAGEABLE_FUNCTION void __attribute__((no_stack_protector)) Arch_KernelEntry } #endif +#if !OBOS_USE_LIMINE + ParseBootContext(bcontext); + Arch_BootContext = bcontext; +#else + OBOS_KernelCmdLine = Arch_LimineKernelCmdlineRequest.response->cmdline; + Arch_KernelBinary = Arch_LimineKernelInfoRequest.response->executable_file; + Arch_RSDPBase = Arch_UnmapFromHHDM(Arch_LimineRSDPRequest.response->address); +#endif + + basicmm_region bump_region = {}; + struct boot_module bump_region_module = {}; + OBOSS_GetModule(&bump_region_module, "BUMP_REGION"); + if (!bump_region_module.address) + OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "Could not find BUMP_REGION kernel module\n"); + bump_region.addr = (uintptr_t)bump_region_module.address; + bump_region.size = bump_region_module.size; + OBOSH_BasicMMSetBumpRegion(&bump_region); + + struct boot_module flanterm_buff = {}; + OBOSS_GetModule(&flanterm_buff, "FLANTERM_BUFF"); + if (!flanterm_buff.address) + OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "Could not find FLANTERM_BUFF kernel module\n"); + Arch_FlantermBumpAllocator.address = (uintptr_t)flanterm_buff.address; + Arch_FlantermBumpAllocator.size = flanterm_buff.size; + + OBOS_ParseCMDLine(); + asm("sti"); + + uint64_t log_level = OBOS_GetOPTD_Ex("log-level", LOG_LEVEL_LOG); + if (log_level > 4) + log_level = LOG_LEVEL_DEBUG; + OBOS_SetLogLevel(log_level); + extern uint64_t Arch_KernelCR3; + Arch_KernelCR3 = getCR3(); + #if 0 init_serial_log_backend(); #endif + static uint32_t ansi_colors[8] = { + __builtin_bswap32(0x000000) >> 8, + __builtin_bswap32(0xbb0000) >> 8, + __builtin_bswap32(0x00bb00) >> 8, + __builtin_bswap32(0xbbbb00) >> 8, + __builtin_bswap32(0x0000bb) >> 8, + __builtin_bswap32(0xbb00bb) >> 8, + __builtin_bswap32(0x00bbbb) >> 8, + __builtin_bswap32(0xbbbbbb) >> 8, + }; + static uint32_t ansi_bright_colors[8] = { + __builtin_bswap32(0x555555) >> 8, + __builtin_bswap32(0xff5555) >> 8, + __builtin_bswap32(0x55ff55) >> 8, + __builtin_bswap32(0xffff55) >> 8, + __builtin_bswap32(0x5555aa) >> 8, + __builtin_bswap32(0xff55ff) >> 8, + __builtin_bswap32(0x55ffff) >> 8, + __builtin_bswap32(0xffffff) >> 8, + }; + OBOS_UNUSED(ansi_bright_colors && ansi_colors); +#if !OBOS_USE_LIMINE if (!Arch_Framebuffer) OBOS_Warning("No framebuffer passed by the bootloader. All kernel logs will be on port 0xE9.\n"); else { - // OBOS_TextRendererState.fg_color = 0xffffffff; - // OBOS_TextRendererState.fb.base = Arch_MapToHHDM(Arch_Framebuffer->physical_address); - // OBOS_TextRendererState.fb.bpp = Arch_Framebuffer->bpp; - // OBOS_TextRendererState.fb.format = Arch_Framebuffer->format; - // OBOS_TextRendererState.fb.height = Arch_Framebuffer->height; - // OBOS_TextRendererState.fb.width = Arch_Framebuffer->width; - // OBOS_TextRendererState.fb.pitch = Arch_Framebuffer->pitch; - // for (size_t y = 0; y < Arch_Framebuffer->height; y++) - // for (size_t x = 0; x < Arch_Framebuffer->width; x++) - // OBOS_PlotPixel(OBOS_TEXT_BACKGROUND, &((uint8_t*)OBOS_TextRendererState.fb.base)[y*Arch_Framebuffer->pitch+x*Arch_Framebuffer->bpp/8], OBOS_TextRendererState.fb.format); - // OBOS_TextRendererState.column = 0; - // OBOS_TextRendererState.row = 0; - // OBOS_TextRendererState.font = font_bin; - // OBOS_AddLogSource(&OBOS_ConsoleOutputCallback); - // if (Arch_Framebuffer->format == ULTRA_FB_FORMAT_INVALID) - // return; uint8_t red_mask_size = 8, red_mask_shift = 0; uint8_t green_mask_size = 8, green_mask_shift = 0; uint8_t blue_mask_size = 8, blue_mask_shift = 0; @@ -276,29 +360,7 @@ OBOS_PAGEABLE_FUNCTION void __attribute__((no_stack_protector)) Arch_KernelEntry blue_mask_shift = 16; bg = bg >> 8; break; - } - static uint32_t ansi_colors[8] = { - __builtin_bswap32(0x000000) >> 8, - __builtin_bswap32(0xbb0000) >> 8, - __builtin_bswap32(0x00bb00) >> 8, - __builtin_bswap32(0xbbbb00) >> 8, - __builtin_bswap32(0x0000bb) >> 8, - __builtin_bswap32(0xbb00bb) >> 8, - __builtin_bswap32(0x00bbbb) >> 8, - __builtin_bswap32(0xbbbbbb) >> 8, - }; - static uint32_t ansi_bright_colors[8] = { - __builtin_bswap32(0x555555) >> 8, - __builtin_bswap32(0xff5555) >> 8, - __builtin_bswap32(0x55ff55) >> 8, - __builtin_bswap32(0xffff55) >> 8, - __builtin_bswap32(0x5555aa) >> 8, - __builtin_bswap32(0xff55ff) >> 8, - __builtin_bswap32(0x55ffff) >> 8, - __builtin_bswap32(0xffffff) >> 8, - - }; OBOS_FlantermContext = flanterm_fb_init( flanterm_malloc, flanterm_free, Arch_MapToHHDM(Arch_Framebuffer->physical_address), Arch_Framebuffer->width, Arch_Framebuffer->height, Arch_Framebuffer->pitch, @@ -318,6 +380,54 @@ OBOS_PAGEABLE_FUNCTION void __attribute__((no_stack_protector)) Arch_KernelEntry if (Arch_LdrPlatformInfo->page_table_depth != 4) OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "5-level paging is unsupported by oboskrnl.\n"); +#else + if (Arch_LimineFBRequest.response->framebuffer_count) + { + struct limine_framebuffer *fb = Arch_LimineFBRequest.response->framebuffers[0]; + OBOS_FlantermContext = flanterm_fb_init( + flanterm_malloc, flanterm_free, + fb->address, fb->width, fb->height, fb->pitch, + fb->red_mask_size, fb->red_mask_shift, + fb->green_mask_size, fb->green_mask_shift, + fb->blue_mask_size, fb->blue_mask_shift, + nullptr, nullptr, + nullptr, nullptr, + nullptr, nullptr, + nullptr, + // (void*)font_bin, 8, 16, 0, + nullptr, 8, 16, 0, + 0,0, + 0); + init_flanterm_backend(); + limine_fb0.physical_address = Arch_UnmapFromHHDM(fb->address); + limine_fb0.bpp = fb->bpp; + limine_fb0.width = fb->width; + limine_fb0.height = fb->height; + limine_fb0.pitch = fb->pitch; + do { + if (limine_fb0.bpp == 24) + { + if (fb->blue_mask_shift == 0 && fb->green_mask_shift == 8 && fb->red_mask_shift == 16) + limine_fb0.format = ULTRA_FB_FORMAT_RGB888; + if (fb->red_mask_shift == 0 && fb->green_mask_shift == 8 && fb->blue_mask_shift == 16) + limine_fb0.format = ULTRA_FB_FORMAT_BGR888; + break; + } + else if (limine_fb0.bpp == 32) + { + uint8_t x_shift = 0; + if (fb->red_mask_shift == 16) x_shift = 24; + else if (fb->red_mask_shift == 24) x_shift = 0; + if (x_shift == 0 && fb->blue_mask_shift == 8 && fb->green_mask_shift == 16 && fb->red_mask_shift == 24) + limine_fb0.format = ULTRA_FB_FORMAT_RGBX8888; + if (fb->blue_mask_shift == 0 && fb->green_mask_shift == 8 && fb->red_mask_shift == 16 && x_shift == 24) + limine_fb0.format = ULTRA_FB_FORMAT_XRGB8888; + break; + } + } while(0); + } +#endif + #if OBOS_RELEASE OBOS_Log("Booting OBOS %s committed on %s. Build time: %s.\n", GIT_SHA1, GIT_DATE, __DATE__ " " __TIME__); @@ -333,8 +443,15 @@ OBOS_PAGEABLE_FUNCTION void __attribute__((no_stack_protector)) Arch_KernelEntry __cpuid__(0x80000003, 0, (uint32_t*)&brand_string[16], (uint32_t*)&brand_string[20], (uint32_t*)&brand_string[24], (uint32_t*)&brand_string[28]); __cpuid__(0x80000004, 0, (uint32_t*)&brand_string[32], (uint32_t*)&brand_string[36], (uint32_t*)&brand_string[40], (uint32_t*)&brand_string[44]); OBOS_Log("Running on a %s processor, cpu brand string, %s. We are currently %srunning on a hypervisor\n", cpu_vendor, brand_string, isHypervisor ? "" : "not "); + +#if OBOS_USE_LIMINE + OBOS_Log("Bootloader is %s-%s\n", Arch_LimineBtldrInfoRequest.response->name, Arch_LimineBtldrInfoRequest.response->version); +#else + OBOS_Log("Bootloader is %.32s\n", Arch_LdrPlatformInfo->loader_name, Arch_LdrPlatformInfo->loader_major, Arch_LdrPlatformInfo->loader_minor); #endif +#endif + OBOS_Debug("%s: Initializing the Boot GDT.\n", __func__); Arch_InitBootGDT(); @@ -373,6 +490,8 @@ OBOS_PAGEABLE_FUNCTION void __attribute__((no_stack_protector)) Arch_KernelEntry CoreH_ThreadReady(&kernelMainThread); CoreH_ThreadReady(&bsp_idleThread); Core_CpuInfo->idleThread = &bsp_idleThread; + Core_CpuInfo->nReadyThreads--; + Core_ReadyThreadCount--; // Initialize the CPU's GDT. Arch_CPUInitializeGDT(&Core_CpuInfo[0], (uintptr_t)Arch_InitialISTStack, sizeof(Arch_InitialISTStack)); @@ -391,6 +510,7 @@ OBOS_PAGEABLE_FUNCTION void __attribute__((no_stack_protector)) Arch_KernelEntry asm volatile("nop" : : :); } +#if !OBOS_USE_LIMINE volatile struct ultra_memory_map_attribute* Arch_MemoryMap; volatile struct ultra_platform_info_attribute* Arch_LdrPlatformInfo; volatile struct ultra_kernel_info_attribute* Arch_KernelInfo; @@ -437,8 +557,6 @@ static OBOS_PAGEABLE_FUNCTION OBOS_NO_KASAN OBOS_NO_UBSAN void ParseBootContext( struct ultra_module_info_attribute* module = (struct ultra_module_info_attribute*)header; if (strcmp(module->name, "__KERNEL__")) Arch_KernelBinary = module; - else if (strcmp(module->name, "FLANTERM_BUFF")) - Arch_FlantermBumpAllocator = module; break; } case ULTRA_ATTRIBUTE_INVALID: @@ -458,9 +576,9 @@ static OBOS_PAGEABLE_FUNCTION OBOS_NO_KASAN OBOS_NO_UBSAN void ParseBootContext( OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "Invalid partition type %d.\n", Arch_KernelInfo->partition_type); if (!Arch_KernelBinary) OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "Could not find the kernel module in boot context!\nDo you set kernel-as-module to true in the hyper.cfg?\n"); - if (!Arch_FlantermBumpAllocator) - OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "Could not find the FLANTERM_BUFF module in boot context!\nMake sure to pass a module named FLANTERM_BUFF with a size big enough for width*pitch?\n"); + Arch_RSDPBase = Arch_LdrPlatformInfo->acpi_rsdp_address; } +#endif extern obos_status Arch_InitializeKernelPageTable(); @@ -548,6 +666,7 @@ void OBOSS_InitializeSMP() Core_GetCurrentThread()->masterCPU = CoreS_GetCPULocalPtr(); } +#if !OBOS_USE_LIMINE static void ultra_module_to_boot_module(const struct ultra_module_info_attribute *ultra_module, struct boot_module* out_module) { if (!ultra_module || !out_module) @@ -572,6 +691,42 @@ void OBOSS_GetKernelModule(struct boot_module *module) { ultra_module_to_boot_module((void*)Arch_KernelBinary, module); } +#else +static void limine_file_to_boot_module(const struct limine_file *file, struct boot_module* out_module) +{ + if (!file || !out_module) + return; + out_module->address = file->address; + out_module->size = file->size; + out_module->name = file->string; + out_module->is_memory = false; + out_module->is_kernel = file == Arch_LimineKernelInfoRequest.response->executable_file; + return; +} +static struct limine_file* find_module(const char* name, size_t name_len) +{ + for (size_t i = 0; i < Arch_LimineModuleRequest.response->module_count; i++) + { + struct limine_file* cur = Arch_LimineModuleRequest.response->modules[i]; + if (strncmp(cur->string, name, name_len)) + return cur; + } + return nullptr; +} + +void OBOSS_GetModule(struct boot_module *module, const char* name) +{ + limine_file_to_boot_module(find_module(name, strlen(name)), module); +} +void OBOSS_GetModuleLen(struct boot_module *module, const char* name, size_t name_len) +{ + limine_file_to_boot_module(find_module(name, name_len), module); +} +void OBOSS_GetKernelModule(struct boot_module *module) +{ + limine_file_to_boot_module(Arch_LimineKernelInfoRequest.response->executable_file, module); +} +#endif void OBOSS_MakeTTY() { diff --git a/src/oboskrnl/arch/x86_64/except.c b/src/oboskrnl/arch/x86_64/except.c index 87192ef5..d57f0b4a 100644 --- a/src/oboskrnl/arch/x86_64/except.c +++ b/src/oboskrnl/arch/x86_64/except.c @@ -94,7 +94,7 @@ __attribute__((no_instrument_function)) OBOS_NO_UBSAN OBOS_NO_KASAN void Arch_Pa if (frame->cs & 3) { OBOS_Log("User thread %d SIGSEGV (rip 0x%p, cr2 0x%p, error code 0x%08x)\n", Core_GetCurrentThread()->tid, frame->rip, getCR2(), frame->errorCode); - Core_GetCurrentThread()->signal_info->signals[SIGSEGV].addr = (void*)getCR2(); + Core_GetCurrentThread()->proc->signal_handlers[SIGSEGV].addr = (void*)getCR2(); OBOS_Kill(Core_GetCurrentThread(), Core_GetCurrentThread(), SIGSEGV); // OBOS_SyncPendingSignal(frame); OBOS_RunSignal(SIGSEGV, frame); // Ensure SIGSEGV runs. diff --git a/src/oboskrnl/arch/x86_64/execve.c b/src/oboskrnl/arch/x86_64/execve.c index 792bc124..17556c38 100644 --- a/src/oboskrnl/arch/x86_64/execve.c +++ b/src/oboskrnl/arch/x86_64/execve.c @@ -160,6 +160,8 @@ OBOS_NORETURN OBOS_NO_KASAN void OBOSS_HandControlTo(struct context* ctx, struct // Core_GetCurrentThread()->context.fs_base = 0; // Core_GetCurrentThread()->context.gs_base = 0; + Mm_VirtualMemoryFree(&Mm_KernelContext, init_vals, szAllocation); + OBOS_Debug("Handing off control to user program.\n"); OBOS_Debug("NOTE: RSP=0x%p.\n", Core_GetCurrentThread()->context.frame.rsp); @@ -180,6 +182,8 @@ void OBOSS_HandOffToInit(struct exec_aux_values* aux) Core_GetCurrentThread()->context.stackBase = Mm_VirtualMemoryAlloc(ctx, nullptr, 4*1024*1024, OBOS_PROTECTION_USER_PAGE, VMA_FLAGS_GUARD_PAGE, nullptr, nullptr); Core_GetCurrentThread()->context.stackSize = 4*1024*1024; + Core_GetCurrentThread()->stackFree = CoreH_VMAStackFree; + Core_GetCurrentThread()->stackFreeUserdata = ctx; CoreS_SetThreadPageTable(&Core_GetCurrentThread()->context, ctx->pt); diff --git a/src/oboskrnl/arch/x86_64/gdbstub/connection.c b/src/oboskrnl/arch/x86_64/gdbstub/connection.c index a3f7d15a..cedc56f9 100644 --- a/src/oboskrnl/arch/x86_64/gdbstub/connection.c +++ b/src/oboskrnl/arch/x86_64/gdbstub/connection.c @@ -432,7 +432,8 @@ obos_status SysS_GDBStubStart() CoreH_ThreadInitialize(&gdb_thread, THREAD_PRIORITY_NORMAL, Core_DefaultThreadAffinity, &ctx); Core_ProcessAppendThread(OBOS_KernelProcess, &gdb_thread); CoreH_ThreadReady(&gdb_thread); - Core_WaitOnObject(WAITABLE_OBJECT(gdb_connected)); - - return OBOS_STATUS_SUCCESS; + obos_status status = Core_WaitOnObject(WAITABLE_OBJECT(gdb_connected)); + if (CoreS_ForceYieldOnSyscallReturn) + CoreS_ForceYieldOnSyscallReturn(); + return status; } \ No newline at end of file diff --git a/src/oboskrnl/arch/x86_64/gdbstub/gdb_udp_backend.c b/src/oboskrnl/arch/x86_64/gdbstub/gdb_udp_backend.c index 70ada517..f2a46ec0 100644 --- a/src/oboskrnl/arch/x86_64/gdbstub/gdb_udp_backend.c +++ b/src/oboskrnl/arch/x86_64/gdbstub/gdb_udp_backend.c @@ -79,7 +79,9 @@ static obos_status read_sync(dev_desc desc, void* buf, size_t blkCount, size_t b while (!hnd->curr_rx) { - Core_WaitOnObject(WAITABLE_OBJECT(hnd->bound_port->recv_event)); + obos_status status = Core_WaitOnObject(WAITABLE_OBJECT(hnd->bound_port->recv_event)); + if (obos_is_error(status)) + return status; Core_EventClear(&hnd->bound_port->recv_event); udp_recv_packet* recv_packet = LIST_GET_HEAD(frame_queue, &hnd->bound_port->packets); if (!recv_packet) diff --git a/src/oboskrnl/arch/x86_64/gdbstub/vFile.c b/src/oboskrnl/arch/x86_64/gdbstub/vFile.c index 44b0907f..e5b4adf2 100644 --- a/src/oboskrnl/arch/x86_64/gdbstub/vFile.c +++ b/src/oboskrnl/arch/x86_64/gdbstub/vFile.c @@ -197,8 +197,8 @@ static obos_status common_stat(vnode* vn, struct gdb_stat* out) out->st_dev = 0; out->st_ino = vn->inode; out->st_nlink = vn->refs; - out->st_uid = vn->owner_uid; - out->st_gid = vn->group_uid; + out->st_uid = vn->uid; + out->st_gid = vn->gid; out->st_rdev = 0; out->st_size = vn->filesize; out->st_blksize = vn->blkSize; diff --git a/src/oboskrnl/arch/x86_64/ioapic.c b/src/oboskrnl/arch/x86_64/ioapic.c index f0149aaf..4c877898 100644 --- a/src/oboskrnl/arch/x86_64/ioapic.c +++ b/src/oboskrnl/arch/x86_64/ioapic.c @@ -32,7 +32,7 @@ size_t Arch_IOAPICCount; static OBOS_PAGEABLE_FUNCTION OBOS_NO_UBSAN obos_status ParseMADT() { // Find the MADT in the ACPI tables. - ACPIRSDPHeader* rsdp = (ACPIRSDPHeader*)Arch_MapToHHDM(Arch_LdrPlatformInfo->acpi_rsdp_address); + ACPIRSDPHeader* rsdp = (ACPIRSDPHeader*)Arch_MapToHHDM(Arch_RSDPBase); bool tables32 = rsdp->Revision < 2; ACPISDTHeader* xsdt = tables32 ? (ACPISDTHeader*)(uintptr_t)rsdp->RsdtAddress : (ACPISDTHeader*)rsdp->XsdtAddress; xsdt = (ACPISDTHeader*)Arch_MapToHHDM((uintptr_t)xsdt); diff --git a/src/oboskrnl/arch/x86_64/map.c b/src/oboskrnl/arch/x86_64/map.c index 93ef56d0..c9125ec6 100644 --- a/src/oboskrnl/arch/x86_64/map.c +++ b/src/oboskrnl/arch/x86_64/map.c @@ -14,7 +14,7 @@ #include #include - +#include #include #include @@ -29,8 +29,12 @@ #include #include +#include + #include +#include + #include #include @@ -144,8 +148,6 @@ bool Arch_FreePageMapAt(uintptr_t pml4Base, uintptr_t at, uint8_t maxDepth) return true; } -static obos_status invlpg_impl(uintptr_t at); - static bool has_xd() { static bool ret = false, init = false; @@ -166,14 +168,11 @@ obos_status Arch_MapPage(uintptr_t cr3, void* at_, uintptr_t phys, uintptr_t fla phys = Arch_MaskPhysicalAddressFromEntry(phys); uintptr_t* pm = Arch_AllocatePageMapAt(cr3, at, flags & ~512, 3); uintptr_t entry = phys | flags; - bool shouldInvplg = pm[AddressToIndex(at, 0)] != entry; // for (volatile bool b = !(flags & 1); b; ) // ; pm[AddressToIndex(at, 0)] = entry; if (free_pte && ~flags & BIT_TYPE(0, UL)) Arch_FreePageMapAt(cr3, at, 3); - if (shouldInvplg) - invlpg_impl(at); return OBOS_STATUS_SUCCESS; } obos_status Arch_MapHugePage(uintptr_t cr3, void* at_, uintptr_t phys, uintptr_t flags, bool free_pte) @@ -191,36 +190,12 @@ obos_status Arch_MapHugePage(uintptr_t cr3, void* at_, uintptr_t phys, uintptr_t phys = Arch_MaskPhysicalAddressFromEntry(phys); uintptr_t* pm = Arch_AllocatePageMapAt(cr3, at, flags & ~512, 2); uintptr_t entry = phys | flags | ((uintptr_t)1 << 7); - bool shouldInvplg = (entry != pm[AddressToIndex(at, 1)]); pm[AddressToIndex(at, 1)] = entry; if (free_pte && ~flags & BIT_TYPE(0, UL)) Arch_FreePageMapAt(cr3, at, 2); - if (shouldInvplg) - invlpg_impl(at); return OBOS_STATUS_SUCCESS; } -static struct { - spinlock lock; - uintptr_t addr; - uintptr_t cr3; - atomic_size_t nCPUsRan; - bool active; - irq* irq; - cpu_local* sender; -} invlpg_ipi_packet; -bool Arch_InvlpgIPI(interrupt_frame* frame) -{ - OBOS_UNUSED(frame); - if (!invlpg_ipi_packet.active) - return false; - if (getCR3() == invlpg_ipi_packet.cr3) - invlpg(invlpg_ipi_packet.addr); - invlpg_ipi_packet.nCPUsRan++; - if (invlpg_ipi_packet.nCPUsRan >= Core_CpuCount) - invlpg_ipi_packet.active = false; - // Arch_LAPICAddress->eoi = 0; - return true; -} + extern bool Arch_SMPInitialized; obos_status Arch_UnmapPage(uintptr_t cr3, void* at_, bool free_pte) { @@ -242,8 +217,61 @@ obos_status Arch_UnmapPage(uintptr_t cr3, void* at_, bool free_pte) pt[AddressToIndex(at, (uint8_t)isHugePage)] &= ~BIT(0); if (free_pte) Arch_FreePageMapAt(cr3, at, 3 - (uint8_t)isHugePage); - return invlpg_impl(at); + return OBOS_STATUS_SUCCESS; +} + +static irq* invlpg_irq; +typedef struct tlb_shootdown_packet { + uintptr_t base; + size_t size; + atomic_size_t refcount; + LIST_NODE(tlb_shootdown_queue, struct tlb_shootdown_packet) node; +} tlb_shootdown_packet; +typedef LIST_HEAD(tlb_shootdown_queue, tlb_shootdown_packet) tlb_shootdown_queue; +LIST_GENERATE_STATIC(tlb_shootdown_queue, tlb_shootdown_packet, node); +tlb_shootdown_queue g_tlb_shootdown_queue; +spinlock g_tlb_shootdown_queue_lock; + +static void deref_tlb_shootdown_pckt(tlb_shootdown_packet* pckt) +{ + if (!--pckt->refcount) + { + irql oldIrql = Core_SpinlockAcquire(&g_tlb_shootdown_queue_lock); + LIST_REMOVE(tlb_shootdown_queue, &g_tlb_shootdown_queue, pckt); + Core_SpinlockRelease(&g_tlb_shootdown_queue_lock, oldIrql); + Free(Mm_Allocator, pckt, sizeof(*pckt)); + } +} + +bool Arch_InvlpgIPI(interrupt_frame* frame) +{ + OBOS_UNUSED(frame); + if (!LIST_GET_NODE_COUNT(tlb_shootdown_queue, &g_tlb_shootdown_queue)) + return false; + tlb_shootdown_packet* curr = CoreS_GetCPULocalPtr()->arch_specific.curr_pckt; + if (!curr) + curr = LIST_GET_HEAD(tlb_shootdown_queue, &g_tlb_shootdown_queue); + else + curr = LIST_GET_NEXT(tlb_shootdown_queue, &g_tlb_shootdown_queue, curr); + + while (curr) + { + for (uintptr_t addr = curr->base; addr <= (curr->base+curr->size); addr += OBOS_PAGE_SIZE) + { + OBOS_ENSURE(addr >= curr->base); + invlpg(addr); + } + + if (curr != LIST_GET_TAIL(tlb_shootdown_queue, &g_tlb_shootdown_queue)) + deref_tlb_shootdown_pckt(curr); + else + CoreS_GetCPULocalPtr()->arch_specific.curr_pckt = curr; + curr = LIST_GET_NEXT(tlb_shootdown_queue, &g_tlb_shootdown_queue, curr); + } + + return true; } + static void invlpg_ipi_bootstrap(struct irq* i, interrupt_frame* frame, void* userdata, irql oldIrql) { OBOS_UNUSED(i); @@ -251,67 +279,68 @@ static void invlpg_ipi_bootstrap(struct irq* i, interrupt_frame* frame, void* us OBOS_UNUSED(oldIrql); Arch_InvlpgIPI(frame); } -static obos_status invlpg_impl(uintptr_t at) + +#define issue_nmi() \ + Arch_LAPICSendIPI((ipi_lapic_info){.isShorthand=true,.info.shorthand=LAPIC_DESTINATION_SHORTHAND_ALL}, \ + (ipi_vector_info){.deliveryMode=LAPIC_DELIVERY_MODE_NMI}) + + +extern uintptr_t Arch_KernelCR3; + +enum { IRQL_INVLPG_IPI=15 }; + +obos_status MmS_TLBShootdown(page_table pt, uintptr_t base, size_t size) { - invlpg(at); -#ifndef OBOS_UP - if (!Arch_SMPInitialized || Core_CpuCount == 1) - return OBOS_STATUS_SUCCESS; - enum { IRQL_INVLPG_IPI=15 }; - if (!invlpg_ipi_packet.irq && Core_IrqInterfaceInitialized()) + if (Core_CpuCount == 1 || !Arch_SMPInitialized) { - static irq irq; - invlpg_ipi_packet.irq = &irq; - Core_IrqObjectInitializeIRQL(&irq, IRQL_INVLPG_IPI, false, true); - irq.handler = invlpg_ipi_bootstrap; - irq.handlerUserdata = nullptr; + for (uintptr_t addr = base; addr < (base + size); addr += OBOS_PAGE_SIZE) + invlpg(addr); + return OBOS_STATUS_SUCCESS; } - extern bool Arch_HaltCPUs; - if (Arch_LAPICAddress->interruptRequest224_255 & (1<<16)) + +#if OBOS_UP + return OBOS_STATUS_SUCCESS; +#endif + + if (pt != Arch_KernelCR3) + goto ipi; + + // Can this allocation cause problems? + // i sure do hope not... + tlb_shootdown_packet* pckt = ZeroAllocate(Mm_Allocator, 1, sizeof(tlb_shootdown_packet), nullptr); + pckt->base = base; + pckt->size = size; + pckt->refcount = Core_CpuCount; + irql oldIrql = Core_SpinlockAcquire(&g_tlb_shootdown_queue_lock); + LIST_APPEND(tlb_shootdown_queue, &g_tlb_shootdown_queue, pckt); + Core_SpinlockRelease(&g_tlb_shootdown_queue_lock, oldIrql); + + ipi: + // Issue the IPI. + + if (Core_IrqInterfaceInitialized()) { - irql oldIrql = Core_GetIrql(); - if (oldIrql >= IRQL_INVLPG_IPI) + static ipi_vector_info vec = {}; + static ipi_lapic_info dest = {.isShorthand=true,.info.shorthand=LAPIC_DESTINATION_SHORTHAND_ALL}; + if (!invlpg_irq) { - Core_LowerIrql(IRQL_DISPATCH); - irql unused = Core_RaiseIrql(oldIrql); - OBOS_UNUSED(unused); + static irq irq; + invlpg_irq = &irq; + Core_IrqObjectInitializeIRQL(&irq, IRQL_INVLPG_IPI, false, true); + irq.handler = invlpg_ipi_bootstrap; + irq.handlerUserdata = nullptr; + + vec.deliveryMode = LAPIC_DELIVERY_MODE_FIXED; + vec.info.vector = irq.vector->id + 0x20; } + Arch_LAPICSendIPI(dest, vec); } - size_t spin = 0; - while (invlpg_ipi_packet.active && ++spin <= 10000) - pause(); - Arch_HaltCPUs = false; - irql oldIrql = Core_SpinlockAcquireExplicit(&invlpg_ipi_packet.lock, IRQL_MASKED, false); - ipi_lapic_info lapic = { - .isShorthand=true, - .info.shorthand = LAPIC_DESTINATION_SHORTHAND_ALL_BUT_SELF - }; - ipi_vector_info vector = {}; - if (invlpg_ipi_packet.irq) - { - vector.deliveryMode = LAPIC_DELIVERY_MODE_FIXED; - vector.info.vector = invlpg_ipi_packet.irq->vector->id+0x20; - } - else - { - vector.deliveryMode = LAPIC_DELIVERY_MODE_NMI; - vector.info.vector = 0; - } - invlpg_ipi_packet.active = true; - invlpg_ipi_packet.addr = at; - invlpg_ipi_packet.cr3 = getCR3(); - invlpg_ipi_packet.nCPUsRan = 1; - invlpg_ipi_packet.sender = CoreS_GetCPULocalPtr(); - obos_status status = Arch_LAPICSendIPI(lapic, vector); - OBOS_ASSERT(obos_is_success(status)); - OBOS_UNUSED(status); - // This can be done async. - // while (invlpg_ipi_packet.nCPUsRan != Core_CpuCount) - // pause(); - Core_SpinlockRelease(&invlpg_ipi_packet.lock, oldIrql); -#endif + else if (pt != Arch_KernelCR3) + issue_nmi(); + return OBOS_STATUS_SUCCESS; } + obos_status OBOSS_MapPage_RW_XD(void* at_, uintptr_t phys) { return Arch_MapPage(getCR3(), at_, phys, 0x8000000000000003, false); @@ -343,24 +372,23 @@ obos_status OBOSS_GetPagePhysicalAddress(void* at_, uintptr_t* oPhys) static basicmm_region kernel_region; static basicmm_region hhdm_region; -static void FreePageTables(uintptr_t* pm, uint8_t level, uint32_t beginIndex, uint32_t* indices) +static void FreePageTables(uintptr_t* pm, uint8_t level, uint32_t beginIndex, bool user, uint32_t* indices) { if (!pm) return; pm = (uintptr_t*)MmS_MapVirtFromPhys((uintptr_t)pm); - for (indices[level] = beginIndex; indices[level] < 512; indices[level]++) + for (indices[level] = beginIndex; indices[level] < (user ? 256 : 512); indices[level]++) { if (!pm[indices[level]]) continue; if (pm[indices[level]] & ((uintptr_t)1<<7) || level == 0) continue; - FreePageTables((uintptr_t*)Arch_MaskPhysicalAddressFromEntry(pm[indices[level]]), level - 1, 0, indices); + FreePageTables((uintptr_t*)Arch_MaskPhysicalAddressFromEntry(pm[indices[level]]), level - 1, 0, false, indices); Mm_FreePhysicalPages(Arch_MaskPhysicalAddressFromEntry(pm[indices[level]]), 1); } } uintptr_t MmS_KernelBaseAddress; uintptr_t MmS_KernelEndAddress; -extern uintptr_t Arch_KernelCR3; obos_status Arch_InitializeKernelPageTable() { obos_status status = OBOS_STATUS_SUCCESS; @@ -373,6 +401,7 @@ obos_status Arch_InitializeKernelPageTable() Elf64_Ehdr* ehdr = (Elf64_Ehdr*)Arch_KernelBinary->address; Elf64_Phdr* phdrs = (Elf64_Phdr*)(Arch_KernelBinary->address + ehdr->e_phoff); size_t i = 0; + uintptr_t kernel_limit = 0; for (; i < ehdr->e_phnum; i++) { Elf64_Phdr* phdr = phdrs + i; @@ -386,8 +415,10 @@ obos_status Arch_InitializeKernelPageTable() if (phdr->p_flags & PF_W) flags |= 2; uintptr_t base = phdr->p_vaddr & ~0xfff; +#if !OBOS_USE_LIMINE if (base < Arch_KernelInfo->virtual_base) OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "Fatal error. Bootloader made a whoopsie! (line %d in file %s). Expression: base < Arch_KernelInfo->virtual_base.\n", __LINE__, __FILE__); +#endif uintptr_t limit = phdr->p_vaddr + phdr->p_memsz; if (limit & 0xfff) limit = (limit + 0xfff) & ~0xfff; @@ -397,6 +428,7 @@ obos_status Arch_InitializeKernelPageTable() OBOS_ASSERT(phys); Arch_MapPage(newCR3, (void*)virt, phys, flags, false); } + kernel_limit = kernel_limit > limit ? kernel_limit : limit; } OBOS_Debug("%s: Mapping HHDM.\n", __func__); for (uintptr_t off = 0; off < Mm_PhysicalMemoryBoundaries; off += 0x200000) @@ -404,10 +436,18 @@ obos_status Arch_InitializeKernelPageTable() asm volatile("mov %0, %%cr3;" : :"r"(newCR3)); // Reclaim old page tables. uint32_t indices[4] = { 0,0,0,0 }; - FreePageTables((uintptr_t*)oldCR3, 3, AddressToIndex(0xffff800000000000, 3), indices); + FreePageTables((uintptr_t*)oldCR3, 3, AddressToIndex(0xffff800000000000, 3), false, indices); Mm_FreePhysicalPages((uintptr_t)oldCR3, 1); +#if OBOS_USE_LIMINE + OBOSH_BasicMMAddRegion( + &kernel_region, + (void*)Arch_LimineKernelAddressRequest.response->virtual_base, + kernel_limit - Arch_LimineKernelAddressRequest.response->virtual_base); + OBOSH_BasicMMAddRegion(&hhdm_region, (void*)Arch_LimineHHDMRequest.response->offset, Mm_PhysicalMemoryBoundaries); +#else OBOSH_BasicMMAddRegion(&kernel_region, (void*)Arch_KernelInfo->virtual_base, Arch_KernelInfo->size); OBOSH_BasicMMAddRegion(&hhdm_region, (void*)Arch_LdrPlatformInfo->higher_half_base, Mm_PhysicalMemoryBoundaries); +#endif Arch_KernelCR3 = newCR3; return OBOS_STATUS_SUCCESS; } @@ -514,7 +554,13 @@ static void map_range(uintptr_t cached_root, uintptr_t base, uintptr_t top, uint top &= ~0xfff; for (uintptr_t addr = base; addr < top; addr += 0x1000) { - uintptr_t phys = Arch_MaskPhysicalAddressFromEntry(Arch_GetPML1Entry(Arch_KernelCR3, addr)); + uintptr_t phys = 0; + uintptr_t pml2ent = Arch_GetPML2Entry(Arch_KernelCR3, addr); + if (pml2ent & BIT_TYPE(7, UL)) + phys = Arch_MaskPhysicalAddressFromEntry(pml2ent) + (addr & (OBOS_HUGE_PAGE_SIZE-1)); + else + phys = Arch_MaskPhysicalAddressFromEntry(Arch_GetPML1Entry(Arch_KernelCR3, addr)); + OBOS_ENSURE(phys != 0); Arch_MapPage(cached_root, (void*)addr, phys, flags, false); } } @@ -554,7 +600,8 @@ page_table MmS_AllocatePageTable() } void MmS_FreePageTable(page_table pt) { - // uint32_t indices[4] = {}; - // FreePageTables(MmS_MapVirtFromPhys(pt), 3, 0, indices); + OBOS_ENSURE(pt != Arch_KernelCR3); + uint32_t indices[4] = {}; + FreePageTables((uintptr_t*)pt, 3, 0, true, indices); Mm_FreePhysicalPages(pt, 1); } diff --git a/src/oboskrnl/arch/x86_64/pmm.c b/src/oboskrnl/arch/x86_64/pmm.c index 43108692..5654d4e1 100644 --- a/src/oboskrnl/arch/x86_64/pmm.c +++ b/src/oboskrnl/arch/x86_64/pmm.c @@ -11,6 +11,7 @@ #include +#if !OBOS_USE_LIMINE #include extern struct ultra_memory_map_attribute* Arch_MemoryMap; @@ -34,6 +35,32 @@ obos_pmem_map_entry* MmS_GetNextPMemMapEntry(obos_pmem_map_entry* current, uintp #define MAP_TO_HHDM(addr, type) ((type*)(Arch_LdrPlatformInfo->higher_half_base + (uintptr_t)(addr))) #define UNMAP_FROM_HHDM(addr) ((uintptr_t)(addr) - Arch_LdrPlatformInfo->higher_half_base) +#else + +#include + +obos_pmem_map_entry* MmS_GetFirstPMemMapEntry(uintptr_t* index) +{ + *index = 0; + return Arch_LimineMemmapRequest.response->entries[0]; +} +// returns nullptr at the end of the list. +obos_pmem_map_entry* MmS_GetNextPMemMapEntry(obos_pmem_map_entry* current, uintptr_t* index) +{ + OBOS_UNUSED(current); + size_t nEntries = Arch_LimineMemmapRequest.response->entry_count; + if (!nEntries) + OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "No memory map entries.\n"); + if ((*index) >= nEntries) + return nullptr; + return Arch_LimineMemmapRequest.response->entries[++(*index)]; +} + +#define MAP_TO_HHDM(addr, type) ((type*)(Arch_LimineHHDMRequest.response->offset + (uintptr_t)(addr))) +#define UNMAP_FROM_HHDM(addr) ((uintptr_t)(addr) - Arch_LimineHHDMRequest.response->offset) + +#endif + OBOS_NO_KASAN OBOS_NO_UBSAN __attribute__((no_instrument_function)) void* Arch_MapToHHDM(uintptr_t phys) { return MAP_TO_HHDM(phys, void); diff --git a/src/oboskrnl/arch/x86_64/pmm.h b/src/oboskrnl/arch/x86_64/pmm.h index cb767ca4..cec0032f 100644 --- a/src/oboskrnl/arch/x86_64/pmm.h +++ b/src/oboskrnl/arch/x86_64/pmm.h @@ -9,6 +9,8 @@ #include #include +#if !OBOS_USE_LIMINE + #include typedef struct ultra_memory_map_entry obos_pmem_map_entry; @@ -19,5 +21,19 @@ typedef struct ultra_memory_map_entry obos_pmem_map_entry; #define PHYSICAL_MEMORY_TYPE_RECLAIMABLE ULTRA_MEMORY_TYPE_RECLAIMABLE #define PHYSICAL_MEMORY_TYPE_LOADER_RECLAIMABLE ULTRA_MEMORY_TYPE_LOADER_RECLAIMABLE +#else + +#include + +typedef struct limine_memmap_entry obos_pmem_map_entry; +#define pmem_map_base base +#define pmem_map_size length +#define pmem_map_type type +#define PHYSICAL_MEMORY_TYPE_USABLE LIMINE_MEMMAP_USABLE +#define PHYSICAL_MEMORY_TYPE_RECLAIMABLE LIMINE_MEMMAP_ACPI_RECLAIMABLE +#define PHYSICAL_MEMORY_TYPE_LOADER_RECLAIMABLE LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE + +#endif + void* Arch_MapToHHDM(uintptr_t phys); uintptr_t Arch_UnmapFromHHDM(void* virt); \ No newline at end of file diff --git a/src/oboskrnl/arch/x86_64/smp.c b/src/oboskrnl/arch/x86_64/smp.c index ff71a8ca..f51f16fa 100644 --- a/src/oboskrnl/arch/x86_64/smp.c +++ b/src/oboskrnl/arch/x86_64/smp.c @@ -49,7 +49,7 @@ obos_status Arch_MapPage(uintptr_t cr3, void* at_, uintptr_t phys, uintptr_t fla static OBOS_NO_UBSAN void ParseMADT() { // Find the MADT in the ACPI tables. - ACPIRSDPHeader* rsdp = (ACPIRSDPHeader*)Arch_MapToHHDM(Arch_LdrPlatformInfo->acpi_rsdp_address); + ACPIRSDPHeader* rsdp = (ACPIRSDPHeader*)Arch_MapToHHDM(Arch_RSDPBase); bool tables32 = rsdp->Revision < 2; ACPISDTHeader* xsdt = tables32 ? (ACPISDTHeader*)(uintptr_t)rsdp->RsdtAddress : (ACPISDTHeader*)rsdp->XsdtAddress; xsdt = (ACPISDTHeader*)Arch_MapToHHDM((uintptr_t)xsdt); @@ -157,6 +157,8 @@ void __attribute__((no_stack_protector)) Arch_APEntry(cpu_local* info) thread* idleThread = CoreH_ThreadAllocate(nullptr); CoreH_ThreadInitialize(idleThread, THREAD_PRIORITY_IDLE, ((thread_affinity)1<id), &ctx); CoreH_ThreadReady(idleThread); + info->nReadyThreads--; + Core_ReadyThreadCount--; Core_ProcessAppendThread(OBOS_KernelProcess, idleThread); info->idleThread = idleThread; Arch_LAPICInitialize(false); @@ -185,14 +187,17 @@ void Arch_SMPStartup() Arch_SaveMTRRs(); Arch_RawRegisterInterrupt(0x2, (uintptr_t)nmiHandler); ParseMADT(); + bool up = false; #ifdef OBOS_UP OBOS_Log("Uniprocessor-build of OBOS. No other cores will be initialized.\n"); - s_nLAPICIDs = 1; + // s_nLAPICIDs = 1; + up = true; #else if (OBOS_GetOPTF("no-smp")) { OBOS_Log("Running OBOS as Uniprocessor. No other cores will be initialized.\n"); - s_nLAPICIDs = 1; + up = true; + // s_nLAPICIDs = 1; } #endif // if (s_nLAPICIDs == 1) @@ -206,7 +211,7 @@ void Arch_SMPStartup() Arch_MapPage(getCR3(), (void*)0x1000, 0x1000, 0x3, false); Arch_SMPTrampolineCR3 = getCR3(); Core_CpuInfo = cpu_info; - Core_CpuCount = s_nLAPICIDs; + Core_CpuCount = up ? 1 : s_nLAPICIDs; // irql oldIrql = Core_RaiseIrql(0xf); for (size_t i = 0; i < s_nLAPICIDs; i++) { @@ -353,3 +358,17 @@ void CoreS_SetKernelStack(void* stck) if (!stck) return; CoreS_GetCPULocalPtr()->arch_specific.tss.rsp0 = (uintptr_t)stck+0x10000; } + +void CoreS_ForceYieldOnSyscallReturn() +{ + ipi_vector_info vector = { + .deliveryMode = LAPIC_DELIVERY_MODE_FIXED, + .info.vector = Core_SchedulerIRQ->vector->id + 0x20 + }; + asm volatile ("cli"); + static ipi_lapic_info self = { + .isShorthand=true, + .info.shorthand=LAPIC_DESTINATION_SHORTHAND_SELF + }; + Arch_LAPICSendIPI(self, vector); +} \ No newline at end of file diff --git a/src/oboskrnl/arch/x86_64/ssignal.c b/src/oboskrnl/arch/x86_64/ssignal.c index d759453c..6fbcd6e9 100644 --- a/src/oboskrnl/arch/x86_64/ssignal.c +++ b/src/oboskrnl/arch/x86_64/ssignal.c @@ -60,7 +60,7 @@ void OBOSS_RunSignalImpl(int sigval, interrupt_frame* frame) { // if (!(frame->cs & 0x3)) // return; - sigaction* sig = &Core_GetCurrentThread()->signal_info->signals[sigval-1]; + sigaction* sig = &Core_GetCurrentThread()->proc->signal_handlers[sigval-1]; if (sig->un.handler == SIG_IGN) return; ucontext_t ctx = { .frame=*frame,.gs_base=rdmsr(!(frame->cs & 0x3) ? GS_BASE : KERNEL_GS_BASE),.fs_base=rdmsr(FS_BASE),.cr3=frame->cr3 }; diff --git a/src/oboskrnl/arch/x86_64/syscall.asm b/src/oboskrnl/arch/x86_64/syscall.asm index d125c255..6b1e0e8a 100644 --- a/src/oboskrnl/arch/x86_64/syscall.asm +++ b/src/oboskrnl/arch/x86_64/syscall.asm @@ -119,6 +119,7 @@ Arch_SyscallTrapHandler: pop rcx mov cr3, r9 + cli mov rsp, r10 swapgs o64 sysret diff --git a/src/oboskrnl/arch/x86_64/syscall.c b/src/oboskrnl/arch/x86_64/syscall.c index b4bc586d..a85fa143 100644 --- a/src/oboskrnl/arch/x86_64/syscall.c +++ b/src/oboskrnl/arch/x86_64/syscall.c @@ -245,6 +245,14 @@ const char* syscall_to_string[] = { "Sys_UMask", "Sys_RenameAt", "Sys_UTimeNSAt", + "Sys_ThreadGetStack", + "Sys_SetRESUid", + "Sys_SetRESGid", + "Sys_GetRESUid", + "Sys_GetRESGid", + "Sys_SigPending", + "Sys_SetGroups", + "Sys_GetGroups", }; const char* status_to_string[] = { diff --git a/src/oboskrnl/arch/x86_64/timer.c b/src/oboskrnl/arch/x86_64/timer.c index c29235ff..5e9be3b4 100644 --- a/src/oboskrnl/arch/x86_64/timer.c +++ b/src/oboskrnl/arch/x86_64/timer.c @@ -80,7 +80,7 @@ static OBOS_PAGEABLE_FUNCTION OBOS_NO_UBSAN void InitializeHPET() { static basicmm_region hpet_region; hpet_region.mmioRange = true; - ACPIRSDPHeader* rsdp = (ACPIRSDPHeader*)Arch_MapToHHDM(Arch_LdrPlatformInfo->acpi_rsdp_address); + ACPIRSDPHeader* rsdp = (ACPIRSDPHeader*)Arch_MapToHHDM(Arch_RSDPBase); bool tables32 = rsdp->Revision < 2; ACPISDTHeader* xsdt = tables32 ? (ACPISDTHeader*)(uintptr_t)rsdp->RsdtAddress : (ACPISDTHeader*)rsdp->XsdtAddress; xsdt = (ACPISDTHeader*)Arch_MapToHHDM((uintptr_t)xsdt); diff --git a/src/oboskrnl/arch/x86_64/wake.c b/src/oboskrnl/arch/x86_64/wake.c index d38e55fa..a881fac0 100644 --- a/src/oboskrnl/arch/x86_64/wake.c +++ b/src/oboskrnl/arch/x86_64/wake.c @@ -41,6 +41,10 @@ #include +#if OBOS_USE_LIMINE +# include +#endif + struct { HPET_Timer timer0; uint64_t mainCounterValue; @@ -111,6 +115,23 @@ void OBOSS_SuspendSavePlatformState() index = 0; size_t nvs_index = 0; +# if OBOS_USE_LIMINE + for (obos_pmem_map_entry* entry = MmS_GetFirstPMemMapEntry(&index); entry; ) + { + if (entry->type == LIMINE_MEMMAP_ACPI_NVS) + { + saved_nvs[nvs_index].region_address = Arch_MapToHHDM(entry->base); + saved_nvs[nvs_index].size = entry->length; + saved_nvs[nvs_index].saved_region = Allocate(OBOS_NonPagedPoolAllocator, + saved_nvs[nvs_index].size, + nullptr); + memcpy(saved_nvs[nvs_index].saved_region, saved_nvs[nvs_index].region_address, saved_nvs[nvs_index].size); + nvs_index++; + } + + entry = MmS_GetNextPMemMapEntry(entry, &index); + } +# else for (obos_pmem_map_entry* entry = MmS_GetFirstPMemMapEntry(&index); entry; ) { if (entry->type == ULTRA_MEMORY_TYPE_NVS) @@ -118,14 +139,15 @@ void OBOSS_SuspendSavePlatformState() saved_nvs[nvs_index].region_address = Arch_MapToHHDM(entry->physical_address); saved_nvs[nvs_index].size = entry->size; saved_nvs[nvs_index].saved_region = Allocate(OBOS_NonPagedPoolAllocator, - saved_nvs[nvs_index].size, - nullptr); + saved_nvs[nvs_index].size, + nullptr); memcpy(saved_nvs[nvs_index].saved_region, saved_nvs[nvs_index].region_address, saved_nvs[nvs_index].size); nvs_index++; } entry = MmS_GetNextPMemMapEntry(entry, &index); } +# endif } #endif } diff --git a/src/oboskrnl/driver_interface/drv_sys.c b/src/oboskrnl/driver_interface/drv_sys.c index 06c41145..2d99ee15 100644 --- a/src/oboskrnl/driver_interface/drv_sys.c +++ b/src/oboskrnl/driver_interface/drv_sys.c @@ -24,9 +24,10 @@ handle Sys_LoadDriver(const void* file, size_t szFile, obos_status* ustatus) { - if (Core_GetCurrentThread()->proc->currentUID != ROOT_UID) + if (Core_GetCurrentThread()->proc->euid != ROOT_UID) { - if (ustatus) *ustatus = OBOS_STATUS_ACCESS_DENIED; + obos_status status = OBOS_STATUS_ACCESS_DENIED; + if (ustatus) memcpy_k_to_usr(ustatus, &status, sizeof(obos_status)); return HANDLE_INVALID; } @@ -62,7 +63,7 @@ handle Sys_LoadDriver(const void* file, size_t szFile, obos_status* ustatus) } #define perm_check_impl(ret) do {\ - if (Core_GetCurrentThread()->proc->currentUID != ROOT_UID)\ + if (Core_GetCurrentThread()->proc->euid != ROOT_UID)\ return (ret);\ } while(0) #define perm_check() perm_check_impl(OBOS_STATUS_ACCESS_DENIED) diff --git a/src/oboskrnl/driver_interface/loader.c b/src/oboskrnl/driver_interface/loader.c index 96e23551..957cfc65 100644 --- a/src/oboskrnl/driver_interface/loader.c +++ b/src/oboskrnl/driver_interface/loader.c @@ -308,6 +308,7 @@ OBOS_NO_UBSAN driver_id *Drv_LoadDriver(const void* file_, size_t szFile, obos_s OBOS_Log("%s: Loaded driver '%s' at 0x%p.\n", __func__, driver->header.driverName, driver->base); else OBOS_Log("%s: Loaded driver at 0x%p.\n", __func__, driver->header.driverName, driver->base); + driver->refCnt++; return driver; } diff --git a/src/oboskrnl/driver_interface/pci.c b/src/oboskrnl/driver_interface/pci.c index 8e6a86cc..22407ba1 100644 --- a/src/oboskrnl/driver_interface/pci.c +++ b/src/oboskrnl/driver_interface/pci.c @@ -322,6 +322,7 @@ static void initialize_irq_resources(pci_device* dev) pci_resource* resource = ZeroAllocate(OBOS_KernelAllocator, 1, sizeof(pci_resource), nullptr); resource->type = PCI_RESOURCE_IRQ; + resource->owner = dev; resource->irq = ZeroAllocate(OBOS_KernelAllocator, 1, sizeof(pci_irq_handle), nullptr); resource->owner = dev; @@ -341,6 +342,7 @@ static void initialize_cmd_register_resource(pci_device* dev) resource->cmd_register = cmd_register & 0xffff; LIST_APPEND(pci_resource_list, &dev->resources, resource); + resource->owner = dev; dev->resource_cmd_register = resource; } diff --git a/src/oboskrnl/driver_interface/pci_irq.c b/src/oboskrnl/driver_interface/pci_irq.c index 4ce507bd..dd9b367d 100644 --- a/src/oboskrnl/driver_interface/pci_irq.c +++ b/src/oboskrnl/driver_interface/pci_irq.c @@ -40,6 +40,7 @@ static void* map_registers(uintptr_t phys, size_t size, bool uc) page.prot.uc = uc; MmS_SetPageMapping(Mm_KernelContext.pt, &page, phys + offset, false); } + MmS_TLBShootdown(Mm_KernelContext.pt, (uintptr_t)virt, size); return virt+phys_page_offset; } static void pci_irq_move_callback(struct irq* i, struct irq_vector* from, struct irq_vector* to, void* userdata) diff --git a/src/oboskrnl/elf/load.c b/src/oboskrnl/elf/load.c index b859217d..ebc69f37 100644 --- a/src/oboskrnl/elf/load.c +++ b/src/oboskrnl/elf/load.c @@ -131,7 +131,7 @@ obos_status OBOS_LoadELF(context* ctx, const void* file, size_t szFile, elf_info uintptr_t real_limit = phdrs[i].p_vaddr+phdrs[i].p_memsz; if (real_limit % OBOS_PAGE_SIZE) real_limit += (OBOS_PAGE_SIZE-(real_limit%OBOS_PAGE_SIZE)); - // printf("ELF: Allocating 0x%p bytes (memsz=0x%p, real_base=0x%p, real_limit=0x%p, vaddr=0x%p)", real_limit-real_base, phdrs[i].p_memsz, real_base, real_limit, phdrs[i].p_vaddr); + // printf("ELF: Allocating 0x%p bytes (memsz=0x%p, real_base=0x%p, real_limit=0x%p, vaddr=0x%p)\n", real_limit-real_base, phdrs[i].p_memsz, real_base, real_limit, phdrs[i].p_vaddr); ubase = Mm_VirtualMemoryAlloc(ctx, (void*)real_base, real_limit-real_base, @@ -159,6 +159,8 @@ obos_status OBOS_LoadELF(context* ctx, const void* file, size_t szFile, elf_info real_limit += base; } + OBOS_ENSURE(phdrs[i].p_filesz <= (real_limit - real_base)); + kbase = Mm_MapViewOfUserMemory(ctx, (void*)real_base, nullptr, diff --git a/src/oboskrnl/execve.c b/src/oboskrnl/execve.c index c09fec4a..12c2f6d6 100644 --- a/src/oboskrnl/execve.c +++ b/src/oboskrnl/execve.c @@ -141,11 +141,11 @@ obos_status Sys_ExecVE(const char* upath, char* const* argv, char* const* envp) return status; Core_GetCurrentThread()->proc->exec_file = VfsH_DirentPath(VfsH_DirentLookup(path), nullptr); size_t szBuf = file.vn->filesize; - void* kbuf = Mm_VirtualMemoryAlloc(&Mm_KernelContext, nullptr, szBuf, 0, VMA_FLAGS_PRIVATE|VMA_FLAGS_PREFAULT, &file, nullptr); + void* kbuf = Mm_VirtualMemoryAlloc(&Mm_KernelContext, nullptr, szBuf, OBOS_PROTECTION_READ_ONLY, 0, &file, nullptr); bool set_uid = file.vn->perm.set_uid; bool set_gid = file.vn->perm.set_gid; - uid target_uid = set_uid ? file.vn->owner_uid : Core_GetCurrentThread()->proc->currentUID; - gid target_gid = set_gid ? file.vn->group_uid : Core_GetCurrentThread()->proc->currentGID; + uid target_euid = set_uid ? file.vn->uid : Core_GetCurrentThread()->proc->euid; + gid target_egid = set_gid ? file.vn->gid : Core_GetCurrentThread()->proc->egid; Vfs_FdClose(&file); char** kargv = allocate_user_vector_as_kernel(ctx, argv, &argc, &status); @@ -309,8 +309,10 @@ obos_status Sys_ExecVE(const char* upath, char* const* argv, char* const* envp) aux.at_secure = set_gid || set_uid; - Core_GetCurrentThread()->proc->currentUID = target_uid; - Core_GetCurrentThread()->proc->currentGID = target_gid; + Core_GetCurrentThread()->proc->euid = target_euid; + Core_GetCurrentThread()->proc->egid = target_egid; + Core_GetCurrentThread()->proc->sgid = target_euid; + Core_GetCurrentThread()->proc->sgid = target_egid; OBOSS_HandControlTo(ctx, &aux); } diff --git a/src/oboskrnl/gpt.c b/src/oboskrnl/gpt.c index e1ff87e2..d9f16d5f 100644 --- a/src/oboskrnl/gpt.c +++ b/src/oboskrnl/gpt.c @@ -35,7 +35,8 @@ obos_status OBOS_IdentifyGPTPartitions(fd *desc, partition *partition_list, size size_t filesize = desc->vn->filesize; if (filesize < sizeof(mbr_t)) return OBOS_STATUS_EOF; - mbr_t *protective_mbr = ZeroAllocate(OBOS_KernelAllocator, 1, sizeof(mbr_t), nullptr); + OBOS_ASSERT(OBOS_PAGE_SIZE > sizeof(mbr_t)); + mbr_t *protective_mbr = ZeroAllocate(OBOS_KernelAllocator, 1, OBOS_PAGE_SIZE, nullptr); obos_status status = Vfs_FdRead(desc, protective_mbr, sizeof(*protective_mbr), &nRead); if (obos_is_error(status)) @@ -44,7 +45,7 @@ obos_status OBOS_IdentifyGPTPartitions(fd *desc, partition *partition_list, size return OBOS_STATUS_INTERNAL_ERROR; if (protective_mbr->signature != MBR_BOOT_SIGNATURE) return OBOS_STATUS_INVALID_FILE; - Free(OBOS_KernelAllocator, protective_mbr, sizeof(*protective_mbr)); + Free(OBOS_KernelAllocator, protective_mbr, OBOS_PAGE_SIZE); size_t blkSize = Vfs_FdGetBlkSz(desc); OBOS_ASSERT(__builtin_popcount(blkSize) == 1); diff --git a/src/oboskrnl/init_proc.c b/src/oboskrnl/init_proc.c index 2ec81d50..b2d1db5a 100644 --- a/src/oboskrnl/init_proc.c +++ b/src/oboskrnl/init_proc.c @@ -61,7 +61,7 @@ void OBOS_LoadInit() if (obos_is_error(status)) OBOS_Panic(OBOS_PANIC_FATAL_ERROR, "Could not open %s. Status: %d\n", init_path, status); - context* new_ctx = Mm_Allocator->ZeroAllocate(Mm_Allocator, 1, sizeof(context), nullptr); + context* new_ctx = ZeroAllocate(Mm_Allocator, 1, sizeof(context), nullptr); Mm_ConstructContext(new_ctx); process* new = Core_ProcessAllocate(nullptr); new->ctx = new_ctx; diff --git a/src/oboskrnl/irq/timer.c b/src/oboskrnl/irq/timer.c index 90ce66eb..ae70bf03 100644 --- a/src/oboskrnl/irq/timer.c +++ b/src/oboskrnl/irq/timer.c @@ -4,6 +4,7 @@ * Copyright (c) 2024 Omar Berrow */ +#include "locks/event.h" #include #include #include @@ -240,3 +241,18 @@ OBOS_EXPORT uint64_t CoreH_TickToNS(timer_tick tick, bool native_tick) return tick * cached_rate; } } + +static void tm_evnt_hnd(void* udata) +{ + event* evnt = udata; + Core_EventSet(evnt, false); +} + +void CoreH_MakeTimerEvent(timer** otm, uint64_t us, event* evnt, bool recurring) +{ + OBOS_ASSERT(otm); + *otm = Core_TimerObjectAllocate(nullptr); + (*otm)->handler = tm_evnt_hnd; + (*otm)->userdata = (void*)evnt; + Core_TimerObjectInitialize(*otm, recurring ? TIMER_MODE_INTERVAL : TIMER_MODE_DEADLINE, us); +} \ No newline at end of file diff --git a/src/oboskrnl/irq/timer.h b/src/oboskrnl/irq/timer.h index 8f54a8af..e1d8dd54 100644 --- a/src/oboskrnl/irq/timer.h +++ b/src/oboskrnl/irq/timer.h @@ -13,6 +13,8 @@ #include #include +#include + typedef uint64_t timer_tick; typedef uint64_t timer_frequency; @@ -111,6 +113,15 @@ OBOS_EXPORT timer_tick CoreH_TimeFrameToTick(uint64_t us); /// The tick count in nanoseconds.. OBOS_EXPORT uint64_t CoreH_TickToNS(timer_tick tick, bool native_tick); +/// +/// Starts a timer for 'us' microseconds, setting evnt when it is triggered.
+/// Useful for timeouts. +///
+/// [out] The timer object used. +/// The time period to start the timer for +/// The event to set when the timer finishes +/// Whether the timer should be an interval or deadline timer +OBOS_EXPORT void CoreH_MakeTimerEvent(timer** otm, uint64_t us, event* evnt, bool recurring); uint64_t CoreS_TimerTickToNS(timer_tick tp); @@ -122,4 +133,4 @@ uint64_t CoreS_TimerTickToNS(timer_tick tp); OBOS_WEAK obos_status CoreS_InitializeTimer(irq_handler handler); #ifdef OBOS_TIMER_IS_DEADLINE obos_status CoreS_ResetTimer(); -#endif +#endif \ No newline at end of file diff --git a/src/oboskrnl/locks/pushlock.c b/src/oboskrnl/locks/pushlock.c index cd11dca2..9ae44e0e 100644 --- a/src/oboskrnl/locks/pushlock.c +++ b/src/oboskrnl/locks/pushlock.c @@ -33,7 +33,10 @@ obos_status Core_PushlockAcquire(pushlock* lock, bool reader /* false: writer, t // Hopefully this is right. // maybe a possible race condition. try_again: - Core_WaitOnObject(&lock->hdr); + (void)0; + obos_status status = Core_WaitOnObject(&lock->hdr); + if (obos_is_error(status)) + return status; CoreH_ClearSignaledState(&lock->hdr); if (lock->nWaitingReaders) goto try_again; diff --git a/src/oboskrnl/locks/semaphore.c b/src/oboskrnl/locks/semaphore.c index a7f1b19a..8a9e7ca1 100644 --- a/src/oboskrnl/locks/semaphore.c +++ b/src/oboskrnl/locks/semaphore.c @@ -35,7 +35,9 @@ obos_status Core_SemaphoreAcquire(semaphore* sem) } Core_SpinlockRelease(&sem->lock, oldIrql); // Add the current thread to the waiting list. - Core_WaitOnObject(&sem->hdr); + obos_status status = Core_WaitOnObject(&sem->hdr); + if (obos_is_error(status)) + return status; oldIrql = Core_SpinlockAcquire(&sem->lock); sem->count--; Core_SpinlockRelease(&sem->lock, oldIrql); diff --git a/src/oboskrnl/locks/spinlock.c b/src/oboskrnl/locks/spinlock.c index a2ff6833..afe8e4a2 100644 --- a/src/oboskrnl/locks/spinlock.c +++ b/src/oboskrnl/locks/spinlock.c @@ -1,7 +1,7 @@ /* - oboskrnl/locks/spinlock.c + oboskrnl/locks/spinlock.c - Copyright (c) 2024-2025 Omar Berrow + Copyright (c) 2024-2025 Omar Berrow */ #include @@ -20,76 +20,78 @@ static uint64_t nanoseconds_since_boot() { #if !OBOS_ENABLE_LOCK_PROFILING - return 0; + return 0; #else - if (!CoreS_GetNativeTimerFrequency()) - return 0; - return CoreH_TickToNS(CoreS_GetNativeTimerTick(), true); + if (!CoreS_GetNativeTimerFrequency()) + return 0; + return CoreH_TickToNS(CoreS_GetNativeTimerTick(), true); #endif } __attribute__((no_instrument_function)) OBOS_NO_UBSAN irql Core_SpinlockAcquireExplicit(spinlock* const lock, irql minIrql, bool irqlNthrVariant) { - // IRQL_INVALID is used to specify not to raise the irql at all - // this way, LowerIrql can lock the DPC queue without breaking. - irql oldIrql = IRQL_INVALID; - if (Core_GetIrql() < minIrql) - oldIrql = Core_RaiseIrqlNoThread(minIrql); - if (!atomic_flag_test_and_set_explicit(&lock->val, memory_order_acq_rel)) + // IRQL_INVALID is used to specify not to raise the irql at all + // this way, LowerIrql can lock the DPC queue without breaking. + irql oldIrql = IRQL_INVALID; + if (obos_expect(Core_GetIrql() < minIrql, false)) + oldIrql = Core_RaiseIrqlNoThread(minIrql); + if (!atomic_flag_test_and_set_explicit(&lock->val, memory_order_acq_rel)) goto done_wait; while (atomic_flag_test_and_set_explicit(&lock->val, memory_order_acq_rel)) - OBOSS_SpinlockHint(); + OBOSS_SpinlockHint(); done_wait: - lock->locked = true; - return oldIrql; + lock->locked = true; + return oldIrql; } __attribute__((no_instrument_function)) OBOS_NO_UBSAN irql Core_SpinlockAcquire(spinlock* const lock) { irql oldIrql = IRQL_INVALID; - if (Core_GetIrql() < IRQL_DISPATCH) + if (obos_expect(Core_GetIrql() < IRQL_DISPATCH, false)) oldIrql = Core_RaiseIrqlNoThread(IRQL_DISPATCH); if (!atomic_flag_test_and_set_explicit(&lock->val, memory_order_acq_rel)) goto locked; - while (atomic_flag_test_and_set_explicit(&lock->val, memory_order_acq_rel)) - OBOSS_SpinlockHint(); + while (atomic_flag_test_and_set_explicit(&lock->val, memory_order_acq_rel)) + OBOSS_SpinlockHint(); locked: - lock->locked = true; + lock->locked = true; #if OBOS_ENABLE_LOCK_PROFILING - lock->lastLockTimeNS = nanoseconds_since_boot(); + lock->lastLockTimeNS = nanoseconds_since_boot(); #endif - return oldIrql; + return oldIrql; } __attribute__((no_instrument_function)) OBOS_NO_UBSAN obos_status Core_SpinlockRelease(spinlock* const lock, irql oldIrql) { - if (oldIrql & 0xf0 && oldIrql != IRQL_INVALID) - { - OBOS_ASSERT(!"funny stuff"); - return OBOS_STATUS_INVALID_IRQL; - } - atomic_flag_clear_explicit(&lock->val, memory_order_relaxed); - lock->locked = false; - Core_LowerIrqlNoThread(oldIrql); +#if OBOS_DEBUG + if (oldIrql & 0xf0 && oldIrql != IRQL_INVALID) + { + OBOS_ASSERT(!"funny stuff"); + return OBOS_STATUS_INVALID_IRQL; + } +#endif + atomic_flag_clear_explicit(&lock->val, memory_order_relaxed); + lock->locked = false; + Core_LowerIrqlNoThread(oldIrql); #if OBOS_ENABLE_LOCK_PROFILING - lock->lastLockTimeNS = nanoseconds_since_boot() - lock->lastLockTimeNS; + lock->lastLockTimeNS = nanoseconds_since_boot() - lock->lastLockTimeNS; #endif - return OBOS_STATUS_SUCCESS; + return OBOS_STATUS_SUCCESS; } /* * No. OBOS_NO_UBSAN void Core_SpinlockForcedRelease(spinlock* const lock) { - atomic_flag_clear_explicit(&lock->val, memory_order_seq_cst); - lock->irqlNThrVariant = false; + atomic_flag_clear_explicit(&lock->val, memory_order_seq_cst); + lock->irqlNThrVariant = false; #ifdef OBOS_DEBUG - lock->owner = nullptr; + lock->owner = nullptr; #endif - lock->locked = false; + lock->locked = false; }*/ __attribute__((no_instrument_function)) bool Core_SpinlockAcquired(spinlock* const lock) { - return lock ? lock->locked : false; + return lock ? lock->locked : false; } diff --git a/src/oboskrnl/locks/sys_futex.c b/src/oboskrnl/locks/sys_futex.c index 9661f9cc..e86d6acb 100644 --- a/src/oboskrnl/locks/sys_futex.c +++ b/src/oboskrnl/locks/sys_futex.c @@ -92,6 +92,8 @@ obos_status Sys_FutexWait(uint32_t *futex, uint32_t cmp_with, uint64_t timeout) // Mm_VirtualMemoryUnlock(CoreS_GetCPULocalPtr()->currentThread->proc->ctx, futex, sizeof(*futex)); obos_status status = Core_WaitOnObject(WAITABLE_OBJECT(*obj)); deref_futex(obj); + if (CoreS_ForceYieldOnSyscallReturn) + CoreS_ForceYieldOnSyscallReturn(); return status; } diff --git a/src/oboskrnl/locks/wait.c b/src/oboskrnl/locks/wait.c index bc725a1a..4644874b 100644 --- a/src/oboskrnl/locks/wait.c +++ b/src/oboskrnl/locks/wait.c @@ -24,7 +24,7 @@ #if OBOS_DEBUG # define assert_initialized() OBOS_ASSERT(obj->initialized == true) #else -# define assert_initialized() (true) +# define assert_initialized() (void)(true) #endif obos_status Core_WaitOnObject(struct waitable_header* obj) diff --git a/src/oboskrnl/locks/wait.h b/src/oboskrnl/locks/wait.h index 9598a069..0ad93c8a 100644 --- a/src/oboskrnl/locks/wait.h +++ b/src/oboskrnl/locks/wait.h @@ -35,9 +35,11 @@ struct waitable_header // otherwise, this will not work, and will corrupt stuff. #define WAITABLE_OBJECT(obj) (struct waitable_header*)(&(obj)) -OBOS_EXPORT obos_status Core_WaitOnObject(struct waitable_header* obj); +OBOS_EXPORT + OBOS_NODISCARD_REASON("Handle errors from Core_WaitOnObject") obos_status Core_WaitOnObject(struct waitable_header* obj); // Waits until at least one object is signaled. -OBOS_EXPORT obos_status Core_WaitOnObjects(size_t nObjects, struct waitable_header** objs, struct waitable_header** signaled); +OBOS_EXPORT + OBOS_NODISCARD_REASON("Handle errors from Core_WaitOnObjects") obos_status Core_WaitOnObjects(size_t nObjects, struct waitable_header** objs, struct waitable_header** signaled); OBOS_EXPORT obos_status CoreH_SignalWaitingThreads(struct waitable_header* obj, bool all, bool boostPriority); OBOS_EXPORT void CoreH_ClearSignaledState(struct waitable_header* obj); OBOS_EXPORT obos_status CoreH_AbortWaitingThreads(struct waitable_header* obj); \ No newline at end of file diff --git a/src/oboskrnl/mm/aging.c b/src/oboskrnl/mm/aging.c index c483d757..decdb72b 100644 --- a/src/oboskrnl/mm/aging.c +++ b/src/oboskrnl/mm/aging.c @@ -67,7 +67,7 @@ obos_status Mm_AgingPRA(context* ctx) if (ent->free) { MmH_RemovePageFromWorkingset(ctx, node_save); - Mm_Allocator->Free(Mm_Allocator, ent, sizeof(*ent)); + Free(Mm_Allocator, ent, sizeof(*ent)); continue; } page_info info = {}; @@ -91,8 +91,8 @@ obos_status Mm_AgingPRA(context* ctx) REMOVE_WORKINGSET_PAGE_NODE(ctx->referenced, node); if (ent->free) { - Mm_Allocator->Free(Mm_Allocator, node, sizeof(*node)); - Mm_Allocator->Free(Mm_Allocator, ent, sizeof(*ent)); + Free(Mm_Allocator, node, sizeof(*node)); + Free(Mm_Allocator, ent, sizeof(*ent)); continue; } ent->age <<= 1; diff --git a/src/oboskrnl/mm/alloc.c b/src/oboskrnl/mm/alloc.c index 42f23cbb..7b65237d 100644 --- a/src/oboskrnl/mm/alloc.c +++ b/src/oboskrnl/mm/alloc.c @@ -289,7 +289,7 @@ void* Mm_VirtualMemoryAllocEx(context* ctx, void* base_, size_t size, prot_flags if (!rng) { - rng = Mm_Allocator->ZeroAllocate(Mm_Allocator, 1, sizeof(page_range), nullptr); + rng = ZeroAllocate(Mm_Allocator, 1, sizeof(page_range), nullptr); present = rng->prot.present = !(flags & VMA_FLAGS_RESERVE); rng->prot.huge_page = flags & VMA_FLAGS_HUGE_PAGE; @@ -493,8 +493,8 @@ obos_status Mm_VirtualMemoryFree(context* ctx, void* base_, size_t size) return OBOS_STATUS_INVALID_ARGUMENT; } // We need two ranges, one for the range behind base, and another for the range after. - page_range* before = Mm_Allocator->ZeroAllocate(Mm_Allocator, 1, sizeof(page_range), nullptr); - page_range* after = Mm_Allocator->ZeroAllocate(Mm_Allocator, 1, sizeof(page_range), nullptr); + page_range* before = ZeroAllocate(Mm_Allocator, 1, sizeof(page_range), nullptr); + page_range* after = ZeroAllocate(Mm_Allocator, 1, sizeof(page_range), nullptr); memcpy(before, rng, sizeof(*before)); memcpy(after, rng, sizeof(*before)); before->size = base-before->virt; @@ -510,7 +510,7 @@ obos_status Mm_VirtualMemoryFree(context* ctx, void* base_, size_t size) if (curr->data->info.virt >= before->virt && curr->data->info.virt < after->virt) { curr->data->free = true; // mark for deletion. - Mm_Allocator->Free(Mm_Allocator, curr, sizeof(*curr)); + Free(Mm_Allocator, curr, sizeof(*curr)); curr = next; continue; } @@ -532,7 +532,7 @@ obos_status Mm_VirtualMemoryFree(context* ctx, void* base_, size_t size) RB_INSERT(page_tree, &ctx->pages, before); RB_INSERT(page_tree, &ctx->pages, after); rng->ctx = nullptr; - Mm_Allocator->Free(Mm_Allocator, rng, sizeof(*rng)); + Free(Mm_Allocator, rng, sizeof(*rng)); rng = nullptr; } else if (rng->virt == base || rng->size == size) @@ -547,7 +547,7 @@ obos_status Mm_VirtualMemoryFree(context* ctx, void* base_, size_t size) { REMOVE_WORKINGSET_PAGE_NODE(rng->working_set_nodes, &curr->data->pr_node); curr->data->free = true; - Mm_Allocator->Free(Mm_Allocator, curr, sizeof(*curr)); + Free(Mm_Allocator, curr, sizeof(*curr)); } curr = next; } @@ -576,6 +576,7 @@ obos_status Mm_VirtualMemoryFree(context* ctx, void* base_, size_t size) } MmS_SetPageMapping(ctx->pt, &pg, 0, true); } + MmS_TLBShootdown(ctx->pt, base, size); if (rng) { @@ -614,11 +615,11 @@ obos_status Mm_VirtualMemoryFree(context* ctx, void* base_, size_t size) // working_set_node* next = curr->next; // REMOVE_WORKINGSET_PAGE_NODE(rng->working_set_nodes, &curr->data->pr_node); // curr->data->free = true; - // Mm_Allocator->Free(Mm_Allocator, curr, sizeof(*curr)); + // Free(Mm_Allocator, curr, sizeof(*curr)); // curr = next; // } RB_REMOVE(page_tree, &ctx->pages, rng); - Mm_Allocator->Free(Mm_Allocator, rng, sizeof(*rng)); + Free(Mm_Allocator, rng, sizeof(*rng)); } Core_SpinlockRelease(&ctx->lock, oldIrql); @@ -689,9 +690,9 @@ obos_status Mm_VirtualMemoryProtect(context* ctx, void* base_, size_t size, prot return OBOS_STATUS_INVALID_ARGUMENT; } // We need three ranges, one for the range behind base, another for the range after, and another for the new protection flags. - page_range* before = Mm_Allocator->ZeroAllocate(Mm_Allocator, 1, sizeof(page_range), nullptr); - page_range* after = Mm_Allocator->ZeroAllocate(Mm_Allocator, 1, sizeof(page_range), nullptr); - page_range* new = Mm_Allocator->ZeroAllocate(Mm_Allocator, 1, sizeof(page_range), nullptr); + page_range* before = ZeroAllocate(Mm_Allocator, 1, sizeof(page_range), nullptr); + page_range* after = ZeroAllocate(Mm_Allocator, 1, sizeof(page_range), nullptr); + page_range* new = ZeroAllocate(Mm_Allocator, 1, sizeof(page_range), nullptr); memcpy(new, rng, sizeof(*rng)); memcpy(before, rng, sizeof(*rng)); memcpy(after, rng, sizeof(*rng)); @@ -746,16 +747,16 @@ obos_status Mm_VirtualMemoryProtect(context* ctx, void* base_, size_t size, prot if (before->size) RB_INSERT(page_tree, &ctx->pages, before); else - Mm_Allocator->Free(Mm_Allocator, before, sizeof(page_range)); + Free(Mm_Allocator, before, sizeof(page_range)); if (after->size) RB_INSERT(page_tree, &ctx->pages, after); else - Mm_Allocator->Free(Mm_Allocator, after, sizeof(page_range)); + Free(Mm_Allocator, after, sizeof(page_range)); if (new->size) RB_INSERT(page_tree, &ctx->pages, new); else - Mm_Allocator->Free(Mm_Allocator, before, sizeof(page_range)); - Mm_Allocator->Free(Mm_Allocator, rng, sizeof(*rng)); + Free(Mm_Allocator, before, sizeof(page_range)); + Free(Mm_Allocator, rng, sizeof(*rng)); rng = new; } else if (rng->virt == base || rng->size == size) @@ -766,7 +767,7 @@ obos_status Mm_VirtualMemoryProtect(context* ctx, void* base_, size_t size, prot // "0x%p-0x%p\n", // rng->virt, rng->virt+rng->size // ); - page_range* new = Mm_Allocator->ZeroAllocate(Mm_Allocator, 1, sizeof(page_range), nullptr); + page_range* new = ZeroAllocate(Mm_Allocator, 1, sizeof(page_range), nullptr); memcpy(new, rng, sizeof(*rng)); new->size = size; rng->size = (rng->size-size); @@ -817,6 +818,7 @@ obos_status Mm_VirtualMemoryProtect(context* ctx, void* base_, size_t size, prot pg.prot.present = info.prot.present; MmS_SetPageMapping(ctx->pt, &pg, info.phys, false); } + MmS_TLBShootdown(ctx->pt, base, size); Core_SpinlockRelease(&ctx->lock, oldIrql); return OBOS_STATUS_SUCCESS; } @@ -868,11 +870,12 @@ void* Mm_MapViewOfUserMemory(context* const user_context, void* ubase_, void* kb } } - page_range* rng = Mm_Allocator->ZeroAllocate(Mm_Allocator, 1, sizeof(page_range), nullptr); + page_range* rng = ZeroAllocate(Mm_Allocator, 1, sizeof(page_range), nullptr); rng->virt = kbase; rng->ctx = &Mm_KernelContext; rng->phys32 = false; rng->hasGuardPage = false; + rng->pageable = false; rng->size = size; rng->prot.huge_page = false; rng->prot.rw = !(prot & OBOS_PROTECTION_READ_ONLY); @@ -909,6 +912,7 @@ void* Mm_MapViewOfUserMemory(context* const user_context, void* ubase_, void* kb if (~prot & OBOS_PROTECTION_READ_ONLY) Mm_MarkAsDirtyPhys(phys); } + OBOS_ENSURE(phys); if (phys && phys->cow_type && ~prot & OBOS_PROTECTION_READ_ONLY) { @@ -934,7 +938,7 @@ void* Mm_MapViewOfUserMemory(context* const user_context, void* ubase_, void* kb info.accessed = false; info.range = rng; info.prot = rng->prot; - info.prot.present = !!phys; + info.prot.present = info.phys != 0; info.prot.rw = rng->prot.rw; OBOS_ENSURE(info.phys); MmS_SetPageMapping(Mm_KernelContext.pt, &info, info.phys, false); @@ -991,7 +995,7 @@ void* Mm_QuickVMAllocate(size_t sz, bool non_pageable) uintptr_t base = (uintptr_t)blk; - page_range* rng = Mm_Allocator->ZeroAllocate(Mm_Allocator, 1, sizeof(page_range), nullptr); + page_range* rng = ZeroAllocate(Mm_Allocator, 1, sizeof(page_range), nullptr); rng->ctx = ctx; rng->size = sz; rng->virt = base; diff --git a/src/oboskrnl/mm/alloc.h b/src/oboskrnl/mm/alloc.h index 521ac3ee..3c3ed17a 100644 --- a/src/oboskrnl/mm/alloc.h +++ b/src/oboskrnl/mm/alloc.h @@ -75,9 +75,14 @@ extern OBOS_EXPORT page* Mm_UserAnonPage; OBOS_EXPORT void* MmH_FindAvailableAddress(context* ctx, size_t size, vma_flags flags, obos_status* status); // file can be nullptr for a anonymous mapping. +OBOS_EXPORT obos_status Mm_VirtualMemoryFree(context* ctx, void* base, size_t size); +#ifndef __clang__ +OBOS_EXPORT __attribute__((malloc, malloc(Mm_VirtualMemoryFree, 2))) void* Mm_VirtualMemoryAlloc(context* ctx, void* base, size_t size, prot_flags prot, vma_flags flags, fd* file, obos_status* status); +OBOS_EXPORT __attribute__((malloc, malloc(Mm_VirtualMemoryFree, 2))) void* Mm_VirtualMemoryAllocEx(context* ctx, void* base, size_t size, prot_flags prot, vma_flags flags, fd* file, uoff_t offset, obos_status* status); +#else OBOS_EXPORT void* Mm_VirtualMemoryAlloc(context* ctx, void* base, size_t size, prot_flags prot, vma_flags flags, fd* file, obos_status* status); OBOS_EXPORT void* Mm_VirtualMemoryAllocEx(context* ctx, void* base, size_t size, prot_flags prot, vma_flags flags, fd* file, uoff_t offset, obos_status* status); -OBOS_EXPORT obos_status Mm_VirtualMemoryFree(context* ctx, void* base, size_t size); +#endif // Note: base must be the exact address as returned by VirtualMemoryAlloc. // isPageable values: // 0: Non-pageable @@ -90,21 +95,10 @@ OBOS_EXPORT obos_status Mm_VirtualMemoryProtect(context* ctx, void* base, size_t // NOTE: The returned address is not aligned down to the page size. OBOS_EXPORT void* Mm_MapViewOfUserMemory(context* const user_context, void* ubase, void* kbase, size_t nBytes, prot_flags protection, bool respectUserProtection, obos_status* status); -typedef enum unmap_behavior { - // Default behavior. - // Allow the pages to be unmapped from the address space, but do not unlock the backing memory. - UNMAP_FLAGS_ALLOW = 0, - // Defers the unmap until the pages are unlocked manually. - UNMAP_FLAGS_DEFER, - // Unlocks the pages on unmap, then unmaps them. - UNMAP_FLAGS_UNLOCK, -} unmap_behavior; - // Locks pages from base to base+sz in the working-set. // If space is not avaliable in the working-set, pages are removed until space can be satisified. // If the working-set's capacity is too small, then it can be inflated until the pages are unlocked. -// The unmap_ -OBOS_EXPORT obos_status Mm_VirtualMemoryLock(context* ctx, void* base, size_t sz, unmap_behavior unmap_action); +OBOS_EXPORT obos_status Mm_VirtualMemoryLock(context* ctx, void* base, size_t sz); // Unlocks pages from base to base+sz from the working-set. // If the pages caused the working-set capacity to be inflated, then it is deflated once again. OBOS_EXPORT obos_status Mm_VirtualMemoryUnlock(context* ctx, void* base, size_t sz); diff --git a/src/oboskrnl/mm/bare_map.c b/src/oboskrnl/mm/bare_map.c index e2357e6c..d6168308 100644 --- a/src/oboskrnl/mm/bare_map.c +++ b/src/oboskrnl/mm/bare_map.c @@ -49,28 +49,18 @@ static OBOS_PAGEABLE_FUNCTION void Unlock(irql oldIrql) Core_SpinlockRelease(&s_regionListLock, oldIrql); } +void OBOSH_BasicMMSetBumpRegion(basicmm_region* region) +{ + irql oldIrql = Lock(); + bump_region = *region; + Unlock(oldIrql); +} + OBOS_NO_KASAN OBOS_PAGEABLE_FUNCTION void* OBOS_BasicMMAllocatePages(size_t sz, obos_status* status) { irql oldIrql = Lock(); if (!bump_region.addr) - { - // OBOS_ALIGNAS(OBOS_PAGE_SIZE) static uint8_t region[256*1024*1024]; // 256M - OBOS_ALIGNAS(OBOS_PAGE_SIZE) static uint8_t region[4*1024*1024]; // 4M - bump_region.size = sizeof(region); - bump_region.addr = (uintptr_t)region; - // for (uintptr_t addr = bump_region.addr; addr < (bump_region.addr + bump_region.size); addr += OBOS_PAGE_SIZE) - // { - // obos_status stat = OBOS_STATUS_SUCCESS; - // uintptr_t mem = Mm_AllocatePhysicalPages(1, 1, &stat); - // if (stat != OBOS_STATUS_SUCCESS) - // { - // if (status) - // *status = stat; - // return nullptr; - // } - // OBOSS_MapPage_RW_XD((void*)addr, mem); - // } - } + OBOS_Panic(OBOS_PANIC_ALLOCATOR_ERROR, "BasicMM: No region specified by platform code.\n"); sz += (OBOS_PAGE_SIZE-(sz%OBOS_PAGE_SIZE)); if ((bump_offset + sz) >= bump_region.size) OBOS_Panic(OBOS_PANIC_NO_MEMORY, "BasicMM: No more space in bump allocator.\n"); diff --git a/src/oboskrnl/mm/bare_map.h b/src/oboskrnl/mm/bare_map.h index 7840af33..dfe2f51d 100644 --- a/src/oboskrnl/mm/bare_map.h +++ b/src/oboskrnl/mm/bare_map.h @@ -67,4 +67,6 @@ void OBOSH_BasicMMAddRegion(basicmm_region* nodeBase, void* base, size_t sz); /// /// The call back. Returns true to continue iteration, otherwise false. Takes in the current region, and the passed user data. /// The user data to pass. -void OBOSH_BasicMMIterateRegions(bool(*callback)(basicmm_region*, void*), void* udata); \ No newline at end of file +void OBOSH_BasicMMIterateRegions(bool(*callback)(basicmm_region*, void*), void* udata); + +void OBOSH_BasicMMSetBumpRegion(basicmm_region* region); \ No newline at end of file diff --git a/src/oboskrnl/mm/context.c b/src/oboskrnl/mm/context.c index b319fe48..99212fdb 100644 --- a/src/oboskrnl/mm/context.c +++ b/src/oboskrnl/mm/context.c @@ -107,7 +107,7 @@ page* MmH_AllocatePage(uintptr_t phys, bool huge) { if (!phys) return nullptr; - page* buf = Mm_Allocator->ZeroAllocate(Mm_Allocator, 1, sizeof(page), nullptr); + page* buf = ZeroAllocate(Mm_Allocator, 1, sizeof(page), nullptr); buf->phys = phys; if (huge) buf->flags |= PHYS_PAGE_HUGE_PAGE; @@ -154,7 +154,7 @@ void MmH_DerefPage(page* buf) } } Mm_PhysicalMemoryUsage -= ((buf->flags & PHYS_PAGE_HUGE_PAGE) ? OBOS_HUGE_PAGE_SIZE : OBOS_PAGE_SIZE); - Mm_Allocator->Free(Mm_Allocator, buf, sizeof(*buf)); + Free(Mm_Allocator, buf, sizeof(*buf)); } } memstat Mm_GlobalMemoryUsage; @@ -173,7 +173,7 @@ OBOS_NODISCARD swap_allocation* MmH_LookupSwapAllocation(uintptr_t id) } swap_allocation* MmH_AddSwapAllocation(uintptr_t id) { - swap_allocation* new = Mm_Allocator->ZeroAllocate(Mm_Allocator, 1, sizeof(swap_allocation), nullptr); + swap_allocation* new = ZeroAllocate(Mm_Allocator, 1, sizeof(swap_allocation), nullptr); new->id = id; new->provider = Mm_SwapProvider; new->refs = 0; @@ -198,7 +198,7 @@ void MmH_DerefSwapAllocation(swap_allocation* alloc) if (alloc->provider->free_obj) alloc->provider->free_obj(alloc->provider); } - Mm_Allocator->Free(Mm_Allocator, alloc, sizeof(*alloc)); + Free(Mm_Allocator, alloc, sizeof(*alloc)); } } LIST_GENERATE(swap_allocation_list, struct swap_allocation, node); @@ -210,3 +210,10 @@ void Mm_ConstructContext(context* ctx) ctx->pt = MmS_AllocatePageTable(); ctx->lock = Core_SpinlockCreate(); } + +OBOS_EXPORT obos_status Drv_TLBShootdown(page_table pt, uintptr_t base, size_t size) +{ + if (MmS_TLBShootdown) + return MmS_TLBShootdown(pt, base, size); + return OBOS_STATUS_UNIMPLEMENTED; +} \ No newline at end of file diff --git a/src/oboskrnl/mm/context.h b/src/oboskrnl/mm/context.h index d94862de..f2ca8dca 100644 --- a/src/oboskrnl/mm/context.h +++ b/src/oboskrnl/mm/context.h @@ -43,6 +43,10 @@ OBOS_EXPORT page_table MmS_GetCurrentPageTable(); /// The status of the function. OBOS_EXPORT obos_status MmS_SetPageMapping(page_table pt, const page_info* page, uintptr_t phys, bool free_pte); +OBOS_WEAK obos_status MmS_TLBShootdown(page_table pt, uintptr_t base, size_t size); + +OBOS_EXPORT obos_status Drv_TLBShootdown(page_table pt, uintptr_t base, size_t size); + typedef struct working_set { struct { diff --git a/src/oboskrnl/mm/fork.c b/src/oboskrnl/mm/fork.c index 69214d66..d861c55d 100644 --- a/src/oboskrnl/mm/fork.c +++ b/src/oboskrnl/mm/fork.c @@ -50,7 +50,7 @@ obos_status Mm_ForkContext(context* into, context* toFork) * Map both page ranges as Sym CoW * Go to the next range */ - page_range* clone = Mm_Allocator->ZeroAllocate(Mm_Allocator, 1, sizeof(page_range), nullptr); + page_range* clone = ZeroAllocate(Mm_Allocator, 1, sizeof(page_range), nullptr); memcpy(clone, curr, sizeof(*curr)); clone->ctx = into; memzero(&clone->rb_node, sizeof(clone->rb_node)); @@ -90,6 +90,7 @@ obos_status Mm_ForkContext(context* into, context* toFork) down: MmS_SetPageMapping(into->pt, &info, info.phys, false); } + MmS_TLBShootdown(toFork->pt, curr->virt, curr->size); } } Core_SpinlockRelease(&toFork->lock, oldIrql); diff --git a/src/oboskrnl/mm/handler.c b/src/oboskrnl/mm/handler.c index f348e7d1..6a6f5fbb 100644 --- a/src/oboskrnl/mm/handler.c +++ b/src/oboskrnl/mm/handler.c @@ -65,6 +65,7 @@ static void map_file_region(page_range* rng, uintptr_t addr, uint32_t ec, fault_ info->prot.rw = rng->prot.rw && !(ec & PF_EC_RW); MmS_SetPageMapping(rng->ctx->pt, info, phys->phys, false); + MmS_TLBShootdown(rng->ctx->pt, info->virt, info->prot.huge_page ? OBOS_HUGE_PAGE_SIZE : OBOS_PAGE_SIZE); } static bool sym_cow_cpy(context* ctx, page_range* rng, uintptr_t addr, uint32_t ec, page* pg, page_info* info) @@ -77,6 +78,7 @@ static bool sym_cow_cpy(context* ctx, page_range* rng, uintptr_t addr, uint32_t info->prot.rw = true; info->prot.ro = false; MmS_SetPageMapping(ctx->pt, info, pg->phys, false); + MmS_TLBShootdown(ctx->pt, info->virt, info->prot.huge_page ? OBOS_HUGE_PAGE_SIZE : OBOS_PAGE_SIZE); pg->cow_type = COW_DISABLED; return true; } @@ -86,6 +88,7 @@ static bool sym_cow_cpy(context* ctx, page_range* rng, uintptr_t addr, uint32_t info->prot.rw = true; info->prot.ro = false; MmS_SetPageMapping(ctx->pt, info, new->phys, false); + MmS_TLBShootdown(ctx->pt, info->virt, info->prot.huge_page ? OBOS_HUGE_PAGE_SIZE : OBOS_PAGE_SIZE); MmH_DerefPage(pg); return true; } @@ -107,14 +110,14 @@ static obos_status ref_page(context* ctx, const page_info *curr) bool allocated_ent = false; if (!ent) { - ent = Mm_Allocator->ZeroAllocate(Mm_Allocator, 1, sizeof(working_set_entry), nullptr); + ent = ZeroAllocate(Mm_Allocator, 1, sizeof(working_set_entry), nullptr); ent->info.virt = curr->virt; ent->info.prot = curr->prot; ent->info.range = rng; allocated_ent = true; } ent->refs++; - working_set_node* node = Mm_Allocator->ZeroAllocate(Mm_Allocator, 1, sizeof(working_set_node), nullptr); + working_set_node* node = ZeroAllocate(Mm_Allocator, 1, sizeof(working_set_node), nullptr); node->data = ent; #if defined(OBOS_PAGE_REPLACEMENT_AGING) status = Mm_AgingReferencePage(ctx, node); @@ -123,9 +126,9 @@ static obos_status ref_page(context* ctx, const page_info *curr) #endif if (obos_is_error(status)) { - Mm_Allocator->Free(Mm_Allocator, node, sizeof(*node)); + Free(Mm_Allocator, node, sizeof(*node)); if (allocated_ent) - Mm_Allocator->Free(Mm_Allocator, ent, sizeof(*ent)); + Free(Mm_Allocator, ent, sizeof(*ent)); return status; } APPEND_WORKINGSET_PAGE_NODE(ctx->referenced, node); @@ -168,6 +171,7 @@ static bool asym_cow_cpy(context* ctx, page_range* rng, uintptr_t addr, uint32_t } done: MmS_SetPageMapping(ctx->pt, info, pg->phys, false); + MmS_TLBShootdown(rng->ctx->pt, info->virt, info->prot.huge_page ? OBOS_HUGE_PAGE_SIZE : OBOS_PAGE_SIZE); info->range = rng; if (ec & PF_EC_RW) Mm_MarkAsDirtyPhys(pg); @@ -332,7 +336,7 @@ void MmH_RemovePageFromWorkingset(context* ctx, working_set_node* node) } if (!ent->free) REMOVE_WORKINGSET_PAGE_NODE(ent->info.range->working_set_nodes, &ent->pr_node); - Mm_Allocator->Free(Mm_Allocator, ent, sizeof(*ent)); + Free(Mm_Allocator, ent, sizeof(*ent)); } - Mm_Allocator->Free(Mm_Allocator, node, sizeof(*node)); + Free(Mm_Allocator, node, sizeof(*node)); } diff --git a/src/oboskrnl/mm/handler.h b/src/oboskrnl/mm/handler.h index c2a6b394..dfa97625 100644 --- a/src/oboskrnl/mm/handler.h +++ b/src/oboskrnl/mm/handler.h @@ -54,7 +54,7 @@ typedef enum { /// The virtual address that faulted. /// The page fault's error code. /// OBOS_STATUS_SUCCESS if the page fault was handled, OBOS_STATUS_UNHANDLED if the page fault went unhandled, otherwise an error. -obos_status Mm_HandlePageFault(context* ctx, uintptr_t addr, uint32_t ec); +OBOS_EXPORT obos_status Mm_HandlePageFault(context* ctx, uintptr_t addr, uint32_t ec); /// /// Runs the page replacement algorithm on pages in a context. /// This essentially chooses pages from within the context, and puts them within the working-set of the context. diff --git a/src/oboskrnl/mm/mm_sys.c b/src/oboskrnl/mm/mm_sys.c index f1adf076..df4b6d0b 100644 --- a/src/oboskrnl/mm/mm_sys.c +++ b/src/oboskrnl/mm/mm_sys.c @@ -116,7 +116,7 @@ handle Sys_MakeNewContext(size_t ws_capacity) ws_capacity = OBOS_DEFAULT_WS_CAPACITY; if (ws_capacity % OBOS_HUGE_PAGE_SIZE) ws_capacity += (OBOS_HUGE_PAGE_SIZE-(ws_capacity%OBOS_HUGE_PAGE_SIZE)); - context* ctx = Mm_Allocator->ZeroAllocate(Mm_Allocator, 1, sizeof(context), nullptr); + context* ctx = ZeroAllocate(Mm_Allocator, 1, sizeof(context), nullptr); Mm_ConstructContext(ctx); ctx->workingSet.capacity = ws_capacity; OBOS_LockHandleTable(OBOS_CurrentHandleTable()); diff --git a/src/oboskrnl/mm/swap.c b/src/oboskrnl/mm/swap.c index 42404e52..7ad49510 100644 --- a/src/oboskrnl/mm/swap.c +++ b/src/oboskrnl/mm/swap.c @@ -60,6 +60,7 @@ obos_status Mm_SwapOut(uintptr_t virt, page_range* rng) return status; page.prot.present = false; status = MmS_SetPageMapping(rng->ctx->pt, &page, phys, false); + MmS_TLBShootdown(rng->ctx->pt, page.virt, page.prot.huge_page ? OBOS_HUGE_PAGE_SIZE : OBOS_PAGE_SIZE); if (obos_is_error(status)) return status; if (page.dirty) @@ -106,7 +107,7 @@ obos_status Mm_SwapIn(page_info* page, fault_type* type) node->pagedCount++; page->prot.present = true; obos_status status = MmS_SetPageMapping(page->range->ctx->pt, page, node->phys, false); - // Mm_Allocator->Free(Mm_Allocator, node, sizeof(*node)); + // Free(Mm_Allocator, node, sizeof(*node)); if (obos_expect(obos_is_error(status), false)) { // Unlikely error. @@ -176,7 +177,8 @@ static __attribute__((no_instrument_function)) void page_writer() // const char* const This = "Page Writer"; while (1) { - Core_WaitOnObject(WAITABLE_OBJECT(page_writer_wake)); + obos_status status = Core_WaitOnObject(WAITABLE_OBJECT(page_writer_wake)); + OBOS_ENSURE(obos_is_success(status)); Core_EventClear(&page_writer_done); if (!Mm_PageWriterOperation) Mm_PageWriterOperation = PAGE_WRITER_SYNC_ALL; @@ -365,8 +367,10 @@ void Mm_WakePageWriter(bool wait) { OBOS_ASSERT(page_writer_thread.status); Core_EventPulse(&page_writer_wake, true); + obos_status status = OBOS_STATUS_SUCCESS; if (wait) - Core_WaitOnObject(WAITABLE_OBJECT(page_writer_done)); + status = Core_WaitOnObject(WAITABLE_OBJECT(page_writer_done)); + OBOS_UNUSED(status); } irql Mm_TakeSwapLock() diff --git a/src/oboskrnl/net/arp.c b/src/oboskrnl/net/arp.c index 0e6226a7..1e0d3d83 100644 --- a/src/oboskrnl/net/arp.c +++ b/src/oboskrnl/net/arp.c @@ -4,6 +4,8 @@ * Copyright (c) 2025 Omar Berrow */ +#include "irq/timer.h" +#include "locks/wait.h" #include #include #include @@ -47,9 +49,12 @@ obos_status NetH_ARPRequest(vnode* nic, ip_addr addr, mac_address* out, address_ address_table_entry* ent = RB_FIND(address_table, &nic->net_tables->arp_cache, &what); Core_PushlockRelease(&nic->net_tables->arp_cache_lock, true); + obos_status status = OBOS_STATUS_SUCCESS; if (ent) { - Core_WaitOnObject(WAITABLE_OBJECT(ent->sync)); + status = Core_WaitOnObject(WAITABLE_OBJECT(ent->sync)); + if (obos_is_error(status)) + return status; if (memcmp_b(ent->phys, 0, sizeof(mac_address))) { Core_PushlockAcquire(&nic->net_tables->arp_cache_lock, true); @@ -89,26 +94,65 @@ obos_status NetH_ARPRequest(vnode* nic, ip_addr addr, mac_address* out, address_ memcpy(payload->sender_mac, nic->net_tables->mac, sizeof(mac_address)); payload->target_ip = addr; memzero(payload->target_mac, sizeof(payload->target_mac)); - - shared_ptr *eth = NetH_FormatEthernetPacket(nic, MAC_BROADCAST, hdr, sz_hdr, ETHERNET2_TYPE_ARP); - obos_status status = NetH_SendEthernetPacket(nic, OBOS_SharedPtrCopy(eth)); - if (obos_is_error(status)) + + event tm_evnt = EVENT_INITIALIZE(EVENT_NOTIFICATION); + timer* tm = nullptr; + CoreH_MakeTimerEvent(&tm, 1000*1000, &tm_evnt, true); + + struct waitable_header* signaled = nullptr; + struct waitable_header* objs[2] = { + WAITABLE_OBJECT(tm_evnt), + WAITABLE_OBJECT(ent->sync) + }; + + size_t nTimeouts = 0; + + do { - Core_PushlockAcquire(&nic->net_tables->table_lock, false); - RB_REMOVE(address_table, &nic->net_tables->arp_cache, ent); - Core_PushlockRelease(&nic->net_tables->table_lock, false); - Free(OBOS_KernelAllocator, ent, sizeof(*ent)); - return status; // hdr_ptr isn't leaked, as we never reference it - } + shared_ptr *eth = NetH_FormatEthernetPacket(nic, MAC_BROADCAST, hdr, sz_hdr, ETHERNET2_TYPE_ARP); + status = NetH_SendEthernetPacket(nic, OBOS_SharedPtrCopy(eth)); + if (obos_is_error(status)) + { + Core_CancelTimer(tm); + Core_TimerObjectFree(tm); + Core_PushlockAcquire(&nic->net_tables->table_lock, false); + RB_REMOVE(address_table, &nic->net_tables->arp_cache, ent); + Core_PushlockRelease(&nic->net_tables->table_lock, false); + Free(OBOS_KernelAllocator, ent, sizeof(*ent)); + return status; // hdr_ptr isn't leaked, as we never reference it + } - status = Core_WaitOnObject(WAITABLE_OBJECT(ent->sync)); - if (obos_is_error(status)) + status = Core_WaitOnObjects(2, objs, &signaled); + if (obos_is_error(status)) + { + Core_CancelTimer(tm); + Core_TimerObjectFree(tm); + Core_PushlockAcquire(&nic->net_tables->arp_cache_lock, true); + RB_REMOVE(address_table, &nic->net_tables->arp_cache, ent); + Core_PushlockRelease(&nic->net_tables->arp_cache_lock, true); + Free(OBOS_KernelAllocator, ent, sizeof(*ent)); + return status; + } + if (signaled == WAITABLE_OBJECT(ent->sync)) + break; + Core_EventClear(&tm_evnt); + // We timed out. + continue; + } while (++nTimeouts <= 10); + + Core_CancelTimer(tm); + Core_TimerObjectFree(tm); + + if (signaled != WAITABLE_OBJECT(ent->sync)) { + status = OBOS_STATUS_TIMED_OUT; Core_PushlockAcquire(&nic->net_tables->arp_cache_lock, true); RB_REMOVE(address_table, &nic->net_tables->arp_cache, ent); Core_PushlockRelease(&nic->net_tables->arp_cache_lock, true); + Free(OBOS_KernelAllocator, ent, sizeof(*ent)); return status; } + if (out) memcpy(*out, ent->phys, sizeof(mac_address)); if (address_table_ent) diff --git a/src/oboskrnl/net/lo.c b/src/oboskrnl/net/lo.c index 4ee2288d..421134b8 100644 --- a/src/oboskrnl/net/lo.c +++ b/src/oboskrnl/net/lo.c @@ -138,6 +138,7 @@ static obos_status finalize_irp(void* req_) memcpy(pckt->buffer, req->cbuff, req->blkCount); pckt->refs = hnd->dev->refs; pckt->size = req->blkCount; + // printf("LO: TX Packet (size: %d)\n", pckt->size); Core_MutexAcquire(&hnd->dev->lock); LIST_APPEND(lo_packet_queue, &hnd->dev->recv, pckt); @@ -165,6 +166,7 @@ static obos_status ioctl(dev_desc what, uint32_t request, void* argp) switch (request) { case IOCTL_IFACE_MAC_REQUEST: memzero(argp, sizeof(mac_address)); + ((uint8_t*)argp)[0] |= BIT(1); return OBOS_STATUS_SUCCESS; default: return Net_InterfaceIoctl(Net_LoopbackDevice, request, argp); diff --git a/src/oboskrnl/net/route.c b/src/oboskrnl/net/route.c index 04c34689..1a8ffff9 100644 --- a/src/oboskrnl/net/route.c +++ b/src/oboskrnl/net/route.c @@ -262,7 +262,9 @@ obos_status NetH_AddressRoute(net_tables** interface, ip_table_entry** routing_e shared_ptr data = {}; OBOS_SharedPtrConstruct(&data, &hdr); NetH_SendIPv4Packet(curr->iface->interface, curr->ent, destination, 0x11, curr->ttl, 0, OBOS_SharedPtrCopy(&data)); - Core_WaitOnObject(WAITABLE_OBJECT(port->recv_event)); + obos_status status = Core_WaitOnObject(WAITABLE_OBJECT(port->recv_event)); + if (obos_is_error(status)) + return status; icmp_header* icmp_hdr = port->icmp_header; shared_ptr* icmp_hdr_ptr = port->icmp_header_ptr; diff --git a/src/oboskrnl/net/tcp.c b/src/oboskrnl/net/tcp.c index da53f5ac..a043e1a9 100644 --- a/src/oboskrnl/net/tcp.c +++ b/src/oboskrnl/net/tcp.c @@ -4,6 +4,8 @@ * Copyright (c) 2025 Omar Berrow */ +#include "error.h" +#include "irq/irql.h" #include #include #include @@ -118,13 +120,14 @@ obos_status NetH_SendTCPSegment(vnode* nic, tcp_connection* con, void* ent_ /* i hdr->chksum = tcp_chksum(&ip_psuedo_header, sizeof(ip_psuedo_header), hdr, sz); hdr->chksum = be16_to_host(hdr->chksum); - // OBOS_Debug("tcp tx segment: hdr->flags=0x%x, hdr->ack=0x%x, hdr->seq=0x%x\n", hdr->flags, be32_to_host(hdr->ack), be32_to_host(hdr->seq)); + //printf("tcp tx segment (%d->%d): hdr->flags=0x%x, hdr->ack=0x%x, hdr->seq=0x%x\n", be16_to_host(hdr->src_port), be16_to_host(hdr->dest_port), hdr->flags, be32_to_host(hdr->ack), be32_to_host(hdr->seq)); // NOTE: Keep the list locked until we append the unacked segment // since if we get an ACK immediately (this includes if we get preempted!), // and the TCP handler sees no unACKed segment, then this segment will be // spuriously retransmitted, which is probably bad. + irql oldIrql = Core_RaiseIrql(IRQL_DISPATCH); if (con) Core_PushlockAcquire(&con->unacked_segments.lock, false); @@ -143,13 +146,17 @@ obos_status NetH_SendTCPSegment(vnode* nic, tcp_connection* con, void* ent_ /* i if (obos_is_error(status)) { + Core_LowerIrql(oldIrql); if (con) Core_PushlockRelease(&con->unacked_segments.lock, false); return status; } if (!con) + { + Core_LowerIrql(oldIrql); return OBOS_STATUS_SUCCESS; + } tcp_unacked_segment* seg = ZeroAllocate(OBOS_KernelAllocator, 1, sizeof(tcp_unacked_segment), nullptr); OBOS_SharedPtrConstructSz(&seg->ptr, seg, sizeof(*seg)); @@ -186,6 +193,8 @@ obos_status NetH_SendTCPSegment(vnode* nic, tcp_connection* con, void* ent_ /* i Core_PushlockRelease(&con->unacked_segments.lock, false); + Core_LowerIrql(oldIrql); + return OBOS_STATUS_SUCCESS; } @@ -270,20 +279,25 @@ PacketProcessSignature(TCP, ip_header*) .addr=ip_hdr->dest_address, .port=be16_to_host(hdr->dest_port), }, - .is_client = true, + .is_client = false, }; - Core_PushlockAcquire(&nic->net_tables->tcp_connections_lock, true); - tcp_connection* con = RB_FIND(tcp_connection_tree, &nic->net_tables->tcp_outgoing_connections, &conn_key); - Core_PushlockRelease(&nic->net_tables->tcp_connections_lock, true); - + tcp_connection* con = nullptr; + if (port) { Core_PushlockAcquire(&port->connection_tree_lock, true); - conn_key.is_client = false; con = RB_FIND(tcp_connection_tree, &port->connections, &conn_key); Core_PushlockRelease(&port->connection_tree_lock, true); } + if (!con) + { + Core_PushlockAcquire(&nic->net_tables->tcp_connections_lock, true); + conn_key.is_client = true; + con = RB_FIND(tcp_connection_tree, &nic->net_tables->tcp_outgoing_connections, &conn_key); + Core_PushlockRelease(&nic->net_tables->tcp_connections_lock, true); + } + if ((!con || con->state.state == TCP_STATE_CLOSED) && !port) { @@ -296,12 +310,7 @@ PacketProcessSignature(TCP, ip_header*) resp.seq = be32_to_host(hdr->ack); else { - // TODO: Is this check valid? -#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ uint8_t header_length = (hdr->data_offset >> 4) * 4; -#else - uint8_t header_length = (hdr->data_offset & 0xf) * 4; -#endif uint32_t segment_length = be16_to_host(ip_hdr->packet_length)-IPv4_GET_HEADER_LENGTH(ip_hdr) - header_length; resp.seq = 0; resp.ack = be32_to_host(hdr->seq)+segment_length+1; @@ -477,8 +486,8 @@ PacketProcessSignature(TCP, ip_header*) { // This is UNACCEPTABLE! // (pun intended) - // OBOS_Debug("received unacceptable segment! discarding\n"); - // OBOS_Debug("NOTE: PCKT.SEQ=%d, PCKT.ACK=%d, RCV.NXT=%d, RCV.WND=%d, PCKT.LEN=%d\n", + //printf("received unacceptable segment! discarding\n"); + //printf("NOTE: PCKT.SEQ=%d, PCKT.ACK=%d, RCV.NXT=%d, RCV.WND=%d, PCKT.LEN=%d\n", // be32_to_host(hdr->seq)-con->state.rcv.irs, be32_to_host(hdr->ack)-con->state.snd.iss, // con->state.rcv.nxt, con->state.rcv.wnd, segment_length // ); @@ -640,8 +649,8 @@ PacketProcessSignature(TCP, ip_header*) size_t nPushed = 0; Net_TCPPushReceivedData(con, segment_data, segment_length, &nPushed); con->state.rcv.nxt += nPushed; - // OBOS_Debug("TCP window (%d, %d) receive window %d->%d\n", con->dest.port, con->src.port, con->state.rcv.wnd, con->state.rcv.wnd-nPushed); - // OBOS_Debug("TCP: Expecting SEQ=%d next (current SEQ=%d)\n", con->state.rcv.nxt-con->state.rcv.irs, be32_to_host(hdr->seq) - con->state.rcv.irs); + //printf("TCP window (%d, %d) receive window %d->%d\n", con->dest.port, con->src.port, con->state.rcv.wnd, con->state.rcv.wnd-nPushed); + //printf("TCP: Expecting SEQ=%d next (current SEQ=%d)\n", con->state.rcv.nxt-con->state.rcv.irs, be32_to_host(hdr->seq) - con->state.rcv.irs); con->state.rcv.wnd -= nPushed; struct tcp_pseudo_hdr resp = {}; resp.src_port = be16_to_host(hdr->dest_port); @@ -744,26 +753,26 @@ void Net_TCPPushReceivedData(tcp_connection* con, const void* buffer, size_t sz, return; } -static const char* state_strs[] = { - "INVALID", - "LISTEN", - "SYN_SENT", - "SYN_RECEIVED", - "ESTABLISHED", - "FIN_WAIT1", - "FIN_WAIT2", - "CLOSE_WAIT", - "CLOSING", - "LAST_ACK", - "TIME_WAIT", - "CLOSED", -}; +// static const char* state_strs[] = { +// "INVALID", +// "LISTEN", +// "SYN_SENT", +// "SYN_RECEIVED", +// "ESTABLISHED", +// "FIN_WAIT1", +// "FIN_WAIT2", +// "CLOSE_WAIT", +// "CLOSING", +// "LAST_ACK", +// "TIME_WAIT", +// "CLOSED", +// }; void Net_TCPChangeConnectionState(tcp_connection* con, int state) { if (state > TCP_STATE_CLOSED || state < TCP_STATE_INVALID) return; - // OBOS_Debug("TCP: Changing from %s to %s\n", con->state.state[state_strs], state[state_strs]); + //printf("TCP: Changing from %s to %s\n", con->state.state[state_strs], state[state_strs]); con->state.state = state; Core_EventPulse(&con->state.state_change_event, false); if (state == TCP_STATE_ESTABLISHED) @@ -810,7 +819,7 @@ bool Net_TCPRemoteACKedSegment(tcp_connection* con, uint32_t ack) nBytesACKed -= seg->nBytesUnACKed; con->state.snd.una += seg->nBytesUnACKed; seg->nBytesUnACKed = 0; - // OBOS_Debug("remote acked packet flags=0x%x remote acked 0x%p seg.seq=0x%p\n", seg->segment.flags, ack - con->state.snd.iss, seg->segment.seq - con->state.snd.iss); + //printf("remote acked packet flags=0x%x remote acked 0x%p seg.seq=0x%p\n", seg->segment.flags, ack - con->state.snd.iss, seg->segment.seq - con->state.snd.iss); } else { @@ -998,6 +1007,19 @@ void Net_TCPPushDataToRemote(tcp_connection* con, const void* buffer, size_t siz } +void Net_TCPReset(tcp_connection* con) +{ + struct tcp_pseudo_hdr hdr = {}; + hdr.ack = con->state.rcv.nxt; + hdr.seq = con->state.snd.nxt; + hdr.flags = TCP_RST; + hdr.src_port = con->src.port; + hdr.dest_port = con->dest.port; + hdr.ttl = con->ttl; + NetH_SendTCPSegment(con->nic, nullptr, con->ip_ent, con->dest.addr, &hdr); + Net_TCPChangeConnectionState(con, TCP_STATE_CLOSED); +} + // LIST_GENERATE(tcp_incoming_list, tcp_incoming_packet, node); RB_GENERATE(tcp_connection_tree, tcp_connection, node, tcp_connection_cmp); RB_GENERATE(tcp_port_tree, tcp_port, node, tcp_port_cmp); @@ -1035,7 +1057,10 @@ void tcp_free(socket_desc* socket) if (!s->is_server) { - Net_TCPSocketBackend.shutdown(socket, SHUT_RDWR); + // Net_TCPSocketBackend.shutdown(socket, SHUT_RDWR); + // Reset the connection. + if (s->connection->state.state < TCP_STATE_TIME_WAIT) + Net_TCPReset(s->connection); net_tables* iface = s->connection->nic->net_tables; Core_PushlockAcquire(&iface->tcp_connections_lock, false); @@ -1174,9 +1199,16 @@ static void internal_listen_thread(void* udata) objs[i] = WAITABLE_OBJECT(s->serv.bound_ports[i-1]->connection_event); while (1) { - Core_WaitOnObjects(s->serv.bound_port_count+1, objs, &signaled); + obos_status status = OBOS_STATUS_SUCCESS; + if (obos_is_error(status = Core_WaitOnObjects(s->serv.bound_port_count+1, objs, &signaled))) + { + NetError("Net: %s: Core_WaitOnObjects returned %d, aborting.\n", __func__, status); + break; + } + if (signaled == objs[0]) break; + for (size_t i = 0; i < s->serv.bound_port_count; i++) { if (signaled == WAITABLE_OBJECT(s->serv.bound_ports[i]->connection_event)) @@ -1387,8 +1419,8 @@ obos_status tcp_connect(socket_desc* socket, struct sockaddr* saddr, size_t addr while (s->connection->state.state != TCP_STATE_ESTABLISHED) { - Core_WaitOnObject(WAITABLE_OBJECT(s->connection->state.state_change_event)); - if (s->connection->reset) + status = Core_WaitOnObject(WAITABLE_OBJECT(s->connection->state.state_change_event)); + if (s->connection->reset || obos_is_error(status)) { Core_PushlockAcquire(&iface->tcp_connections_lock, false); RB_REMOVE(tcp_connection_tree, &iface->tcp_outgoing_connections, s->connection); @@ -1502,8 +1534,8 @@ static void irp_on_event_set(irp* req) if (req->dryOp) return; - if (req->socket_flags) - // OBOS_Debug("TCP: Recv got 0x%p for flags\n", req->socket_flags); + // if (req->socket_flags) + //printf("TCP: Recv got 0x%p for flags\n", req->socket_flags); Core_MutexAcquire(&s->connection->recv_buffer.lock); @@ -1512,8 +1544,8 @@ static void irp_on_event_set(irp* req) if (~req->socket_flags & MSG_PEEK) { s->connection->recv_buffer.in_ptr += read_size; - // OBOS_Debug("TCP: Read %d bytes\n", read_size); - // OBOS_Debug("TCP window (%d, %d) receive window %d->%d\n", s->connection->dest.port, s->connection->src.port, s->connection->state.rcv.wnd, s->connection->state.rcv.wnd+read_size); + //printf("TCP: Read %d bytes\n", read_size); + //printf("TCP window (%d, %d) receive window %d->%d\n", s->connection->dest.port, s->connection->src.port, s->connection->state.rcv.wnd, s->connection->state.rcv.wnd+read_size); s->connection->state.rcv.wnd += read_size; OBOS_ENSURE(s->connection->recv_buffer.in_ptr <= s->connection->recv_buffer.ptr); if (s->connection->recv_buffer.in_ptr == s->connection->recv_buffer.ptr) @@ -1684,15 +1716,15 @@ socket_ops Net_TCPSocketBackend = { .proto_type.protocol = IPPROTO_TCP, .domain = AF_INET, .create = tcp_create, - .free = tcp_free, - .accept = tcp_accept, - .bind = tcp_bind, - .connect = tcp_connect, - .getpeername = tcp_getpeername, - .getsockname = tcp_getsockname, - .listen = tcp_listen, - .submit_irp = tcp_submit_irp, - .finalize_irp = tcp_finalize_irp, - .shutdown = tcp_shutdown, - .sockatmark = tcp_sockatmark + .free = tcp_free, + .accept = tcp_accept, + .bind = tcp_bind, + .connect = tcp_connect, + .getpeername = tcp_getpeername, + .getsockname = tcp_getsockname, + .listen = tcp_listen, + .submit_irp = tcp_submit_irp, + .finalize_irp = tcp_finalize_irp, + .shutdown = tcp_shutdown, + .sockatmark = tcp_sockatmark }; \ No newline at end of file diff --git a/src/oboskrnl/net/tcp.h b/src/oboskrnl/net/tcp.h index a1cd0d45..9d38cf9a 100644 --- a/src/oboskrnl/net/tcp.h +++ b/src/oboskrnl/net/tcp.h @@ -226,6 +226,7 @@ void Net_TCPCancelAllOutstandingSegments(tcp_connection* con); void Net_TCPChangeConnectionState(tcp_connection* con, int state); void Net_TCPPushReceivedData(tcp_connection* con, const void* buffer, size_t size, size_t *nPushed); void Net_TCPPushDataToRemote(tcp_connection* con, const void* buffer, size_t size, bool oob); +void Net_TCPReset(tcp_connection* con); static inline int tcp_connection_cmp(tcp_connection* lhs, tcp_connection* rhs) { diff --git a/src/oboskrnl/net/udp.c b/src/oboskrnl/net/udp.c index a7db1e39..ba6c3c33 100644 --- a/src/oboskrnl/net/udp.c +++ b/src/oboskrnl/net/udp.c @@ -231,7 +231,12 @@ static void internal_read_thread(void* userdata) while (!ports->read_closed) { struct waitable_header* signaled = nullptr; - Core_WaitOnObjects(1+ports->nPorts, events, &signaled); + obos_status status = Core_WaitOnObjects(1+ports->nPorts, events, &signaled); + if (obos_is_error(status)) + { + NetError("Net: %s: Core_WaitOnObjects returned %d, aborting.\n", __func__, status); + break; + } if (signaled == WAITABLE_OBJECT(ports->wake_read_thread)) break; for (size_t i = 0; i < ports->nPorts; i++) diff --git a/src/oboskrnl/power/shutdown.c b/src/oboskrnl/power/shutdown.c index ebf012d2..1a6ea0af 100644 --- a/src/oboskrnl/power/shutdown.c +++ b/src/oboskrnl/power/shutdown.c @@ -41,6 +41,7 @@ OBOS_NORETURN void OBOS_Reboot() { if (Mm_SwapProvider->deinit_dev) Mm_SwapProvider->deinit_dev(Mm_SwapProvider); + irql oldIrql = Core_RaiseIrql(IRQL_MASKED); Core_SuspendScheduler(true); Core_WaitForSchedulerSuspend(); uacpi_reboot(); @@ -55,6 +56,7 @@ OBOS_NORETURN void OBOS_Reboot() // We should not be here anymore. OBOS_UNREACHABLE; #endif + (void)oldIrql; while(1) asm volatile(""); } diff --git a/src/oboskrnl/scheduler/process.c b/src/oboskrnl/scheduler/process.c index 1601acef..36569a20 100644 --- a/src/oboskrnl/scheduler/process.c +++ b/src/oboskrnl/scheduler/process.c @@ -86,6 +86,12 @@ OBOS_PAGEABLE_FUNCTION obos_status Core_ProcessStart(process* proc, thread* main proc->prev = proc->parent->children.tail; proc->parent->children.tail = proc; proc->parent->children.nChildren++; + proc->ruid = proc->parent->ruid; + proc->euid = proc->parent->euid; + proc->suid = proc->parent->suid; + proc->rgid = proc->parent->rgid; + proc->egid = proc->parent->egid; + proc->sgid = proc->parent->sgid; proc->refcount++; Core_SetProcessGroup(proc, proc->parent->pgrp->pgid); proc->waiting_threads = WAITABLE_HEADER_INITIALIZE(false, true); @@ -225,7 +231,7 @@ uintptr_t ExitCurrentProcess(uintptr_t unused) } MmS_FreePageTable(proc->ctx->pt); - Mm_Allocator->Free(Mm_Allocator, proc->ctx, sizeof(context)); + Free(Mm_Allocator, proc->ctx, sizeof(context)); thread* ready = nullptr; thread* running = nullptr; @@ -324,6 +330,7 @@ void Core_ExitProcessGroup() Core_MutexRelease(&Core_ProcessGroupTreeLock); } Core_MutexRelease(&pgrp->lock); + proc->refcount--; } obos_status Core_SetProcessGroup(process* proc, uint32_t pgid) @@ -363,6 +370,7 @@ obos_status Core_SetProcessGroup(process* proc, uint32_t pgid) Core_MutexAcquire(&pgrp->lock); LIST_APPEND(process_list, &pgrp->processes, proc); + proc->refcount++; proc->pgrp = pgrp; Core_MutexRelease(&pgrp->lock); diff --git a/src/oboskrnl/scheduler/process.h b/src/oboskrnl/scheduler/process.h index b97d0af2..e77fc051 100644 --- a/src/oboskrnl/scheduler/process.h +++ b/src/oboskrnl/scheduler/process.h @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -36,8 +37,12 @@ typedef struct process struct process_group* pgrp; - uid currentUID; - gid currentGID; + uid euid, ruid, suid; + gid egid, rgid, sgid; + struct { + gid *list; + size_t nEntries; + } groups; uint32_t exitCode; bool dead; @@ -59,6 +64,8 @@ typedef struct process // Only exists for POSIX, ignored in most parts of the kernel. uint32_t umask; + sigaction signal_handlers[64]; + LIST_NODE(process_list, struct process) node; } process; typedef LIST_HEAD(process_list, process) process_list; diff --git a/src/oboskrnl/scheduler/sched_sys.c b/src/oboskrnl/scheduler/sched_sys.c index cdcd7053..45d5a7d4 100644 --- a/src/oboskrnl/scheduler/sched_sys.c +++ b/src/oboskrnl/scheduler/sched_sys.c @@ -4,7 +4,6 @@ * Copyright (c) 2024-2025 Omar Berrow */ -#include "vfs/mount.h" #include #include #include @@ -24,6 +23,8 @@ #include #include +#include + #include #include @@ -184,7 +185,6 @@ handle Sys_ThreadCreate(thread_priority priority, thread_affinity affinity, hand thr->references++; OBOS_UnlockHandleTable(OBOS_CurrentHandleTable()); - memcpy(thr->signal_info->signals, Core_GetCurrentThread()->signal_info->signals, sizeof(thr->signal_info->signals)); thr->signal_info->mask = Core_GetCurrentThread()->signal_info->mask; return hnd; @@ -472,6 +472,7 @@ handle Sys_ProcessStart(handle mainThread, handle vmmContext, bool is_fork) OBOS_LockHandleTable(OBOS_CurrentHandleTable()); handle_desc* desc = nullptr; + new->refcount++; handle hnd = OBOS_HandleAllocate(OBOS_CurrentHandleTable(), HANDLE_TYPE_PROCESS, &desc); desc->un.process = new; OBOS_UnlockHandleTable(OBOS_CurrentHandleTable()); @@ -663,29 +664,187 @@ obos_status Sys_WaitProcess(handle proc, int* wstatus, int options, uint32_t* pi return status; } +uid Sys_GetUid() +{ return Core_GetCurrentThread()->proc->ruid; } +gid Sys_GetGid() +{ return Core_GetCurrentThread()->proc->rgid; } -obos_status Sys_SetUid(uid to) +static bool check_unpriv_uid(uid uid) { - process* proc = Core_GetCurrentThread()->proc; - if (proc->currentUID != 0) - return OBOS_STATUS_ACCESS_DENIED; - proc->currentUID = to; + return (uid != Core_GetCurrentThread()->proc->ruid) && + (uid != Core_GetCurrentThread()->proc->euid) && + (uid != Core_GetCurrentThread()->proc->suid); +} +static bool check_unpriv_gid(gid gid) +{ + return (gid != Core_GetCurrentThread()->proc->rgid) && + (gid != Core_GetCurrentThread()->proc->egid) && + (gid != Core_GetCurrentThread()->proc->sgid); +} + +obos_status Sys_SetRESUid(uid ruid, uid euid, uid suid) +{ + if (Core_GetCurrentThread()->proc->euid != 0) + { + if ((ruid != -1) && !check_unpriv_uid(ruid)) + return OBOS_STATUS_ACCESS_DENIED; + if ((euid != -1) && !check_unpriv_uid(euid)) + return OBOS_STATUS_ACCESS_DENIED; + if ((suid != -1) && !check_unpriv_uid(suid)) + return OBOS_STATUS_ACCESS_DENIED; + if (ruid != -1) + Core_GetCurrentThread()->proc->ruid = ruid; + if (euid != -1) + Core_GetCurrentThread()->proc->euid = euid; + if (suid != -1) + Core_GetCurrentThread()->proc->suid = suid; + } + else + { + if (ruid != -1) Core_GetCurrentThread()->proc->ruid = ruid; + if (euid != -1) Core_GetCurrentThread()->proc->euid = euid; + if (suid != -1) Core_GetCurrentThread()->proc->suid = suid; + } return OBOS_STATUS_SUCCESS; } -obos_status Sys_SetGid(gid to) +obos_status Sys_SetRESGid(gid rgid, gid egid, gid sgid) { - process* proc = Core_GetCurrentThread()->proc; - if (proc->currentUID != 0) - return OBOS_STATUS_ACCESS_DENIED; - proc->currentGID = to; + if (Core_GetCurrentThread()->proc->euid != 0) + { + if ((rgid != -1) && !check_unpriv_gid(rgid)) + return OBOS_STATUS_ACCESS_DENIED; + if ((egid != -1) && !check_unpriv_gid(egid)) + return OBOS_STATUS_ACCESS_DENIED; + if ((sgid != -1) && !check_unpriv_gid(sgid)) + return OBOS_STATUS_ACCESS_DENIED; + if (rgid != -1) + Core_GetCurrentThread()->proc->rgid = rgid; + if (egid != -1) + Core_GetCurrentThread()->proc->egid = egid; + if (sgid != -1) + Core_GetCurrentThread()->proc->sgid = sgid; + } + else + { + if (rgid != -1) Core_GetCurrentThread()->proc->rgid = rgid; + if (egid != -1) Core_GetCurrentThread()->proc->egid = egid; + if (sgid != -1) Core_GetCurrentThread()->proc->sgid = sgid; + } return OBOS_STATUS_SUCCESS; } -uid Sys_GetUid() -{ return Core_GetCurrentThread()->proc->currentUID; } -gid Sys_GetGid() -{ return Core_GetCurrentThread()->proc->currentGID; } +obos_status Sys_GetRESUid(uid* ruid, uid* euid, uid* suid) +{ + if (ruid) + memcpy_k_to_usr(ruid, &Core_GetCurrentThread()->proc->ruid, sizeof(uid)); + if (euid) + memcpy_k_to_usr(euid, &Core_GetCurrentThread()->proc->euid, sizeof(uid)); + if (suid) + memcpy_k_to_usr(suid, &Core_GetCurrentThread()->proc->suid, sizeof(uid)); + return OBOS_STATUS_SUCCESS; +} + +obos_status Sys_GetRESGid(gid* rgid, gid* egid, gid* sgid) +{ + if (rgid) + memcpy_k_to_usr(rgid, &Core_GetCurrentThread()->proc->rgid, sizeof(gid)); + if (egid) + memcpy_k_to_usr(egid, &Core_GetCurrentThread()->proc->egid, sizeof(gid)); + if (sgid) + memcpy_k_to_usr(sgid, &Core_GetCurrentThread()->proc->sgid, sizeof(gid)); + return OBOS_STATUS_SUCCESS; +} + +obos_status Sys_SetUid(uid uid) +{ + if (Core_GetCurrentThread()->proc->euid == 0) + { + Core_GetCurrentThread()->proc->ruid = uid; + Core_GetCurrentThread()->proc->euid = uid; + Core_GetCurrentThread()->proc->suid = uid; + return OBOS_STATUS_SUCCESS; + } + return OBOS_STATUS_ACCESS_DENIED; +} + +obos_status Sys_SetGid(gid gid) +{ + if (Core_GetCurrentThread()->proc->euid == 0) + { + Core_GetCurrentThread()->proc->rgid = gid; + Core_GetCurrentThread()->proc->egid = gid; + Core_GetCurrentThread()->proc->sgid = gid; + return OBOS_STATUS_SUCCESS; + } + return OBOS_STATUS_ACCESS_DENIED; +} + +obos_status Sys_SetGroups(handle process, size_t size, gid* ulist) +{ + struct process* proc = + HANDLE_TYPE(process) == HANDLE_TYPE_CURRENT ? + Core_GetCurrentThread()->proc : + nullptr; + obos_status status = OBOS_STATUS_SUCCESS; + if (!proc) + { + OBOS_LockHandleTable(OBOS_CurrentHandleTable()); + handle_desc* desc = OBOS_HandleLookup(OBOS_CurrentHandleTable(), process, HANDLE_TYPE_PROCESS, false, &status); + if (!desc) + { + OBOS_UnlockHandleTable(OBOS_CurrentHandleTable()); + return status; + } + proc = desc->un.process; + OBOS_UnlockHandleTable(OBOS_CurrentHandleTable()); + } + + gid* list = Mm_MapViewOfUserMemory(Core_GetCurrentThread()->proc->ctx, + ulist, nullptr, + size * sizeof(gid), + OBOS_PROTECTION_READ_ONLY, true, + &status); + if (obos_is_error(status) && size) + return status; + + proc->groups.list = Reallocate(OBOS_KernelAllocator, proc->groups.list, size*sizeof(gid), proc->groups.nEntries*sizeof(gid), nullptr); + if (list) + memcpy(proc->groups.list, list, size * sizeof(gid)); + proc->groups.nEntries = size; + + if (size) + Mm_VirtualMemoryFree(&Mm_KernelContext, list, size*sizeof(gid)); + return OBOS_STATUS_SUCCESS; +} +obos_status Sys_GetGroups(handle process, size_t *size, gid* list) +{ + struct process* proc = + HANDLE_TYPE(process) == HANDLE_TYPE_CURRENT ? + Core_GetCurrentThread()->proc : + nullptr; + obos_status status = OBOS_STATUS_SUCCESS; + if (!proc) + { + OBOS_LockHandleTable(OBOS_CurrentHandleTable()); + handle_desc* desc = OBOS_HandleLookup(OBOS_CurrentHandleTable(), process, HANDLE_TYPE_PROCESS, false, &status); + if (!desc) + { + OBOS_UnlockHandleTable(OBOS_CurrentHandleTable()); + return status; + } + proc = desc->un.process; + OBOS_UnlockHandleTable(OBOS_CurrentHandleTable()); + } + size_t sz = 0; + status = memcpy_usr_to_k(&sz, size, sizeof(sz)); + if (obos_is_error(status)) + return status; + status = memcpy_k_to_usr(list, proc->groups.list, OBOS_MIN(sz, proc->groups.nEntries) * sizeof(gid)); + if (obos_is_error(status)) + return status; + return memcpy_k_to_usr(size, &proc->groups.nEntries, sizeof(size_t)); +} obos_status Sys_SetProcessGroup(handle process, uint32_t pgid) { diff --git a/src/oboskrnl/scheduler/sched_sys.h b/src/oboskrnl/scheduler/sched_sys.h index d0381dc5..06d8b31d 100644 --- a/src/oboskrnl/scheduler/sched_sys.h +++ b/src/oboskrnl/scheduler/sched_sys.h @@ -66,10 +66,17 @@ handle Sys_ProcessGetChildHandle(); // If HANDLE_ANY to make it choose an arbitrary child process. obos_status Sys_WaitProcess(handle proc, int* status, int options, uint32_t* ret_pid); -obos_status Sys_SetUid(uid to); -obos_status Sys_SetGid(gid to); uid Sys_GetUid(); gid Sys_GetGid(); +obos_status Sys_SetRESUid(uid ruid, uid euid, uid suid); +obos_status Sys_SetRESGid(gid rgid, gid egid, gid sgid); +obos_status Sys_GetRESUid(uid* ruid, uid* euid, uid* suid); +obos_status Sys_GetRESGid(gid* rgid, gid* egid, gid* sgid); +obos_status Sys_SetUid(uid uid); +obos_status Sys_SetGid(gid gid); + +obos_status Sys_SetGroups(handle proc, size_t size, gid* list); +obos_status Sys_GetGroups(handle proc, size_t *size, gid* list); obos_status Sys_SetProcessGroup(handle proc, uint32_t pgid); obos_status Sys_GetProcessGroup(handle proc, uint32_t* pgid); \ No newline at end of file diff --git a/src/oboskrnl/scheduler/thread.h b/src/oboskrnl/scheduler/thread.h index b115df02..0e2d7081 100644 --- a/src/oboskrnl/scheduler/thread.h +++ b/src/oboskrnl/scheduler/thread.h @@ -219,3 +219,10 @@ OBOS_EXPORT thread_affinity CoreH_CPUIdToAffinity(uint32_t cpuId); /// Exits the current thread. /// OBOS_NORETURN OBOS_EXPORT void Core_ExitCurrentThread(); + +/// +/// Forces a yield on syscall return. Should only be called before the syscall returns.
+/// This function exists so that blocking syscalls can give any signals a chance to run
+/// if it was interrupted by a signal. +///
+OBOS_WEAK void CoreS_ForceYieldOnSyscallReturn(); \ No newline at end of file diff --git a/src/oboskrnl/signal.c b/src/oboskrnl/signal.c index 1631d02f..3871a937 100644 --- a/src/oboskrnl/signal.c +++ b/src/oboskrnl/signal.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -44,6 +45,8 @@ obos_status OBOS_Kill(struct thread* as, struct thread* thr, int sigval) return OBOS_STATUS_INVALID_OPERATION; if (thr->proc->pid == 0) return OBOS_STATUS_INVALID_OPERATION; + if (thr->proc->euid != as->proc->euid && as->proc->euid != 0) + return OBOS_STATUS_ACCESS_DENIED; if (sigval == 0) return OBOS_STATUS_SUCCESS; // see man fork.2, "If sig is 0, then no signal is sent, but existence and permission checks are still performed" @@ -74,22 +77,27 @@ obos_status OBOS_Kill(struct thread* as, struct thread* thr, int sigval) else if (sigval == SIGSTOP) { // Stop the thread. - thr->signal_info->signals[sigval].sender = as; + thr->proc->signal_handlers[sigval].sender = as; CoreH_ThreadBlock(thr, true); Core_MutexRelease(&thr->signal_info->lock); return OBOS_STATUS_SUCCESS; } + if (thr->proc->signal_handlers[sigval-1].un.handler == SIG_IGN) + { + Core_MutexRelease(&thr->signal_info->lock); + return OBOS_STATUS_SUCCESS; + } thr->signal_info->pending |= BIT(sigval - 1); // set these up before the call to kill. - // thr->signal_info->signals[sigval].addr = nullptr; - // thr->signal_info->signals[sigval].status = 0; - // thr->signal_info->signals[sigval].udata = 0; - // thr->signal_info->signals[sigval].sigcode = 0; - thr->signal_info->signals[sigval].sender = as; + // thr->proc->signal_handlers[sigval].addr = nullptr; + // thr->proc->signal_handlers[sigval].status = 0; + // thr->proc->signal_handlers[sigval].udata = 0; + // thr->proc->signal_handlers[sigval].sigcode = 0; + thr->proc->signal_handlers[sigval].sender = as; Core_MutexRelease(&thr->signal_info->lock); if (thr->status == THREAD_STATUS_BLOCKED) { - if (sigval == SIGTSTP && thr->signal_info->mask & BIT(SIGTSTP - 1)) + if (thr->signal_info->mask & BIT(SIGTSTP - 1)) return OBOS_STATUS_SUCCESS; // TODO: Use CoreH_AbortWaitingThreads instead of this? thr->interrupted = true; @@ -104,13 +112,13 @@ obos_status OBOS_SigAction(int signum, const sigaction* act, sigaction* oldact) if (!(signum >= 0 && signum < SIGMAX)) return OBOS_STATUS_INVALID_ARGUMENT; if (oldact) - *oldact = Core_GetCurrentThread()->signal_info->signals[signum]; + *oldact = Core_GetCurrentThread()->proc->signal_handlers[signum]; if (act) { Core_MutexAcquire(&Core_GetCurrentThread()->signal_info->lock); - Core_GetCurrentThread()->signal_info->signals[signum - 1] = *act; + Core_GetCurrentThread()->proc->signal_handlers[signum - 1] = *act; // what. - // Core_GetCurrentThread()->signal_info->signals[signum].un.handler = SIG_DFL /* default handler is the kernel */; + // Core_GetCurrentThread()->proc->signal_handlers[signum].un.handler = SIG_DFL /* default handler is the kernel */; Core_MutexRelease(&Core_GetCurrentThread()->signal_info->lock); } return OBOS_STATUS_SUCCESS; @@ -120,7 +128,8 @@ obos_status OBOS_SigSuspend(sigset_t mask) Core_MutexAcquire(&Core_GetCurrentThread()->signal_info->lock); sigset_t old = Core_GetCurrentThread()->signal_info->mask; Core_GetCurrentThread()->signal_info->mask = mask; - Core_WaitOnObject(WAITABLE_OBJECT(Core_GetCurrentThread()->signal_info->event)); + obos_status status = Core_WaitOnObject(WAITABLE_OBJECT(Core_GetCurrentThread()->signal_info->event)); + if (obos_is_error(status)) return status; Core_GetCurrentThread()->signal_info->mask = old; Core_MutexRelease(&Core_GetCurrentThread()->signal_info->lock); return OBOS_STATUS_SUCCESS; @@ -200,8 +209,12 @@ obos_status OBOS_KillProcess(struct process* proc, int sigval) case SIGCONT: case SIGSTOP: case SIGTSTP: - OBOS_Kill(Core_GetCurrentThread(), thr, sigval); + { + obos_status status = OBOS_Kill(Core_GetCurrentThread(), thr, sigval); + if (obos_is_error(status)) + return status; continue; + } default: break; } @@ -270,7 +283,7 @@ obos_status OBOS_KillProcessGroup(process_group* pgrp, int sigval) void OBOS_RunSignal(int sigval, interrupt_frame* frame) { - sigaction* sig = &Core_GetCurrentThread()->signal_info->signals[sigval]; + sigaction* sig = &Core_GetCurrentThread()->proc->signal_handlers[sigval]; if (!(sig->flags & SA_NODEFER)) Core_GetCurrentThread()->signal_info->mask |= BIT_TYPE(sigval-1, L); Core_EventSet(&Core_GetCurrentThread()->signal_info->event, false); @@ -295,7 +308,7 @@ OBOS_NO_UBSAN bool OBOS_SyncPendingSignal(interrupt_frame* frame) sigval += 1; Core_MutexRelease(&Core_GetCurrentThread()->signal_info->lock); OBOS_RunSignal(sigval, frame); - return Core_GetCurrentThread()->signal_info->signals[sigval-1].un.handler != SIG_IGN; + return Core_GetCurrentThread()->proc->signal_handlers[sigval-1].un.handler != SIG_IGN; } #define T SIGNAL_DEFAULT_TERMINATE_PROC, diff --git a/src/oboskrnl/signal.h b/src/oboskrnl/signal.h index de6c02bf..49cecafc 100644 --- a/src/oboskrnl/signal.h +++ b/src/oboskrnl/signal.h @@ -26,78 +26,8 @@ #define SIG_DFL (nullptr) #define SIG_IGN ((void*)1) -// Public -enum { - SIGHUP = 1 , SIGINT, SIGQUIT, SIGILL, SIGTRAP, - SIGABRT , SIGBUS, SIGFPE, SIGKILL, SIGUSR1, - SIGSEGV , SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, - SIGSTKFLT , SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, - SIGTTIN , SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, - SIGVTALRM , SIGSYS, SIGMAX = 64, -}; - -// Public -typedef uint64_t sigset_t; +#include -// Public -enum { - SA_SIGINFO = BIT(0), - SA_ONSTACK = BIT(1), - SA_RESETHAND = BIT(2), - SA_NODEFER = BIT(3), - SA_NOCLDWAIT = BIT(4), // unimplemented - SA_NOCLDSTOP = BIT(5), // unimplemented -}; -// Public -typedef struct siginfo_t -{ - int signum; - int sigcode; - struct thread* sender; - void* addr; - int status; - union { - void* ptr; - uintptr_t integer; - } udata; -} siginfo_t; -// Public -typedef struct user_sigaction { - union { - void(*handler)(int signum); - void(*sa_sigaction)(int signum, siginfo_t* info, void* unknown); - } un; - // NOTE(oberrow): Set to __mlibc_restorer in the mlibc sysdeps. - uintptr_t trampoline_base; // required - uint32_t flags; -} user_sigaction; -typedef struct sigaction { - union { - void(*handler)(int signum); - void(*sa_sigaction)(int signum, siginfo_t* info, void* unknown); - } un; - // NOTE(oberrow): Set to __mlibc_restorer in the mlibc sysdeps. - uintptr_t trampoline_base; // required - uint32_t flags; - // The following fields are not to be carried to userspace. - // Fields of 'siginfo_t' are set with this - uintptr_t udata; - void* addr; - int status; - int sigcode; - struct thread* sender; -} sigaction; -// Internal -typedef struct signal_header { - // NOTE: To get the first signal to dispatch, use __builtin_ctzll(pending & ~masked) - sigaction signals[64]; - sigset_t pending; - sigset_t mask; - uintptr_t sp; - size_t stack_size; // Unused in the actual signal implemtation, only exists for Sys_SigAltStack. - mutex lock; // take when modifying this structure. - event event; // set when a signal runs, clear when it exits (sigreturn) -} signal_header; signal_header* OBOSH_AllocateSignalHeader(); obos_status OBOS_Kill(struct thread* as, struct thread* thr, int sigval); @@ -126,17 +56,6 @@ OBOS_WEAK void OBOSS_SigReturn(ucontext_t* frame); OBOS_WEAK void OBOSS_RunSignalImpl(int sigval, interrupt_frame* frame); -enum signal_default_action -{ - // When this is the default, the signal runner returns normally. - SIGNAL_DEFAULT_IGNORE, - // When this is the default, the current thread is exited. - SIGNAL_DEFAULT_TERMINATE_PROC, - // Blocks the thread. - SIGNAL_DEFAULT_STOP, - // Readies the thread. - SIGNAL_DEFAULT_CONTINUE, -}; extern enum signal_default_action OBOS_SignalDefaultActions[SIGMAX+1]; void OBOS_DefaultSignalHandler(int signum, siginfo_t* info, void* unknown); diff --git a/src/oboskrnl/signal_def.h b/src/oboskrnl/signal_def.h new file mode 100644 index 00000000..997dd5e2 --- /dev/null +++ b/src/oboskrnl/signal_def.h @@ -0,0 +1,90 @@ +#pragma once + +#include + +#include +#include + +enum signal_default_action +{ + // When this is the default, the signal runner returns normally. + SIGNAL_DEFAULT_IGNORE, + // When this is the default, the current thread is exited. + SIGNAL_DEFAULT_TERMINATE_PROC, + // Blocks the thread. + SIGNAL_DEFAULT_STOP, + // Readies the thread. + SIGNAL_DEFAULT_CONTINUE, +}; + +// Public +enum { + SIGHUP = 1 , SIGINT, SIGQUIT, SIGILL, SIGTRAP, + SIGABRT , SIGBUS, SIGFPE, SIGKILL, SIGUSR1, + SIGSEGV , SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, + SIGSTKFLT , SIGCHLD, SIGCONT, SIGSTOP, SIGTSTP, + SIGTTIN , SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, + SIGVTALRM , SIGSYS, SIGMAX = 64, +}; + +// Public +typedef uint64_t sigset_t; + +// Public +enum { + SA_SIGINFO = BIT(0), + SA_ONSTACK = BIT(1), + SA_RESETHAND = BIT(2), + SA_NODEFER = BIT(3), + SA_NOCLDWAIT = BIT(4), // unimplemented + SA_NOCLDSTOP = BIT(5), // unimplemented +}; +// Public +typedef struct siginfo_t +{ + int signum; + int sigcode; + struct thread* sender; + void* addr; + int status; + union { + void* ptr; + uintptr_t integer; + } udata; +} siginfo_t; +// Public +typedef struct user_sigaction { + union { + void(*handler)(int signum); + void(*sa_sigaction)(int signum, siginfo_t* info, void* unknown); + } un; + // NOTE(oberrow): Set to __mlibc_restorer in the mlibc sysdeps. + uintptr_t trampoline_base; // required + uint32_t flags; +} user_sigaction; +typedef struct sigaction { + union { + void(*handler)(int signum); + void(*sa_sigaction)(int signum, siginfo_t* info, void* unknown); + } un; + // NOTE(oberrow): Set to __mlibc_restorer in the mlibc sysdeps. + uintptr_t trampoline_base; // required + uint32_t flags; + // The following fields are not to be carried to userspace. + // Fields of 'siginfo_t' are set with this + uintptr_t udata; + void* addr; + int status; + int sigcode; + struct thread* sender; +} sigaction; +// Internal +typedef struct signal_header { + // NOTE: To get the first signal to dispatch, use __builtin_ctzll(pending & ~masked) + sigset_t pending; + sigset_t mask; + uintptr_t sp; + size_t stack_size; // Unused in the actual signal implemtation, only exists for Sys_SigAltStack. + mutex lock; // take when modifying this structure. + event event; // set when a signal runs, clear when it exits (sigreturn) +} signal_header; \ No newline at end of file diff --git a/src/oboskrnl/syscall.c b/src/oboskrnl/syscall.c index 98eed26a..da8a315b 100644 --- a/src/oboskrnl/syscall.c +++ b/src/oboskrnl/syscall.c @@ -89,7 +89,7 @@ void Sys_LibCLog(const char* ustr) static handle Sys_MmFork() { // Zeroed in Mm_ConstructContext - context* ctx = Mm_Allocator->Allocate(Mm_Allocator, sizeof(context), nullptr); + context* ctx = Allocate(Mm_Allocator, sizeof(context), nullptr); Mm_ConstructContext(ctx); Mm_ForkContext(ctx, Core_GetCurrentThread()->proc->ctx); ctx->workingSet.capacity = Core_GetCurrentThread()->proc->ctx->workingSet.capacity; @@ -165,6 +165,8 @@ obos_status Sys_SleepMS(uint64_t ms, uint64_t* uleft) timer_tick deadline = CoreS_GetTimerTick() + CoreH_TimeFrameToTick(ms*1000); while (deadline > CoreS_GetTimerTick()) OBOSS_SpinlockHint(); + if (CoreS_ForceYieldOnSyscallReturn) + CoreS_ForceYieldOnSyscallReturn(); return OBOS_STATUS_SUCCESS; } @@ -285,15 +287,70 @@ obos_status Sys_IsATTY(handle desc) return OBOS_STATUS_SUCCESS; } +obos_status Sys_ThreadGetStack(handle thr, void** stack_base, size_t *stack_size) +{ + thread* thread = HANDLE_TYPE(thr) == HANDLE_TYPE_CURRENT ? Core_GetCurrentThread() : nullptr; + if (!thread) + { + obos_status status = OBOS_STATUS_SUCCESS; + handle_desc* hnd = OBOS_HandleLookup(OBOS_CurrentHandleTable(), thr, HANDLE_TYPE_THREAD, false, &status); + if (obos_is_error(status)) + { + OBOS_UnlockHandleTable(OBOS_CurrentHandleTable()); + return status; + } + OBOS_UnlockHandleTable(OBOS_CurrentHandleTable()); + thread = hnd->un.thread; + } + + if (!stack_base && !stack_size) + return OBOS_STATUS_SUCCESS; + + void* res_base = nullptr; + size_t res_size = 0; + + res_base = CoreS_GetThreadStack(&thread->context); + res_size = CoreS_GetThreadStackSize(&thread->context); + + if (stack_base) + memcpy_k_to_usr(stack_base, &res_base, sizeof(*stack_base)); + if (stack_base) + memcpy_k_to_usr(stack_base, &res_size, sizeof(*stack_size)); + + return OBOS_STATUS_SUCCESS; +} + +obos_status Sys_Shutdown() +{ + if (Core_GetCurrentThread()->proc->euid != 0) + return OBOS_STATUS_ACCESS_DENIED; + OBOS_Shutdown(); + OBOS_UNREACHABLE; +} +obos_status Sys_Reboot() +{ + if (Core_GetCurrentThread()->proc->euid != 0) + return OBOS_STATUS_ACCESS_DENIED; + OBOS_Reboot(); + OBOS_UNREACHABLE; +} +obos_status Sys_Suspend() +{ + if (Core_GetCurrentThread()->proc->euid != 0) + return OBOS_STATUS_ACCESS_DENIED; + OBOS_Suspend(); + OBOS_UNREACHABLE; +} + uintptr_t OBOS_SyscallTable[SYSCALL_END-SYSCALL_BEGIN] = { (uintptr_t)Core_ExitCurrentThread, (uintptr_t)Core_Yield, - (uintptr_t)OBOS_Reboot, - (uintptr_t)OBOS_Shutdown, + (uintptr_t)Sys_Reboot, + (uintptr_t)Sys_Shutdown, (uintptr_t)Sys_HandleClose, (uintptr_t)Sys_HandleClone, (uintptr_t)Sys_ThreadContextCreate, // 6 - (uintptr_t)OBOS_Suspend, + (uintptr_t)Sys_Suspend, (uintptr_t)Sys_ThreadOpen, (uintptr_t)Sys_ThreadCreate, (uintptr_t)Sys_ThreadReady, @@ -422,6 +479,14 @@ uintptr_t OBOS_SyscallTable[SYSCALL_END-SYSCALL_BEGIN] = { (uintptr_t)Sys_UMask, (uintptr_t)Sys_RenameAt, (uintptr_t)Sys_UTimeNSAt, + (uintptr_t)Sys_ThreadGetStack, + (uintptr_t)Sys_SetRESUid, + (uintptr_t)Sys_SetRESGid, + (uintptr_t)Sys_GetRESUid, + (uintptr_t)Sys_GetRESGid, + (uintptr_t)Sys_SigPending, + (uintptr_t)Sys_SetGroups, + (uintptr_t)Sys_GetGroups, }; // Arch syscall table is defined per-arch diff --git a/src/oboskrnl/vfs/create.c b/src/oboskrnl/vfs/create.c index 6ca818a2..c4dae200 100644 --- a/src/oboskrnl/vfs/create.c +++ b/src/oboskrnl/vfs/create.c @@ -23,27 +23,6 @@ #include #include -static bool has_write_perm(vnode* parent) -{ - uid current_uid = Core_GetCurrentThread()->proc->currentUID; - uid current_gid = Core_GetCurrentThread()->proc->currentGID; - if (parent->flags & VFLAGS_MOUNTPOINT) - { - drv_fs_info info = {}; - parent->un.mounted->fs_driver->driver->header.ftable.stat_fs_info(parent->un.mounted->device, &info); - if (parent->owner_uid == current_uid || parent->group_uid == current_gid) - return ~info.flags & FS_FLAGS_RDONLY; - else - return false; - } - if (parent->owner_uid == current_uid) - return parent->perm.owner_write; - else if (parent->group_uid == current_gid) - return parent->perm.group_write; - else - return parent->perm.other_write; -} - #ifdef __x86_64__ # include #endif @@ -54,17 +33,29 @@ obos_status Vfs_CreateNode(dirent* parent, const char* name, uint32_t vtype, fil parent = Vfs_Root; if (!name || !vtype || vtype >= VNODE_TYPE_BAD) return OBOS_STATUS_INVALID_ARGUMENT; + + obos_status status = Vfs_Access(parent->vnode, + false, + true, + false); + if (obos_is_error(status)) + return status; + vnode* parent_vn = parent->vnode; if (!parent_vn) return OBOS_STATUS_INVALID_ARGUMENT; if (parent_vn->vtype != VNODE_TYPE_DIR) return OBOS_STATUS_INVALID_ARGUMENT; - if (!has_write_perm(parent_vn)) - return OBOS_STATUS_ACCESS_DENIED; - mount *parent_mnt = parent_vn->flags & VFLAGS_MOUNTPOINT ? - parent_vn->un.mounted: - parent_vn->mount_point; - driver_ftable* ftable = &parent_mnt->fs_driver->driver->header.ftable; + + mount *parent_mnt = Vfs_GetVnodeMount(parent->vnode); + driver_header* header = Vfs_GetVnodeDriver(parent_mnt->root->vnode); + if (!header) + return OBOS_STATUS_INTERNAL_ERROR; + + driver_ftable* ftable = &header->ftable; + if (!ftable->remove_file) + return OBOS_STATUS_UNIMPLEMENTED; + if (!ftable->mk_file) return OBOS_STATUS_UNIMPLEMENTED; @@ -94,8 +85,8 @@ obos_status Vfs_CreateNode(dirent* parent, const char* name, uint32_t vtype, fil return OBOS_STATUS_INVALID_ARGUMENT; } vnode* vn = Vfs_Calloc(1, sizeof(vnode)); - vn->group_uid = Core_GetCurrentThread()->proc->currentGID; - vn->owner_uid = Core_GetCurrentThread()->proc->currentUID; + vn->gid = Core_GetCurrentThread()->proc->egid; + vn->uid = Core_GetCurrentThread()->proc->euid; vn->perm = mode; vn->flags = 0; vn->vtype = vtype; @@ -114,7 +105,7 @@ obos_status Vfs_CreateNode(dirent* parent, const char* name, uint32_t vtype, fil OBOS_InitString(&ent->name, name); ent->vnode = vn; vnode* mount_vn = parent_mnt->device; - obos_status status = OBOS_STATUS_SUCCESS; + status = OBOS_STATUS_SUCCESS; if (parent_mnt->fs_driver->driver->header.flags & DRIVER_HEADER_DIRENT_CB_PATHS) { char* parent_path = VfsH_DirentPath(parent, parent_mnt->root); @@ -144,19 +135,29 @@ OBOS_EXPORT obos_status Vfs_UnlinkNode(dirent* node) return OBOS_STATUS_SUCCESS; if (node->d_children.nChildren) return OBOS_STATUS_IN_USE; // cannot remove a directory with children - if (!has_write_perm(node->d_parent->vnode)) - return OBOS_STATUS_ACCESS_DENIED; + obos_status status = Vfs_Access(node->d_parent->vnode, + false, + true, + false); + if (obos_is_error(status)) + return status; - mount *parent_mnt = node->vnode->flags & VFLAGS_MOUNTPOINT ? - node->vnode->un.mounted: - node->vnode->mount_point; - driver_ftable* ftable = &parent_mnt->fs_driver->driver->header.ftable; + mount *parent_mnt = Vfs_GetVnodeMount(node->vnode); + if (!parent_mnt) + return OBOS_STATUS_INTERNAL_ERROR; + OBOS_ENSURE(parent_mnt->root); + driver_header* header = Vfs_GetVnodeDriver(parent_mnt->root->vnode); + if (!header) + return OBOS_STATUS_INTERNAL_ERROR; + + driver_ftable* ftable = &header->ftable; if (!ftable->remove_file) return OBOS_STATUS_UNIMPLEMENTED; + if (LIST_GET_NODE_COUNT(fd_list, &node->vnode->opened)) return OBOS_STATUS_IN_USE; // TODO: Handle correctly (when the last FD is closed, then free+delete the vnode) - obos_status status = OBOS_STATUS_SUCCESS; + status = OBOS_STATUS_SUCCESS; if (node->vnode->vtype == VNODE_TYPE_DIR || node->vnode->vtype == VNODE_TYPE_REG || node->vnode->vtype == VNODE_TYPE_LNK) { @@ -212,6 +213,13 @@ obos_status Vfs_RenameNode(dirent* node, dirent* newparent, const char* name) if (!header) return OBOS_STATUS_INVALID_ARGUMENT; + obos_status status = Vfs_Access((newparent ? newparent : node->d_parent)->vnode, + false, + true, + false); + if (obos_is_error(status)) + return status; + // Rename the entry if (!newparent || newparent == node->d_parent) { @@ -268,7 +276,7 @@ obos_status Vfs_RenameNode(dirent* node, dirent* newparent, const char* name) // Move and rename the entry. - obos_status status = OBOS_STATUS_SUCCESS; + status = OBOS_STATUS_SUCCESS; if (header->flags & DRIVER_HEADER_DIRENT_CB_PATHS) { char* node_path = VfsH_DirentPath(node, Vfs_Root); diff --git a/src/oboskrnl/vfs/dirent.c b/src/oboskrnl/vfs/dirent.c index 4c110ce8..25ea9463 100644 --- a/src/oboskrnl/vfs/dirent.c +++ b/src/oboskrnl/vfs/dirent.c @@ -42,6 +42,7 @@ static vnode* create_vnode(mount* mountpoint, dev_desc desc, file_type* t) obos_status status = mountpoint->fs_driver->driver->header.ftable.vnode_search((void**)&vn, desc, mountpoint->fs_driver); if (obos_is_success(status)) { + OBOS_ENSURE(vn); vn->mount_point = mountpoint; if (t) { @@ -303,6 +304,7 @@ static dirent* lookup(const char* path, dirent* root_par, bool only_cache) if (!last) break; mountpoint = last->vnode->flags & VFLAGS_MOUNTPOINT ? last->vnode->un.mounted : last->vnode->mount_point; + fs_driver = mountpoint->fs_driver; currentPath = VfsH_DirentPath(last, mountpoint->root); currentPathLen = strlen(currentPath); if (currentPath[currentPathLen-1] != '/') @@ -312,6 +314,11 @@ static dirent* lookup(const char* path, dirent* root_par, bool only_cache) currentPath[++currentPathLen] = 0; } } + else + { + mountpoint = last->vnode->flags & VFLAGS_MOUNTPOINT ? last->vnode->un.mounted : last->vnode->mount_point; + fs_driver = mountpoint->fs_driver; + } tok += str_search(tok, '/'); size_t currentPathLen2 = strlen(tok)-1; @@ -461,8 +468,8 @@ vnode* Drv_AllocateVNode(driver_id* drv, dev_desc desc, size_t filesize, vdev** vn->inode = devfs_inode++; vn->perm = default_fileperm; vn->vtype = type; - vn->group_uid = ROOT_GID; - vn->owner_uid = ROOT_UID; + vn->gid = ROOT_GID; + vn->uid = ROOT_UID; vn->times.access = get_current_time(); vn->times.birth = vn->times.access; vn->times.change = vn->times.access; @@ -512,7 +519,8 @@ static iterate_decision populate_cb(dev_desc desc, size_t blkSize, size_t blkCou child = child->d_next_child; } - mount* point = dent->vnode->mount_point ? dent->vnode->mount_point : dent->vnode->un.mounted; + + mount* point = Vfs_GetVnodeMount(dent->vnode); vnode* vn = create_vnode(point, desc, nullptr); dirent* new = Vfs_Calloc(1, sizeof(dirent)); OBOS_StringSetAllocator(&new->name, Vfs_Allocator); @@ -525,12 +533,16 @@ static iterate_decision populate_cb(dev_desc desc, size_t blkSize, size_t blkCou void Vfs_PopulateDirectory(dirent* dent) { - mount* point = dent->vnode->mount_point ? dent->vnode->mount_point : dent->vnode->un.mounted; - const driver_header* driver = &point->fs_driver->driver->header; + mount* point = Vfs_GetVnodeMount(dent->vnode); + driver_header* driver = Vfs_GetVnodeDriver(dent->vnode); if (dent->vnode->vtype != VNODE_TYPE_DIR) return; if (driver->ftable.list_dir) - OBOS_ENSURE(obos_is_success(driver->ftable.list_dir(dent->vnode->desc, point->device, populate_cb, dent))); + { + obos_status status = driver->ftable.list_dir(dent->vnode->flags & VFLAGS_MOUNTPOINT ? UINTPTR_MAX : dent->vnode->desc, point->device, populate_cb, dent); + if (obos_is_error(status)) + OBOS_Error("list_dir returned %d!\n", status); + } else OBOS_Error("driver->ftable.list_dir == nullptr!\n"); } @@ -650,15 +662,7 @@ char* VfsH_DirentPath(dirent* ent, dirent* relative_to) static bool check_chdir_perms(dirent* ent) { - uid uid = Core_GetCurrentThread()->proc->currentUID; - gid gid = Core_GetCurrentThread()->proc->currentGID; - - if (uid == ent->vnode->owner_uid) - return ent->vnode->perm.owner_exec; - else if (gid == ent->vnode->group_uid) - return ent->vnode->perm.group_exec; - else - return ent->vnode->perm.other_exec; + return Vfs_Access(ent->vnode, false, false, true) == OBOS_STATUS_SUCCESS; } obos_status VfsH_Chdir(void* target_, const char *path) @@ -785,5 +789,73 @@ mount* Vfs_GetVnodeMount(vnode* vn) return nullptr; if (vn->vtype == VNODE_TYPE_FIFO || vn->vtype == VNODE_TYPE_SOCK) return nullptr; - return vn->mount_point ? vn->mount_point : vn->un.mounted; + return vn->flags & VFLAGS_MOUNTPOINT ? vn->un.mounted : vn->mount_point; +} + +obos_status Vfs_Access(vnode* vn, bool read, bool write, bool exec) +{ + uid euid = Core_GetCurrentThread() && Core_GetCurrentThread()->proc ? Core_GetCurrentThread()->proc->euid : 0; + gid egid = Core_GetCurrentThread() && Core_GetCurrentThread()->proc ? Core_GetCurrentThread()->proc->egid : 0; + obos_status status = Vfs_AccessAs(euid, egid, vn, read, write, exec); + if (obos_is_success(status)) + return OBOS_STATUS_SUCCESS; + if (!Core_GetCurrentThread() || !Core_GetCurrentThread()->proc) + return status; + if (status == OBOS_STATUS_READ_ONLY) + return OBOS_STATUS_READ_ONLY; + for (size_t i = 0; i < Core_GetCurrentThread()->proc->groups.nEntries; i++) + { + status = Vfs_AccessAs(euid, Core_GetCurrentThread()->proc->groups.list[i], vn, read, write, exec); + if (obos_is_success(status)) + return OBOS_STATUS_SUCCESS; + } + return status; } + +obos_status Vfs_AccessAs(uid asUid, gid asGid, vnode* vn, bool read, bool write, bool exec) +{ + if (write) + { + drv_fs_info info = {}; + driver_header* header = Vfs_GetVnodeDriver(vn); + mount* mount = Vfs_GetVnodeMount(vn); + if (header && mount && header->ftable.stat_fs_info) + header->ftable.stat_fs_info(mount->device, &info); + if (info.flags & FS_FLAGS_RDONLY) + return OBOS_STATUS_READ_ONLY; + } + + if (vn->uid == asUid || asUid == 0) + { + if (!vn->perm.owner_read && read) + return OBOS_STATUS_ACCESS_DENIED; + else if (!vn->perm.owner_write && write) + return OBOS_STATUS_ACCESS_DENIED; + else if (!vn->perm.owner_exec && exec) + return OBOS_STATUS_ACCESS_DENIED; + else + return OBOS_STATUS_SUCCESS; + } + else if (vn->gid == asGid) + { + if (!vn->perm.group_read && read) + return OBOS_STATUS_ACCESS_DENIED; + else if (!vn->perm.group_write && write) + return OBOS_STATUS_ACCESS_DENIED; + else if (!vn->perm.group_exec && exec) + return OBOS_STATUS_ACCESS_DENIED; + else + return OBOS_STATUS_SUCCESS; + } + else + { + if (!vn->perm.other_read && read) + return OBOS_STATUS_ACCESS_DENIED; + else if (!vn->perm.other_write && write) + return OBOS_STATUS_ACCESS_DENIED; + else if (!vn->perm.other_exec && exec) + return OBOS_STATUS_ACCESS_DENIED; + else + return OBOS_STATUS_SUCCESS; + } +} \ No newline at end of file diff --git a/src/oboskrnl/vfs/dummy_devices.c b/src/oboskrnl/vfs/dummy_devices.c index 0275881d..a4e043d5 100644 --- a/src/oboskrnl/vfs/dummy_devices.c +++ b/src/oboskrnl/vfs/dummy_devices.c @@ -417,8 +417,8 @@ static void init_desc(dev_desc desc) dirent* ent = Vfs_Calloc(1, sizeof(dirent)); vnode* vn = Vfs_Calloc(1, sizeof(vnode)); - vn->owner_uid = 0; - vn->group_uid = 0; + vn->uid = 0; + vn->gid = 0; vn->desc = desc; get_max_blk_count(desc, &vn->filesize); diff --git a/src/oboskrnl/vfs/fd.c b/src/oboskrnl/vfs/fd.c index 33f98597..533eba8a 100644 --- a/src/oboskrnl/vfs/fd.c +++ b/src/oboskrnl/vfs/fd.c @@ -91,46 +91,19 @@ OBOS_EXPORT obos_status Vfs_FdOpenVnode(fd* const desc, void* vn, uint32_t oflag if (vnode->vtype == VNODE_TYPE_DIR || vnode->vtype == VNODE_TYPE_LNK) return OBOS_STATUS_NOT_A_FILE; desc->vn = vnode; - desc->flags |= FD_FLAGS_OPEN; - desc->flags |= FD_FLAGS_READ; - desc->flags |= FD_FLAGS_WRITE; - if (desc->vn->owner_uid == Core_GetCurrentThread()->proc->currentUID || Core_GetCurrentThread()->proc->currentUID == 0) - { - // We have owner perms. - struct vnode* const vn = desc->vn; - if (!vn->perm.owner_read) - desc->flags &= ~FD_FLAGS_READ; - if (!vn->perm.owner_write) - desc->flags &= ~FD_FLAGS_WRITE; - if (oflags & FD_OFLAGS_EXECUTE && !vn->perm.owner_exec) - return OBOS_STATUS_ACCESS_DENIED; - } - else if (desc->vn->group_uid == Core_GetCurrentThread()->proc->currentGID) - { - // We have group perms. - struct vnode* const vn = desc->vn; - if (!vn->perm.group_read) - desc->flags &= ~FD_FLAGS_READ; - if (!vn->perm.group_write) - desc->flags &= ~FD_FLAGS_WRITE; - if (oflags & FD_OFLAGS_EXECUTE && !vn->perm.group_exec) - return OBOS_STATUS_ACCESS_DENIED; - } - else - { - // We have other perms. - struct vnode* const vn = desc->vn; - if (!vn->perm.other_read) - desc->flags &= ~FD_FLAGS_READ; - if (!vn->perm.other_write) - desc->flags &= ~FD_FLAGS_WRITE; - if (oflags & FD_OFLAGS_EXECUTE && !vn->perm.other_exec) - return OBOS_STATUS_ACCESS_DENIED; - } - if (~oflags & FD_OFLAGS_READ) - desc->flags &= ~FD_FLAGS_READ; - if (~oflags & FD_OFLAGS_WRITE) - desc->flags &= ~FD_FLAGS_WRITE; + + obos_status status = Vfs_Access(vnode, + oflags & FD_OFLAGS_READ, + oflags & FD_OFLAGS_WRITE, + oflags & FD_OFLAGS_EXECUTE); + if (obos_is_error(status)) + return status; + + if (oflags & FD_OFLAGS_READ) + desc->flags |= FD_FLAGS_READ; + if (oflags & FD_OFLAGS_WRITE) + desc->flags |= FD_FLAGS_WRITE; + if (oflags & FD_OFLAGS_UNCACHED) desc->flags |= FD_FLAGS_UNCACHED; if (oflags & FD_OFLAGS_NOEXEC) @@ -139,6 +112,11 @@ OBOS_EXPORT obos_status Vfs_FdOpenVnode(fd* const desc, void* vn, uint32_t oflag desc->flags |= FD_FLAGS_UNCACHED; if (vnode->flags & VFLAGS_EVENT_DEV) desc->flags &= ~(FD_FLAGS_READ|FD_FLAGS_WRITE); + else + { + if (!(desc->flags & (FD_FLAGS_WRITE|FD_FLAGS_READ))) + return OBOS_STATUS_ACCESS_DENIED; + } desc->vn->refs++; LIST_APPEND(fd_list, &desc->vn->opened, desc); if (~desc->vn->flags & VFLAGS_EVENT_DEV) diff --git a/src/oboskrnl/vfs/fd_sys.c b/src/oboskrnl/vfs/fd_sys.c index 66f6e654..50ab5462 100644 --- a/src/oboskrnl/vfs/fd_sys.c +++ b/src/oboskrnl/vfs/fd_sys.c @@ -15,6 +15,7 @@ #include +#include #include #include #include @@ -89,6 +90,10 @@ static file_perm unix_to_obos_mode(uint32_t mode, bool respect_umask) real_mode.owner_write = true; if (mode & 0400) real_mode.owner_read = true; + if (mode & 04000) + real_mode.set_uid = true; + if (mode & 02000) + real_mode.set_gid = true; return real_mode; } obos_status Sys_FdOpenEx(handle desc, const char* upath, uint32_t oflags, uint32_t mode) @@ -287,6 +292,9 @@ obos_status Sys_FdWrite(handle desc, const void* buf, size_t nBytes, size_t* nWr Mm_VirtualMemoryFree(&Mm_KernelContext, kbuf, nBytes); + if (CoreS_ForceYieldOnSyscallReturn) + CoreS_ForceYieldOnSyscallReturn(); + return OBOS_STATUS_SUCCESS; } @@ -323,6 +331,9 @@ obos_status Sys_FdRead(handle desc, void* buf, size_t nBytes, size_t* nRead) Mm_VirtualMemoryFree(&Mm_KernelContext, kbuf, nBytes); + if (CoreS_ForceYieldOnSyscallReturn) + CoreS_ForceYieldOnSyscallReturn(); + return OBOS_STATUS_SUCCESS; } @@ -366,6 +377,9 @@ obos_status Sys_FdPWrite(handle desc, const void* buf, size_t nBytes, size_t* nW Mm_VirtualMemoryFree(&Mm_KernelContext, kbuf, nBytes); + if (CoreS_ForceYieldOnSyscallReturn) + CoreS_ForceYieldOnSyscallReturn(); + return OBOS_STATUS_SUCCESS; } @@ -399,7 +413,10 @@ obos_status Sys_FdPRead(handle desc, void* buf, size_t nBytes, size_t* nRead, si } Mm_VirtualMemoryFree(&Mm_KernelContext, kbuf, nBytes); - + + if (CoreS_ForceYieldOnSyscallReturn) + CoreS_ForceYieldOnSyscallReturn(); + return OBOS_STATUS_SUCCESS; } @@ -506,6 +523,8 @@ obos_status Sys_FdIoctl(handle desc, uintptr_t request, void* argp, size_t sz_ar obos_status Sys_FdFlush(handle desc) { + if (HANDLE_TYPE(desc) == HANDLE_TYPE_DIRENT) + return OBOS_STATUS_SUCCESS; OBOS_LockHandleTable(OBOS_CurrentHandleTable()); obos_status status = OBOS_STATUS_SUCCESS; handle_desc* fd = OBOS_HandleLookup(OBOS_CurrentHandleTable(), desc, HANDLE_TYPE_FD, false, &status); @@ -607,6 +626,10 @@ obos_status Sys_Stat(int fsfdt, handle desc, const char* upath, int flags, struc return status; st.st_size = to_stat->filesize; st.st_mode = 0; + if (to_stat->perm.set_uid) + st.st_mode |= 04000; + if (to_stat->perm.set_gid) + st.st_mode |= 02000; if (to_stat->perm.owner_read) st.st_mode |= 0400; if (to_stat->perm.owner_write) @@ -665,8 +688,8 @@ obos_status Sys_Stat(int fsfdt, handle desc, const char* upath, int flags, struc st.st_atim.tv_nsec = 0; st.st_ctim.tv_nsec = 0; st.st_mtim.tv_nsec = 0; - st.st_gid = to_stat->group_uid; - st.st_uid = to_stat->owner_uid; + st.st_gid = to_stat->gid; + st.st_uid = to_stat->uid; st.st_ino = to_stat->inode; if (to_stat->flags & VFLAGS_EVENT_DEV && ~to_stat->flags & VFLAGS_DRIVER_DEAD) goto done; @@ -790,6 +813,8 @@ obos_status Sys_ReadLinkAt(handle parent, const char *upath, void* ubuff, size_t if (length) memcpy_k_to_usr(length, &len, sizeof(size_t)); + Mm_VirtualMemoryFree(&Mm_KernelContext, buff, max_size); + return OBOS_STATUS_SUCCESS; } @@ -847,6 +872,16 @@ handle Sys_OpenDir(const char* upath, obos_status *statusp) dent = VfsH_FollowLink(dent); + if (dent->vnode) + { + obos_status status = Vfs_Access(dent->vnode, + true, + false, + false); + if (obos_is_error(status)) + return status; + } + Vfs_PopulateDirectory(dent); handle_desc* desc = nullptr; @@ -1309,8 +1344,8 @@ obos_status Sys_CreateNamedPipe(handle dirfd, const char* upath, int mode, size_ fifo_name = path; } - gid current_gid = Core_GetCurrentThread()->proc->currentGID; - uid current_uid = Core_GetCurrentThread()->proc->currentUID; + gid current_gid = Core_GetCurrentThread()->proc->egid; + uid current_uid = Core_GetCurrentThread()->proc->euid; status = Vfs_CreateNamedPipe(perm, current_gid, current_uid, parent, fifo_name, pipesize); Free(OBOS_KernelAllocator, path, sz_path); @@ -1377,7 +1412,9 @@ obos_status Sys_PSelect(size_t nFds, uint8_t* uread_set, uint8_t *uwrite_set, ui if (!uread_set && !uwrite_set && !uexcept_set) return OBOS_STATUS_SUCCESS; // We waited for nothing, so assume success. OBOS_UNUSED(uexcept_set && "We can't really monitor exceptional cases..."); - + if (uexcept_set) + return OBOS_STATUS_UNIMPLEMENTED; + uint8_t *read_set = Mm_MapViewOfUserMemory(CoreS_GetCPULocalPtr()->currentContext, uread_set, nullptr, 128, 0, true, &status); if (obos_is_error(status) && uread_set) return status; @@ -1388,7 +1425,6 @@ obos_status Sys_PSelect(size_t nFds, uint8_t* uread_set, uint8_t *uwrite_set, ui return status; } - sigset_t sigmask = 0, oldmask = 0; if (extra.sigmask) { @@ -1479,7 +1515,13 @@ obos_status Sys_PSelect(size_t nFds, uint8_t* uread_set, uint8_t *uwrite_set, ui waitable_list[unsignaledIRPIndex] = WAITABLE_OBJECT(tm_evnt); } - Core_WaitOnObjects(nWaitableObjects, waitable_list, nullptr); + status = Core_WaitOnObjects(nWaitableObjects, waitable_list, nullptr); + if (obos_is_error(status)) + { + Core_CancelTimer(&tm); + CoreH_FreeDPC(&tm.handler_dpc, false); + goto timeout; + } if (tm.mode == TIMER_EXPIRED) { // Just In Case @@ -1509,6 +1551,10 @@ obos_status Sys_PSelect(size_t nFds, uint8_t* uread_set, uint8_t *uwrite_set, ui out2: Mm_VirtualMemoryFree(CoreS_GetCPULocalPtr()->currentContext, read_set, 128); Mm_VirtualMemoryFree(CoreS_GetCPULocalPtr()->currentContext, write_set, 128); + + if (CoreS_ForceYieldOnSyscallReturn) + CoreS_ForceYieldOnSyscallReturn(); + return status; } @@ -1665,7 +1711,13 @@ obos_status Sys_PPoll(struct pollfd* ufds, size_t nFds, const uintptr_t* utimeou } struct waitable_header* signaled = nullptr; - Core_WaitOnObjects(n_waitable_objects, waitable_list, &signaled); + status = Core_WaitOnObjects(n_waitable_objects, waitable_list, &signaled); + if (obos_is_error(status)) + { + Core_CancelTimer(&tm); + CoreH_FreeDPC(&tm.handler_dpc, false); + goto out; + } if (signaled == WAITABLE_OBJECT(tm_evnt)) { Core_CancelTimer(&tm); @@ -1689,6 +1741,9 @@ obos_status Sys_PPoll(struct pollfd* ufds, size_t nFds, const uintptr_t* utimeou OBOS_SigProcMask(SIG_SETMASK, &oldmask, nullptr); Mm_VirtualMemoryFree(&Mm_KernelContext, fds, nFds*sizeof(struct pollfd)); + if (CoreS_ForceYieldOnSyscallReturn) + CoreS_ForceYieldOnSyscallReturn(); + return status; } @@ -2466,6 +2521,9 @@ obos_status Sys_SendTo(handle desc, const void* buffer, size_t size, int flags, OBOS_MAYBE_UNUSED fail1: Mm_VirtualMemoryFree(&Mm_KernelContext, (void*)params, sizeof(*params)); + if (CoreS_ForceYieldOnSyscallReturn) + CoreS_ForceYieldOnSyscallReturn(); + return status; } @@ -2518,6 +2576,9 @@ obos_status Sys_RecvFrom(handle desc, void* buffer, size_t size, int flags, stru OBOS_MAYBE_UNUSED fail1: Mm_VirtualMemoryFree(&Mm_KernelContext, params, sizeof(*params)); + if (CoreS_ForceYieldOnSyscallReturn) + CoreS_ForceYieldOnSyscallReturn(); + return status; } @@ -2574,6 +2635,9 @@ obos_status Sys_Accept(handle desc, handle empty_fd, sockaddr* uaddr_ptr, size_t OBOS_MAYBE_UNUSED fail1: Free(OBOS_KernelAllocator, buf, addr_length); + if (CoreS_ForceYieldOnSyscallReturn) + CoreS_ForceYieldOnSyscallReturn(); + return status; } @@ -2626,6 +2690,9 @@ obos_status Sys_Connect(handle desc, const sockaddr *uaddr, size_t addr_length) OBOS_MAYBE_UNUSED fail1: Free(OBOS_KernelAllocator, buf, addr_length); + if (CoreS_ForceYieldOnSyscallReturn) + CoreS_ForceYieldOnSyscallReturn(); + return status; } @@ -2781,17 +2848,40 @@ obos_status Sys_FChmodAt(handle dirfd, const char* upathname, int mode, int flag pathname = ZeroAllocate(OBOS_KernelAllocator, sz_path+1, sizeof(char), nullptr); OBOSH_ReadUserString(upathname, pathname, nullptr); + vnode* target = nullptr; + dirent* parent = nullptr; const char* name = nullptr; if (dirfd != AT_FDCWD) { + if (HANDLE_TYPE(dirfd) != HANDLE_TYPE_DIRENT && HANDLE_TYPE(dirfd) != HANDLE_TYPE_FD) + { + status = OBOS_STATUS_INVALID_ARGUMENT; + goto fail; + } + if (HANDLE_TYPE(dirfd) == HANDLE_TYPE_FD && strlen(pathname)) + { + status = OBOS_STATUS_INVALID_ARGUMENT; + goto fail; + } OBOS_LockHandleTable(OBOS_CurrentHandleTable()); - handle_desc* desc = OBOS_HandleLookup(OBOS_CurrentHandleTable(), dirfd, HANDLE_TYPE_DIRENT, false, &status); + handle_desc* desc = OBOS_HandleLookup(OBOS_CurrentHandleTable(), dirfd, 0, true, &status); if (obos_is_error(status)) { OBOS_UnlockHandleTable(OBOS_CurrentHandleTable()); goto fail; } + if (HANDLE_TYPE(dirfd) == HANDLE_TYPE_FD) + { + target = desc->un.fd->vn; + OBOS_UnlockHandleTable(OBOS_CurrentHandleTable()); + if (!target) + { + status = OBOS_STATUS_INVALID_ARGUMENT; + goto fail; + } + goto have_target; + } parent = desc->un.dirent->parent; OBOS_UnlockHandleTable(OBOS_CurrentHandleTable()); @@ -2823,18 +2913,22 @@ obos_status Sys_FChmodAt(handle dirfd, const char* upathname, int mode, int flag name = pathname; } - dirent* target = VfsH_DirentLookupFrom(name, parent); - if (!target) + dirent* targetd = VfsH_DirentLookupFrom(name, parent); + if (!targetd) { status = OBOS_STATUS_NOT_FOUND; goto fail; } if (~flags & AT_SYMLINK_NOFOLLOW) - target = VfsH_FollowLink(target); + targetd = VfsH_FollowLink(targetd); // NOTE(oberrow): AT_EMPTY_PATH is the default on obos, and can actually not be // changed, because of the nature of the lookup() function + + target = targetd->vnode; + + have_target: - if (target->vnode->owner_uid != Sys_GetUid() && Sys_GetUid() != ROOT_UID) + if (target->uid != Sys_GetUid() && Sys_GetUid() != ROOT_UID) { status = OBOS_STATUS_ACCESS_DENIED; goto fail; @@ -2842,18 +2936,19 @@ obos_status Sys_FChmodAt(handle dirfd, const char* upathname, int mode, int flag file_perm real_mode = unix_to_obos_mode(mode, true); - driver_header* header = Vfs_GetVnodeDriver(target->vnode); + mount* mount = Vfs_GetVnodeMount(target); + driver_header* header = Vfs_GetVnodeDriver(mount->root->vnode); if (!header) { status = OBOS_STATUS_INTERNAL_ERROR; goto fail; } - status = !header->ftable.set_file_perms ? OBOS_STATUS_UNIMPLEMENTED : header->ftable.set_file_perms(target->vnode->desc, real_mode); + status = !header->ftable.set_file_perms ? OBOS_STATUS_UNIMPLEMENTED : header->ftable.set_file_perms(target->desc, real_mode); if (obos_is_error(status)) goto fail; - target->vnode->perm = real_mode; + target->perm = real_mode; fail: Free(OBOS_KernelAllocator, pathname, sz_path); @@ -2869,24 +2964,44 @@ obos_status Sys_FChownAt(handle dirfd, const char *upathname, uid owner, gid gro size_t sz_path = 0; status = OBOSH_ReadUserString(upathname, nullptr, &sz_path); if (obos_is_error(status)) - { - Free(OBOS_KernelAllocator, pathname, sz_path); return status; - } pathname = ZeroAllocate(OBOS_KernelAllocator, sz_path+1, sizeof(char), nullptr); OBOSH_ReadUserString(upathname, pathname, nullptr); + vnode* target = nullptr; + dirent* parent = nullptr; const char* name = nullptr; if (dirfd != AT_FDCWD) { + if (HANDLE_TYPE(dirfd) != HANDLE_TYPE_DIRENT && HANDLE_TYPE(dirfd) != HANDLE_TYPE_FD) + { + status = OBOS_STATUS_INVALID_ARGUMENT; + goto fail; + } + if (HANDLE_TYPE(dirfd) == HANDLE_TYPE_FD && strlen(pathname)) + { + status = OBOS_STATUS_INVALID_ARGUMENT; + goto fail; + } OBOS_LockHandleTable(OBOS_CurrentHandleTable()); - handle_desc* desc = OBOS_HandleLookup(OBOS_CurrentHandleTable(), dirfd, HANDLE_TYPE_DIRENT, false, &status); + handle_desc* desc = OBOS_HandleLookup(OBOS_CurrentHandleTable(), dirfd, 0, true, &status); if (obos_is_error(status)) { OBOS_UnlockHandleTable(OBOS_CurrentHandleTable()); goto fail; } + if (HANDLE_TYPE(dirfd) == HANDLE_TYPE_FD) + { + target = desc->un.fd->vn; + OBOS_UnlockHandleTable(OBOS_CurrentHandleTable()); + if (!target) + { + status = OBOS_STATUS_INVALID_ARGUMENT; + goto fail; + } + goto have_target; + } parent = desc->un.dirent->parent; OBOS_UnlockHandleTable(OBOS_CurrentHandleTable()); @@ -2918,38 +3033,43 @@ obos_status Sys_FChownAt(handle dirfd, const char *upathname, uid owner, gid gro name = pathname; } - dirent* target = VfsH_DirentLookupFrom(name, parent); - if (!target) + dirent* targetd = VfsH_DirentLookupFrom(name, parent); + if (!targetd) { status = OBOS_STATUS_NOT_FOUND; goto fail; } if (~flags & AT_SYMLINK_NOFOLLOW) - target = VfsH_FollowLink(target); + targetd = VfsH_FollowLink(targetd); // NOTE(oberrow): AT_EMPTY_PATH is the default on obos, and can actually not be // changed, because of the nature of the lookup() function + + target = targetd->vnode; + + have_target: + OBOS_ENSURE(target); - if (target->vnode->owner_uid != Sys_GetUid() && Sys_GetUid() != ROOT_UID) + if (Sys_GetUid() != ROOT_UID) { status = OBOS_STATUS_ACCESS_DENIED; goto fail; } - driver_header* header = Vfs_GetVnodeDriver(target->vnode); + driver_header* header = Vfs_GetVnodeDriver(target); if (!header) { status = OBOS_STATUS_INTERNAL_ERROR; goto fail; } - status = !header->ftable.set_file_owner ? OBOS_STATUS_UNIMPLEMENTED : header->ftable.set_file_owner(target->vnode->desc, owner, group); + status = !header->ftable.set_file_owner ? OBOS_STATUS_UNIMPLEMENTED : header->ftable.set_file_owner(target->desc, owner, group); if (obos_is_error(status)) goto fail; if (owner != -1) - target->vnode->owner_uid = owner; + target->uid = owner; if (group != -1) - target->vnode->group_uid = group; + target->gid = group; fail: Free(OBOS_KernelAllocator, pathname, sz_path); diff --git a/src/oboskrnl/vfs/local_socket.c b/src/oboskrnl/vfs/local_socket.c index 872769f8..2091c18e 100644 --- a/src/oboskrnl/vfs/local_socket.c +++ b/src/oboskrnl/vfs/local_socket.c @@ -371,7 +371,9 @@ static obos_status stream_accept(socket_desc* socket, struct sockaddr* addr, siz if (!Core_EventGetState(&s->serv.doorbell) && nonblocking) return OBOS_STATUS_WOULD_BLOCK; - Core_WaitOnObject(WAITABLE_OBJECT(s->serv.doorbell)); + obos_status status = Core_WaitOnObject(WAITABLE_OBJECT(s->serv.doorbell)); + if (obos_is_error(status)) + return status; Core_EventClear(&s->serv.doorbell); Core_MutexAcquire(&s->serv.lock); diff --git a/src/oboskrnl/vfs/mount.c b/src/oboskrnl/vfs/mount.c index c269bc88..297b7634 100644 --- a/src/oboskrnl/vfs/mount.c +++ b/src/oboskrnl/vfs/mount.c @@ -183,6 +183,8 @@ obos_status Vfs_Mount(const char* at_, vnode* on, vdev* fs_driver, mount** pMoun at->vnode->un.mounted = mountpoint; // at->vnode->mount_point = mountpoint; at->vnode->flags |= VFLAGS_MOUNTPOINT; + mountpoint->old_root_desc = at->vnode->desc; + at->vnode->desc = UINTPTR_MAX; mountpoint->root = at; mountpoint->lock = MUTEX_INITIALIZE(); // uintptr_t udata[3] = { @@ -313,6 +315,7 @@ obos_status Vfs_Unmount(mount* what) Vfs_Root->vnode->mount_point = nullptr; Vfs_Root->vnode->un.mounted = nullptr; } + what->root->vnode->desc = what->old_root_desc; what->awaitingFree = true; if (!what->nWaiting) Vfs_Free(what); diff --git a/src/oboskrnl/vfs/mount.h b/src/oboskrnl/vfs/mount.h index 0c0bb862..5de4f51b 100644 --- a/src/oboskrnl/vfs/mount.h +++ b/src/oboskrnl/vfs/mount.h @@ -23,6 +23,7 @@ typedef struct mount LIST_NODE(mount_list, struct mount) node; mutex lock; dirent* root; + dev_desc old_root_desc; vdev* fs_driver; vnode* device; // the block device the filesystem is situated on. vnode* mounted_on; diff --git a/src/oboskrnl/vfs/pagecache.h b/src/oboskrnl/vfs/pagecache.h index a962f489..c842d741 100644 --- a/src/oboskrnl/vfs/pagecache.h +++ b/src/oboskrnl/vfs/pagecache.h @@ -31,6 +31,8 @@ static inline page* VfsH_PageCacheCreateEntry(vnode* vn, size_t offset) page* phys = MmH_PgAllocatePhysical(false, false); phys->backing_vn = vn; phys->file_offset = offset; + phys->file_offset -= (phys->file_offset % OBOS_PAGE_SIZE); + phys->end_offset = phys->file_offset + OBOS_PAGE_SIZE; RB_INSERT(pagecache_tree, &vn->cache, phys); driver_header* driver = Vfs_GetVnodeDriver(vn); if (!driver) return nullptr; diff --git a/src/oboskrnl/vfs/pipe.c b/src/oboskrnl/vfs/pipe.c index 34e27764..3be564d1 100644 --- a/src/oboskrnl/vfs/pipe.c +++ b/src/oboskrnl/vfs/pipe.c @@ -148,7 +148,7 @@ static obos_status write_sync(dev_desc desc, const void* buf, size_t blkCount, s else { OBOS_Kill(Core_GetCurrentThread(), Core_GetCurrentThread(), SIGPIPE); - return OBOS_STATUS_SUCCESS; + return OBOS_STATUS_PIPE_CLOSED; } } @@ -159,7 +159,11 @@ static obos_status write_sync(dev_desc desc, const void* buf, size_t blkCount, s const char* write_buf = buf; obos_status status = OBOS_STATUS_SUCCESS; while ((written_count += tmp) < blkCount && obos_is_success(status)) + { + if (Core_GetCurrentThread()->signal_info && Core_GetCurrentThread()->signal_info->pending & BIT(SIGPIPE-1)) + break; status = write_sync(desc, write_buf + written_count, (blkCount - written_count) % pipe->size, 0, &tmp); + } if (nBlkWritten) *nBlkWritten = written_count; return status; @@ -171,7 +175,9 @@ static obos_status write_sync(dev_desc desc, const void* buf, size_t blkCount, s pipe_ready_count(pipe, &ready_count); if ((pipe->size - ready_count) >= blkCount) break; - Core_WaitOnObject(WAITABLE_OBJECT(pipe->write_evnt)); + obos_status status = Core_WaitOnObject(WAITABLE_OBJECT(pipe->write_evnt)); + if (obos_is_error(status)) + return status; } pipe_write(pipe, buf, blkCount, nBlkWritten); @@ -436,8 +442,8 @@ obos_status Vfs_CreateNamedPipe(file_perm perm, gid group_uid, uid owner_uid, di dirent* ent = Vfs_Calloc(1, sizeof(dirent)); vnode* vn = Vfs_Calloc(1, sizeof(vnode)); desc->vn = vn; - vn->owner_uid = owner_uid; - vn->group_uid = group_uid; + vn->uid = owner_uid; + vn->gid = group_uid; vn->desc = (uintptr_t)desc; vn->perm = perm; vn->vtype = VNODE_TYPE_FIFO; diff --git a/src/oboskrnl/vfs/socket.c b/src/oboskrnl/vfs/socket.c index c4ead232..6d255377 100644 --- a/src/oboskrnl/vfs/socket.c +++ b/src/oboskrnl/vfs/socket.c @@ -113,6 +113,8 @@ static obos_status reference_device(dev_desc* pdesc) static obos_status unreference_device(dev_desc desc) { socket_desc* socket = (void*)desc; + if (!socket) + return OBOS_STATUS_INVALID_ARGUMENT; if (!(--socket->refs)) socket->ops->free(socket); return OBOS_STATUS_SUCCESS; @@ -558,4 +560,4 @@ void VfsH_InitializeSocketInterface() NetH_AddSocketBackend(&Net_TCPSocketBackend); NetH_AddSocketBackend(&Vfs_LocalDgramSocketBackend); NetH_AddSocketBackend(&Vfs_LocalStreamSocketBackend); -} \ No newline at end of file +} diff --git a/src/oboskrnl/vfs/tty.c b/src/oboskrnl/vfs/tty.c index b8c20cbb..bece653b 100644 --- a/src/oboskrnl/vfs/tty.c +++ b/src/oboskrnl/vfs/tty.c @@ -290,19 +290,19 @@ static obos_status tty_ioctl(dev_desc what, uint32_t request, void *argp) } case TTY_IOCTL_FLOW: switch (*(uint32_t*)argp) { - case TCION: + case TCOON: tty->paused = true; break; - case TCIOFF: + case TCOOFF: tty->paused = false; break; - case TCOOFF: + case TCIOFF: { char ch = tty->termios.iflag & IXON ? tty->termios.cc[VSTOP] : '\023' /* assume it is this */; tty->interface.write(tty, &ch, 1); break; } - case TCOON: + case TCION: { char ch = tty->termios.iflag & IXON ? tty->termios.cc[VSTART] : '\021' /* assume it is this */; tty->interface.write(tty, &ch, 1); @@ -439,29 +439,44 @@ static size_t strrfind(const char* str, char ch) return SIZE_MAX; } +static bool char_is_nl(tty* tty, char ch) +{ + return ch == '\n' || ch == '\r' || + (tty->termios.cc[VEOL] == ch && tty->termios.cc[VEOL]) || + (tty->termios.cc[VEOL2] == ch && tty->termios.cc[VEOL2]); +} + void erase_bytes(tty* tty, size_t nBytesToErase) { if (nBytesToErase == SIZE_MAX) nBytesToErase = tty->input_buffer.out_ptr % tty->input_buffer.size; for (size_t j = 0; j < nBytesToErase && tty->input_buffer.out_ptr > 0; j++) { + if (char_is_nl(tty, tty->input_buffer.buf[tty->input_buffer.out_ptr]) || char_is_nl(tty, tty->input_buffer.buf[tty->input_buffer.out_ptr-1])) + { + if (tty->input_buffer.buf[tty->input_buffer.out_ptr] != '\n' && tty->input_buffer.buf[tty->input_buffer.out_ptr-1] == '\n') + tty->input_buffer.out_ptr--; + if (tty->input_buffer.in_ptr > tty->input_buffer.out_ptr) + tty->input_buffer.in_ptr = tty->input_buffer.out_ptr; + break; + } if (tty->input_buffer.out_ptr == tty->input_buffer.in_ptr) tty->input_buffer.in_ptr--; tty->input_buffer.buf[tty->input_buffer.out_ptr-- % tty->input_buffer.size] = 0; - tty->interface.write(tty, "\b", 1); + tty->interface.write(tty, "\b \b", 3); } } static void tty_kill(tty* tty, int sigval) { - if (tty->termios.lflag & ISIG) - OBOS_KillProcessGroup(tty->fg_job, sigval); + OBOS_KillProcessGroup(tty->fg_job, sigval); } static void data_ready(void *tty_, const void *buf, size_t nBytesReady) { tty *tty = (struct tty *)tty_; const uint8_t *buf8 = buf; + bool inserted_any_bytes = false; for (size_t i = 0; i < nBytesReady; i++) { char ch = buf8[i]; @@ -520,6 +535,7 @@ static void data_ready(void *tty_, const void *buf, size_t nBytesReady) tty->quoted = false; if (!insert_byte) continue; + inserted_any_bytes = true; if (tty->termios.lflag & ECHO) tty_write_sync((dev_desc)tty, &ch, 1, 0, nullptr); if (tty->termios.lflag & ICANON) @@ -533,6 +549,8 @@ static void data_ready(void *tty_, const void *buf, size_t nBytesReady) toupper(ch & mask) : (ch & mask); } + if (!inserted_any_bytes) + return; if (tty->termios.lflag & ICANON) find_eol(tty, &tty->input_buffer.buf[(tty->input_buffer.out_ptr - 1) % tty->input_buffer.size]) == SIZE_MAX ? (void)0 : Core_EventSet(&tty->data_ready_evnt, true); else @@ -567,6 +585,7 @@ obos_status Vfs_RegisterTTY(const tty_interface *i, dirent **onode, bool pty) VNODE_TYPE_CHR); vn->flags |= VFLAGS_IS_TTY; vn->data = tty; + vn->gid = 5; // tty size_t index = pty ? last_pty_index++ : last_tty_index++; size_t szName = snprintf(nullptr, 0, "tty%ld", index); char *name = nullptr; @@ -641,7 +660,7 @@ static void poll_keyboard(struct screen_tty* data) while (1) { while (data->input_paused) - OBOSS_SpinlockHint(); + Core_Yield(); size_t nReady = 1; irp* req = VfsH_IRPAllocate(); req->vn = data->keyboard.vn; diff --git a/src/oboskrnl/vfs/vnode.h b/src/oboskrnl/vfs/vnode.h index d0475e83..537bc422 100644 --- a/src/oboskrnl/vfs/vnode.h +++ b/src/oboskrnl/vfs/vnode.h @@ -90,8 +90,8 @@ typedef struct vnode size_t refs; file_perm perm; size_t filesize; // filesize. - uid owner_uid; // the owner's UID. - gid group_uid; // the group's GID. + uid uid; // the owner's UID. + gid gid; // the group's GID. dev_desc desc; // the cached device descriptor. fd_list opened; size_t nMappedRegions; @@ -119,4 +119,7 @@ OBOS_EXPORT vnode* Drv_AllocateVNode(driver_id* drv, dev_desc desc, size_t files OBOS_EXPORT driver_header* Vfs_GetVnodeDriver(vnode* vn); // For files that can and can't have I/O on them (directories, symbolic links, FIFOs, regular files, CHR/BLK devices, and sockets) OBOS_EXPORT driver_header* Vfs_GetVnodeDriverStat(vnode* vn); -OBOS_EXPORT struct mount* Vfs_GetVnodeMount(vnode* vn); \ No newline at end of file +OBOS_EXPORT struct mount* Vfs_GetVnodeMount(vnode* vn); + +OBOS_EXPORT obos_status Vfs_Access(vnode* vn, bool read, bool write, bool exec); +OBOS_EXPORT obos_status Vfs_AccessAs(uid asUid, gid asGid, vnode* vn, bool read, bool write, bool exec); \ No newline at end of file diff --git a/src/uACPI/CMakeLists.txt b/src/uACPI/CMakeLists.txt index 72b4b86a..abb3f543 100644 --- a/src/uACPI/CMakeLists.txt +++ b/src/uACPI/CMakeLists.txt @@ -23,11 +23,13 @@ if (OBOS_ENABLE_PROFILER) target_compile_options(uacpi PRIVATE $<$:-finstrument-functions>) endif() +if (OBOS_ENABLE_FANALYZER) + target_compile_options(uacpi PRIVATE "-fno-analyzer") +endif() + # All symbols exported, except for the kernel api of course. set_source_files_properties("kernel_api.c" PROPERTIES COMPILE_OPTIONS "-fvisibility=hidden") -message(${OBOSKRNL_EXTERNAL_INCLUDES}) - target_include_directories(uacpi PRIVATE "${CMAKE_SOURCE_DIR}/src/oboskrnl") target_include_directories(uacpi PRIVATE "${CMAKE_SOURCE_DIR}/src/sanitizers") target_include_directories(uacpi PRIVATE ${OBOSKRNL_EXTERNAL_INCLUDES}) diff --git a/src/uACPI/kernel_api.c b/src/uACPI/kernel_api.c index b8f77090..5f9a65c7 100644 --- a/src/uACPI/kernel_api.c +++ b/src/uACPI/kernel_api.c @@ -571,7 +571,7 @@ uacpi_status uacpi_kernel_get_rsdp(uacpi_phys_addr* out) { uintptr_t rsdp = 0; #ifdef __x86_64__ - rsdp = Arch_LdrPlatformInfo->acpi_rsdp_address; + rsdp = Arch_RSDPBase; #endif *out = rsdp; return UACPI_STATUS_OK; diff --git a/src/uHDA/hdadev.c b/src/uHDA/hdadev.c index 060a6aa1..c0ce2efa 100644 --- a/src/uHDA/hdadev.c +++ b/src/uHDA/hdadev.c @@ -264,7 +264,8 @@ void fd_fill_worker(void* user) struct fd_fill_userdata *udata = user; while (!udata->request_thread_kill) { - Core_WaitOnObject(WAITABLE_OBJECT(udata->wake_thr)); + if (obos_is_error(Core_WaitOnObject(WAITABLE_OBJECT(udata->wake_thr)))) + break; Core_EventClear(&udata->wake_thr); if (udata->request_thread_kill) break; diff --git a/src/uHDA/kernel_api.c b/src/uHDA/kernel_api.c index 6f5683be..54bcffc4 100644 --- a/src/uHDA/kernel_api.c +++ b/src/uHDA/kernel_api.c @@ -157,6 +157,7 @@ static void* map_registers(uintptr_t phys, size_t size, bool uc) page.phys = phys+offset; MmS_SetPageMapping(Mm_KernelContext.pt, &page, phys + offset, false); } + Drv_TLBShootdown(Mm_KernelContext.pt, (uintptr_t)virt, size); return virt+phys_page_offset; } diff --git a/src/user-utilities/CMakeLists.txt b/src/user-utilities/CMakeLists.txt index df2357a9..eb538c32 100644 --- a/src/user-utilities/CMakeLists.txt +++ b/src/user-utilities/CMakeLists.txt @@ -29,10 +29,14 @@ add_executable (lsmod "lsmod.c") add_executable (ldmod "ldmod.c") add_executable (stmod "stmod.c") add_executable (rmmod "rmmod.c") -install(TARGETS powerctl klog-level fork-test mem-usage mount umount swapon mkswap sync-anon lsmod ldmod stmod rmmod) +add_executable (login "login.c") +target_link_libraries(login crypt) +install(TARGETS powerctl klog-level fork-test mem-usage mount umount swapon mkswap sync-anon) +install(TARGETS lsmod ldmod stmod rmmod login DESTINATION sbin) if (${OBOS_ARCHITECTURE} STREQUAL "x86_64") add_executable(obos-gettime "x86_obos-gettime.c") add_executable(enable-kgdbstub "x86_enable-kgdbstub.c") - install(TARGETS obos-gettime enable-kgdbstub) + install(TARGETS obos-gettime) + install(TARGETS enable-kgdbstub DESTINATION sbin) endif() diff --git a/src/user-utilities/login.c b/src/user-utilities/login.c new file mode 100644 index 00000000..f7dd3646 --- /dev/null +++ b/src/user-utilities/login.c @@ -0,0 +1,271 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if __obos__ +#include +#endif + +char g_hostname[32]; + +static char* readline() +{ + char* buf = NULL; + size_t size = 0; + while (1) + { + char ch = getchar(); + if (ch == '\n') + break; + buf = realloc(buf, ++size); + buf[size-1] = ch; + } + buf = realloc(buf, size + 1); + buf[size] = 0; + return buf; +} + +static void prompt(char** ousername, char** opassword) +{ + struct termios tc = {}; + tcgetattr(0, &tc); + tc.c_lflag |= ECHO; + tc.c_iflag |= ICRNL; + tcsetattr(0, 0, &tc); + + retry_uname_prompt: + fprintf(stderr, "%.*s login: ", (int)sizeof(g_hostname), g_hostname); + *ousername = readline(); + if (!strlen(*ousername)) + { + free(*ousername); + goto retry_uname_prompt; + } + fprintf(stderr, "%s password: ", *ousername); + struct termios old_tc = tc; + tc.c_lflag &= ~ECHO; + tc.c_lflag |= ECHONL; + tcsetattr(0, 0, &tc); + *opassword = readline(); + tcsetattr(0, 0, &old_tc); +} + +#define invalid_pwd_timeout (5) +#define invalid_pwd_msg "Invalid username or password" + +static int login(char* username, char* password, struct passwd** ouser) +{ + struct passwd* user = getpwnam(username); + if (!user) + return 0; + + // Check password + if (strcmp(user->pw_passwd, "x") == 0) + { + struct spwd* ent = getspnam(user->pw_name); + if (!ent) + { + endspent(); + if (errno == 0) + return 1; // authenticated + else + { + perror("getspnam"); + return 0; + } + } + if (strlen(ent->sp_pwdp) == 0) + { + endspent(); + goto success; + } + // Verify password. + // NOTE: If the user account cannot be signed in using a password, + // then this code will still be able to handle that, as ent->sp_pwdp + // would be invalid. + char* hash = crypt(password, ent->sp_pwdp); + if (!hash) + { + perror("crypt_ra"); + return 0; + } + if (strcmp(hash, ent->sp_pwdp) == 0) + { + endspent(); + goto success; + } + endspent(); + return 0; + } + else + { + if (strcmp(user->pw_passwd, password) == 0) + goto success; + return 0; + } + + success: + + *ouser = user; + return 1; +} + +int do_waitpid(int child) +{ + int status = 0; + do { + if (waitpid(child, &status, 0) == 0) + break; + switch (errno) { + case EINTR: + errno = 0; + continue; + case ECHILD: + break; + case 0: + break; + default: + status = -1; + perror("waitpid"); + continue; + } + break; + } while(1); + return status; +} + +int main() +{ + if (geteuid() != 0) + { + fprintf(stderr, "FATAL: euid != 0\n"); + return -1; + } + + signal(SIGINT, SIG_IGN); + signal(SIGTSTP, SIG_IGN); + + gethostname(g_hostname, sizeof(g_hostname)); + + while (1) + { + char* username = NULL; + char* password = NULL; + prompt(&username, &password); + + struct passwd* user = NULL; + + if (!login(username, password, &user)) + { + sleep(invalid_pwd_timeout); + puts(invalid_pwd_msg); + free(username); + memset(password, 0xde, strlen(password)); +#if __obos__ + // Make sure the cleared password is noted in the swap. + // Note: Ideally we would not have the password on swap at all. + // (TODO) + syscall0(Sys_SyncAnonPages); +#endif + free(password); + continue; + } + + free(username); + memset(password, 0xde, strlen(password)); +#if __obos__ + // Make sure the cleared password is noted in the swap. + // Ideally we would not have the password on swap at all. + // (TODO) + syscall0(Sys_SyncAnonPages); +#endif + free(password); + + int child = fork(); + if (child == 0) + { + // TODO: Session IDs? + // TODO: Parse /etc/environment + + if (setresgid(user->pw_gid, user->pw_gid, user->pw_gid) != 0) + { + perror("setresgid"); + exit(-1); + } + + int ngroups = 0; + gid_t* groups = 0; + getgrouplist(user->pw_name, user->pw_gid, groups, &ngroups); + groups = calloc(ngroups, sizeof(gid_t)); + getgrouplist(user->pw_name, user->pw_gid, groups, &ngroups); + + setgroups(0, NULL); + int ret = setgroups(ngroups, groups); + if (ret == -1) + { + switch (errno) { + case ENOSYS: + break; + default: + perror("setgroups"); + return -1; + } + } + + if (setresuid(user->pw_uid, user->pw_uid, user->pw_uid) != 0) + { + perror("setresuid"); + exit(-1); + } + + const char* term = getenv("TERM"); + clearenv(); + setenv("HOME", user->pw_dir, 1); + setenv("TERM", term, 1); + setenv("SHELL", user->pw_shell, 1); + setenv("USER", user->pw_name, 1); + setenv("LOGNAME", user->pw_name, 1); + // Sensible value? + if (user->pw_uid == 0) + setenv("PATH", "/usr/local/bin:/usr/bin:/usr/sbin", 1); + else + setenv("PATH", "/usr/local/bin:/usr/bin:/usr/local/games:/usr/games", 1); + char* argv[3] = { user->pw_shell, NULL, NULL }; + if (strcmp(basename(user->pw_shell), "bash") == 0) + argv[1] = "--login"; + + if (chdir(user->pw_dir) == -1) + { + perror("chdir(user->pw_dir)"); + return -1; + } + + execvp(user->pw_shell, argv); + + perror("execvp"); + return -1; + } + else + { + if (do_waitpid(child) == 0) + // god forgive me + system("reset"); + else + continue; + } + } + + return 0; +} \ No newline at end of file diff --git a/src/user-utilities/x86_enable-kgdbstub.c b/src/user-utilities/x86_enable-kgdbstub.c index ab27937f..f09f8b47 100644 --- a/src/user-utilities/x86_enable-kgdbstub.c +++ b/src/user-utilities/x86_enable-kgdbstub.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include