diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index fea26ac..ffa131c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -14,11 +14,11 @@ jobs: - name: Install apt packages run: | sudo apt update - sudo apt install clang lld llvm grub-efi-amd64-bin mtools + sudo apt install clang lld llvm grub-efi-amd64-bin mtools meson ninja-build - name: Build ModulOS run: | - make -j$(nproc) build + make build - name: Run test suite run: | diff --git a/LICENSES/ACPICA b/LICENSES/ACPICA deleted file mode 100644 index 1937727..0000000 --- a/LICENSES/ACPICA +++ /dev/null @@ -1,187 +0,0 @@ -The ACPICA source code has been modified in the following ways on January 9th 2026: -* The platform/acmodulos.h file as been added, heavily based on platform/aclinux.h and platform/aclinuxex.h -* The platform/acenv.h file now includes platform/acmodulos.h - -Most of ACPICA is under the following license: - -1. Copyright Notice - -Some or all of this work - Copyright (c) 1999 - 2025, Intel Corp. -All rights reserved. - -2. License - -2.1. This is your license from Intel Corp. under its intellectual property -rights. You may have additional license terms from the party that provided -you this software, covering your right to use that party's intellectual -property rights. - -2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a -copy of the source code appearing in this file ("Covered Code") an -irrevocable, perpetual, worldwide license under Intel's copyrights in the -base code distributed originally by Intel ("Original Intel Code") to copy, -make derivatives, distribute, use and display any portion of the Covered -Code in any form, with the right to sublicense such rights; and - -2.3. Intel grants Licensee a non-exclusive and non-transferable patent -license (with the right to sublicense), under only those claims of Intel -patents that are infringed by the Original Intel Code, to make, use, sell, -offer to sell, and import the Covered Code and derivative works thereof -solely to the minimum extent necessary to exercise the above copyright -license, and in no event shall the patent license extend to any additions -to or modifications of the Original Intel Code. No other license or right -is granted directly or by implication, estoppel or otherwise; - -The above copyright and patent license is granted only if the following -conditions are met: - -3. Conditions - -3.1. Redistribution of Source with Rights to Further Distribute Source. -Redistribution of source code of any substantial portion of the Covered -Code or modification with rights to further distribute source must include -the above Copyright Notice, the above License, this list of Conditions, -and the following Disclaimer and Export Compliance provision. In addition, -Licensee must cause all Covered Code to which Licensee contributes to -contain a file documenting the changes Licensee made to create that Covered -Code and the date of any change. Licensee must include in that file the -documentation of any changes made by any predecessor Licensee. Licensee -must include a prominent statement that the modification is derived, -directly or indirectly, from Original Intel Code. - -3.2. Redistribution of Source with no Rights to Further Distribute Source. -Redistribution of source code of any substantial portion of the Covered -Code or modification without rights to further distribute source must -include the following Disclaimer and Export Compliance provision in the -documentation and/or other materials provided with distribution. In -addition, Licensee may not authorize further sublicense of source of any -portion of the Covered Code, and must include terms to the effect that the -license from Licensee to its licensee is limited to the intellectual -property embodied in the software Licensee provides to its licensee, and -not to intellectual property embodied in modifications its licensee may -make. - -3.3. Redistribution of Executable. Redistribution in executable form of any -substantial portion of the Covered Code or modification must reproduce the -above Copyright Notice, and the following Disclaimer and Export Compliance -provision in the documentation and/or other materials provided with the -distribution. - -3.4. Intel retains all right, title, and interest in and to the Original -Intel Code. - -3.5. Neither the name Intel nor any other trademark owned or controlled by -Intel shall be used in advertising or otherwise to promote the sale, use or -other dealings in products derived from or relating to the Covered Code -without prior written authorization from Intel. - -4. Disclaimer and Export Compliance - -4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED -HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE -IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, -INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY -UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY -IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A -PARTICULAR PURPOSE. - -4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES -OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR -COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, -SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY -CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL -HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS -SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY -LIMITED REMEDY. - -4.3. Licensee shall not export, either directly or indirectly, any of this -software or system incorporating such software without first obtaining any -required license or other approval from the U. S. Department of Commerce or -any other agency or department of the United States Government. In the -event Licensee exports any such software from the United States or -re-exports any such software from a foreign destination, Licensee shall -ensure that the distribution and export/re-export of the software is in -compliance with all laws, regulations, orders, or other restrictions of the -U.S. Export Administration Regulations. Licensee agrees that neither it nor -any of its subsidiaries will export/re-export any technical data, process, -software, or service, directly or indirectly, to any country for which the -United States government or any agency thereof requires an export license, -other governmental approval, or letter of assurance, without first obtaining -such license, approval or letter. - -*************************************************************************** - -Submitting Contributions to ACPICA: -Any contribution (including patches, bug fixes, improvements, or new features) -submitted to the ACPICA project is governed by the “simplified” BSD license -reproduced below. Contributions to ACPICA are accepted under this license in -order to preserve ACPICA’s ability to license ACPICA under all three of the -licenses described above. The way to submit patches and/or bug reports or -fixes is by creating the appropriate ticket (Issue, PR) on our GitHub page. - -License for Contributions to ACPICA: -Copyright © 2000 – 2025 Intel Corp. -All rights reserved. - -Alternatively, you may choose to be licensed under the terms of the -following license: - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions, and the following disclaimer, - without modification. -2. Redistributions in binary form must reproduce at minimum a disclaimer - substantially similar to the "NO WARRANTY" disclaimer below - ("Disclaimer") and any redistribution must be conditioned upon - including a substantially similar Disclaimer requirement for further - binary redistribution. -3. Neither the names of the above-listed copyright holders nor the names - of any contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -Alternatively, you may choose to be licensed under the terms of the -GNU General Public License ("GPL") version 2 as published by the Free -Software Foundation. - ----------------------------------- -tests/misc/grammar.asl is under the following license: - -Some or all of this work - Copyright (c) 2006 - 2025, Intel Corp. -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, -this list of conditions and the following disclaimer. -Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. -Neither the name of Intel Corporation nor the names of its contributors -may be used to endorse or promote products derived from this software -without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, -EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/LICENSES/MLIBC b/LICENSES/MLIBC new file mode 100644 index 0000000..16ab10b --- /dev/null +++ b/LICENSES/MLIBC @@ -0,0 +1,45 @@ +Copyright (C) 2015-2025 mlibc Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +---- + +Some parts of mlibc are adapted from musl (http://www.musl-libc.org/), which +is licensed as follows: + +Copyright © 2005-2020 Rich Felker, et al. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Makefile b/Makefile index 1dc75bb..3a4a4f4 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ #export DEBUG = 1 export DEBUG_LOGGING = 1 export SMP_ENABLE = 1 +#export CHECK_ALLOC = 1 # Global options @@ -83,7 +84,11 @@ COPY_DRIVERS_TO := $(OBJ_DIR)/rootfs/lib/drivers/ COPY_USERLAND_TO := $(OBJ_DIR)/rootfs/ -SRC := $(shell find . -type f \( -name "*.c" -o -name "*.S" -o -name "*.h" \)) +SRC_FIND := find . \ + \( -path './userland/mlibc' -o -path './build' \) -prune \ + -o -type f \( -name "*.c" -o -name "*.S" -o -name "*.h" \) -print + +SRC := $(shell $(SRC_FIND)) include $(SRC_TREE_ROOT)/scripts/Makefile.kcflags @@ -95,11 +100,12 @@ all: index build test-all .PHONY: index index: cscope.files - ctags --C-kinds=+pxzL -R $(SRC) - cscope -q -R -b -i cscope.files + ctags --C-kinds=+pxzL -L $< + cscope -b -q -i $< .PHONY: clean clean: + $(MAKE) -C userland clean -rm -rd $(OBJ_DIR)/ tags cscope.* .PHONY: test-all @@ -114,7 +120,7 @@ $(SUBDIRS): $(MAKE) -C $@ build cscope.files: $(SRC) - find . -type f \( -name "*.c" -o -name "*.S" -o -name "*.h" \) > $@ + $(SRC_FIND) > $@ %/: -mkdir -p $@ @@ -132,15 +138,15 @@ $(TEST_EXEC): %: %.a $(OBJ_DIR)/boot.a $(OBJ_DIR)/kernel.a $(OBJ_DIR)/drivers.a .PHONY: copy-doc copy-doc: COPYING LICENSES | $(COPY_DOC_TO) - cp -r $^ $| + cp -u -r $^ $| .PHONY: copy-runtime-drivers copy-runtime-drivers: $(RUNTIME_DRIVERS_TARGETS) | $(COPY_DRIVERS_TO) - cp -r $^ $| + cp -u -r $^ $| .PHONY: copy-userland copy-userland: $(USERLAND_TARGETS) | $(COPY_USERLAND_TO) - cp -r $^/* $| + cp -u -r $^/* $| $(OBJ_DIR)/stub.img: | $(OBJ_DIR)/ truncate -s 4G $@ diff --git a/README b/README index cbce485..36733a6 100644 --- a/README +++ b/README @@ -3,7 +3,8 @@ An operating system that aims to be customizable and modular to provide a fast u ## Licensing -This software is provided under the GPLv3 license, found in COPYING. This software also contains third party source code with their own licenses, all found under LICENSES/ +This software is provided under the GPLv3 license, found in COPYING. This project also uses +mlibc which has a seperate license in LICENCES/MLIBC. ## Installing diff --git a/boot/multiboot2/boot.S b/boot/multiboot2/boot.S index 8dc2eba..c8a8f77 100644 --- a/boot/multiboot2/boot.S +++ b/boot/multiboot2/boot.S @@ -50,7 +50,7 @@ #define CPUID_LONGMODE 0x80000001 #define CPUID_LONGMODE_EXIST 0x20000000 -#define PAEPSE 0x30 +#define PAEPSE 0x30 #define EFER 0xC0000080 #define LME 0x100 diff --git a/boot/multiboot2/init.c b/boot/multiboot2/init.c index 2a762bf..b53a244 100644 --- a/boot/multiboot2/init.c +++ b/boot/multiboot2/init.c @@ -26,6 +26,8 @@ #include #include +#include + #include #ifdef SERIAL @@ -142,6 +144,8 @@ static void next_segment(uint64_t* handle, struct mem_segment_t* seg) { void multiboot2_init(struct mb2_info_t* info) { + kmemset(&bsp_proc_data, 0, sizeof(struct proc_data_t)); + bsp_proc_data_ptr = &bsp_proc_data; proc_data_ptr = &bsp_proc_data_ptr; proc_data_set_id(0); diff --git a/drivers/ext2/ext2.c b/drivers/ext2/ext2.c index cedee64..dd71869 100644 --- a/drivers/ext2/ext2.c +++ b/drivers/ext2/ext2.c @@ -527,6 +527,14 @@ static enum file_status_t ext2_stat(struct file_handle_t* handle, struct file_in return FILE_OK; } +static uint64_t ext2_get_seek(struct file_handle_t* handle) { + struct ext2_inode_handle_t* inode_handle = (struct ext2_inode_handle_t*)handle; + const struct ext2_superblock_t* superblock = inode_handle->ext2->superblock; + const uint64_t block_size = 1024u << superblock->s_log_block_size; + + return inode_handle->seek_block * block_size + inode_handle->seek; +} + static size_t ext2_read(struct file_handle_t* handle, void* buffer, size_t count) { struct ext2_inode_t inode; struct ext2_inode_handle_t* inode_handle = (struct ext2_inode_handle_t*)handle; @@ -545,6 +553,11 @@ static size_t ext2_read(struct file_handle_t* handle, void* buffer, size_t count uint64_t index; uint64_t write_seek = 0; size_t write_len; + uint64_t full_seek = ext2_get_seek(handle); + + if (full_seek > size) { + return 0; + } while (count) { track.block = inode_handle->seek_block; @@ -575,6 +588,12 @@ static size_t ext2_read(struct file_handle_t* handle, void* buffer, size_t count return read; } + if (write_len + full_seek > size) { + // full block read, but only copy up to limit of the file + write_len = size - full_seek; + count = 0; + } + kmemcpy((uint8_t*)buffer + write_seek, block_buffer + inode_handle->seek, write_len); kfree(block_buffer); @@ -587,6 +606,7 @@ static size_t ext2_read(struct file_handle_t* handle, void* buffer, size_t count } write_seek += write_len; + full_seek += write_len; inode_handle->seek += write_len; count -= write_len; read += write_len; @@ -600,14 +620,6 @@ static size_t ext2_read(struct file_handle_t* handle, void* buffer, size_t count return read; } -static uint64_t ext2_get_seek(struct file_handle_t* handle) { - struct ext2_inode_handle_t* inode_handle = (struct ext2_inode_handle_t*)handle; - const struct ext2_superblock_t* superblock = inode_handle->ext2->superblock; - const uint64_t block_size = 1024u << superblock->s_log_block_size; - - return inode_handle->seek_block * block_size + inode_handle->seek; -} - static enum file_status_t ext2_seek(struct file_handle_t* handle, uint64_t seek) { struct ext2_inode_handle_t* inode_handle = (struct ext2_inode_handle_t*)handle; const struct ext2_superblock_t* superblock = inode_handle->ext2->superblock; @@ -619,6 +631,13 @@ static enum file_status_t ext2_seek(struct file_handle_t* handle, uint64_t seek) return FILE_OK; } +static size_t ext2_write(struct file_handle_t* handle, void* buffer, size_t count) { + (void)handle; + (void)buffer; + (void)count; + return 0; +} + uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_lba) { struct ext2_superblock_t* superblock = kmalloc(sizeof(struct ext2_superblock_t)); struct ext2_bg_desc_t* bgdt; @@ -673,7 +692,8 @@ uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_ ext2_stat, ext2_read, ext2_get_seek, - ext2_seek + ext2_seek, + ext2_write ) != FILE_OK) { logging_log_error("Failed to mount rootfs"); panic(PANIC_STATE); @@ -698,18 +718,18 @@ uint8_t ext2_attempt_init(struct disk_t* disk, uint64_t start_lba, uint64_t end_ } - struct fs_handle_t* test_file = fs_open("/test"); - if (!test_file) { - logging_log_error("Failed to open test file"); + struct fs_handle_t* shell = fs_open("/bin/shell"); + if (!shell) { + logging_log_error("Failed to open shell file"); } else { - struct pcb_t* test_pcb = elf_load(test_file, process_assign_pid()); - if (!test_pcb) { - logging_log_error("Failed to load test file"); + struct pcb_t* shell_pcb = elf_load(shell, process_assign_pid(), "/bin/shell ModulOS", "USER=root PWD=/"); + if (!shell_pcb) { + logging_log_error("Failed to load shell file"); } - fs_close(test_file); + fs_close(shell); - scheduler_schedule(test_pcb); + scheduler_schedule(shell_pcb); } } diff --git a/drivers/include/serial/interrupts.h b/drivers/include/serial/interrupts.h new file mode 100644 index 0000000..033c5c8 --- /dev/null +++ b/drivers/include/serial/interrupts.h @@ -0,0 +1,27 @@ +/* interrupts.h - serial interrupts interface */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#ifndef DRIVERS_SERIAL_INTERRUPTS_H +#define DRIVERS_SERIAL_INTERRUPTS_H + +#include + +extern void serial_init_interrupts(void); + +extern void serial_isr_dispatch(uint16_t com); + +#endif /* DRIVERS_SERIAL_INTERRUPTS_H */ diff --git a/drivers/include/serial/serial.h b/drivers/include/serial/serial.h index bd60bbd..9319f7d 100644 --- a/drivers/include/serial/serial.h +++ b/drivers/include/serial/serial.h @@ -15,8 +15,8 @@ * along with this program. If not, see */ -#ifndef DRIVERS_SERIAL_SERIAL -#define DRIVERS_SERIAL_SERIAL +#ifndef DRIVERS_SERIAL_SERIAL_H +#define DRIVERS_SERIAL_SERIAL_H #include @@ -26,4 +26,7 @@ extern void serial_init_com2(void); extern void serial_write_com1(uint8_t b); extern void serial_write_com2(uint8_t b); -#endif /* DRIVERS_SERIAL_SERIAL */ +extern void serial_isr_com1(void); +extern void serial_isr_com2(void); + +#endif /* DRIVERS_SERIAL_SERIAL_H */ diff --git a/drivers/serial/interrupts.c b/drivers/serial/interrupts.c new file mode 100644 index 0000000..fae9540 --- /dev/null +++ b/drivers/serial/interrupts.c @@ -0,0 +1,87 @@ +/* interrupts.c - serial interrupts handler */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +#define COM1_IRQ 4 +#define COM2_IRQ 3 + +#define COM1 0x3F8 +#define COM2 0x2F8 + +#define READ 0 +#define LSR 5 + +#define DR_MASK 1 + +void serial_init_interrupts(void) { + uint8_t com1_v = idt_get_vector(); + uint8_t com2_v = idt_get_vector(); + + idt_install(com1_v, (uint64_t)serial_isr_com1, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); + idt_install(com2_v, (uint64_t)serial_isr_com2, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); + + ioapic_conf_gsi( + ioapic_routing_legacy_gsi(COM1_IRQ), + com1_v, + IOAPIC_REDIR_TRG_EDG | IOAPIC_REDIR_POL_HI, + 0); + + ioapic_conf_gsi( + ioapic_routing_legacy_gsi(COM2_IRQ), + com2_v, + IOAPIC_REDIR_TRG_EDG | IOAPIC_REDIR_POL_HI, + 0); +} + +void serial_isr_dispatch(uint16_t com) { + struct tty_handle_t* tty; + + switch (com) { + case COM1: + tty = tty_com1(); + break; + case COM2: + tty = tty_com2(); + break; + default: + goto cleanup; + } + + //TODO: handle serial errors + while (inb(com + LSR) & DR_MASK) { + tty_queue_read(tty, inb(com + READ)); + io_wait(); + } + +cleanup: + apic_write_reg(APIC_REG_EOI, APIC_EOI); +} diff --git a/drivers/serial/serial.S b/drivers/serial/serial.S index cc8b1e2..899b8d3 100644 --- a/drivers/serial/serial.S +++ b/drivers/serial/serial.S @@ -36,15 +36,13 @@ #define F_EN 0x01 #define F_CLTR 0x06 // clear trms & recv #define F_SNGL 0x00 -#define F_INT1B 0x00 //TODO: maybe increase thresh +#define F_INT1B 0x00 #define DTR 0x01 #define RTS 0x02 #define OUT1 0x04 #define OUT2 0x08 -//TODO: test ports via loopback - .section .text .globl serial_init_com1 @@ -86,7 +84,7 @@ movb $(DTR + RTS + OUT1 + OUT2), %al lea MCR(%rdi), %rdx out %al, %dx -mov INT_EN, %al +movb $INT_EN, %al lea IER(%rdi), %rdx out %al, %dx @@ -105,3 +103,73 @@ mov $(COM2 + TRSM), %dx movb %dil, %al out %al, %dx ret + +.globl serial_isr_com1 +serial_isr_com1: + +pushq %rax +pushq %rcx +pushq %rdx +pushq %rsi +pushq %rdi +pushq %r8 +pushq %r9 +pushq %r10 +pushq %r11 + +movq $COM1, %rdi + +pushq %rbp + +movq %rsp, %rbp +movq %rsp, %rax +andq $0xF, %rax +jz dispatch_isr +subq %rax, %rsp +jmp dispatch_isr + + +.globl serial_isr_com2 +serial_isr_com2: + +pushq %rax +pushq %rcx +pushq %rdx +pushq %rsi +pushq %rdi +pushq %r8 +pushq %r9 +pushq %r10 +pushq %r11 + +movq $COM2, %rdi + +pushq %rbp + +movq %rsp, %rbp +movq %rsp, %rax +andq $0xF, %rax +jz dispatch_isr +subq %rax, %rsp +jmp dispatch_isr + + +dispatch_isr: +.extern serial_isr_dispatch +call serial_isr_dispatch + +movq %rbp, %rsp + +popq %rbp + +popq %r11 +popq %r10 +popq %r9 +popq %r8 +popq %rdi +popq %rsi +popq %rdx +popq %rcx +popq %rax + +iretq diff --git a/kernel/Makefile b/kernel/Makefile index c95b483..f32a7d5 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -25,6 +25,7 @@ $(call add_directory,apic,APIC) $(call add_directory,ioapic,IOAPIC) $(call add_directory,pic_8259,PIC_8259) $(call add_directory,acpi,ACPI) +$(call add_directory,devfs,DEVFS) ifdef BUILD_KERNEL_GRAPHICSBASE $(call add_directory,graphicsbase,GRAPHICSBASE) diff --git a/kernel/apic/apic_init.c b/kernel/apic/apic_init.c index aac77e5..85817b9 100644 --- a/kernel/apic/apic_init.c +++ b/kernel/apic/apic_init.c @@ -40,6 +40,7 @@ #include #include +#include #define APIC_BASE_MASK 0xFFFFFFFFFF000 @@ -68,7 +69,7 @@ #define APIC_CAL_BATCH 20 #define APIC_CAL_TOL 8000 -#define APIC_CLOCK_MS 50 +#define APIC_CLOCK_MS 10 // pic master spurious (irq 7, int 0x27) works for apic spurious as well #define PIC_SPURIOUS_VEC 0x27 @@ -124,8 +125,6 @@ void apic_init(void) { idt_install(timer_vector, (uint64_t)apic_isr_timer, GDT_CODE_SEL, IST_SCHED, IDT_GATE_TRP, 0); idt_install(error_vector, (uint64_t)apic_isr_error, GDT_CODE_SEL, 0, IDT_GATE_TRP, 0); - apic_init_shootdowns(num_apic); - apic_init_ap(); // init stacks @@ -141,6 +140,7 @@ void apic_init(void) { for (--num_apic; num_apic; num_apic--) { proc_data_ptr[num_apic] = kmalloc(sizeof(struct proc_data_t)); + kmemset(proc_data_ptr[num_apic], 0, sizeof(struct proc_data_t)); init_stacks_vaddr[num_apic] = mm_alloc_v(PAGE_SIZE_4K * 5); if (!init_stacks_vaddr[num_apic]) { @@ -288,7 +288,7 @@ void apic_init_ap(void) { apic_write_lve(APIC_REG_ERE, error_vector, APIC_LVT_MT_FIXED | APIC_LVT_TRG_EDGE, 0); - apic_register_barrier(apic_id); + mm_register_barrier(apic_id); // enable apic apic_write_reg(APIC_REG_ESR, 0); diff --git a/kernel/apic/ipi.c b/kernel/apic/ipi.c index 68dd5e8..04b69b5 100644 --- a/kernel/apic/ipi.c +++ b/kernel/apic/ipi.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include @@ -37,42 +39,20 @@ #define ICR_PID_SHFT 24 -static uint8_t tlb_shootdown_lock; -static uint8_t* registered_barrier; -static volatile uint8_t* tlb_shootdown_barrier = 0; static uint8_t tlb_shootdown_vector; -static uint8_t barrier_len; -static volatile uint64_t tlb_shootdown_addr; +uint8_t shootdown_enable = 0; struct shootdown_node_t { struct shootdown_node_t* next; uint8_t apic_id; }; -static struct shootdown_node_t* shootdown_list; - static uint8_t ipi_lock; void apic_ipi_init(void) { lock_init(&ipi_lock); } -void apic_init_shootdowns(uint8_t num_apic) { - lock_init(&tlb_shootdown_lock); - - registered_barrier = kmalloc(sizeof(uint8_t) * num_apic); - - kmemset(registered_barrier, 0, sizeof(uint8_t) * num_apic); - shootdown_list = 0; - - tlb_shootdown_barrier = kmalloc(sizeof(uint8_t) * num_apic); - barrier_len = num_apic; - - tlb_shootdown_vector = idt_get_vector(); - - idt_install(tlb_shootdown_vector, (uint64_t)apic_isr_tlb_shootdown, GDT_CODE_SEL, 0, IDT_GATE_INT, 0); -} - void apic_wait_for_ipi(void) { while (apic_read_reg(APIC_REG_ICL) & ICR_DS) { cpu_pause(); @@ -103,64 +83,38 @@ void apic_send_ipi_sipi(uint8_t apic_id) { lock_release(&ipi_lock); } -static inline uint8_t check_barrier(volatile uint8_t* barrier) { - uint8_t i; - for (i = 0; i < barrier_len; i++) { - if (barrier[i]) { - return 1; - } - } +void apic_init_shootdowns(void) { + tlb_shootdown_vector = idt_get_vector(); - return 0; + idt_install(tlb_shootdown_vector, (uint64_t)apic_isr_tlb_shootdown, GDT_CODE_SEL, 0, IDT_GATE_INT, 0); + + shootdown_enable = 1; } -void apic_tlb_shootdown(uint64_t vaddr) { - struct shootdown_node_t* node; - if (!tlb_shootdown_barrier) { +void apic_shootdown(uint8_t id) { + if (!shootdown_enable) { return; } - lock_acquire(&tlb_shootdown_lock); - - uint8_t i; - for (i = 0; i < barrier_len; i++) { - tlb_shootdown_barrier[i] = registered_barrier[i]; - } - - tlb_shootdown_addr = vaddr; - - - for (node = shootdown_list; node; node = node->next) { - lock_acquire(&ipi_lock); - apic_wait_for_ipi(); - apic_wait_for_ipi(); - apic_write_reg(APIC_REG_ICH, (uint32_t)node->apic_id << ICR_PID_SHFT); - apic_write_reg(APIC_REG_ICL, tlb_shootdown_vector | ICR_ASSERT); - lock_release(&ipi_lock); - } - - while (check_barrier(tlb_shootdown_barrier)) cpu_pause(); - - lock_release(&tlb_shootdown_lock); + lock_acquire(&ipi_lock); + apic_wait_for_ipi(); + apic_wait_for_ipi(); + apic_write_reg(APIC_REG_ICH, (uint32_t)id << ICR_PID_SHFT); + apic_write_reg(APIC_REG_ICL, tlb_shootdown_vector | ICR_ASSERT); + lock_release(&ipi_lock); } void apic_tlb_shootdown_dispatch(void) { - cpu_invlpg(tlb_shootdown_addr); + uint64_t off; + struct free_transaction_list_t* list; - tlb_shootdown_barrier[proc_data_get()->arb_id] = 0; - - apic_write_reg(APIC_REG_EOI, APIC_EOI); -} - -void apic_register_barrier(uint8_t apic_id) { - struct shootdown_node_t* node = kmalloc(sizeof(struct shootdown_node_t)); - node->apic_id = apic_id; - - lock_acquire(&tlb_shootdown_lock); + for (list = mm_get_shootdown_list(); list; list = list->next) { + for (off = 0; off < list->size; off += PAGE_SIZE_4K) { + cpu_invlpg(list->base + off); + } + } - node->next = shootdown_list; - shootdown_list = node; - registered_barrier[proc_data_get()->arb_id] = 1; + mm_barrier_disarm(proc_data_get()->arb_id); - lock_release(&tlb_shootdown_lock); + apic_write_reg(APIC_REG_EOI, APIC_EOI); } diff --git a/kernel/core/alloc.c b/kernel/core/alloc.c index b413663..78110bf 100644 --- a/kernel/core/alloc.c +++ b/kernel/core/alloc.c @@ -27,121 +27,219 @@ #include #include -#define HEADER_SIZE_MASK 0xFFFFFFFFFFFFFFF8uLL -#define HEADER_USED 0x1uLL +#define TYPE_HEADER_USED 0x0uLL +#define TYPE_HEADER_FREE 0x1uLL +#define TYPE_HEADER_LAST 0x2uLL -struct free_node_t { - uint64_t base; - size_t size; - struct free_node_t* next; -}; +#define MASK_HEADER_USED 0x1uLL +#define MASK_HEADER_LAST 0x2uLL + +#define ARENA_SIZE 0x200000 +#define INIT_BLOCK_SIZE (ARENA_SIZE - sizeof(struct alloc_arena_t)) + +#define ALLOC_ALIGN 16 + +#define IS_USED(x) ((x & MASK_HEADER_USED) == TYPE_HEADER_USED) +#define IS_FREE(x) ((x & MASK_HEADER_USED) == TYPE_HEADER_FREE) +#define IS_LAST(x) ((x & MASK_HEADER_LAST) == TYPE_HEADER_LAST) + +#define GET_SIZE(x) (x & ~0xFuLL) +#define GET_FLAGS(x) (x & 0xFuLL); + +_Static_assert(GET_SIZE(ALLOC_ALIGN) == ALLOC_ALIGN, "Bad size mask"); + +struct alloc_arena_t; struct alloc_header_t { - uint64_t header; + uint64_t size; + struct alloc_header_t* prev; + union { + struct alloc_header_t* next_free; + struct alloc_arena_t* arena; + } next_free; + struct alloc_header_t* prev_free; +}; + +struct alloc_arena_t { + struct alloc_header_t* free; + struct alloc_arena_t* next; uint64_t resv; -} __attribute__((packed)); + uint8_t arena_lock; +}; -_Static_assert(sizeof(struct alloc_header_t) == 16, "struct alloc_header_t must be 16 bytes wide"); +_Static_assert(sizeof(struct alloc_header_t) % ALLOC_ALIGN == 0, "Bad alloc header struct"); +_Static_assert(sizeof(struct alloc_arena_t) % ALLOC_ALIGN == 0, "Bad arena metadata struct"); -static struct free_node_t* free_list; -static struct free_node_t* node_pool; +static struct alloc_arena_t* arena_head; static uint8_t alloc_lock; -void alloc_init(void) { +static inline struct alloc_header_t* get_next(struct alloc_header_t* header) { + return IS_LAST(header->size) ? 0 : (struct alloc_header_t*)((uint64_t)header + GET_SIZE(header->size)); +} + +#ifdef CHECK_ALLOC +static void alloc_check(void) { + for (struct alloc_arena_t* i = arena_head; i; i = i->next) { + lock_acquire(&i->arena_lock); + + for (struct alloc_header_t* j = i->free; j; j = j->next_free.next_free) { + if (IS_USED(j->size)) { + logging_log_error("Inconsistent heap state. Used block on free list"); + panic(PANIC_STATE); + } + } + lock_release(&i->arena_lock); + } +} +#endif /* CHECK_ALLOC */ + +void alloc_init() { lock_init(&alloc_lock); - free_list = 0; - node_pool = 0; + + arena_head = 0; } -static struct free_node_t* alloc_node(void) { - struct free_node_t* ret = 0; - uint64_t addr, i; +static void patch_list(struct alloc_arena_t* arena, struct alloc_header_t* header) { + if (header->prev_free) { + header->prev_free->next_free.next_free = header->next_free.next_free; - lock_acquire(&alloc_lock); - if (node_pool) { - ret = node_pool; - node_pool = node_pool->next; + if (header->next_free.next_free) { + header->next_free.next_free->prev_free = header->prev_free; + } } - lock_release(&alloc_lock); + else { + arena->free = header->next_free.next_free; + + if (header->next_free.next_free) { + header->next_free.next_free->prev_free = 0; + } + } +} + +static void* alloc(struct alloc_arena_t* arena, struct alloc_header_t* header, size_t size) { + struct alloc_header_t* split_header; + + if (IS_USED(header->size)) { + logging_log_error("Inconsistent heap state. Attempted allocation on used block"); + panic(PANIC_STATE); + } + + if (size > GET_SIZE(header->size)) { + return 0; + } + + // split block + if (GET_SIZE(header->size) - size > sizeof(struct alloc_header_t)) { + split_header = (struct alloc_header_t*)((uint64_t)header + size); + split_header->prev = header; + + split_header->size = (GET_SIZE(header->size) - size) | TYPE_HEADER_FREE; - if (!ret) { - addr = mm_alloc_p(PAGE_SIZE_4K); - if (!addr) { - logging_log_error("Failed to allocate free list pointers for heap"); - panic(PANIC_NO_MEM); + if (IS_LAST(header->size)) { + split_header->size |= TYPE_HEADER_LAST; + header->size &= ~TYPE_HEADER_LAST; } + else { + get_next(header)->prev = split_header; + } + + // patch free list + split_header->next_free.next_free = header->next_free.next_free; + split_header->prev_free = header; - addr = paging_ident(addr); - ret = (struct free_node_t*)addr; - for (i = 1; i < PAGE_SIZE_4K / sizeof(struct free_node_t) - 1; i++) { - ret[i].next = &ret[i+1]; + if (header->next_free.next_free) { + header->next_free.next_free->prev_free = split_header; } - lock_acquire(&alloc_lock); - ret[PAGE_SIZE_4K / sizeof(struct free_node_t) - 1].next = node_pool; - node_pool = &ret[1]; - lock_release(&alloc_lock); + header->next_free.next_free = split_header; + + header->size = size; // general case deals with flags } - ret->next = 0; - return ret; + header->size = GET_SIZE(header->size) | TYPE_HEADER_USED | (header->size & MASK_HEADER_LAST); + + // patch free list + patch_list(arena, header); + + header->next_free.arena = arena; + + return (void*)((uint64_t)header + sizeof(struct alloc_header_t)); } void* kmalloc(size_t size) { - struct free_node_t* node, **next; - uint64_t ret = 0, adj; - - size += sizeof(struct alloc_header_t); - - adj = size % 16; - if (adj) { - size += 16 - adj; + struct alloc_arena_t* i; + struct alloc_header_t* header; + void* ret; + uint64_t arena_base; + + size_t adjusted_size = size + sizeof(struct alloc_header_t); + if (adjusted_size % ALLOC_ALIGN) { + adjusted_size += ALLOC_ALIGN - (adjusted_size % ALLOC_ALIGN); } lock_acquire(&alloc_lock); - node = free_list; - next = &free_list; - - while (node) { - if (node->size >= size) { - ret = node->base; - node->size -= size; - node->base += size; - - if (!node->size) { - *next = node->next; - node->next = node_pool; - node_pool = node; - } + i = arena_head; + lock_release(&alloc_lock); + + while (i) { + lock_acquire(&i->arena_lock); - break; + if (!i->free) { + goto next_arena; } + + for (header = i->free; header; header = header->next_free.next_free) { + if (GET_SIZE(header->size) >= adjusted_size) { + ret = alloc(i, header, adjusted_size); + lock_release(&i->arena_lock); + +#ifdef CHECK_ALLOC + alloc_check(); +#endif /* CHECK_ALLOC */ + return ret; + } + } + +next_arena: + lock_release(&i->arena_lock); + + lock_acquire(&alloc_lock); + i = i->next; + lock_release(&alloc_lock); + }; + + // out of heap space, new arena + arena_base = mm_alloc_p(ARENA_SIZE); - next = &node->next; - node = node->next; + if (!arena_base) { + logging_log_error("Out of memory for heap"); + return 0; } - lock_release(&alloc_lock); + arena_base = paging_ident(arena_base); - if (!ret) { - adj = size % PAGE_SIZE_4K; - if (adj) { - size += PAGE_SIZE_4K - adj; - } + i = (struct alloc_arena_t*)arena_base; + i->free = (struct alloc_header_t*)(arena_base + sizeof(struct alloc_arena_t)); + lock_init(&i->arena_lock); - ret = mm_alloc_p(size); // aligness does not matter for ident - if (!ret) { - logging_log_error("Failed to allocate memory for heap"); - return 0; - } + *i->free = (struct alloc_header_t) { + .size = INIT_BLOCK_SIZE | TYPE_HEADER_FREE | TYPE_HEADER_LAST, + .prev = 0, + .next_free.next_free = 0, + .prev_free = 0 + }; - ret = paging_ident(ret); - } + ret = alloc(i, i->free, adjusted_size); - ((struct alloc_header_t*)ret)->header = (size) | HEADER_USED; - ret += sizeof(struct alloc_header_t); + lock_acquire(&alloc_lock); + i->next = arena_head; + arena_head = i; + lock_release(&alloc_lock); - return (void*)ret; +#ifdef CHECK_ALLOC + alloc_check(); +#endif /* CHECK_ALLOC */ + return ret; } void kfree(void* ptr) { @@ -150,22 +248,60 @@ void kfree(void* ptr) { } struct alloc_header_t* header = (struct alloc_header_t*)((uint64_t)ptr - sizeof(struct alloc_header_t)); - if (!(header->header & HEADER_USED)) { - logging_log_warning("Double free @ 0x%lx", ptr); -#ifdef DEBUG - cpu_trap(); -#endif /* DEBUG */ + struct alloc_arena_t* arena; + struct alloc_header_t* next; + + if (IS_FREE(header->size)) { + logging_log_warning("Double free @ 0x%x", ptr); return; } - header->header &= ~HEADER_USED; + arena = header->next_free.arena; - struct free_node_t* node = alloc_node(); - node->size = header->header & HEADER_SIZE_MASK; - node->base = (uint64_t)header; + lock_acquire(&arena->arena_lock); - lock_acquire(&alloc_lock); - node->next = free_list; - free_list = node; - lock_release(&alloc_lock); + header->size = GET_SIZE(header->size) | TYPE_HEADER_FREE | (header->size & MASK_HEADER_LAST); + + next = get_next(header); + + // coallecse with prev + if (header->prev && IS_FREE(header->prev->size)) { + header->prev->size = (GET_SIZE(header->prev->size) + GET_SIZE(header->size)) | TYPE_HEADER_FREE | (header->size & MASK_HEADER_LAST); + + header = header->prev; + + if (next) { + next->prev = header; + } + } + else { + // insert into free list's begining + header->next_free.next_free = arena->free; + header->prev_free = 0; + + if (arena->free) { + arena->free->prev_free = header; + } + + arena->free = header; + } + + // coallecse with next + if (next && IS_FREE(next->size)) { + header->size = (GET_SIZE(header->size) + GET_SIZE(next->size)) | TYPE_HEADER_FREE | (next->size & MASK_HEADER_LAST); + + patch_list(arena, next); + + next = get_next(next); + + if (next) { + next->prev = header; + } + } + + lock_release(&arena->arena_lock); + +#ifdef CHECK_ALLOC + alloc_check(); +#endif /* CHECK_ALLOC */ } diff --git a/kernel/core/cpu_instr.S b/kernel/core/cpu_instr.S index e84e36a..ff3caed 100644 --- a/kernel/core/cpu_instr.S +++ b/kernel/core/cpu_instr.S @@ -15,6 +15,8 @@ * along with this program. If not, see */ +.section .text + .globl cpu_lidt cpu_lidt: lidt (%rdi) @@ -83,3 +85,47 @@ jz skip_cr3 movq %rdi, %cr3 skip_cr3: ret + +.globl cpu_hlt +cpu_hlt: +hlt +ret + +.globl cpu_set_cr4 +cpu_set_cr4: +movq %cr4, %rax +orq %rdi, %rax +movq %rax, %cr4 +ret + +.globl cpu_get_fsbase +cpu_get_fsbase: +rdfsbaseq %rax +ret + +.globl cpu_set_fsbase +cpu_set_fsbase: +wrfsbaseq %rdi +ret + +.globl cpu_save_fx +cpu_save_fx: +fxsave (%rdi) +ret + +.globl cpu_restore_fx +cpu_restore_fx: +fxrstor (%rdi) +ret + +.globl cpu_init_fx +cpu_init_fx: +movq %cr0, %rax +andw $0xFFFB, %ax +orw $2, %ax +movq %rax, %cr0 + +movq %cr4, %rax +orq $(3 << 9), %rax +movq %rax, %cr4 +ret diff --git a/kernel/core/elf.c b/kernel/core/elf.c index 27664f1..ba01228 100644 --- a/kernel/core/elf.c +++ b/kernel/core/elf.c @@ -28,9 +28,13 @@ #include #include #include +#include #include #include +#include +#include +#include #define EI_MAG0 0 #define EI_CLASS 4 @@ -75,6 +79,77 @@ #define INIT_USERLAND_SB 0x7FFFFF800000 #define INIT_STACK_SIZE PAGE_SIZE_4K * 8 +// auxv +#define AT_NULL 0 +#define AT_IGNORE 1 +#define AT_EXECFD 2 +#define AT_PHDR 3 +#define AT_PHENT 4 +#define AT_PHNUM 5 +#define AT_PAGESZ 6 +#define AT_BASE 7 +#define AT_FLAGS 8 +#define AT_ENTRY 9 +#define AT_NOTELF 10 +#define AT_UID 11 +#define AT_EUID 12 +#define AT_GID 13 +#define AT_EGID 14 + +// linux vector entries +#define AT_PLATFORM 15 +#define AT_HWCAP 16 +#define AT_CLKTCK 17 +#define AT_FPUCW 18 +#define AT_SECURE 23 +#define AT_RANDOM 25 +#define AT_HWCAP2 26 +#define AT_HWCAP3 29 +#define AT_HWCAP4 30 +#define AT_EXECFN 31 +#define AT_SYSINFO_EHDR 33 + +enum { + AT_INDEX_PHDR, + AT_INDEX_PHENT, + AT_INDEX_PHNUM, + AT_INDEX_PAGESZ, + AT_INDEX_UID, + AT_INDEX_EUID, + AT_INDEX_GID, + AT_INDEX_EGID, + AT_INDEX_SECURE, + AT_INDEX_RANDOM, + AT_INDEX_CLKTCK, + + AT_INDEX_NULL +} at_index_t; + +typedef struct { + int a_type; + union { + long a_val; + void *a_ptr; + void (*a_fnc)(); + } a_un; +} auxv_t; + +static auxv_t default_auxv[] = { + [AT_INDEX_PHDR] = {.a_type = AT_PHDR}, + [AT_INDEX_PHENT] = {.a_type = AT_PHENT}, + [AT_INDEX_PHNUM] = {.a_type = AT_PHNUM}, + [AT_INDEX_PAGESZ] = {.a_type = AT_PAGESZ, .a_un.a_val = PAGE_SIZE_4K}, + [AT_INDEX_UID] = {.a_type = AT_UID, .a_un.a_val = 0}, + [AT_INDEX_EUID] = {.a_type = AT_EUID, .a_un.a_val = 0}, + [AT_INDEX_GID] = {.a_type = AT_GID, .a_un.a_val = 0}, + [AT_INDEX_EGID] = {.a_type = AT_EGID, .a_un.a_val = 0}, + [AT_INDEX_SECURE] = {.a_type = AT_SECURE, .a_un.a_val = 0}, + [AT_INDEX_RANDOM] = {.a_type = AT_RANDOM}, + [AT_INDEX_CLKTCK] = {.a_type = AT_CLKTCK, .a_un.a_val = 100}, + + [AT_INDEX_NULL] = {.a_type = AT_NULL} // extra qword is ignored +}; + typedef uint64_t Elf64_Addr; typedef uint64_t Elf64_Off; typedef uint16_t Elf64_Half; @@ -122,7 +197,7 @@ typedef struct { Elf64_Word p_flags; Elf64_Off p_offset; Elf64_Addr p_vaddr; - Elf64_Addr v_paddr; + Elf64_Addr p_paddr; Elf64_Xword p_filesz; Elf64_Xword p_memsz; Elf64_Xword p_align; @@ -140,15 +215,20 @@ struct mem_reg_t { static const uint8_t elf_magic[4] = {0x7f, 'E', 'L', 'F'}; static uint8_t check_valid(struct fs_handle_t* file, Elf64_Ehdr* header) { - return + if ( fs_seek(file, 0) != FILE_OK || /* file ok seek */ fs_read(file, header, sizeof(*header)) != sizeof(*header) || /* file ok read */ kmemcmp(elf_magic, &header->e_ident[EI_MAG0], sizeof(elf_magic)) || /* magic */ header->e_ident[EI_CLASS] != ELFCLASS64 || /* 64 bit */ header->e_ident[EI_DATA] != ELFDATA2LSB || /* little endian */ - header->e_ident[EI_OSABI] != ELFOSABI_SYSV || /* sys V */ + //header->e_ident[EI_OSABI] != ELFOSABI_SYSV || /* sys V */ // unreliable header->e_type != ET_EXEC || /* executable */ - header->e_machine != EM_X86_64; /* amd64 */ + header->e_machine != EM_X86_64 /* amd64 */ + ) { + return 1; + } + + return 0; } uint8_t elf_is_elf(struct fs_handle_t* file) { @@ -157,7 +237,7 @@ uint8_t elf_is_elf(struct fs_handle_t* file) { return check_valid(file, &header); } -struct pcb_t* elf_load(struct fs_handle_t* file, uint64_t pid) { +struct pcb_t* elf_load(struct fs_handle_t* file, uint64_t pid, const char* invoker, const char* env) { Elf64_Ehdr header; uint64_t stack_paddr, stack_vaddr, rsp; @@ -189,8 +269,6 @@ struct pcb_t* elf_load(struct fs_handle_t* file, uint64_t pid) { pcb->r15 = 0; - pcb->saved_usr_rsp = INIT_USERLAND_RSP; - pcb->init_k_rsp_paddr = stack_paddr; pcb->init_k_rsp_vaddr = stack_vaddr; pcb->rsp = rsp; @@ -198,11 +276,12 @@ struct pcb_t* elf_load(struct fs_handle_t* file, uint64_t pid) { pcb->k_rsp_lo = rsp & 0xFFFFFFFF; pcb->k_rsp_hi = rsp >> 32; + pcb->fsbase = 0; + pcb->rflags = INIT_USERLAND_RFL; pcb->rdi = header.e_entry; // rip pcb->rsi = INIT_USERLAND_RFL; // rflags - pcb->rdx = pcb->saved_usr_rsp; // rsp pcb->rip = (uint64_t)syscall_return; pcb->cs = GDT_KERNEL_CS; @@ -211,6 +290,8 @@ struct pcb_t* elf_load(struct fs_handle_t* file, uint64_t pid) { pcb->sched_cntr = SCHED_READY; pcb->pid = pid; + cpu_restore_fx(pcb->fxdata); + pcb->cr3 = paging_create_pml4(); if (!pcb->cr3) { logging_log_error("Failed to create pml4 for process"); @@ -230,6 +311,8 @@ struct pcb_t* elf_load(struct fs_handle_t* file, uint64_t pid) { struct mem_reg_t* j; struct mem_reg_t* temp; + uint64_t memtop = 0; + // first pass to determine memory layout for (Elf64_Half i = 0; i < header.e_phnum; i++) { fs_seek(file, ph_off); @@ -310,6 +393,10 @@ struct pcb_t* elf_load(struct fs_handle_t* file, uint64_t pid) { // map in memory for copying for (j = mem_regs; j; j = j->next) { + if (j->top > memtop) { + memtop = j->top; + } + for (uint64_t off = 0; off < j->top - j->base; off += PAGE_SIZE_4K) { paddr = mm_alloc_p(PAGE_SIZE_4K); @@ -324,6 +411,37 @@ struct pcb_t* elf_load(struct fs_handle_t* file, uint64_t pid) { } } + + memtop += PAGE_SIZE_4K; + uint64_t pheaders_base = memtop; + + // map in pheaders + size_t pheader_total = header.e_phentsize & header.e_phnum; + for (size_t off = 0; off < pheader_total; off += PAGE_SIZE_4K) { + paddr = mm_alloc_p(PAGE_SIZE_4K); + + if (!paddr) { + paging_free_userspace((uint64_t*)pcb->cr3); + kfree(pcb); + pcb = 0; + goto restore_cr3; + } + + paging_map_proc(pheaders_base + off, paddr, PAGE_PRESENT | PAGE_RW | PAGE_US | PAGE_XD, PAGE_4K, (uint64_t*)pcb->cr3); + memtop += PAGE_SIZE_4K; + } + + memtop += PAGE_SIZE_4K; + pcb->mem_top = memtop; + + ph_off = 0; + // copy pheaders + for (Elf64_Half i = 0; i < header.e_phnum; i++) { + fs_seek(file, ph_off + header.e_phoff); + fs_read(file, (void*)(pheaders_base + ph_off), sizeof(pheader)); + ph_off += header.e_phentsize; + } + // map in stack for (img_off = INIT_USERLAND_RSP - INIT_STACK_SIZE; img_off < INIT_USERLAND_RSP; img_off += PAGE_SIZE_4K) { paddr = mm_alloc_p(PAGE_SIZE_4K); @@ -339,6 +457,62 @@ struct pcb_t* elf_load(struct fs_handle_t* file, uint64_t pid) { kmemset((void*)img_off, 0, PAGE_SIZE_4K); } + // create auxv + uint64_t invoke_addr = INIT_USERLAND_RSP - kstrlen(invoker) - 1; + uint64_t env_addr = invoke_addr - kstrlen(env) - 1; + uint64_t random_addr = env_addr - 16; + auxv_t* auxv_addr = (auxv_t*)(random_addr - sizeof(default_auxv)); + + kstrcpy((char*)invoke_addr, invoker); + kstrcpy((char*)env_addr, env); + kmemcpy(auxv_addr, default_auxv, sizeof(default_auxv)); + + // leave upper bytes untouched for "randomness" + *(volatile uint64_t*)random_addr = time_since_init_fs(); //TODO: better randomization + + auxv_addr[AT_INDEX_PHDR].a_un.a_val = (int64_t)pheaders_base; + auxv_addr[AT_INDEX_PHENT].a_un.a_val = header.e_phentsize; + auxv_addr[AT_INDEX_PHNUM].a_un.a_val = header.e_phnum; + auxv_addr[AT_INDEX_RANDOM].a_un.a_val = (int64_t)random_addr; + + uint64_t* stack_builder = (uint64_t*)auxv_addr; + stack_builder--; + *stack_builder = 0; // env end + + char* inf_chars; + for (inf_chars = (char*)(env_addr + kstrlen(env)); inf_chars >= (char*)env_addr; inf_chars--) { + if (*inf_chars == ' ') { + stack_builder--; + *stack_builder = (uint64_t)inf_chars + 1; + *inf_chars = 0; + } + } + + stack_builder--; + *stack_builder = (uint64_t)inf_chars + 1; + + stack_builder--; + *stack_builder = 0; // env start + + uint64_t argc = 1; + + for (inf_chars = (char*)(invoke_addr + kstrlen(invoker)); inf_chars >= (char*)invoke_addr; inf_chars--) { + if (*inf_chars == ' ') { + stack_builder--; + *stack_builder = (uint64_t)inf_chars + 1; + *inf_chars = 0; + argc++; + } + } + + stack_builder--; + *stack_builder = (uint64_t)inf_chars + 1; + + stack_builder--; + *stack_builder = argc; + + pcb->rdx = (uint64_t)stack_builder; // rsp + // copy in executable ph_off = header.e_phoff; for (Elf64_Half i = 0; i < header.e_phnum; i++) { @@ -353,7 +527,7 @@ struct pcb_t* elf_load(struct fs_handle_t* file, uint64_t pid) { fs_seek(file, pheader.p_offset); fs_read(file, (void*)pheader.p_vaddr, pheader.p_filesz); - kmemset((void*)(pheader.p_vaddr + pheader.p_memsz - pheader.p_filesz), 0, pheader.p_memsz - pheader.p_filesz); + kmemset((void*)(pheader.p_vaddr + pheader.p_filesz), 0, pheader.p_memsz - pheader.p_filesz); } // update page permissions @@ -363,6 +537,12 @@ struct pcb_t* elf_load(struct fs_handle_t* file, uint64_t pid) { } } + kmemset(pcb->fd_table, 0, sizeof(struct fs_handle_t*) * MAX_FD); + + pcb->fd_table[0] = fs_open("/dev/ttyS0"); + pcb->fd_table[1] = fs_open("/dev/ttyS0"); + pcb->fd_table[2] = fs_open("/dev/ttyS0"); + restore_cr3: while (mem_regs) { diff --git a/kernel/core/fs.c b/kernel/core/fs.c index a78351e..975e0eb 100644 --- a/kernel/core/fs.c +++ b/kernel/core/fs.c @@ -29,6 +29,10 @@ #include #include +#include + +//TODO: implement per file blocking + static uint8_t fs_lock; struct vfs_mount_t { @@ -40,6 +44,7 @@ struct vfs_mount_t { fs_read_t read; fs_get_seek_t get_seek; fs_seek_t seek; + fs_write_t write; }; struct fs_handle_t { @@ -57,6 +62,18 @@ struct vfs_tree_node_t { }; static struct vfs_tree_node_t vfs_root; +static struct vfs_tree_node_t dev_root; + +static struct vfs_mount_t dev_mount = { + .cntx = 0, + .open = devfs_open, + .close = devfs_close, + .stat = devfs_stat, + .read = devfs_read, + .get_seek = devfs_get_seek, + .seek = devfs_seek, + .write = devfs_write +}; static inline char* path_next(char* path, size_t* len) { *len = 0; @@ -77,9 +94,14 @@ void fs_init(void) { lock_init(&fs_lock); vfs_root.co = 0; - vfs_root.sub = 0; + vfs_root.sub = &dev_root; vfs_root.name = ""; vfs_root.mount = 0; + + dev_root.co = 0; + dev_root.sub = 0; + dev_root.name = "dev"; + dev_root.mount = &dev_mount; } enum file_status_t fs_mount( @@ -90,7 +112,8 @@ enum file_status_t fs_mount( fs_stat_t stat, fs_read_t read, fs_get_seek_t get_seek, - fs_seek_t seek + fs_seek_t seek, + fs_write_t write ) { if (kstrcmp(mountpoint, "") && !vfs_root.mount) { @@ -108,6 +131,7 @@ enum file_status_t fs_mount( vfs_root.mount->read = read; vfs_root.mount->get_seek = get_seek; vfs_root.mount->seek = seek; + vfs_root.mount->write = write; return FILE_OK; } @@ -176,7 +200,7 @@ struct fs_handle_t* fs_open(const char* path) { } - lock_acquire(&fs_lock); + //lock_acquire(&fs_lock); do { if (node->mount) { @@ -188,15 +212,15 @@ struct fs_handle_t* fs_open(const char* path) { path_write = path_next(path_write, &len); for (walk = node->sub; walk; walk = walk->co) { - if (kstrlen(node->name) == len && kmemcmp(node->name, path_read, len) == 0) { + if (kstrlen(walk->name) == len && kmemcmp(walk->name, path_read, len) == 0) { node = walk; break; } } - } while (walk && node != walk); + } while (walk && node == walk); - lock_release(&fs_lock); + //lock_release(&fs_lock); if (!mount) { kfree(clean_path); @@ -214,28 +238,28 @@ struct fs_handle_t* fs_open(const char* path) { } void fs_close(struct fs_handle_t* handle) { - lock_acquire(&fs_lock); + //lock_acquire(&fs_lock); handle->mount->close(handle->handle); - lock_release(&fs_lock); + //lock_release(&fs_lock); kfree(handle); } enum file_status_t fs_stat(struct fs_handle_t* handle, struct file_info_t* info) { - lock_acquire(&fs_lock); + //lock_acquire(&fs_lock); enum file_status_t ret = handle->mount->stat(handle->handle, info); - lock_release(&fs_lock); + //lock_release(&fs_lock); return ret; } size_t fs_read(struct fs_handle_t* handle, void* buffer, size_t count) { size_t ret; - lock_acquire(&fs_lock); + //lock_acquire(&fs_lock); ret = handle->mount->read(handle->handle, buffer, count); - lock_release(&fs_lock); + //lock_release(&fs_lock); return ret; } @@ -243,9 +267,9 @@ size_t fs_read(struct fs_handle_t* handle, void* buffer, size_t count) { uint64_t fs_get_seek(struct fs_handle_t* handle) { uint64_t seek; - lock_acquire(&fs_lock); + //lock_acquire(&fs_lock); seek = handle->mount->get_seek(handle->handle); - lock_release(&fs_lock); + //lock_release(&fs_lock); return seek; } @@ -253,9 +277,19 @@ uint64_t fs_get_seek(struct fs_handle_t* handle) { enum file_status_t fs_seek(struct fs_handle_t* handle, uint64_t seek) { enum file_status_t sts; - lock_acquire(&fs_lock); + //lock_acquire(&fs_lock); sts = handle->mount->seek(handle->handle, seek); - lock_release(&fs_lock); + //lock_release(&fs_lock); return sts; } + +size_t fs_write(struct fs_handle_t* handle, void* buffer, size_t count) { + size_t ret; + + //lock_acquire(&fs_lock); + ret = handle->mount->write(handle->handle, buffer, count); + //lock_release(&fs_lock); + + return ret; +} diff --git a/kernel/core/kentry.c b/kernel/core/kentry.c index d061da4..9476028 100644 --- a/kernel/core/kentry.c +++ b/kernel/core/kentry.c @@ -33,9 +33,13 @@ #include #include #include +#include +#include #include +#include + #ifdef MEM_TEST #include #endif /* MEM_TEST */ @@ -51,6 +55,14 @@ #include #include +#ifdef SERIAL +#include +#endif /* SERIAL */ + +#define RFL_MASK 0xD5 + +#define CR4_FSGSBASE (1 << 16) + struct boot_context_t boot_context; extern uint8_t ap_bootstrap_start; @@ -65,6 +77,12 @@ extern uint64_t init_stack_paddr; extern uint64_t* init_stacks_paddr; extern uint64_t* init_stacks_vaddr; +static inline void write_syscall_msr(void) { + msr_write(MSR_STAR, ((GDT_USER_CS - 0x10) << 48) | (GDT_KERNEL_CS << 32)); + msr_write(MSR_LSTAR, (uint64_t)syscall_entry); + msr_write(MSR_FMASK, RFL_MASK); +} + void kentry(void) { logging_log_debug("Kernel Entry"); @@ -81,8 +99,11 @@ void kentry(void) { paging_ensure_mapped(); scheduler_init(); + mm_transaction_init(); - msr_write(MSR_STAR, ((GDT_USER_CS - 0x10) << 48) | (GDT_KERNEL_CS << 32)); + write_syscall_msr(); + cpu_set_cr4(CR4_FSGSBASE); + cpu_init_fx(); logging_log_debug("TSS and IDT init done"); @@ -102,12 +123,20 @@ void kentry(void) { apic_timer_calib(apic_get_bsp_id()); apic_nmi_enab(); ioapic_init(); + apic_init_shootdowns(); cpu_sti(); logging_log_debug("APIC and IOAPIC init done"); + proc_data_get()->sts |= PROC_STS_INT_READY; + +#ifdef SERIAL + serial_init_interrupts(); +#endif /* SERIAL */ + logging_log_debug("Early PCIE init"); disk_init(); fs_init(); + tty_init(); pcie_init(); pcie_enumerate(); logging_log_debug("Early PCIE init done"); @@ -136,7 +165,9 @@ void kapentry(uint64_t arb_id) { proc_data_set_id((uint8_t)arb_id); proc_data_get()->arb_id = (uint8_t)arb_id; - msr_write(MSR_STAR, ((GDT_USER_CS - 0x10) << 48) | (GDT_KERNEL_CS << 32)); + write_syscall_msr(); + cpu_set_cr4(CR4_FSGSBASE); + cpu_init_fx(); alloc_init(); @@ -153,6 +184,8 @@ void kapentry(uint64_t arb_id) { cpu_sti(); logging_log_debug("AP APIC init done"); + proc_data_get()->sts |= PROC_STS_INT_READY; + logging_log_info("AP init complete"); process_kill_current(); diff --git a/kernel/core/lock.S b/kernel/core/lock.S index 3f04ca8..2ca21a6 100644 --- a/kernel/core/lock.S +++ b/kernel/core/lock.S @@ -17,21 +17,25 @@ .globl lock_init lock_init: -movq $0, (%rdi) +movb $0, (%rdi) +mfence ret .globl lock_acquire lock_acquire: -movq $1, %rax +movb $1, %al + .loop: pause -xchgb %al, (%rdi) -testq %rax, %rax +testb $1, (%rdi) +jnz .loop + +lock xchgb %al, (%rdi) +testb %al, %al jnz .loop ret .globl lock_release lock_release: -xorq %rax, %rax -xchgb %al, (%rdi) +movb $0, (%rdi) ret diff --git a/kernel/core/mm.c b/kernel/core/mm.c index 278c4a9..8005c88 100644 --- a/kernel/core/mm.c +++ b/kernel/core/mm.c @@ -25,15 +25,22 @@ #include #include #include +#include +#include +#include #include +#include + #define PAGE_4K_MASK 0xFFFFFFFFFFFFF000 #define SIZE_GIB (1024 * 1024 * 1024) #define MAX_INIT_NODES 64 #define WITHIN_NODE(base, b, l) (base >= b && base < b + l) +#define SHOOTDOWN_DELAY_MS 5000 + struct mm_tree_node_t { struct mm_tree_node_t* less; struct mm_tree_node_t* more; @@ -41,6 +48,12 @@ struct mm_tree_node_t { uint64_t limit; }; +struct disarm_list_t { + struct disarm_list_t* next; + uint8_t id; + volatile uint8_t state; +}; + static struct mm_tree_node_t* p_tree; static struct mm_tree_node_t* v_tree; @@ -55,6 +68,11 @@ static uint8_t n_lock; static struct mm_tree_node_t node_pool[MAX_INIT_NODES]; static struct mm_tree_node_t* free_nodes; +static struct free_transaction_list_t* volatile pending_free; +static struct free_transaction_list_t* transaction_list; +uint8_t pending_free_lock; +static struct disarm_list_t* disarm_list; + static struct mm_tree_node_t* alloc_node(void) { struct mm_tree_node_t* next; lock_acquire(&n_lock); @@ -178,6 +196,7 @@ static void mm_free(uint64_t base, uint64_t size, struct mm_tree_node_t* root, u size += PAGE_SIZE_4K - adj; } + cpu_cli_if(); lock_acquire(lock); node = find_base_node(base, root->more, root); @@ -210,6 +229,7 @@ static void mm_free(uint64_t base, uint64_t size, struct mm_tree_node_t* root, u //TODO: coallese lock_release(lock); + cpu_sti_if(); } static uint64_t mm_alloc_max(size_t size, uint64_t align, uint64_t max, struct mm_tree_node_t* root, uint8_t* lock) { @@ -257,6 +277,7 @@ extern void mm_init( lock_init(&p_lock); lock_init(&v_lock); lock_init(&n_lock); + lock_init(&pending_free_lock); uint64_t blocks; @@ -266,6 +287,8 @@ extern void mm_init( node_pool[MAX_INIT_NODES - 1].less = 0; free_nodes = &node_pool[0]; + pending_free = 0; + disarm_list = 0; // find memory limit uint64_t mem_limit = 0; @@ -403,5 +426,93 @@ void mm_free_p(uint64_t base, size_t size) { } void mm_free_v(uint64_t base, size_t size) { - mm_free(base, size, v_tree, &v_lock); + volatile struct free_transaction_list_t* pending = kmalloc(sizeof(struct free_transaction_list_t)); + pending->base = base; + pending->size = size; + lock_acquire(&pending_free_lock); + pending->next = pending_free; + pending_free = (struct free_transaction_list_t* volatile)pending; + lock_release(&pending_free_lock); +} + +static void free_all_pending(void* _ign) { + (void)_ign; + + struct free_transaction_list_t* next; + struct disarm_list_t* disarm; + uint8_t cntrl; + + while (1) { + do { + time_sleep(SHOOTDOWN_DELAY_MS); + } while (!pending_free); + + lock_acquire(&pending_free_lock); + + if (!pending_free) { + lock_release(&pending_free_lock); + continue; + } + + transaction_list = pending_free; + pending_free = 0; + + for (disarm = disarm_list; disarm; disarm = disarm->next) { + disarm->state = 1; + apic_shootdown(disarm->id); + } + + lock_release(&pending_free_lock); + + do { + cpu_pause(); + + cntrl = 0; + lock_acquire(&pending_free_lock); + for (disarm = disarm_list; disarm; disarm = disarm->next) { + if (disarm->state) { + cntrl = 1; + break; + } + } + lock_release(&pending_free_lock); + } while(cntrl); + + while (transaction_list) { + next = transaction_list->next; + + mm_free(transaction_list->base, transaction_list->size, v_tree, &v_lock); + + kfree(transaction_list); + transaction_list = next; + } + } +} + +void mm_transaction_init(void) { + scheduler_schedule(process_from_func(free_all_pending, 0)); +} + +struct free_transaction_list_t* mm_get_shootdown_list(void) { + return transaction_list; +} + +void mm_register_barrier(uint8_t id) { + struct disarm_list_t* l = kmalloc(sizeof(struct disarm_list_t)); + l->id = id; + l->state = 0; + + lock_acquire(&pending_free_lock); + l->next = disarm_list; + disarm_list = l; + lock_release(&pending_free_lock); +} + +void mm_barrier_disarm(uint8_t id) { + for (struct disarm_list_t* l = disarm_list; l; l = l->next) { + if (id == l->id) { + l->state = 0; + break; + } + } } diff --git a/kernel/core/paging.c b/kernel/core/paging.c index d48287a..3320f7c 100644 --- a/kernel/core/paging.c +++ b/kernel/core/paging.c @@ -209,7 +209,6 @@ void paging_unmap(uint64_t vaddr, enum page_size_t page_size) { *access = 0; lock_release(&paging_lock); - apic_tlb_shootdown(vaddr); } uint64_t paging_ident(uint64_t paddr) { @@ -288,10 +287,7 @@ static void free_pages(uint64_t entry, enum page_size_t lvl) { for (uint16_t i = 0; i < 512; i++) { if (access[i] & PAGE_PRESENT) { - if (lvl == PAGE_4K || (access[i] & PAGE_PS)) { - mm_free_v(access[i] & PAGE_ADDR_MASK, PAGE_SIZE_4K); - } - else { + if (lvl != PAGE_4K && !(access[i] & PAGE_PS)) { free_pages(access[i], lvl-1); } } @@ -305,7 +301,7 @@ void paging_free_userspace(uint64_t* pml4) { for (uint16_t i = 0; i < PML4_CONSISTENT_START; i++) { if (access[i] & PAGE_PRESENT) { - free_pages(access[i], _PAGE_512G); // lvl being the size of each entry, not entry itself + free_pages(access[i], PAGE_1G); } } diff --git a/kernel/core/process.c b/kernel/core/process.c index 5d88f8f..83f21e7 100644 --- a/kernel/core/process.c +++ b/kernel/core/process.c @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include @@ -68,6 +70,7 @@ void process_init_ap(uint64_t init_rsp_vaddr, uint64_t init_rsp_paddr) { pcb->init_k_rsp_vaddr = init_rsp_vaddr; pcb->init_k_rsp_paddr = init_rsp_paddr; pcb->sched_cntr = SCHED_SKIP; + kmemset(pcb->fd_table, 0, sizeof(struct fs_handle_t*) * MAX_FD); proc_data_get()->current_process = pcb; proc_data_get()->current_process->pid = process_assign_pid(); proc_data_get()->current_process->cr3 = 0; @@ -104,7 +107,10 @@ struct pcb_t* process_from_vaddr(uint64_t vaddr) { pcb->init_k_rsp_vaddr = stack_vaddr; pcb->init_k_rsp_paddr = stack_paddr; - pcb->saved_usr_rsp = 0; + cpu_save_fx(pcb->fxdata); + + pcb->fsbase = 0; + pcb->k_rsp_lo = 0; pcb->k_rsp_hi = 0; @@ -120,6 +126,12 @@ struct pcb_t* process_from_vaddr(uint64_t vaddr) { pcb->pid = process_assign_pid(); + kmemset(pcb->fd_table, 0, sizeof(struct fs_handle_t*) * MAX_FD); + + pcb->fd_table[0] = fs_open("/dev/ttyS0"); + pcb->fd_table[1] = fs_open("/dev/ttyS0"); + pcb->fd_table[2] = fs_open("/dev/ttyS0"); + return pcb; } @@ -160,6 +172,12 @@ void process_discard(struct pcb_t* pcb) { paging_free_userspace((uint64_t*)pcb->cr3); } + for (uint64_t i = 0; i < MAX_FD; i++) { + if (pcb->fd_table[i]) { + fs_close(pcb->fd_table[i]); + } + } + logging_log_debug("Killed %ld", pcb->pid); kfree(pcb); @@ -167,26 +185,30 @@ void process_discard(struct pcb_t* pcb) { void process_preempt_entry(struct preempt_frame_t* context) { struct pcb_t* pcb = proc_data_get()->current_process; - pcb->rsp = context->rsp; - pcb->rbp = context->rbp; - pcb->r15 = context->r15; - pcb->r14 = context->r14; - pcb->r13 = context->r13; - pcb->r12 = context->r12; - pcb->r11 = context->r11; - pcb->r10 = context->r10; - pcb->r9 = context->r9; - pcb->r8 = context->r8; - pcb->rdi = context->rdi; - pcb->rsi = context->rsi; - pcb->rdx = context->rdx; - pcb->rcx = context->rcx; - pcb->rbx = context->rbx; - pcb->rax = context->rax; - pcb->rip = context->rip; - pcb->cs = context->cs; - pcb->rflags = context->rflags; - pcb->ss = context->ss; + if (pcb) { + pcb->rsp = context->rsp; + pcb->rbp = context->rbp; + pcb->r15 = context->r15; + pcb->r14 = context->r14; + pcb->r13 = context->r13; + pcb->r12 = context->r12; + pcb->r11 = context->r11; + pcb->r10 = context->r10; + pcb->r9 = context->r9; + pcb->r8 = context->r8; + pcb->rdi = context->rdi; + pcb->rsi = context->rsi; + pcb->rdx = context->rdx; + pcb->rcx = context->rcx; + pcb->rbx = context->rbx; + pcb->rax = context->rax; + pcb->rip = context->rip; + pcb->cs = context->cs; + pcb->rflags = context->rflags; + pcb->ss = context->ss; + pcb->fsbase = cpu_get_fsbase(); + cpu_save_fx(pcb->fxdata); + } scheduler_run(); } @@ -223,3 +245,14 @@ uint8_t process_create_guarded_stack(uint64_t* init_vaddr, uint64_t* init_paddr, return 0; } + +void process_sleep(uint64_t wake_time) { + struct pcb_t* current = proc_data_get()->current_process; + + current->sleep_state.wake_time = wake_time; + current->sched_cntr = SCHED_SLEEP; + + while (time_since_init_fs() < wake_time) { + cpu_hlt(); + } +} diff --git a/kernel/core/scheduler.c b/kernel/core/scheduler.c index 6e2847a..7a88438 100644 --- a/kernel/core/scheduler.c +++ b/kernel/core/scheduler.c @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -31,9 +32,11 @@ static uint8_t lock_sched; static volatile struct pcb_t* active_queue; static volatile struct pcb_t* active_queue_tail; -void scheduler_schedule(struct pcb_t* pcb) { +static struct pcb_t* sleep_queue; + +static void _scheduler_schedule(struct pcb_t* pcb) { pcb->next = 0; - lock_acquire(&lock_sched); + if (active_queue_tail) { active_queue_tail->next = pcb; active_queue_tail = active_queue_tail->next; @@ -42,6 +45,11 @@ void scheduler_schedule(struct pcb_t* pcb) { active_queue = pcb; active_queue_tail = pcb; } +} + +void scheduler_schedule(struct pcb_t* pcb) { + lock_acquire(&lock_sched); + _scheduler_schedule(pcb); lock_release(&lock_sched); } @@ -50,48 +58,88 @@ void scheduler_init(void) { active_queue = 0; active_queue_tail = 0; + sleep_queue = 0; } void scheduler_run(void) { struct proc_data_t* pd = proc_data_get(); struct pcb_t* current_pcb = pd->current_process; - switch (current_pcb->sched_cntr) { - case SCHED_SKIP: - cpu_cli(); - apic_write_reg(APIC_REG_EOI, APIC_EOI); - process_resume(current_pcb); - break; - case SCHED_KILL: - process_discard(current_pcb); - break; - default: - scheduler_schedule(current_pcb); - break; + if (current_pcb) { + switch (current_pcb->sched_cntr) { + case SCHED_SKIP: + cpu_cli(); + apic_write_reg(APIC_REG_EOI, APIC_EOI); + process_resume(current_pcb); + break; + case SCHED_KILL: + process_discard(current_pcb); + break; + case SCHED_SLEEP: + current_pcb->sched_cntr = SCHED_READY; + + lock_acquire(&lock_sched); + struct pcb_t* i = sleep_queue, **prev = &sleep_queue; + + for (; i && current_pcb->sleep_state.wake_time < i->sleep_state.wake_time; i = i->next) { + prev = &i->next; + } + + *prev = current_pcb; + current_pcb->next = i; + + lock_release(&lock_sched); + break; + default: + scheduler_schedule(current_pcb); + break; + } + } + + lock_acquire(&lock_sched); + + // wakup sleeping processes + const uint64_t now = time_since_init_fs(); + struct pcb_t* i, * next; + for (i = sleep_queue; i && i->sleep_state.wake_time <= now; i = next) { + next = i->next; + _scheduler_schedule(i); } - struct pcb_t* run = 0; - while (!run) { - cpu_pause(); - lock_acquire(&lock_sched); - if (active_queue) { - run = (struct pcb_t*)active_queue; - active_queue = active_queue->next; - if (!active_queue) { - active_queue_tail = 0; - } - lock_release(&lock_sched); - break; + sleep_queue = i; + + struct pcb_t* run; + if (active_queue) { + // next process + run = (struct pcb_t*)active_queue; + active_queue = active_queue->next; + if (!active_queue) { + active_queue_tail = 0; } + lock_release(&lock_sched); } + else { + // wait for process - pd->tss->rsp0_lo = run->k_rsp_lo; - pd->tss->rsp0_hi = run->k_rsp_hi; - pd->current_process = run; + lock_release(&lock_sched); + pd->current_process = 0; + + apic_write_reg(APIC_REG_EOI, APIC_EOI); + cpu_wait_loop(); + } + cpu_cli(); - apic_write_reg(APIC_REG_EOI, APIC_EOI); + pd->tss->rsp0_lo = run->k_rsp_lo; + pd->tss->rsp0_hi = run->k_rsp_hi; + pd->kernel_rsp = (uint64_t)run->k_rsp_lo | ((uint64_t)run->k_rsp_hi << 32); + pd->current_process = run; cpu_set_cr3(run->cr3); + cpu_set_fsbase(run->fsbase); + cpu_restore_fx(run->fxdata); + + apic_write_reg(APIC_REG_EOI, APIC_EOI); + process_resume(run); } diff --git a/kernel/core/syscall.S b/kernel/core/syscall.S index eb3dfcb..d4738ff 100644 --- a/kernel/core/syscall.S +++ b/kernel/core/syscall.S @@ -15,10 +15,64 @@ * along with this program. If not, see */ +#include + +.section .text + .globl syscall_return syscall_return: movq %rdi, %rcx // rip movq %rsi, %r11 // rflags movq %rdx, %rsp // rsp +movq %rcx, %rax // return value + +sysretq + +.globl syscall_entry +syscall_entry: +cmpq $SYSCALL_MAX, %rax +jae syscall_fail + +pushq %rbp +movq %rsp, %rbp + +movq %gs:0, %rsp +movq (%rsp), %rsp + +pushq %rcx +pushq %r11 + +movq %r10, %rcx +call *syscall_handlers(,%rax,8) + +popq %r11 +popq %rcx + +movq %rbp, %rsp +popq %rbp + +sysretq + +syscall_fail: +movq $SYSCALL_STS_FAIL, %rax sysretq + +.section .rodata + +.extern syscall_dispatch_exit +.extern syscall_dispatch_open +.extern syscall_disaptch_close +.extern syscall_dispatch_read +.extern syscall_dispatch_write +.extern syscall_dispatch_alloc + +.global syscall_handlers +syscall_handlers: + +.quad syscall_dispatch_exit +.quad syscall_dispatch_open +.quad syscall_dispatch_close +.quad syscall_dispatch_read +.quad syscall_dispatch_write +.quad syscall_dispatch_alloc diff --git a/kernel/core/syscall_dispatch.c b/kernel/core/syscall_dispatch.c new file mode 100644 index 0000000..1f6481c --- /dev/null +++ b/kernel/core/syscall_dispatch.c @@ -0,0 +1,152 @@ +/* syscall_dispatch.c - kernel system call dispatcher */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define ARGC_0 \ + (void)arg1; \ + (void)arg2; \ + (void)arg3; \ + (void)arg4; \ + (void)arg5; \ + (void)arg6 + +#define ARGC_1 \ + (void)arg2; \ + (void)arg3; \ + (void)arg4; \ + (void)arg5; \ + (void)arg6 + +#define ARGC_2 \ + (void)arg3; \ + (void)arg4; \ + (void)arg5; \ + (void)arg6 + +#define ARGC_3 \ + (void)arg4; \ + (void)arg5; \ + (void)arg6 + +#define ARGC_4 \ + (void)arg5; \ + (void)arg6 + +#define ARGC_5 \ + (void)arg6 + +#define ARGC_6 + +DECLARE_SYSCALL(exit) { + ARGC_1; + + //TODO: handle exit code + (void)arg1; + + process_kill_current(); +} + +DECLARE_SYSCALL(open) { + ARGC_0; + + int fd; + struct pcb_t* pcb = proc_data_get()->current_process; + + for (fd = 0; fd < MAX_FD; fd++) { + if (!pcb->fd_table[fd]) { + pcb->fd_table[fd] = fs_open((const char*)arg1); + if (!pcb->fd_table[fd]) { + return SYSCALL_STS_FAIL; + } + + return (uint64_t)fd; + } + } + + return SYSCALL_STS_FAIL; +} + +DECLARE_SYSCALL(close) { + ARGC_0; + + struct pcb_t* pcb = proc_data_get()->current_process; + + if (!pcb->fd_table[arg1]) { + return SYSCALL_STS_FAIL; + } + + fs_close(pcb->fd_table[arg1]); + pcb->fd_table[arg1] = 0; + + return SYSCALL_STS_OK; +} + +DECLARE_SYSCALL(read) { + ARGC_3; + + struct pcb_t* pcb = proc_data_get()->current_process; + return (uint64_t)fs_read(pcb->fd_table[arg1], (void*)arg2, (size_t)arg3); +} + +DECLARE_SYSCALL(write) { + ARGC_3; + + struct pcb_t* pcb = proc_data_get()->current_process; + return (uint64_t)fs_write(pcb->fd_table[arg1], (void*)arg2, (size_t)arg3); +} + +DECLARE_SYSCALL(alloc) { + ARGC_1; + + if (arg1 % PAGE_SIZE_4K) { + arg1 += PAGE_SIZE_4K - (arg1 % PAGE_SIZE_4K); + } + + struct pcb_t* pcb = proc_data_get()->current_process; + uint64_t paddr = mm_alloc_p(arg1); + + if (!paddr) { + return 0; + } + + uint64_t vaddr = pcb->mem_top; + + for (uint64_t i = 0; i < arg1; i += PAGE_SIZE_4K) { + paging_map_proc(vaddr + i, + paddr + i, + PAGE_PRESENT | PAGE_RW | PAGE_US | PAGE_XD, PAGE_4K, + (uint64_t*)proc_data_get()->current_process->cr3); + } + + pcb->mem_top += arg1; + + return vaddr; +} diff --git a/kernel/core/time.c b/kernel/core/time.c index 6088f0d..f0af19a 100644 --- a/kernel/core/time.c +++ b/kernel/core/time.c @@ -20,6 +20,7 @@ #include #include #include +#include static struct clock_src_t* clock; @@ -43,6 +44,15 @@ uint64_t time_busy_wait(uint64_t min_ns) { return actual - start; } +uint64_t time_sleep(uint64_t min_ms) { + const uint64_t start = clock->counter(clock->meta) * clock->period_fs; + const uint64_t stop = start + min_ms * TIME_CONV_MS_TO_FS; + process_sleep(stop); + + return clock->counter(clock->meta) * clock->period_fs - start; +} + + uint64_t time_since_init_ns(void) { return clock->counter(clock->meta) * clock->period_fs / TIME_CONV_NS_TO_FS; } diff --git a/kernel/devfs/devfs.c b/kernel/devfs/devfs.c new file mode 100644 index 0000000..e0c9103 --- /dev/null +++ b/kernel/devfs/devfs.c @@ -0,0 +1,144 @@ +/* devfs.c - kernel device block file system subsystem routing */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#include +#include + +#include +#include + +#include +#include + +#include + +struct dev_handle_t { + enum { + DEV_TYPE_TTY + } type; + union { + struct tty_handle_t* tty; + } dev_handle; +}; + +struct file_handle_t* devfs_open(struct mount_cntx_t* cntx, char* path) { + (void)cntx; + struct dev_handle_t* dev_handle; + + // tty devices + if (!kmemcmp(path, "tty", 3)) { + struct tty_handle_t* handle = tty_open(path + 3); + if (!handle) { + // invalid tty + return 0; + } + + dev_handle = kmalloc(sizeof(struct dev_handle_t)); + dev_handle->type = DEV_TYPE_TTY; + dev_handle->dev_handle.tty = handle; + + return (struct file_handle_t*)dev_handle; + } + + return 0; +} + +void devfs_close(struct file_handle_t* handle) { + struct dev_handle_t* dev_handle = (struct dev_handle_t*)handle; + + if (!dev_handle) { + return; + } + + switch (dev_handle->type) { + case DEV_TYPE_TTY: + break; + } + + kfree(dev_handle); +} + +enum file_status_t devfs_stat(struct file_handle_t* handle, struct file_info_t* info) { + struct dev_handle_t* dev_handle = (struct dev_handle_t*)handle; + + if (!dev_handle) { + return FILE_ERROR; + } + + switch (dev_handle->type) { + case DEV_TYPE_TTY: + info->type = FILE_TYPE_CHAR; + info->size = TTY_READ_BUFFER_SIZE; + return FILE_OK; + } +} + +size_t devfs_read(struct file_handle_t* handle, void* buffer, size_t count) { + struct dev_handle_t* dev_handle = (struct dev_handle_t*)handle; + + if (!dev_handle) { + return FILE_ERROR; + } + + switch (dev_handle->type) { + case DEV_TYPE_TTY: + return tty_read(dev_handle->dev_handle.tty, buffer, count); + } +} + +uint64_t devfs_get_seek(struct file_handle_t* handle) { + struct dev_handle_t* dev_handle = (struct dev_handle_t*)handle; + + if (!dev_handle) { + return FILE_ERROR; + } + + switch (dev_handle->type) { + case DEV_TYPE_TTY: + return 0; + } +} + + +enum file_status_t devfs_seek(struct file_handle_t* handle, uint64_t seek) { + (void)seek; + + struct dev_handle_t* dev_handle = (struct dev_handle_t*)handle; + + if (!dev_handle) { + return FILE_ERROR; + } + + switch (dev_handle->type) { + case DEV_TYPE_TTY: + return FILE_NO_SUPPORT; + } +} + +size_t devfs_write(struct file_handle_t* handle, void* buffer, size_t count) { + struct dev_handle_t* dev_handle = (struct dev_handle_t*)handle; + + if (!dev_handle) { + return FILE_ERROR; + } + + switch (dev_handle->type) { + case DEV_TYPE_TTY: + tty_write(dev_handle->dev_handle.tty, buffer, count); + return count; + } +} diff --git a/kernel/devfs/tty.c b/kernel/devfs/tty.c new file mode 100644 index 0000000..2c7c60b --- /dev/null +++ b/kernel/devfs/tty.c @@ -0,0 +1,180 @@ +/* tty.c - tty device handler */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#define TTY_RING_MASK 0x3FFF + +#define MASK(i) ((i) & TTY_RING_MASK) +#define EMPTY(r, w) (r == w) +#define FULL(r, w) (MASK(w + 1) == r) + +#ifdef SERIAL +#include +#endif /* SERIAL */ + +typedef void (*tty_write_t)(uint8_t byte); + +struct tty_handle_t { + tty_write_t writer; + uint8_t* read_buffer; + volatile uint16_t write_index; + volatile uint16_t read_index; + enum { + TTY_MODE_COOKED, + TTY_MODE_RAW + } tty_mode; + uint8_t lock; +}; + +#ifdef SERIAL + +static struct tty_handle_t com1; +static struct tty_handle_t com2; + +#endif /* SERIAL */ + +void tty_init(void) { +#ifdef SERIAL + com1.writer = serial_write_com1; + com1.read_buffer = (uint8_t*)paging_ident(mm_alloc_p(TTY_READ_BUFFER_SIZE)); + com1.write_index = 0; + com1.read_index = 0; + lock_init(&com1.lock); + + com2.writer = serial_write_com2; + com2.read_buffer = (uint8_t*)paging_ident(mm_alloc_p(TTY_READ_BUFFER_SIZE)); + com2.write_index = 0; + com2.read_index = 0; + lock_init(&com2.lock); +#endif /* SERIAL */ +} + +#ifdef SERIAL +struct tty_handle_t* tty_com1(void) { + return &com1; +} + +struct tty_handle_t* tty_com2(void) { + return &com2; +} +#endif /* SERIAL */ + +struct tty_handle_t* tty_open(char* name) { +#ifdef SERIAL + if (!kstrcmp(name, "S0")) { + // COM1 + return &com1; + } + else if (!kstrcmp(name, "S1")) { + // COM2 + return &com2; + } +#endif /* SERIAL */ + + return 0; +} + +size_t tty_read(struct tty_handle_t* tty, void* buffer, size_t count) { + size_t read = 0; + uint8_t* write = buffer; + + while (count) { + while (EMPTY(tty->read_index, tty->write_index)) { + cpu_pause(); //TODO futex wait + } + + lock_acquire(&tty->lock); + + while (count && !EMPTY(tty->read_index, tty->write_index)) { + *write = tty->read_buffer[MASK(tty->read_index)]; + + tty->read_index++; + count--; + read++; + + if (*write == '\n' && tty->tty_mode == TTY_MODE_COOKED) { + // cooked mode must return early on newline + count = 0; + } + + write++; + + tty->read_index &= TTY_RING_MASK; + } + + lock_release(&tty->lock); + } + + return read; +} + +void tty_write(struct tty_handle_t* tty, void* buffer, size_t count) { + for (size_t i = 0; i < count; i++) { + uint8_t val = ((uint8_t*)buffer)[i]; + switch (val) { + case '\n': + tty->writer('\r'); + __attribute__((fallthrough)); + default: + tty->writer(((uint8_t*)buffer)[i]); + break; + } + } +} + +uint8_t tty_queue_read(struct tty_handle_t* tty, uint8_t byte) { + if (FULL(tty->read_index, tty->write_index)) { + return 0; + } + + if (byte == '\r') { + byte = '\n'; + } + + tty->read_buffer[MASK(tty->write_index)] = byte; + + tty->write_index++; + tty->write_index &= TTY_RING_MASK; + + if (tty->tty_mode == TTY_MODE_COOKED) { + // echoback on cooked + switch (byte) { + case '\n': + tty->writer('\r'); + __attribute__((fallthrough)); + default: + tty->writer(byte); + break; + } + } + + return 1; +} diff --git a/kernel/include/apic/ipi.h b/kernel/include/apic/ipi.h index fc7ca22..1714a4b 100644 --- a/kernel/include/apic/ipi.h +++ b/kernel/include/apic/ipi.h @@ -22,7 +22,6 @@ #define AP_ENTRY_PAGE 8 -extern void apic_init_shootdowns(uint8_t num_apic); extern void apic_ipi_init(void); extern void apic_wait_for_ipi(void); @@ -30,9 +29,9 @@ extern void apic_send_ipi_init_set(uint8_t apic_id); extern void apic_send_ipi_init_clear(uint8_t apic_id); extern void apic_send_ipi_sipi(uint8_t apic_id); -extern void apic_tlb_shootdown(uint64_t vaddr); extern void apic_tlb_shootdown_dispatch(void); -extern void apic_register_barrier(uint8_t apic_id); +extern void apic_init_shootdowns(void); +extern void apic_shootdown(uint8_t id); #endif /* KERNEL_APIC_IPI_H */ diff --git a/kernel/include/core/cpu_instr.h b/kernel/include/core/cpu_instr.h index bf414d8..7a32618 100644 --- a/kernel/include/core/cpu_instr.h +++ b/kernel/include/core/cpu_instr.h @@ -20,6 +20,8 @@ #include +#include + extern void cpu_lidt(uint64_t idt_ptr); extern void cpu_ltr_28(void); @@ -46,4 +48,28 @@ extern uint64_t cpu_get_cr3(void); extern void cpu_set_cr3(uint64_t cr3); +extern void cpu_hlt(void); + +static inline void cpu_sti_if(void) { + if (proc_data_get()->sts & PROC_STS_INT_READY) { + cpu_sti(); + } +} + +static inline void cpu_cli_if(void) { + cpu_cli(); +} + +extern void cpu_set_cr4(uint64_t bits); + +extern uint64_t cpu_get_fsbase(void); + +extern void cpu_set_fsbase(uint64_t base); + +extern void cpu_save_fx(uint8_t* data); + +extern void cpu_restore_fx(uint8_t* data); + +extern void cpu_init_fx(void); + #endif /* KERNEL_CORE_CPU_INSTR_H */ diff --git a/kernel/include/core/elf.h b/kernel/include/core/elf.h index 803f23f..49e080c 100644 --- a/kernel/include/core/elf.h +++ b/kernel/include/core/elf.h @@ -25,6 +25,6 @@ extern uint8_t elf_is_elf(struct fs_handle_t* file); -extern struct pcb_t* elf_load(struct fs_handle_t* file, uint64_t pid); +extern struct pcb_t* elf_load(struct fs_handle_t* file, uint64_t pid, const char* invoker, const char* env); #endif /* KERNEL_CORE_ELF_H */ diff --git a/kernel/include/core/fs.h b/kernel/include/core/fs.h index 14a4009..8c2e754 100644 --- a/kernel/include/core/fs.h +++ b/kernel/include/core/fs.h @@ -38,12 +38,12 @@ enum file_status_t { struct file_info_t { enum { FILE_TYPE_REG, - FILE_TYPE_DIR + FILE_TYPE_DIR, + FILE_TYPE_CHAR } type; uint64_t size; }; - typedef struct file_handle_t* (*fs_open_t)(struct mount_cntx_t*, char*); typedef void (*fs_close_t)(struct file_handle_t*); @@ -51,6 +51,7 @@ typedef enum file_status_t (*fs_stat_t)(struct file_handle_t*, struct file_info_ typedef size_t (*fs_read_t)(struct file_handle_t*, void*, size_t); typedef uint64_t (*fs_get_seek_t)(struct file_handle_t*); typedef enum file_status_t (*fs_seek_t)(struct file_handle_t*, uint64_t); +typedef size_t (*fs_write_t)(struct file_handle_t*, void*, size_t); void fs_init(void); @@ -62,7 +63,8 @@ enum file_status_t fs_mount( fs_stat_t stat, fs_read_t read, fs_get_seek_t get_seek, - fs_seek_t seek + fs_seek_t seek, + fs_write_t write ); extern struct fs_handle_t* fs_open(const char* path); @@ -72,5 +74,6 @@ extern enum file_status_t fs_stat(struct fs_handle_t* handle, struct file_info_t extern size_t fs_read(struct fs_handle_t* handle, void* buffer, size_t count); extern uint64_t fs_get_seek(struct fs_handle_t* handle); extern enum file_status_t fs_seek(struct fs_handle_t* handle, uint64_t seek); +extern size_t fs_write(struct fs_handle_t* handle, void* buffer, size_t count); #endif /* KERNEL_CORE_FS_H */ diff --git a/kernel/include/core/mm.h b/kernel/include/core/mm.h index 2dc0273..c756a08 100644 --- a/kernel/include/core/mm.h +++ b/kernel/include/core/mm.h @@ -36,6 +36,12 @@ struct mem_segment_t { struct mm_tree_node_t; +struct free_transaction_list_t { + uint64_t base; + size_t size; + struct free_transaction_list_t* next; +}; + extern void mm_init( void (*first_segment)(uint64_t* handle), void (*next_segment)(uint64_t* handle, struct mem_segment_t* seg)); @@ -52,5 +58,10 @@ extern uint64_t mm_alloc_vmax(size_t size, uint64_t align, uint64_t max); extern void mm_free_p(uint64_t base, size_t size); extern void mm_free_v(uint64_t base, size_t size); +extern void mm_transaction_init(void); +extern struct free_transaction_list_t* mm_get_shootdown_list(void); +extern void mm_register_barrier(uint8_t id); +extern void mm_barrier_disarm(uint8_t id); + #endif /* KERNEL_CORE_MM_H */ diff --git a/kernel/include/core/msr.h b/kernel/include/core/msr.h index 440b0ae..ddbf55f 100644 --- a/kernel/include/core/msr.h +++ b/kernel/include/core/msr.h @@ -22,6 +22,8 @@ #define MSR_APIC_BASE 0x0000001B #define MSR_STAR 0xC0000081 +#define MSR_LSTAR 0xC0000082 +#define MSR_FMASK 0xC0000084 extern void msr_write(uint64_t msr, uint64_t val); diff --git a/kernel/include/core/proc_data.h b/kernel/include/core/proc_data.h index 8c0068b..20890f0 100644 --- a/kernel/include/core/proc_data.h +++ b/kernel/include/core/proc_data.h @@ -23,10 +23,14 @@ #include #include +#define PROC_STS_INT_READY 0x01 + struct proc_data_t { + uint64_t kernel_rsp; // order matters uint8_t arb_id; volatile struct tss_t* tss; struct pcb_t* current_process; + uint64_t sts; }; extern struct proc_data_t bsp_proc_data; diff --git a/kernel/include/core/process.h b/kernel/include/core/process.h index 8fa479b..aa2757a 100644 --- a/kernel/include/core/process.h +++ b/kernel/include/core/process.h @@ -22,6 +22,9 @@ #include #include +#include + +#define MAX_FD 256 struct pcb_t { // order is important @@ -52,23 +55,31 @@ struct pcb_t { uint64_t pid; uint32_t k_rsp_lo; uint32_t k_rsp_hi; - uint64_t saved_usr_rsp; uint64_t init_k_rsp_vaddr; uint64_t init_k_rsp_paddr; - - struct process_memory_region_t* mem; + uint64_t fsbase; + uint64_t mem_top; uint64_t cr3; struct pcb_t* next; + struct fs_handle_t* fd_table[MAX_FD]; + + uint8_t fxdata[512] __attribute__((aligned(16))); + enum { SCHED_READY, SCHED_KILL, - SCHED_SKIP + SCHED_SKIP, + SCHED_SLEEP } sched_cntr; -} __attribute__((packed)); + union { + uint64_t wake_time; + } sleep_state; + +}; struct preempt_frame_t { uint64_t rbp; @@ -118,4 +129,6 @@ extern void process_preempt_entry(struct preempt_frame_t* context) __attribute__ extern uint8_t process_create_guarded_stack(uint64_t* init_vaddr, uint64_t* init_paddr, uint64_t* stack); +extern void process_sleep(uint64_t wake_time); + #endif /* KERNEL_CORE_PROCESS_H */ diff --git a/kernel/include/core/syscall.h b/kernel/include/core/syscall.h index b57f731..bdc9a42 100644 --- a/kernel/include/core/syscall.h +++ b/kernel/include/core/syscall.h @@ -20,6 +20,8 @@ #include -extern void syscall_return(uint64_t rip, uint64_t rfl, uint64_t rsp); +extern void syscall_return(uint64_t rip, uint64_t rfl, uint64_t rsp, uint64_t rax) __attribute__((noreturn)); + +extern void syscall_entry(void) __attribute__((noreturn)); #endif /* KERNEL_CORE_SYSCALL_H */ diff --git a/kernel/include/core/syscall_dispatch.h b/kernel/include/core/syscall_dispatch.h new file mode 100644 index 0000000..bd82d6f --- /dev/null +++ b/kernel/include/core/syscall_dispatch.h @@ -0,0 +1,52 @@ +/* syscall_dispatch.h - kernel system call dispatching interface */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#ifndef KERNEL_CORE_SYSCALL_DISPATCH_H +#define KERNEL_CORE_SYSCALL_DISPATCH_H + +#include + +#include + +#define DECLARE_SYSCALL(name) \ + uint64_t syscall_dispatch_##name ( \ + uint64_t arg1, \ + uint64_t arg2, \ + uint64_t arg3, \ + uint64_t arg6, \ + uint64_t arg4, \ + uint64_t arg5) + +typedef uint64_t (*syscall_dispatch_t)( + uint64_t arg1, + uint64_t arg2, + uint64_t arg3, + uint64_t arg6, + uint64_t arg4, + uint64_t arg5); + + +extern syscall_dispatch_t syscall_handlers[SYSCALL_MAX]; + +extern DECLARE_SYSCALL(exit); +extern DECLARE_SYSCALL(open); +extern DECLARE_SYSCALL(close); +extern DECLARE_SYSCALL(read); +extern DECLARE_SYSCALL(write); +extern DECLARE_SYSCALL(alloc); + +#endif /* KERNEL_CORE_SYSCALL_DISPATCH_H */ diff --git a/kernel/include/core/syscall_vectors.h b/kernel/include/core/syscall_vectors.h new file mode 100644 index 0000000..92d0a40 --- /dev/null +++ b/kernel/include/core/syscall_vectors.h @@ -0,0 +1,80 @@ +/* syscall_vectors.h - ModulOS system call vectors */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +/* + * System call convention + * rax: vector + * rdi: arg1 + * rsi: arg2 + * rdx: arg3 + * r8 : arg4 + * r9 : arg5 + * r10: arg6 + * + * arguments not guaranteed to be preserved + * + * rcx and r11 are clobbered + * all other registers are preserved + * return status stored in rax + */ + +#define SYSCALL_STS_OK 0 +#define SYSCALL_STS_FAIL -1uLL + +/* + * rdi: exit status (int) + * ret: (void) + */ +#define SYSCALL_EXIT 0 + +/* + * rdi: path (const char*) + * ret: handle (int) + */ +#define SYSCALL_OPEN 1 + +/* + * rdi: handle (int) + * ret: (void) + */ +#define SYSCALL_CLOSE 2 + +/* + * rdi: handle (int) + * rsi: buffer (char*) + * rdx: count (size_t) + * ret: bytes read (size_t) + */ +#define SYSCALL_READ 3 + +/* + * rdi: handle (int) + * rsi: buffer (char*) + * rdx: count (size_t) + * ret: bytes written (size_t) + */ +#define SYSCALL_WRITE 4 + +/* + * rdi: size (long) + * ret: mem region (void*) + */ +#define SYSCALL_ALLOC 5 + +#define SYSCALL_MAX 6 + + diff --git a/kernel/include/core/time.h b/kernel/include/core/time.h index 7976c0c..16e884b 100644 --- a/kernel/include/core/time.h +++ b/kernel/include/core/time.h @@ -27,11 +27,13 @@ extern void time_init(void); -//TODO: implement task sleep extern uint64_t time_busy_wait(uint64_t min_ns); +extern uint64_t time_sleep(uint64_t min_ms); + extern uint64_t time_since_init_ns(void); extern uint64_t time_since_init_fs(void); + #endif /* KERNEL_CORE_TIME_H */ diff --git a/kernel/include/devfs/devfs.h b/kernel/include/devfs/devfs.h new file mode 100644 index 0000000..4a2996d --- /dev/null +++ b/kernel/include/devfs/devfs.h @@ -0,0 +1,35 @@ +/* devfs.h - kernel device block file system interface */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#ifndef KERNEL_DEVFS_DEVFS_H +#define KERNEL_DEVFS_DEVFS_H + +#include +#include + +#include + +extern struct file_handle_t* devfs_open(struct mount_cntx_t* cntx, char* path); +extern void devfs_close(struct file_handle_t* handle); + +extern enum file_status_t devfs_stat(struct file_handle_t* handle, struct file_info_t* info); +extern size_t devfs_read(struct file_handle_t* handle, void* buffer, size_t count); +extern uint64_t devfs_get_seek(struct file_handle_t* handle); +extern enum file_status_t devfs_seek(struct file_handle_t* handle, uint64_t seek); +extern size_t devfs_write(struct file_handle_t* handle, void* buffer, size_t count); + +#endif /* KERNEL_DEVFS_DEVFS_H */ diff --git a/kernel/include/devfs/tty.h b/kernel/include/devfs/tty.h new file mode 100644 index 0000000..0b8a157 --- /dev/null +++ b/kernel/include/devfs/tty.h @@ -0,0 +1,41 @@ +/* tty.h - tty device interface */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#ifndef KERNEL_DEVFS_TTY_H +#define KERNEL_DEVFS_TTY_H + +#include +#include + +#define TTY_READ_BUFFER_SIZE 0x4000 + +struct tty_handle_t; + +extern void tty_init(void); + +#ifdef SERIAL +extern struct tty_handle_t* tty_com1(void); +extern struct tty_handle_t* tty_com2(void); +#endif /* SERIAL */ + +extern struct tty_handle_t* tty_open(char* name); +extern void tty_close(struct tty_handle_t* tty); +extern size_t tty_read(struct tty_handle_t* tty, void* buffer, size_t count); +extern uint8_t tty_queue_read(struct tty_handle_t* tty, uint8_t byte); +extern void tty_write(struct tty_handle_t* tty, void* buffer, size_t count); + +#endif /* KERNEL_DEVFS_TTY_H */ diff --git a/kernel/ioapic/routing.c b/kernel/ioapic/routing.c index d297958..f318d36 100644 --- a/kernel/ioapic/routing.c +++ b/kernel/ioapic/routing.c @@ -66,7 +66,6 @@ void ioapic_routing_init(uint64_t num_gsi) { for (uint64_t i = 0; i < num_gsi; i++) { gsi_routing[i].purpose = "Unused"; gsi_routing[i].type = GSI_TYPE_UNUSED; - legacy_routing[i] = i; } // map legacy @@ -74,6 +73,7 @@ void ioapic_routing_init(uint64_t num_gsi) { gsi_routing[i].purpose = legacy_purpose[i]; gsi_routing[i].type = GSI_TYPE_LEGACY; gsi_routing[i].meta.isa_src = i; + legacy_routing[i] = i; } uint64_t handle; diff --git a/scripts/Makefile.header b/scripts/Makefile.header index e9b4cb3..853e43d 100644 --- a/scripts/Makefile.header +++ b/scripts/Makefile.header @@ -43,3 +43,8 @@ endif ifdef SMP_ENABLE DEFINES := $(DEFINES) -DSMP_ENABLE endif + +ifdef CHECK_ALLOC +DEFINES := $(DEFINES) -DCHECK_ALLOC +endif + diff --git a/scripts/Makefile.kcflags b/scripts/Makefile.kcflags index b9017ea..2e5cf8d 100644 --- a/scripts/Makefile.kcflags +++ b/scripts/Makefile.kcflags @@ -22,7 +22,7 @@ ifndef DEBUG CWARN := $(CWARN) -Werror endif -LD_USR_FLAGS := -std=c23 -fno-pie -mno-mmx -mno-sse -mno-sse2 \ +LD_USR_FLAGS := -std=c23 -fno-pie -mno-mmx -mno-sse -mno-sse2 -mno-avx -mno-avx2 -mno-avx512f \ -fomit-frame-pointer -nodefaultlibs -nostdlib -mcmodel=kernel \ -ffreestanding -fno-unwind-tables -fno-exceptions -fno-rtti \ -fno-semantic-interposition -fvisibility=hidden \ diff --git a/scripts/simulate_qemu b/scripts/simulate_qemu index 013438a..2dbdaf1 100755 --- a/scripts/simulate_qemu +++ b/scripts/simulate_qemu @@ -9,8 +9,9 @@ qemu-system-x86_64 \ -s -smp 4 \ -serial vc \ -serial file:build/test-runtime/serial \ - -d cpu_reset,int \ + -d cpu_reset,int,guest_errors \ -m 16G \ + -cpu max \ -monitor stdio \ -drive if=none,id=disk0,file=build/modulos.img,format=raw \ -drive if=none,id=disk1,file=build/test-runtime/disk1.img,format=raw \ diff --git a/userland/.gitignore b/userland/.gitignore new file mode 100644 index 0000000..0c91cc2 --- /dev/null +++ b/userland/.gitignore @@ -0,0 +1 @@ +mlibc/ diff --git a/userland/Makefile b/userland/Makefile index 4261cb4..e9fb829 100644 --- a/userland/Makefile +++ b/userland/Makefile @@ -14,21 +14,57 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see -export SRC_TREE_ROOT := ../$(SRC_TREE_ROOT) +SRC_TREE_ROOT := ../$(SRC_TREE_ROOT) include $(SRC_TREE_ROOT)/scripts/Makefile.header -export OBJ_DIR := $(OBJ_DIR)/userland +OBJ_DIR := $(OBJ_DIR)/userland -SUBTARGETS := test +U_CFLAGS := -g -fno-pie -static \ + -nostdlib -nodefaultlibs \ + -fno-exceptions -fno-unwind-tables -fno-asynchronous-unwind-tables \ + --sysroot=$(OBJ_DIR)/../userland_files/ + +LIB := $(OBJ_DIR)/../userland_files/usr/lib .PHONY: all all: build +%/: + mkdir -p $@ + .PHONY: build -build: $(OBJ_DIR)/../userland_files/ +build: libc $(OBJ_DIR)/../userland_files/bin/shell + +.PHONY: clean +clean: + -rm -rdf $(OBJ_DIR)/mlibc-meson-setup mlibc/ + + +$(OBJ_DIR)/mlibc-meson-setup: | $(OBJ_DIR)/libc-build/ $(OBJ_DIR)/../userland_files/usr/ + -rm -rdf mlibc/ + git clone https://github.com/managarm/mlibc.git mlibc + git -C mlibc/ checkout v6.3.1 + git -C mlibc/ apply ../mlibc-patch/mlibc-v6-3-1-port.patch + cp -r mlibc-patch/* mlibc/ + meson setup \ + --native-file mlibc/ci/linux-x86_64-clang.cross-file \ + --cross-file mlibc/ci/modulos.cross-file \ + --prefix $(abspath $(OBJ_DIR)/../userland_files/usr/) \ + --reconfigure \ + -Ddefault_library=static \ + $(OBJ_DIR)/libc-build \ + mlibc/ + touch $@ + +.PHONY: libc +libc: $(OBJ_DIR)/mlibc-meson-setup + ninja -C $(OBJ_DIR)/libc-build/ + meson install --only-changed -C $(OBJ_DIR)/libc-build/ + +$(LIB)/crt1.o $(LIB)/libc.a: libc -$(OBJ_DIR)/../userland_files/: $(SUBTARGETS) +$(OBJ_DIR)/shell.o: shell/main.c | $(OBJ_DIR) + $(CC) $(U_CFLAGS) -c -o $(OBJ_DIR)/shell.o $< -.PHONY: $(SUBTARGETS) -$(SUBTARGETS): - $(MAKE) -C $@ build +$(OBJ_DIR)/../userland_files/bin/shell: $(OBJ_DIR)/shell.o $(LIB)/crt1.o $(LIB)/libc.a | $(OBJ_DIR)/../userland_files/bin/ + $(CC) $(U_CFLAGS) -fuse-ld=lld -o $@ $(LIB)/crt1.o $< $(LIB)/libc.a diff --git a/userland/mlibc-patch/abis/modulos/auxv.h b/userland/mlibc-patch/abis/modulos/auxv.h new file mode 100644 index 0000000..b86f199 --- /dev/null +++ b/userland/mlibc-patch/abis/modulos/auxv.h @@ -0,0 +1,16 @@ +#ifndef _ABIBITS_AUXV_H +#define _ABIBITS_AUXV_H + +#define AT_PLATFORM 15 +#define AT_HWCAP 16 +#define AT_CLKTCK 17 +#define AT_FPUCW 18 +#define AT_SECURE 23 +#define AT_RANDOM 25 +#define AT_HWCAP2 26 +#define AT_HWCAP3 29 +#define AT_HWCAP4 30 +#define AT_EXECFN 31 +#define AT_SYSINFO_EHDR 33 + +#endif /* _ABIBITS_AUXV_H */ diff --git a/userland/mlibc-patch/abis/modulos/clockid_t.h b/userland/mlibc-patch/abis/modulos/clockid_t.h new file mode 100644 index 0000000..8d92826 --- /dev/null +++ b/userland/mlibc-patch/abis/modulos/clockid_t.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_CLOCKID_T_H +#define _ABIBITS_CLOCKID_T_H + +typedef int clockid_t; + +#endif /* _ABIBITS_CLOCKID_T_H */ + diff --git a/userland/mlibc-patch/abis/modulos/errno.h b/userland/mlibc-patch/abis/modulos/errno.h new file mode 100644 index 0000000..0c01d33 --- /dev/null +++ b/userland/mlibc-patch/abis/modulos/errno.h @@ -0,0 +1,144 @@ +#ifndef _ABIBITS_ERRNO_H +#define _ABIBITS_ERRNO_H + +#define EPERM 1 +#define ENOENT 2 +#define ESRCH 3 +#define EINTR 4 +#define EIO 5 +#define ENXIO 6 +#define E2BIG 7 +#define ENOEXEC 8 +#define EBADF 9 +#define ECHILD 10 +#define EAGAIN 11 +#define ENOMEM 12 +#define EACCES 13 +#define EFAULT 14 +#define ENOTBLK 15 +#define EBUSY 16 +#define EEXIST 17 +#define EXDEV 18 +#define ENODEV 19 +#define ENOTDIR 20 +#define EISDIR 21 +#define EINVAL 22 +#define ENFILE 23 +#define EMFILE 24 +#define ENOTTY 25 +#define ETXTBSY 26 +#define EFBIG 27 +#define ENOSPC 28 +#define ESPIPE 29 +#define EROFS 30 +#define EMLINK 31 +#define EPIPE 32 +#define EDOM 33 +#define ERANGE 34 +#define EDEADLK 35 +#define ENAMETOOLONG 36 +#define ENOLCK 37 +#define ENOSYS 38 +#define ENOTEMPTY 39 +#define ELOOP 40 +#define EWOULDBLOCK EAGAIN +#define ENOMSG 42 +#define EIDRM 43 +#define ECHRNG 44 +#define EL2NSYNC 45 +#define EL3HLT 46 +#define EL3RST 47 +#define ELNRNG 48 +#define EUNATCH 49 +#define ENOCSI 50 +#define EL2HLT 51 +#define EBADE 52 +#define EBADR 53 +#define EXFULL 54 +#define ENOANO 55 +#define EBADRQC 56 +#define EBADSLT 57 +#define EDEADLOCK EDEADLK +#define EBFONT 59 +#define ENOSTR 60 +#define ENODATA 61 +#define ETIME 62 +#define ENOSR 63 +#define ENONET 64 +#define ENOPKG 65 +#define EREMOTE 66 +#define ENOLINK 67 +#define EADV 68 +#define ESRMNT 69 +#define ECOMM 70 +#define EPROTO 71 +#define EMULTIHOP 72 +#define EDOTDOT 73 +#define EBADMSG 74 +#define EOVERFLOW 75 +#define ENOTUNIQ 76 +#define EBADFD 77 +#define EREMCHG 78 +#define ELIBACC 79 +#define ELIBBAD 80 +#define ELIBSCN 81 +#define ELIBMAX 82 +#define ELIBEXEC 83 +#define EILSEQ 84 +#define ERESTART 85 +#define ESTRPIPE 86 +#define EUSERS 87 +#define ENOTSOCK 88 +#define EDESTADDRREQ 89 +#define EMSGSIZE 90 +#define EPROTOTYPE 91 +#define ENOPROTOOPT 92 +#define EPROTONOSUPPORT 93 +#define ESOCKTNOSUPPORT 94 +#define EOPNOTSUPP 95 +#define ENOTSUP EOPNOTSUPP +#define EPFNOSUPPORT 96 +#define EAFNOSUPPORT 97 +#define EADDRINUSE 98 +#define EADDRNOTAVAIL 99 +#define ENETDOWN 100 +#define ENETUNREACH 101 +#define ENETRESET 102 +#define ECONNABORTED 103 +#define ECONNRESET 104 +#define ENOBUFS 105 +#define EISCONN 106 +#define ENOTCONN 107 +#define ESHUTDOWN 108 +#define ETOOMANYREFS 109 +#define ETIMEDOUT 110 +#define ECONNREFUSED 111 +#define EHOSTDOWN 112 +#define EHOSTUNREACH 113 +#define EALREADY 114 +#define EINPROGRESS 115 +#define ESTALE 116 +#define EUCLEAN 117 +#define ENOTNAM 118 +#define ENAVAIL 119 +#define EISNAM 120 +#define EREMOTEIO 121 +#define EDQUOT 122 +#define ENOMEDIUM 123 +#define EMEDIUMTYPE 124 +#define ECANCELED 125 +#define ENOKEY 126 +#define EKEYEXPIRED 127 +#define EKEYREVOKED 128 +#define EKEYREJECTED 129 +#define EOWNERDEAD 130 +#define ENOTRECOVERABLE 131 +#define ERFKILL 132 +#define EHWPOISON 133 + + +/* This is mlibc-specific. */ +#define EIEIO 4095 + +#endif /* _ABIBITS_ERRNO_H */ + diff --git a/userland/mlibc-patch/abis/modulos/fcntl.h b/userland/mlibc-patch/abis/modulos/fcntl.h new file mode 100644 index 0000000..4e7eb2e --- /dev/null +++ b/userland/mlibc-patch/abis/modulos/fcntl.h @@ -0,0 +1,125 @@ +#ifndef _ABIBITS_FCNTL_H +#define _ABIBITS_FCNTL_H + +#include +#include + +#define O_PATH 010000000 + +#define O_ACCMODE (03 | O_PATH) +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDWR 02 + +#define O_CREAT 0100 +#define O_EXCL 0200 +#define O_NOCTTY 0400 +#define O_TRUNC 01000 +#define O_APPEND 02000 +#define O_NONBLOCK 04000 +#define O_DSYNC 010000 +#define O_ASYNC 020000 +#define O_DIRECT 040000 +#define O_DIRECTORY 0200000 +#define O_NOFOLLOW 0400000 +#define O_CLOEXEC 02000000 +#define O_SYNC 04010000 +#define O_RSYNC 04010000 +#define O_LARGEFILE 0100000 +#define O_NOATIME 01000000 +#define O_TMPFILE 020000000 + +#define O_EXEC O_PATH +#define O_SEARCH O_PATH + +#define F_DUPFD 0 +#define F_GETFD 1 +#define F_SETFD 2 +#define F_GETFL 3 +#define F_SETFL 4 + +#define F_SETOWN 8 +#define F_GETOWN 9 +#define F_SETSIG 10 +#define F_GETSIG 11 + +#define F_GETLK 5 +#define F_SETLK 6 +#define F_SETLK64 F_SETLK +#define F_SETLKW 7 +#define F_SETLKW64 F_SETLKW + +#define F_SETOWN_EX 15 +#define F_GETOWN_EX 16 + +#define F_GETOWNER_UIDS 17 + +#define F_SETLEASE 1024 +#define F_GETLEASE 1025 +#define F_NOTIFY 1026 +#define F_DUPFD_CLOEXEC 1030 +#define F_SETPIPE_SZ 1031 +#define F_GETPIPE_SZ 1032 +#define F_ADD_SEALS 1033 +#define F_GET_SEALS 1034 + +#define F_SEAL_SEAL 0x0001 +#define F_SEAL_SHRINK 0x0002 +#define F_SEAL_GROW 0x0004 +#define F_SEAL_WRITE 0x0008 + +#define F_OFD_GETLK 36 +#define F_OFD_SETLK 37 +#define F_OFD_SETLKW 38 + +#define F_RDLCK 0 +#define F_WRLCK 1 +#define F_UNLCK 2 + +#define FD_CLOEXEC 1 + +#define AT_FDCWD -100 +#define AT_SYMLINK_NOFOLLOW 0x100 +#define AT_REMOVEDIR 0x200 +#define AT_SYMLINK_FOLLOW 0x400 +#define AT_EACCESS 0x200 +#define AT_NO_AUTOMOUNT 0x800 +#define AT_EMPTY_PATH 0x1000 + +#if __MLIBC_LINUX_OPTION + +#define DN_ACCESS 1 +#define DN_MODIFY 2 +#define DN_CREATE 4 +#define DN_DELETE 8 +#define DN_RENAME 16 +#define DN_ATTRIB 32 +#define DN_MULTISHOT 0x80000000 + +#define AT_STATX_SYNC_AS_STAT 0x0000 +#define AT_STATX_FORCE_SYNC 0x2000 +#define AT_STATX_DONT_SYNC 0x4000 +#define AT_STATX_SYNC_TYPE 0x6000 + +#endif /* __MLIBC_LINUX_OPTION */ + +#if defined(_GNU_SOURCE) +struct f_owner_ex { + int type; + pid_t pid; +}; +#endif /* _GNU_SOURCE */ + +#define F_OWNER_TID 0 +#define F_OWNER_PID 1 +#define F_OWNER_PGRP 2 + +#define POSIX_FADV_NORMAL 0 +#define POSIX_FADV_RANDOM 1 +#define POSIX_FADV_SEQUENTIAL 2 +#define POSIX_FADV_WILLNEED 3 +#define POSIX_FADV_DONTNEED 4 +#define POSIX_FADV_NOREUSE 5 + +#endif /* _ABIBITS_FCNTL_H */ + diff --git a/userland/mlibc-patch/abis/modulos/limits.h b/userland/mlibc-patch/abis/modulos/limits.h new file mode 100644 index 0000000..e6d6200 --- /dev/null +++ b/userland/mlibc-patch/abis/modulos/limits.h @@ -0,0 +1,11 @@ +#ifndef _ABIBITS_LIMITS_H +#define _ABIBITS_LIMITS_H + +#define IOV_MAX 1024 +#define LOGIN_NAME_MAX 256 +#define HOST_NAME_MAX 64 +#define NAME_MAX 255 +#define OPEN_MAX 256 + +#endif /*_ABIBITS_LIMITS_H */ + diff --git a/userland/mlibc-patch/abis/modulos/mode_t.h b/userland/mlibc-patch/abis/modulos/mode_t.h new file mode 100644 index 0000000..b00bb97 --- /dev/null +++ b/userland/mlibc-patch/abis/modulos/mode_t.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_MODE_T_H +#define _ABIBITS_MODE_T_H + +typedef unsigned int mode_t; + +#endif /* _ABIBITS_MODE_T_H */ + diff --git a/userland/mlibc-patch/abis/modulos/pid_t.h b/userland/mlibc-patch/abis/modulos/pid_t.h new file mode 100644 index 0000000..05e8a97 --- /dev/null +++ b/userland/mlibc-patch/abis/modulos/pid_t.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_PID_T_H +#define _ABIBITS_PID_T_H + +typedef unsigned long pid_t; + +#endif /* _ABIBITS_PID_T_H */ + diff --git a/userland/mlibc-patch/abis/modulos/seek-whence.h b/userland/mlibc-patch/abis/modulos/seek-whence.h new file mode 100644 index 0000000..b8864db --- /dev/null +++ b/userland/mlibc-patch/abis/modulos/seek-whence.h @@ -0,0 +1,11 @@ +#ifndef _ABIBITS_SEEK_WHENCE_H +#define _ABIBITS_SEEK_WHENCE_H + +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 +#define SEEK_DATA 3 +#define SEEK_HOLE 4 + +#endif /* _ABIBITS_SEEK_WHENCE_H */ + diff --git a/userland/mlibc-patch/abis/modulos/signal.h b/userland/mlibc-patch/abis/modulos/signal.h new file mode 100644 index 0000000..71d12e3 --- /dev/null +++ b/userland/mlibc-patch/abis/modulos/signal.h @@ -0,0 +1,243 @@ +#ifndef _ABIBITS_SIGNAL_H +#define _ABIBITS_SIGNAL_H + +#include +#include +#include +#include + +#define POLL_IN 1 +#define POLL_OUT 2 +#define POLL_MSG 3 +#define POLL_ERR 4 +#define POLL_PRI 5 +#define POLL_HUP 6 + +union sigval {}; + +typedef struct { + int si_signo, si_errno, si_code; + union { + char __pad[128 - 2*sizeof(int) - sizeof(long)]; + struct { + union { + struct { + pid_t si_pid; + uid_t si_uid; + } __piduid; + struct { + int si_timerid; + int si_overrun; + } __timer; + } __first; + union { + union sigval si_value; + struct { + int si_status; + clock_t si_utime, si_stime; + } __sigchld; + } __second; + } __si_common; + struct { + void *si_addr; + short si_addr_lsb; + union { + struct { + void *si_lower; + void *si_upper; + } __addr_bnd; + unsigned si_pkey; + } __first; + } __sigfault; + struct { + long si_band; + int si_fd; + } __sigpoll; + struct { + void *si_call_addr; + int si_syscall; + unsigned si_arch; + } __sigsys; + } __si_fields; +} siginfo_t; + +#define si_pid __si_fields.__si_common.__first.__piduid.si_pid +#define si_uid __si_fields.__si_common.__first.__piduid.si_uid +#define si_status __si_fields.__si_common.__second.__sigchld.si_status +#define si_utime __si_fields.__si_common.__second.__sigchld.si_utime +#define si_stime __si_fields.__si_common.__second.__sigchld.si_stime +#define si_value __si_fields.__si_common.__second.si_value +#define si_addr __si_fields.__sigfault.si_addr +#define si_addr_lsb __si_fields.__sigfault.si_addr_lsb +#define si_lower __si_fields.__sigfault.__first.__addr_bnd.si_lower +#define si_upper __si_fields.__sigfault.__first.__addr_bnd.si_upper +#define si_pkey __si_fields.__sigfault.__first.si_pkey +#define si_band __si_fields.__sigpoll.si_band +#define si_fd __si_fields.__sigpoll.si_fd +#define si_timerid __si_fields.__si_common.__first.__timer.si_timerid +#define si_overrun __si_fields.__si_common.__first.__timer.si_overrun +#define si_ptr si_value.sival_ptr +#define si_int si_value.sival_int +#define si_call_addr __si_fields.__sigsys.si_call_addr +#define si_syscall __si_fields.__sigsys.si_syscall +#define si_arch __si_fields.__sigsys.si_arch + +/* Required for sys_sigaction sysdep. */ +#define SA_NOCLDSTOP 1 +#define SA_NOCLDWAIT 2 +#define SA_SIGINFO 4 +#define SA_ONSTACK 0x08000000 +#define SA_RESTART 0x10000000 +#define SA_NODEFER 0x40000000 +#define SA_RESETHAND 0x80000000 +#define SA_RESTORER 0x04000000 + +/* SA_NOMASK is an alias for SA_NODEFER */ +/* SA_ONESHOT is an alias for SA_RESETHAND */ +#define SA_NOMASK SA_NODEFER +#define SA_ONESHOT SA_RESETHAND + +/* Argument for signal() */ +typedef void (*__sighandler) (int); + +#define SIG_ERR ((__sighandler)(void *)(-1)) +#define SIG_DFL ((__sighandler)(void *)(0)) +#define SIG_IGN ((__sighandler)(void *)(1)) + +#define SIGABRT 6 +#define SIGFPE 8 +#define SIGILL 4 +#define SIGINT 2 +#define SIGSEGV 11 +#define SIGTERM 15 +#define SIGPROF 27 +#define SIGIO 29 +#define SIGPWR 30 +#define SIGRTMIN 35 +#define SIGRTMAX 64 + +typedef struct { + unsigned long sig[1024 / (8 * sizeof(long))]; +} sigset_t; + +/* constants for sigprocmask() */ +#define SIG_BLOCK 0 +#define SIG_UNBLOCK 1 +#define SIG_SETMASK 2 + +#define SIGHUP 1 +#define SIGQUIT 3 +#define SIGTRAP 5 +#define SIGIOT SIGABRT +#define SIGBUS 7 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGWINCH 28 +#define SIGPOLL 29 +#define SIGSYS 31 +#define SIGUNUSED SIGSYS +#define SIGCANCEL 32 +#define SIGTIMER 33 + +#define MINSIGSTKSZ 2048 +#define SIGSTKSZ 8192 +#define SS_ONSTACK 1 +#define SS_DISABLE 2 + +typedef struct __stack { + //TODO +} stack_t; + +/* constants for sigev_notify of struct sigevent */ +#define SIGEV_SIGNAL 0 +#define SIGEV_NONE 1 +#define SIGEV_THREAD 2 +#define SIGEV_THREAD_ID 4 + +#define SEGV_MAPERR 1 +#define SEGV_ACCERR 2 + +#define BUS_ADRALN 1 +#define BUS_ADRERR 2 +#define BUS_OBJERR 3 +#define BUS_MCEERR_AR 4 +#define BUS_MCEERR_AO 5 + +#define ILL_ILLOPC 1 +#define ILL_ILLOPN 2 +#define ILL_ILLADR 3 +#define ILL_ILLTRP 4 +#define ILL_PRVOPC 5 +#define ILL_PRVREG 6 +#define ILL_COPROC 7 +#define ILL_BADSTK 8 +#define ILL_BADIADDR 9 + +#define NSIG 65 + +#define SI_ASYNCNL (-60) +#define SI_TKILL (-6) +#define SI_SIGIO (-5) +#define SI_ASYNCIO (-4) +#define SI_MESGQ (-3) +#define SI_TIMER (-2) +#define SI_QUEUE (-1) +#define SI_USER 0 +#define SI_KERNEL 128 + +#define REG_R8 0 +#define REG_R9 1 +#define REG_R10 2 +#define REG_R11 3 +#define REG_R12 4 +#define REG_R13 5 +#define REG_R14 6 +#define REG_R15 7 +#define REG_RDI 8 +#define REG_RSI 9 +#define REG_RBP 10 +#define REG_RBX 11 +#define REG_RDX 12 +#define REG_RAX 13 +#define REG_RCX 14 +#define REG_RSP 15 +#define REG_RIP 16 +#define REG_EFL 17 +#define REG_CSGSFS 18 +#define REG_ERR 19 +#define REG_TRAPNO 20 +#define REG_OLDMASK 21 +#define REG_CR2 22 +#define NGREG 23 + +#include + +struct sigaction { + union { + void (*sa_handler)(int); + void (*sa_sigaction)(int, siginfo_t *, void *); + } __sa_handler; + unsigned long sa_flags; + void (*sa_restorer)(void); + sigset_t sa_mask; +}; + +#define sa_handler __sa_handler.sa_handler +#define sa_sigaction __sa_handler.sa_sigaction + + +#endif /* _ABIBITS_SIGNAL_H */ diff --git a/userland/mlibc-patch/abis/modulos/stat.h b/userland/mlibc-patch/abis/modulos/stat.h new file mode 100644 index 0000000..9bc4686 --- /dev/null +++ b/userland/mlibc-patch/abis/modulos/stat.h @@ -0,0 +1,41 @@ +#ifndef _ABIBITS_STAT_H +#define _ABIBITS_STAT_H + +#include +#include + +#define S_IFMT 0x0F000 +#define S_IFBLK 0x06000 +#define S_IFCHR 0x02000 +#define S_IFIFO 0x01000 +#define S_IFREG 0x08000 +#define S_IFDIR 0x04000 +#define S_IFLNK 0x0A000 +#define S_IFSOCK 0x0C000 + +#define S_IRWXU 0700 +#define S_IRUSR 0400 +#define S_IWUSR 0200 +#define S_IXUSR 0100 +#define S_IRWXG 070 +#define S_IRGRP 040 +#define S_IWGRP 020 +#define S_IXGRP 010 +#define S_IRWXO 07 +#define S_IROTH 04 +#define S_IWOTH 02 +#define S_IXOTH 01 +#define S_ISUID 04000 +#define S_ISGID 02000 +#define S_ISVTX 01000 + +#define S_IREAD S_IRUSR +#define S_IWRITE S_IWUSR +#define S_IEXEC S_IXUSR + +struct stat { + size_t st_size; +}; + +#endif /* _ABIBITS_STAT_H */ + diff --git a/userland/mlibc-patch/abis/modulos/uid_t.h b/userland/mlibc-patch/abis/modulos/uid_t.h new file mode 100644 index 0000000..3720a9f --- /dev/null +++ b/userland/mlibc-patch/abis/modulos/uid_t.h @@ -0,0 +1,7 @@ +#ifndef _ABIBITS_UID_H +#define _ABIBITS_UID_H + +typedef int uid_t; + +#endif /* _ABIBITS_UID_T_H */ + diff --git a/userland/mlibc-patch/abis/modulos/vm-flags.h b/userland/mlibc-patch/abis/modulos/vm-flags.h new file mode 100644 index 0000000..02d0486 --- /dev/null +++ b/userland/mlibc-patch/abis/modulos/vm-flags.h @@ -0,0 +1,82 @@ +#ifndef _ABIBITS_VM_FLAGS_H +#define _ABIBITS_VM_FLAGS_H + +#include + +#define PROT_NONE 0x00 +#define PROT_READ 0x01 +#define PROT_WRITE 0x02 +#define PROT_EXEC 0x04 + +#define MAP_FAILED ((void *)(-1)) +#define MAP_FILE 0x00 +#define MAP_SHARED 0x01 +#define MAP_PRIVATE 0x02 +#define MAP_FIXED 0x10 +#define MAP_ANON 0x20 +#define MAP_ANONYMOUS 0x20 + +#if __MLIBC_LINUX_OPTION + +#define MAP_GROWSDOWN 0x100 +#define MAP_DENYWRITE 0x800 +#define MAP_EXECUTABLE 0x1000 +#define MAP_LOCKED 0x2000 +#define MAP_NORESERVE 0x4000 +#define MAP_POPULATE 0x8000 +#define MAP_NONBLOCK 0x10000 +#define MAP_STACK 0x20000 +#define MAP_HUGETLB 0x40000 +#define MAP_SYNC 0x80000 +#define MAP_FIXED_NOREPLACE 0x100000 + +#endif /* __MLIBC_LINUX_OPTION */ + +#define MS_ASYNC 0x01 +#define MS_INVALIDATE 0x02 +#define MS_SYNC 0x04 + +#define MCL_CURRENT 0x01 +#define MCL_FUTURE 0x02 + +#define POSIX_MADV_NORMAL 0 +#define POSIX_MADV_RANDOM 1 +#define POSIX_MADV_SEQUENTIAL 2 +#define POSIX_MADV_WILLNEED 3 +#define POSIX_MADV_DONTNEED 4 + +#if __MLIBC_LINUX_OPTION + +#define MADV_NORMAL 0 +#define MADV_RANDOM 1 +#define MADV_SEQUENTIAL 2 +#define MADV_WILLNEED 3 +#define MADV_DONTNEED 4 +#define MADV_FREE 8 +#define MADV_REMOVE 9 +#define MADV_DONTFORK 10 +#define MADV_DOFORK 11 +#define MADV_MERGEABLE 12 +#define MADV_UNMERGEABLE 13 +#define MADV_HUGEPAGE 14 +#define MADV_NOHUGEPAGE 15 +#define MADV_DONTDUMP 16 +#define MADV_DODUMP 17 +#define MADV_WIPEONFORK 18 +#define MADV_KEEPONFORK 19 +#define MADV_COLD 20 +#define MADV_PAGEOUT 21 +#define MADV_HWPOISON 100 +#define MADV_SOFT_OFFLINE 101 + +#define MREMAP_MAYMOVE 1 +#define MREMAP_FIXED 2 + +#define MFD_CLOEXEC 1U +#define MFD_ALLOW_SEALING 2U +#define MFD_HUGETLB 4U + +#endif /* __MLIBC_LINUX_OPTION */ + +#endif /* _ABIBITS_VM_FLAGS_H */ + diff --git a/userland/mlibc-patch/abis/modulos/wait.h b/userland/mlibc-patch/abis/modulos/wait.h new file mode 100644 index 0000000..f0e7329 --- /dev/null +++ b/userland/mlibc-patch/abis/modulos/wait.h @@ -0,0 +1,35 @@ +#ifndef _ABIBITS_WAIT_H +#define _ABIBITS_WAIT_H + +#include + +#define WNOHANG 1 +#define WUNTRACED 2 +#define WSTOPPED 2 +#define WEXITED 4 +#define WCONTINUED 8 +#define WNOWAIT 0x01000000 + +#if __MLIBC_LINUX_OPTION + +#define __WALL 0x40000000 +#define __WCLONE 0x80000000 + +#endif /* __MLIBC_LINUX_OPTION */ + +#define WCOREFLAG 0x80 + +#define WEXITSTATUS(x) (((x) & 0xff00) >> 8) +#define WTERMSIG(x) ((x) & 0x7f) +#define WSTOPSIG(x) WEXITSTATUS(x) +#define WIFEXITED(x) (WTERMSIG(x) == 0) +#define WIFSIGNALED(x) (((signed char) (((x) & 0x7f) + 1) >> 1) > 0) +#define WIFSTOPPED(x) (((x) & 0xff) == 0x7f) +#define WIFCONTINUED(x) ((x) == 0xffff) +#define WCOREDUMP(x) ((x) & WCOREFLAG) + +/* glibc extension, but also useful for kernels */ +#define W_EXITCODE(ret, sig) (((ret) << 8) | (sig)) + +#endif /*_ABIBITS_WAIT_H */ + diff --git a/userland/mlibc-patch/ci/modulos.cross-file b/userland/mlibc-patch/ci/modulos.cross-file new file mode 100644 index 0000000..f1a8647 --- /dev/null +++ b/userland/mlibc-patch/ci/modulos.cross-file @@ -0,0 +1,20 @@ +[binaries] +c = 'clang' +cpp = 'clang++' +ar = 'llvm-ar' +ld = 'llvm-ld' +strip = 'llvm-strip' + +[host_machine] +system = 'modulos' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' + +[properties] +sizeof_int = 4 +sizeof_void* = 8 + +alignment_char = 1 +alignment_void* = 8 +alignment_double = 8 diff --git a/userland/mlibc-patch/mlibc-v6-3-1-port.patch b/userland/mlibc-patch/mlibc-v6-3-1-port.patch new file mode 100644 index 0000000..0379c13 --- /dev/null +++ b/userland/mlibc-patch/mlibc-v6-3-1-port.patch @@ -0,0 +1,35 @@ +diff --git a/meson.build b/meson.build +index 27d78ab1..84f991e7 100644 +--- a/meson.build ++++ b/meson.build +@@ -75,6 +75,7 @@ if not headers_only + add_project_arguments('-nostdinc', '-fno-builtin', '-ffreestanding', language: ['c', 'cpp']) + add_project_arguments('-Werror=misleading-indentation', language: ['c', 'cpp']) + add_project_arguments('-fno-rtti', '-fno-exceptions', language: 'cpp') ++ add_project_arguments('-mno-avx', '-mno-avx2', '-mno-avx512f', language: ['c', 'cpp']) + add_project_link_arguments('-nostdlib', language: ['c', 'cpp']) + + if get_option('buildtype').startswith('debug') +@@ -274,6 +275,10 @@ elif host_machine.system() == 'nyaux' + rtld_include_dirs += include_directories('sysdeps/nyaux/include') + libc_include_dirs += include_directories('sysdeps/nyaux/include') + subdir('sysdeps/nyaux') ++elif host_machine.system() == 'modulos' ++ rtld_include_dirs += include_directories('sysdeps/modulos/include') ++ libc_include_dirs += include_directories('sysdeps/modulos/include') ++ subdir('sysdeps/modulos') + else + error('No sysdeps defined for OS: ' + host_machine.system()) + endif +diff --git a/options/internal/include/mlibc/internal-sysdeps.hpp b/options/internal/include/mlibc/internal-sysdeps.hpp +index 8c058cfb..6e819043 100644 +--- a/options/internal/include/mlibc/internal-sysdeps.hpp ++++ b/options/internal/include/mlibc/internal-sysdeps.hpp +@@ -7,6 +7,7 @@ + #include + #include + #include ++#include + #include + #include + diff --git a/userland/mlibc-patch/sysdeps/modulos/crt1.S b/userland/mlibc-patch/sysdeps/modulos/crt1.S new file mode 100644 index 0000000..a5f3e5f --- /dev/null +++ b/userland/mlibc-patch/sysdeps/modulos/crt1.S @@ -0,0 +1,35 @@ +/* crt1.S - C runtime init */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +.section .text +.global _start +_start: + fninit + emms + ldmxcsr _mxcsr_reset + + movq %rsp, %rdi + movq $main, %rsi + call __mlibc_entry +.section .note.GNU-stack,"",%progbits + +.section .data +_mxcsr_reset: .quad 0x1F80 + +.section .bss +.globl __dso_handle +__dso_handle: .quad 0 diff --git a/userland/mlibc-patch/sysdeps/modulos/entry.cpp b/userland/mlibc-patch/sysdeps/modulos/entry.cpp new file mode 100644 index 0000000..fcc6206 --- /dev/null +++ b/userland/mlibc-patch/sysdeps/modulos/entry.cpp @@ -0,0 +1,36 @@ +/* entry.cpp - userland entry point */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#include +#include +#include +#include +#include + +extern "C" void __dlapi_enter(uintptr_t *); + +extern char **environ; + +size_t __hwcap; + +extern "C" void __mlibc_entry(uintptr_t *entry_stack, int (*main_fn)(int argc, char *argv[], char *env[])) { + __dlapi_enter(entry_stack); + __hwcap = getauxval(AT_HWCAP); + auto result = main_fn(mlibc::entry_stack.argc, mlibc::entry_stack.argv, environ); + exit(result); +} + diff --git a/userland/mlibc-patch/sysdeps/modulos/include/abi-bits b/userland/mlibc-patch/sysdeps/modulos/include/abi-bits new file mode 120000 index 0000000..cfd2155 --- /dev/null +++ b/userland/mlibc-patch/sysdeps/modulos/include/abi-bits @@ -0,0 +1 @@ +../../../abis/modulos \ No newline at end of file diff --git a/userland/mlibc-patch/sysdeps/modulos/include/syscall.h b/userland/mlibc-patch/sysdeps/modulos/include/syscall.h new file mode 100644 index 0000000..3d6bc1e --- /dev/null +++ b/userland/mlibc-patch/sysdeps/modulos/include/syscall.h @@ -0,0 +1,59 @@ +/* syscall.h - userland system call interface */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#include + +extern "C" uint64_t syscall_0(uint64_t __attribute((unused)), + uint64_t __attribute__((unused)), + uint64_t __attribute__((unused)), + uint64_t v); + +extern "C" uint64_t syscall_1(uint64_t arg1, + uint64_t __attribute__((unused)), + uint64_t __attribute__((unused)), + uint64_t v); + +extern "C" uint64_t syscall_2(uint64_t arg1, + uint64_t arg2, + uint64_t __attribute__((unused)), + uint64_t v); + +extern "C" uint64_t syscall_3(uint64_t arg1, + uint64_t arg2, + uint64_t arg3, + uint64_t v); + +extern "C" uint64_t syscall_4(uint64_t arg1, + uint64_t arg2, + uint64_t arg3, + uint64_t v, + uint64_t arg4); + +extern "C" uint64_t syscall_5(uint64_t arg1, + uint64_t arg2, + uint64_t arg3, + uint64_t v, + uint64_t arg4, + uint64_t arg5); + +extern "C" uint64_t syscall_6(uint64_t arg1, + uint64_t arg2, + uint64_t arg3, + uint64_t v, + uint64_t arg4, + uint64_t arg5, + uint64_t arg6); diff --git a/userland/mlibc-patch/sysdeps/modulos/include/syscall_vectors.h b/userland/mlibc-patch/sysdeps/modulos/include/syscall_vectors.h new file mode 120000 index 0000000..1373ee3 --- /dev/null +++ b/userland/mlibc-patch/sysdeps/modulos/include/syscall_vectors.h @@ -0,0 +1 @@ +../../../../../kernel/include/core/syscall_vectors.h \ No newline at end of file diff --git a/userland/mlibc-patch/sysdeps/modulos/meson.build b/userland/mlibc-patch/sysdeps/modulos/meson.build new file mode 100644 index 0000000..246dbd7 --- /dev/null +++ b/userland/mlibc-patch/sysdeps/modulos/meson.build @@ -0,0 +1,68 @@ +# meson.build - ModulOS mlibc meson build config +# Copyright (C) 2026 Ebrahim Aleem +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see + +sysdep_supported_options = { + 'linux': false, + 'glibc': false, + 'bsd': false, + 'posix': false, +} + +rtld_dso_sources += files( + 'syscall.S', + 'sysdeps.cpp' +) + +libc_sources += files( + 'syscall.S', + 'entry.cpp', + 'sysdeps.cpp' +) + +if not no_headers + install_headers( + 'include/abi-bits/auxv.h', + 'include/abi-bits/clockid_t.h', + 'include/abi-bits/errno.h', + 'include/abi-bits/fcntl.h', + 'include/abi-bits/limits.h', + 'include/abi-bits/mode_t.h', + 'include/abi-bits/pid_t.h', + 'include/abi-bits/seek-whence.h', + 'include/abi-bits/signal.h', + 'include/abi-bits/stat.h', + 'include/abi-bits/uid_t.h', + 'include/abi-bits/vm-flags.h', + 'include/abi-bits/wait.h', + subdir: 'abi-bits', + follow_symlinks: true + ) + + install_headers('include/syscall.h') + install_headers('include/syscall_vectors.h') +endif + +if not headers_only + crt = custom_target('crt1', + build_by_default: true, + command: c_compiler.cmd_array() + ['-c', '-o', '@OUTPUT@', '@INPUT@'], + input: 'crt1.S', + output: 'crt1.o', + install: true, + install_dir: get_option('libdir') + ) +endif + diff --git a/userland/mlibc-patch/sysdeps/modulos/syscall.S b/userland/mlibc-patch/sysdeps/modulos/syscall.S new file mode 100644 index 0000000..f9f4850 --- /dev/null +++ b/userland/mlibc-patch/sysdeps/modulos/syscall.S @@ -0,0 +1,38 @@ +/* syscall.S - userland system call transfer implementation */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +.globl syscall_0 +.globl syscall_1 +.globl syscall_2 +.globl syscall_3 +.globl syscall_4 +.globl syscall_5 +.globl syscall_6 + +.section .text + +syscall_6: +popq %r10 +syscall_5: +syscall_4: +syscall_3: +syscall_2: +syscall_1: +syscall_0: +movq %rcx, %rax +syscall +ret diff --git a/userland/mlibc-patch/sysdeps/modulos/sysdeps.cpp b/userland/mlibc-patch/sysdeps/modulos/sysdeps.cpp new file mode 100644 index 0000000..a6a16cf --- /dev/null +++ b/userland/mlibc-patch/sysdeps/modulos/sysdeps.cpp @@ -0,0 +1,165 @@ +/* sysdeps.cpp - mlibc system dependant dependencies implementation */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#include +#include + +#include + +#include +#include + +#define stderr 2 + +#define TRAP asm volatile ("int3" : : : "memory") + +namespace mlibc { + +// internal + +void sys_libc_log(const char *message) { + ssize_t _ign; + sys_write(stderr, message, strlen(message), &_ign); + sys_write(stderr, "\n", 1, &_ign); +} + +[[noreturn]] void sys_libc_panic() { + sys_libc_log("mlibc panic"); + sys_exit(-1); +} + +int sys_tcb_set(void *pointer) { + asm volatile ("wrfsbaseq %0" : : "r"(pointer) : "memory"); + return 0; +} + +int sys_futex_wait(int *pointer, int expected, const struct timespec *time) { + (void)pointer; + (void)expected; + (void)time; + return 0; +} + +int sys_futex_wake(int *pointer) { + (void)pointer; + return 0; +} + +int sys_anon_allocate(size_t size, void **pointer) { + uint64_t addr = syscall_1(size, 0, 0, SYSCALL_ALLOC); + if (!addr) { + return 1; + } + + memset((void*)addr, 0, size); + + *pointer = (void*)addr; + return 0; +} + +int sys_anon_free(void *pointer, size_t size) { + (void)pointer; + (void)size; + return 0; +} + +int sys_open(const char *pathname, int flags, mode_t mode, int *fd) { + (void)flags; + (void)mode; + + int f = syscall_1((uint64_t)pathname, 0, 0, SYSCALL_OPEN); + if (!f) { + return 1; + } + + *fd = f; + return 0; +} + +int sys_read(int fd, void *buf, size_t count, ssize_t *bytes_read) { + *bytes_read = (ssize_t)syscall_3((uint64_t)fd, (uint64_t)buf, (uint64_t)count, SYSCALL_READ); + + return 0; +} + +int sys_seek(int fd, off_t offset, int whence, off_t *new_offset) { + (void)fd; + (void)offset; + (void)whence; + (void)new_offset; + + return 0; +} + +int sys_close(int fd) { + syscall_1(fd, 0, 0, SYSCALL_CLOSE); + return 0; +} + +// mlibc assumes that anonymous memory returned by sys_vm_map() is zeroed by the kernel / whatever is behind the sysdeps +int sys_vm_map(void *hint, size_t size, int prot, int flags, int fd, off_t offset, void **window) { + (void)hint; + (void)size; + (void)prot; + (void)flags; + (void)fd; + (void)offset; + (void)window; + + TRAP; + return 0; +} + +int sys_vm_unmap(void *pointer, size_t size) { + (void)pointer; + (void)size; + return 0; +} + +// ansi + +[[noreturn]] void sys_exit(int status) { + syscall_1(status, 0, 0, SYSCALL_EXIT); + __builtin_unreachable(); +} + +int sys_write(int fd, const void *buf, size_t count, ssize_t *bytes_written) { + *bytes_written = syscall_3((uint64_t)fd, (uint64_t)buf , (uint64_t)count, SYSCALL_WRITE); + + return 0; +} + +int sys_isatty(int fd) { + switch (fd) { + case 0: + case 1: + case 2: + return 0; //mlibc expects 0 for tty + default: + return ENOTTY; + } +} + +int sys_clock_get(int clock, time_t *secs, long *nanos) { + (void)clock; + (void)secs; + (void)nanos; + TRAP; + return 0; +} + +} //namespace mlibc diff --git a/userland/shell/main.c b/userland/shell/main.c new file mode 100644 index 0000000..113cfeb --- /dev/null +++ b/userland/shell/main.c @@ -0,0 +1,47 @@ +/* main.c - ModulOS shell */ +/* Copyright (C) 2026 Ebrahim Aleem +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, either version 3 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see +*/ + +#include +#include + +int main(int argc, char** argv) { + printf("%s\n", argv[0]); + if (argc > 1) { + printf("%s ", argv[1]); + } + printf("Shell\n"); + + FILE* f = fopen(argv[0], "r"); + + if (!f) { + perror("Failed top open file"); + } + + static char buffer[4]; + + ssize_t read = fread(buffer, 1, sizeof(buffer), f); + if (read != 4) { + fprintf(stderr, "Failed to read file\n"); + return EXIT_FAILURE; + } + + printf("%3s\n", &buffer[1]); + + fclose(f); + + return EXIT_SUCCESS; +} diff --git a/userland/test/Makefile b/userland/test/Makefile deleted file mode 100644 index 9a2eee5..0000000 --- a/userland/test/Makefile +++ /dev/null @@ -1,46 +0,0 @@ -# Makefile - userland test executable build toolchain -# Copyright (C) 2026 Ebrahim Aleem -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see - -SRC_TREE_ROOT := ../$(SRC_TREE_ROOT) -include $(SRC_TREE_ROOT)/scripts/Makefile.header - -USERLAND_DIR := $(OBJ_DIR)/../userland_files/ -OBJ_DIR := $(OBJ_DIR)/test/ - -LCL_TARGETS := \ - $(USERLAND_DIR)/hello_world.txt \ - $(USERLAND_DIR)/test - -include $(SRC_TREE_ROOT)/scripts/Makefile.kcflags - -%/: - -mkdir -p $@ - -.PHONY: all -all: build - -.PHONY: build -build: $(LCL_TARGETS) - -$(USERLAND_DIR)/hello_world.txt: | $(USERLAND_DIR) - echo Hello, World! > $@ - -$(USERLAND_DIR)/test: $(OBJ_DIR)/test.o | $(USERLAND_DIR) - $(CC) -o $@ $(LD_USR_FLAGS) -fuse-ld=lld $^ - -$(OBJ_DIR)/test.o: test.S | $(OBJ_DIR) - $(CC) $(LD_USR_FLAGS) -c -o $@ $< - diff --git a/userland/test/test.S b/userland/test/test.S deleted file mode 100644 index 24d5fc3..0000000 --- a/userland/test/test.S +++ /dev/null @@ -1,9 +0,0 @@ - -.section .text - -.globl _start -_start: -movq $0xdeadbeef, %rax -pushq %rax -hang: -jmp hang