├── .clang-format ├── .gitignore ├── CMakeLists.txt ├── bochsrc.bxrc ├── cmake └── mac_toolchain.cmake ├── docs └── build_gcc_macos.md ├── grub.cfg ├── kernel ├── CMakeLists.txt ├── include │ ├── arch │ │ ├── x86.h │ │ └── x86 │ │ │ ├── instructions.h │ │ │ ├── interrupt.h │ │ │ ├── interrupt_vectors.h │ │ │ ├── msr.h │ │ │ ├── system.h │ │ │ └── vmm.h │ ├── console.h │ ├── cpu.h │ ├── defs.h │ ├── device │ │ └── uart.h │ ├── error.h │ ├── fs │ │ └── fs.h │ ├── kprintf.h │ ├── mem │ │ ├── boot_alloc.h │ │ ├── kmalloc.h │ │ ├── memlayout.h │ │ ├── page_alloc.h │ │ └── vm.h │ ├── param.h │ ├── proc.h │ ├── spinlock.h │ ├── string.h │ ├── syscall.h │ ├── systick.h │ └── util │ │ ├── fifo.h │ │ └── queue.h ├── kernel.ld ├── script │ ├── .gdbinit │ ├── gen_vector.py │ └── qemu.sh └── src │ ├── arch │ └── x86 │ │ ├── asm │ │ ├── bsp_init.s │ │ ├── multiboot.s │ │ ├── swtch.s │ │ ├── trap.s │ │ └── vector.s │ │ ├── console.c │ │ ├── interrupt.c │ │ ├── ioapic.c │ │ ├── lapic.c │ │ ├── mem │ │ └── vm.c │ │ ├── system.c │ │ └── x86_pic.c │ ├── cpu.c │ ├── device │ └── uart │ │ └── uart.c │ ├── kmain.c │ ├── kshell.c │ ├── mem │ ├── boot_alloc.c │ ├── kmalloc.c │ ├── memlayout.c │ └── page_alloc.c │ ├── proc │ ├── proc.c │ └── sched.c │ ├── spinlock.c │ ├── syscall.c │ ├── time │ └── systick.c │ ├── usys.c │ └── util │ ├── fifo.c │ ├── helpers.c │ ├── kprintf.c │ ├── queue.c │ └── string.c ├── lib └── libsys │ ├── CMakeLists.txt │ ├── include │ ├── syscall_number.h │ ├── types.h │ └── usys.h │ └── src │ └── syscall.c ├── stage1_bootloader ├── CMakeLists.txt ├── src │ └── asm │ │ └── init.s └── stage1.ld └── stage2_bootloader ├── CMakeLists.txt ├── src ├── asm │ ├── protected_mode.s │ └── stage2.s └── stage2_loader.c └── stage2.ld /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: LLVM 3 | IndentWidth: 2 4 | --- 5 | Language: Cpp 6 | PointerAlignment: Left -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | cmake-* 2 | build/ 3 | .vscode/ 4 | .idea/ 5 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | 3 | project(guide_os C) 4 | 5 | message("USING objdump ${CMAKE_OBJDUMP}") 6 | 7 | set(CMAKE_C_STANDARD 11) 8 | 9 | set(CMAKE_C_FLAGS "-fno-strict-aliasing -Wall -ggdb -Werror -fno-omit-frame-pointer -fno-stack-protector -m64") 10 | 11 | set(CMAKE_C_FLAGS_RELEASE "-O2 -DNDEBUG") 12 | set(CMAKE_C_FLAGS_DEBUG "-O0 -ggdb3") 13 | 14 | set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS}") 15 | 16 | add_subdirectory(stage1_bootloader) 17 | add_subdirectory(stage2_bootloader) 18 | 19 | add_subdirectory(lib/libsys) 20 | add_subdirectory(kernel) 21 | 22 | add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/guideos.img 23 | COMMAND dd if=/dev/zero of=${CMAKE_CURRENT_BINARY_DIR}/guideos.img bs=1048576 count=10 24 | COMMAND dd if=${CMAKE_CURRENT_BINARY_DIR}/stage1_bootloader/stage1.bin of=${CMAKE_CURRENT_BINARY_DIR}/guideos.img bs=512 count=1 conv=notrunc 25 | COMMAND dd if=${CMAKE_CURRENT_BINARY_DIR}/stage2_bootloader/stage2.bin of=${CMAKE_CURRENT_BINARY_DIR}/guideos.img bs=512 seek=1 count=64 conv=notrunc 26 | COMMAND dd if=${CMAKE_CURRENT_BINARY_DIR}/kernel/kernel.bin of=${CMAKE_CURRENT_BINARY_DIR}/guideos.img bs=512 seek=65 conv=notrunc 27 | DEPENDS 28 | stage1Binary ${CMAKE_CURRENT_BINARY_DIR}/stage1_bootloader/stage1.bin 29 | stage2Binary ${CMAKE_CURRENT_BINARY_DIR}/stage2_bootloader/stage2.bin 30 | kernelBinary ${CMAKE_CURRENT_BINARY_DIR}/kernel/kernel.bin 31 | ) 32 | 33 | add_custom_target( 34 | disk_image ALL 35 | DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/guideos.img 36 | ) 37 | 38 | configure_file(kernel/script/qemu.sh qemu.sh COPYONLY) 39 | configure_file(kernel/script/.gdbinit .gdbinit COPYONLY) -------------------------------------------------------------------------------- /bochsrc.bxrc: -------------------------------------------------------------------------------- 1 | # configuration file generated by Bochs 2 | plugin_ctrl: voodoo=false, unmapped=true, biosdev=true, speaker=true, extfpuirq=true, parallel=true, serial=true, busmouse=false, e1000=false, es1370=false, gameport=true, ne2k=false, sb16=false, usb_uhci=false, usb_ohci=false, usb_ehci=false, usb_xhci=false 3 | config_interface: win32config 4 | display_library: win32 5 | memory: host=512, guest=512 6 | romimage: file="C:\Program Files\Bochs-2.7/BIOS-bochs-latest", address=0x00000000, options=none 7 | vgaromimage: file="C:\Program Files\Bochs-2.7/VGABIOS-lgpl-latest" 8 | boot: disk 9 | floppy_bootsig_check: disabled=0 10 | floppya: type=1_44 11 | # no floppyb 12 | ata0: enabled=true, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 13 | ata0-master: type=disk, path="C:\Users\user\projects\github.com\codetector1374\guide_os\cmake-build-debug\guideos.img", mode=flat, cylinders=0, heads=16, spt=63, sect_size=512, model="Generic 1234", biosdetect=auto, translation=lba 14 | ata0-slave: type=none 15 | ata1: enabled=true, ioaddr1=0x170, ioaddr2=0x370, irq=15 16 | ata1-master: type=none 17 | ata1-slave: type=none 18 | ata2: enabled=false 19 | ata3: enabled=false 20 | optromimage1: file=none 21 | optromimage2: file=none 22 | optromimage3: file=none 23 | optromimage4: file=none 24 | optramimage1: file=none 25 | optramimage2: file=none 26 | optramimage3: file=none 27 | optramimage4: file=none 28 | pci: enabled=1, chipset=i440fx, slot1=none, slot2=none, slot3=none, slot4=none, slot5=none 29 | vga: extension=vbe, update_freq=5, realtime=1, ddc=builtin 30 | cpu: count=1, ips=4000000, model=corei7_sandy_bridge_2600k, reset_on_triple_fault=1, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0 31 | print_timestamps: enabled=0 32 | port_e9_hack: enabled=0 33 | private_colormap: enabled=0 34 | clock: sync=none, time0=local, rtc_sync=0 35 | # no cmosimage 36 | log: - 37 | logprefix: %t%e%d 38 | debug: action=ignore 39 | info: action=report 40 | error: action=report 41 | panic: action=ask 42 | keyboard: type=mf, serial_delay=250, paste_delay=100000, user_shortcut=none 43 | mouse: type=ps2, enabled=false, toggle=ctrl+mbutton 44 | sound: waveoutdrv=win, waveout=none, waveindrv=win, wavein=none, midioutdrv=win, midiout=none 45 | speaker: enabled=true, mode=sound, volume=15 46 | parport1: enabled=true, file=none 47 | parport2: enabled=false 48 | com1: enabled=true, mode=null 49 | com2: enabled=false 50 | com3: enabled=false 51 | com4: enabled=false 52 | -------------------------------------------------------------------------------- /cmake/mac_toolchain.cmake: -------------------------------------------------------------------------------- 1 | if (NOT DEFINED GNU_TOOLCHAIN_PATH) 2 | set(GNU_TOOLCHAIN_PATH "/usr/bin") 3 | endif() 4 | 5 | if (NOT DEFINED GNU_TOOLCHAIN_TARGET) 6 | set(GNU_TOOLCHAIN_TARGET "x86_64-pc-elf") 7 | endif() 8 | 9 | message("GNU Toolchain configured with ${GNU_TOOLCHAIN_PATH}/${GNU_TOOLCHAIN_TARGET}-") 10 | 11 | set(CMAKE_AR "${GNU_TOOLCHAIN_PATH}/${GNU_TOOLCHAIN_TARGET}-ar") 12 | set(CMAKE_ASM_COMPILER "${GNU_TOOLCHAIN_PATH}/${GNU_TOOLCHAIN_TARGET}-gcc") 13 | set(CMAKE_C_COMPILER "${GNU_TOOLCHAIN_PATH}/${GNU_TOOLCHAIN_TARGET}-gcc") 14 | set(CMAKE_CXX_COMPILER "${GNU_TOOLCHAIN_PATH}/${GNU_TOOLCHAIN_TARGET}-g++") 15 | set(CMAKE_LINKER "${GNU_TOOLCHAIN_PATH}/${GNU_TOOLCHAIN_TARGET}-ld") 16 | set(CMAKE_OBJCOPY "${GNU_TOOLCHAIN_PATH}/${GNU_TOOLCHAIN_TARGET}-objcopy") 17 | set(CMAKE_RANLIB "${GNU_TOOLCHAIN_PATH}/${GNU_TOOLCHAIN_TARGET}-ranlib") 18 | set(CMAKE_SIZE "${GNU_TOOLCHAIN_PATH}/${GNU_TOOLCHAIN_TARGET}-size") 19 | set(CMAKE_STRIP "${GNU_TOOLCHAIN_PATH}/${GNU_TOOLCHAIN_TARGET}-strip") 20 | set(CMAKE_OBJDUMP "${GNU_TOOLCHAIN_PATH}/${GNU_TOOLCHAIN_TARGET}-objdump") 21 | 22 | set(CMAKE_SYSTEM_NAME Generic) 23 | set(CMAKE_SYSTEM_PROCESSOR x86_64) 24 | 25 | set(CMAKE_C_COMPILER_WORKS 1) -------------------------------------------------------------------------------- /docs/build_gcc_macos.md: -------------------------------------------------------------------------------- 1 | # Guide on creating a cross-compiler on macOS 2 | 3 | ## Gcc Configure 4 | ```shell 5 | ../gcc-11.2.0/configure --enable-targets=x86_64-pc-elf,i686-pc-elf --prefix=$PREFIX --disable-nls --enable-languages=c --without-headers 6 | ``` 7 | 8 | ## Binutils 9 | ```shell 10 | ../binutils-2.38/configure --target=x86_64-pc-elf --enable-targets=x86_64-elf,i686-elf --prefix="$PREFIX" --with-sysroot --disable-nls --disable-werror 11 | ``` 12 | -------------------------------------------------------------------------------- /grub.cfg: -------------------------------------------------------------------------------- 1 | menuentry "Tiny Kern" { 2 | multiboot2 /boot/kernel.bin 3 | boot 4 | } -------------------------------------------------------------------------------- /kernel/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(kernel ASM C) 2 | 3 | add_library(kernel OBJECT 4 | src/arch/x86/asm/bsp_init.s 5 | src/arch/x86/asm/multiboot.s 6 | src/arch/x86/asm/trap.s 7 | src/arch/x86/asm/vector.s 8 | src/arch/x86/asm/swtch.s 9 | 10 | src/arch/x86/console.c 11 | src/arch/x86/interrupt.c 12 | src/arch/x86/system.c 13 | src/arch/x86/mem/vm.c 14 | src/arch/x86/lapic.c 15 | src/arch/x86/x86_pic.c 16 | src/arch/x86/ioapic.c 17 | 18 | src/mem/boot_alloc.c 19 | src/mem/page_alloc.c 20 | src/mem/memlayout.c 21 | src/mem/kmalloc.c 22 | 23 | src/time/systick.c 24 | 25 | src/proc/proc.c 26 | src/proc/sched.c 27 | 28 | src/syscall.c 29 | src/usys.c 30 | 31 | src/kshell.c 32 | 33 | src/device/uart/uart.c 34 | 35 | src/cpu.c 36 | src/spinlock.c 37 | 38 | src/kmain.c 39 | 40 | src/util/kprintf.c 41 | src/util/string.c 42 | src/util/helpers.c 43 | src/util/fifo.c 44 | src/util/queue.c 45 | ) 46 | 47 | target_link_libraries(kernel libsys) 48 | 49 | target_include_directories(kernel PRIVATE include) 50 | 51 | set(CMAKE_C_FLAGS "-static -fno-pic -ffreestanding -fno-stack-protector \ 52 | -mcmodel=large -mgeneral-regs-only -m64 -Wall \ 53 | -Werror-implicit-function-declaration -fdata-sections -ffunction-sections") 54 | set(CMAKE_ASM_FLAGS "-m64 -x assembler-with-cpp") 55 | 56 | set(CMAKE_C_FLAGS_RELEASE "-O2") 57 | set(CMAKE_C_FLAGS_DEBUG "-O2 -ggdb") 58 | 59 | add_custom_command( 60 | OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/kernel.obj 61 | COMMAND ${CMAKE_LINKER} -m elf_x86_64 -T ${CMAKE_CURRENT_SOURCE_DIR}/kernel.ld -o ${CMAKE_CURRENT_BINARY_DIR}/kernel.obj 62 | --gc-sections 63 | $ 64 | $ 65 | COMMAND ${CMAKE_OBJDUMP} -M intel -S ${CMAKE_CURRENT_BINARY_DIR}/kernel.obj > ${CMAKE_CURRENT_BINARY_DIR}/kernel.asm 66 | COMMAND ${CMAKE_OBJDUMP} -x ${CMAKE_CURRENT_BINARY_DIR}/kernel.obj > ${CMAKE_CURRENT_BINARY_DIR}/kernel.objdump 67 | COMMAND_EXPAND_LISTS 68 | BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/kernel.asm 69 | DEPENDS $ kernel ${CMAKE_CURRENT_SOURCE_DIR}/kernel.ld 70 | ) 71 | 72 | add_custom_command( 73 | OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/kernel.bin 74 | COMMAND ${CMAKE_OBJCOPY} -O binary ${CMAKE_CURRENT_BINARY_DIR}/kernel.obj ${CMAKE_CURRENT_BINARY_DIR}/kernel.bin 75 | DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/kernel.obj 76 | ) 77 | 78 | add_custom_target(kernelBinary 79 | DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/kernel.bin 80 | ) -------------------------------------------------------------------------------- /kernel/include/arch/x86.h: -------------------------------------------------------------------------------- 1 | // 2 | // Guide OS 3 | // Copyright (c) 2022 Codetector 4 | // MIT License 5 | // 6 | 7 | #ifndef GUIDE_OS_X86_H 8 | #define GUIDE_OS_X86_H 9 | 10 | #include "types.h" 11 | #include "arch/x86/instructions.h" 12 | 13 | #endif //GUIDE_OS_X86_H 14 | -------------------------------------------------------------------------------- /kernel/include/arch/x86/instructions.h: -------------------------------------------------------------------------------- 1 | // 2 | // Guide OS 3 | // Copyright (c) 2022 Codetector 4 | // MIT License 5 | // 6 | 7 | #ifndef GUIDE_OS_INSTRUCTIONS_H 8 | #define GUIDE_OS_INSTRUCTIONS_H 9 | 10 | #include "types.h" 11 | 12 | #define RFLAGS_IF 0x00000200 13 | 14 | static inline void 15 | cli(void) 16 | { 17 | __asm__ volatile("cli"); 18 | } 19 | 20 | static inline void 21 | hlt(void) 22 | { 23 | __asm__ volatile("hlt"); 24 | } 25 | 26 | static inline void 27 | sti(void) 28 | { 29 | __asm__ volatile("sti"); 30 | } 31 | 32 | static inline u8 33 | inb(u16 port) 34 | { 35 | u8 data; 36 | 37 | __asm__ volatile("in %1,%0" : "=a" (data) : "d" (port)); 38 | return data; 39 | } 40 | 41 | static inline void 42 | insl(int port, void *addr, int cnt) 43 | { 44 | __asm__ volatile("cld; rep insl" : 45 | "=D" (addr), "=c" (cnt) : 46 | "d" (port), "0" (addr), "1" (cnt) : 47 | "memory", "cc"); 48 | } 49 | 50 | static inline void 51 | outb(u16 port, u8 data) 52 | { 53 | __asm__ volatile("out %0,%1" : : "a" (data), "d" (port)); 54 | } 55 | 56 | static inline void 57 | outw(u16 port, u16 data) 58 | { 59 | __asm__ volatile("out %0,%1" : : "a" (data), "d" (port)); 60 | } 61 | 62 | static inline void 63 | outsl(int port, const void *addr, int cnt) 64 | { 65 | __asm__ volatile("cld; rep outsl" : 66 | "=S" (addr), "=c" (cnt) : 67 | "d" (port), "0" (addr), "1" (cnt) : 68 | "cc"); 69 | } 70 | 71 | static inline void 72 | stosb(void *addr, int data, int cnt) 73 | { 74 | __asm__ volatile("cld; rep stosb" : 75 | "=D" (addr), "=c" (cnt) : 76 | "0" (addr), "1" (cnt), "a" (data) : 77 | "memory", "cc"); 78 | } 79 | 80 | static inline void 81 | stosl(void *addr, int data, int cnt) 82 | { 83 | __asm__ volatile("cld; rep stosl" : 84 | "=D" (addr), "=c" (cnt) : 85 | "0" (addr), "1" (cnt), "a" (data) : 86 | "memory", "cc"); 87 | } 88 | 89 | static inline size_t 90 | read_flags() 91 | { 92 | size_t flags; 93 | __asm__ volatile("pushf; pop %0" : "=r" (flags)); 94 | return flags; 95 | } 96 | 97 | static inline size_t 98 | rcr2(void) 99 | { 100 | size_t val; 101 | __asm__ volatile("mov %%cr2,%0" : "=r" (val)); 102 | return val; 103 | } 104 | 105 | static inline void 106 | lcr3(size_t cr3) 107 | { 108 | __asm__ volatile("mov %0, %%cr3" : : "r"(cr3) : "memory"); 109 | } 110 | 111 | static inline u64 112 | rdmsr(u32 msr_addr) { 113 | u32 msrh, msrl; 114 | __asm__ volatile("rdmsr" 115 | : "=d"(msrh), "=a"(msrl) 116 | : "c"(msr_addr) 117 | ); 118 | return (((u64)msrh) << 32) | msrl; 119 | } 120 | 121 | static inline void 122 | wrmsr(u32 msr_addr, u64 msr_data) { 123 | u32 msrh, msrl; 124 | msrh = msr_data >> 32; 125 | msrl = (u32) msr_data; 126 | __asm__ volatile("wrmsr" 127 | : 128 | : "c"(msr_addr), "a"(msrl), "d"(msrh) 129 | ); 130 | } 131 | 132 | #endif //GUIDE_OS_INSTRUCTIONS_H 133 | -------------------------------------------------------------------------------- /kernel/include/arch/x86/interrupt.h: -------------------------------------------------------------------------------- 1 | // 2 | // Guide OS 3 | // Copyright (c) 2022 Codetector 4 | // MIT License 5 | // 6 | 7 | #ifndef GUIDE_OS_INTERRUPT_H 8 | #define GUIDE_OS_INTERRUPT_H 9 | 10 | #include "types.h" 11 | #include "interrupt_vectors.h" 12 | 13 | #define IDT_OFFSET_1(ptr) ((size_t)(ptr) & 0xFFFF) 14 | #define IDT_OFFSET_2(ptr) (((size_t)(ptr) >> 16) & 0xFFFF) 15 | #define IDT_OFFSET_3(ptr) (((size_t)(ptr) >> 32) & 0xFFFFFFFF) 16 | 17 | #pragma pack(push, 1) 18 | typedef struct InterruptGate64 { 19 | uint16_t offset_1; // offset bits 0..15 20 | uint16_t selector; // a code segment selector in GDT or LDT 21 | uint8_t ist; // bits 0..2 holds Interrupt Stack Table offset, rest of bits zero. 22 | uint8_t type_attributes; // gate type, dpl, and p fields 23 | uint16_t offset_2; // offset bits 16..31 24 | uint32_t offset_3; // offset bits 32..63 25 | uint32_t zero; // reserved 26 | } interrupt_gate_64_t; 27 | 28 | typedef struct IDT64 { 29 | interrupt_gate_64_t entries[256]; 30 | } idt64_t; 31 | #pragma pack(pop) 32 | 33 | typedef void (*int_handler_t)(void*); 34 | 35 | typedef struct trapframe { 36 | uint64_t rax; 37 | uint64_t rcx; 38 | uint64_t rdx; 39 | uint64_t rbx; 40 | uint64_t rsi; 41 | uint64_t rdi; 42 | uint64_t rbp; 43 | uint64_t r8; 44 | uint64_t r9; 45 | uint64_t r10; 46 | uint64_t r11; 47 | uint64_t r12; 48 | uint64_t r13; 49 | uint64_t r14; 50 | uint64_t r15; 51 | uint64_t trap_no; 52 | uint64_t error_code; 53 | uint64_t rip; 54 | uint64_t cs; 55 | uint64_t flags; 56 | uint64_t rsp; 57 | uint64_t ss; 58 | } trapframe_t; 59 | 60 | #define IDT_GATE_FLAGS_INT 0xE 61 | #define IDT_GATE_FLAGS_TRAP 0xF 62 | #define IDT_GATE_FLAGS_DPL_USER (0x3U << 5U) 63 | #define IDT_GATE_FLAGS_DPL_KRNL (0x0U << 5U) 64 | #define IDT_GATE_FLAGS_P 0x80 65 | 66 | void handle_interrupt(trapframe_t *tf); 67 | __attribute__((noreturn)) void return_from_isr(void); 68 | 69 | inline 70 | interrupt_gate_64_t 71 | mk_idt_entry(int_handler_t handler_fn, uint8_t ist, uint8_t type_attr, uint8_t cs) 72 | { 73 | return (interrupt_gate_64_t) { 74 | .offset_1 = IDT_OFFSET_1(handler_fn), 75 | .offset_2 = IDT_OFFSET_2(handler_fn), 76 | .offset_3 = IDT_OFFSET_3(handler_fn), 77 | .ist = ist & 0x7, 78 | .type_attributes = type_attr, 79 | .selector = cs, 80 | .zero = 0 81 | }; 82 | } 83 | 84 | void interrupt_init(void); 85 | 86 | void load_idt(idt64_t *idt); 87 | 88 | // lapic.c 89 | u8 lapic_id(void); 90 | void lapic_init(void); 91 | void lapic_eoi(void); 92 | 93 | // x86_pic.c 94 | void pic_init(void); 95 | 96 | // ioapic.c 97 | void ioapic_init(void); 98 | void ioapic_unmask(u8 irq, u8 vector, u8 apicid); 99 | void ioapic_mask(u8 irq); 100 | 101 | #endif //GUIDE_OS_INTERRUPT_H 102 | -------------------------------------------------------------------------------- /kernel/include/arch/x86/interrupt_vectors.h: -------------------------------------------------------------------------------- 1 | // 2 | // Guide OS 3 | // Copyright (c) 2022 Codetector 4 | // MIT License 5 | // 6 | 7 | #ifndef GUIDE_OS_INTERRUPT_VECTORS_H 8 | #define GUIDE_OS_INTERRUPT_VECTORS_H 9 | 10 | #define IDT_ENTRY_DIV_BY_ZERO 0 11 | #define IDT_ENTRY_DEBUG 1 12 | #define IDT_ENTRY_NMI 2 13 | #define IDT_ENTRY_BP 3 14 | #define IDT_ENTRY_OF 4 15 | 16 | #define IDT_ENTRY_INV_OPCODE 6 17 | #define IDT_ENTRY_DOUBLE_FAULT 8 18 | 19 | #define IDT_ENTRY_GP 13 20 | #define IDT_ENTRY_PAGE_FAULT 14 21 | 22 | #define IDT_ENTRY_IRQ_0 32 23 | #define IDT_ENTRY_IRQ_TIMER (IDT_ENTRY_IRQ_0 + 0) 24 | #define IDT_ENTRY_IRQ_COM1 (IDT_ENTRY_IRQ_0 + 4) 25 | #define IDT_ENTRY_IRQ_ERROR (IDT_ENTRY_IRQ_0 + 19) 26 | #define IDT_ENTRY_IRQ_SPURIOUS (IDT_ENTRY_IRQ_0 + 31) 27 | 28 | #define VECTOR_SYSCALL 0x80 29 | 30 | #endif //GUIDE_OS_INTERRUPT_VECTORS_H 31 | -------------------------------------------------------------------------------- /kernel/include/arch/x86/msr.h: -------------------------------------------------------------------------------- 1 | // 2 | // Guide OS 3 | // Copyright (c) 2022 Codetector 4 | // MIT License 5 | // 6 | 7 | #ifndef GUIDE_OS_MSR_H 8 | #define GUIDE_OS_MSR_H 9 | 10 | #define IA32_APIC_BASE_MSR 0x1B 11 | # define IA32_APIC_BASE_MSR_ENABLED (1UL << 11U) 12 | # define IA32_APIC_BASE_MSR_BSP (1UL << 8U) 13 | # define IA32_APIC_BASE_MSR_BASE_ADDR_MSK (~0xFFFUL) 14 | 15 | #endif //GUIDE_OS_MSR_H 16 | -------------------------------------------------------------------------------- /kernel/include/arch/x86/system.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Codetector on 3/6/22. 3 | // 4 | #pragma once 5 | 6 | #define GDT_KERNEL_CODE 0x1 7 | #define GDT_KERNEL_DATA 0x2 8 | #define GDT_USER_CODE 0x3 9 | #define GDT_USER_DATA 0x4 10 | #define GDT_TSS 0x5 11 | 12 | struct cpu; 13 | 14 | #pragma pack(push, 1) 15 | struct task_state_segment { 16 | u32 _rsvd1; 17 | u64 rsp[3]; 18 | u64 _rsvd2; 19 | u64 ist[7]; 20 | u64 _rsvd3; 21 | u16 _rsvd4; 22 | u16 iopb; 23 | }; 24 | _Static_assert(sizeof(struct task_state_segment) == 0x68, "task_state_segment size"); 25 | 26 | struct tss_descriptor { 27 | u16 limit_15_0; 28 | u16 base_15_0; 29 | u8 base_23_16; 30 | u8 type:5; 31 | u8 dpl:2; 32 | u8 p:1; 33 | u8 limit_19_16:4; 34 | u8 flags:4; 35 | u8 base_31_24; 36 | u32 base_63_32; 37 | u32 _resvd; 38 | }; 39 | _Static_assert(sizeof(struct tss_descriptor) == 16, "tss_descriptor packing wrong"); 40 | 41 | struct segment_descriptor { 42 | u16 limit_15_0; 43 | u16 base_15_0; 44 | u8 base_23_16; 45 | u8 type:5; 46 | u8 dpl:2; 47 | u8 p:1; 48 | u8 limit_19_16:4; 49 | u8 flags:4; 50 | u8 base_31_24; 51 | }; 52 | _Static_assert(sizeof(struct segment_descriptor) == 8, "segment_descriptor packing wrong"); 53 | 54 | #define GDT_DESC_TYPE_CODE 0b11010 55 | #define GDT_DESC_TYPE_DATA 0b10010 56 | #define GDT_DESC_TYPE_TSS 0b01001 57 | 58 | #define GDT_DESC_FLAGS_L 0b0010 59 | #define GDT_DESC_FLAGS_DB 0b0100 60 | #define GDT_DESC_FLAGS_G 0b1000 61 | 62 | 63 | struct gdt { 64 | struct segment_descriptor seg_descs[5]; 65 | struct tss_descriptor tss_entry; 66 | }; 67 | #pragma pack(pop) 68 | 69 | void tss_setup(struct cpu* cpu); 70 | 71 | /** 72 | * @brief Setup GDT for the provided CPU and switch to it. 73 | * @note Must be called after tss_setup() for each cpu. 74 | * 75 | * @param cpu the current running CPU 76 | */ 77 | void gdt_setup(struct cpu* cpu); 78 | -------------------------------------------------------------------------------- /kernel/include/arch/x86/vmm.h: -------------------------------------------------------------------------------- 1 | // 2 | // Guide OS 3 | // Copyright (c) 2022 Codetector 4 | // MIT License 5 | // 6 | 7 | #pragma once 8 | #include "types.h" 9 | 10 | #define PTE_ADDR(pte) ((pte) & 0xFFFFFFFFFFFFF000) 11 | #define PTE_FLAG(pte) ((pte) & 0x0000000000000FFF) 12 | #define PTE_FLAG_P (1UL << 0U) 13 | #define PTE_FLAG_WRITE (1UL << 1U) 14 | #define PTE_FLAG_USER (1UL << 2U) 15 | #define PTE_FLAG_PWT (1UL << 3U) 16 | #define PTE_FLAG_PCD (1UL << 4U) 17 | #define PTE_FLAG_ACCESS (1UL << 5U) 18 | #define PTE_FLAG_DIRTY (1UL << 6U) 19 | #define PTE_FLAG_SZ (1UL << 7U) 20 | #define PTE_FLAG_PT_PAT (1UL << 7U) // Applies only to PTE 21 | #define PTE_FLAG_GLOBAL (1UL << 8U) 22 | #define PTE_FLAG_PAT (1UL << 12U) // Applies only to PTE 23 | 24 | 25 | #define PG_OFFSET(addr) ((addr) & 0xFFF) 26 | #define PG_L1_IDX(addr) ((addr >> 12) & 0x1FF) 27 | #define PG_L2_IDX(addr) ((addr >> (12 + 9)) & 0x1FF) 28 | #define PG_L3_IDX(addr) ((addr >> (12 + 18)) & 0x1FF) 29 | #define PG_L4_IDX(addr) ((addr >> (12 + 27)) & 0x1FF) 30 | 31 | 32 | typedef uint64_t pte_t; 33 | typedef uint64_t pde_t; 34 | typedef uint64_t pdpe_t; 35 | typedef uint64_t pml4e_t; 36 | 37 | -------------------------------------------------------------------------------- /kernel/include/console.h: -------------------------------------------------------------------------------- 1 | #ifndef GUIDE_OS_CONSOLE_H 2 | #define GUIDE_OS_CONSOLE_H 3 | 4 | void console_init(void); 5 | void putchar(int c); 6 | /** 7 | * @brief Blocking getc from console (Will sleep) 8 | * 9 | * @return int character 10 | */ 11 | int console_getc(void); 12 | void console_isr_handler(void); 13 | 14 | #endif //GUIDE_OS_CONSOLE_H 15 | -------------------------------------------------------------------------------- /kernel/include/cpu.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | #include "arch/x86/system.h" 5 | 6 | // Per-CPU state 7 | struct cpu { 8 | u32 started; 9 | u32 int_disable_layer; 10 | u32 int_enabled; 11 | struct gdt gdt; 12 | struct task_state_segment tss; 13 | struct proc* proc; 14 | struct proc_context* scheduler_ctx; 15 | u8 apicid; 16 | }; 17 | 18 | void cpu_bsp_init(void); 19 | -------------------------------------------------------------------------------- /kernel/include/defs.h: -------------------------------------------------------------------------------- 1 | // 2 | // Guide OS 3 | // Copyright (c) 2022 Codetector 4 | // MIT License 5 | // 6 | 7 | #ifndef GUIDE_OS_DEFS_H 8 | #define GUIDE_OS_DEFS_H 9 | 10 | #include "param.h" 11 | #include "types.h" 12 | #include "kprintf.h" 13 | #include "mem/memlayout.h" 14 | #include "string.h" 15 | #include "cpu.h" 16 | 17 | #define ROUNDUP_PWR2(x, sz) (((x) + ((sz) - 1UL)) & ~((sz) - 1UL)) 18 | #define ROUNDDOWN_PWR2(x, sz) ((x) & ~((sz) - 1)) 19 | 20 | #define MIN(a, b) ((a) < (b) ? (a) : (b)) 21 | 22 | // Arch specific implementaiton 23 | void panic(char *s); 24 | bool disable_interrupt(void); 25 | void enable_interrupt(); 26 | void wait_for_interrupt(void); 27 | 28 | // cpu.c 29 | void push_int_disable(void); 30 | void pop_int_disable(void); 31 | /** 32 | * @brief get the current cpu id between 0 and NCPU 33 | * @note must be called with interrupt disabled 34 | * 35 | * @return u16 36 | */ 37 | u16 cpu_id(void); 38 | /** 39 | * @brief get a pointer to the current cpu strcture. 40 | * @note must be called with interrupt disabled 41 | * 42 | * @return struct cpu* 43 | */ 44 | struct cpu* cur_cpu(void); 45 | struct proc* curproc(void); 46 | 47 | // kmalloc.c 48 | void *kmalloc(size_t size); 49 | void *krealloc(void *ptr, size_t size); 50 | void *kcalloc(size_t nmemb, size_t size); 51 | void kfree(void *ptr); 52 | 53 | // systick.c 54 | void spin_sleep(uint64_t ticks); 55 | 56 | #endif //GUIDE_OS_DEFS_H 57 | -------------------------------------------------------------------------------- /kernel/include/device/uart.h: -------------------------------------------------------------------------------- 1 | // 2 | // Guide OS 3 | // Copyright (c) 2022 Codetector 4 | // MIT License 5 | // 6 | 7 | #ifndef GUIDE_OS_UART_H 8 | #define GUIDE_OS_UART_H 9 | 10 | #include "spinlock.h" 11 | #include "types.h" 12 | 13 | #define UART_COM1 0x3F8 14 | 15 | typedef struct uart_device { 16 | void* mmio_base; 17 | u16 pio_base; 18 | } uart_device_t; 19 | 20 | /** 21 | * @brief Construct a uart device with pio address pio_base 22 | * 23 | * @param u the struct to operate on 24 | * @param pio_base 25 | * @return 0 on success 26 | */ 27 | int uart_pio_init(uart_device_t* u, u16 pio_base); 28 | int uart_mmio_init(uart_device_t* u, void* mmio_base); 29 | void uart_putc(uart_device_t* u, int c); 30 | bool uart_hasbyte(uart_device_t* u); 31 | int uart_getc(uart_device_t* u); 32 | 33 | #endif // GUIDE_OS_UART_H 34 | -------------------------------------------------------------------------------- /kernel/include/error.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | 4 | typedef enum os_error { 5 | OSERR_OK = 0, 6 | OSERR_INVALID_ARGUMENT = 0x1000, 7 | OSERR_NO_MEMORY = 0x2000, 8 | } os_error_t; -------------------------------------------------------------------------------- /kernel/include/fs/fs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | -------------------------------------------------------------------------------- /kernel/include/kprintf.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // \author (c) Marco Paland (info@paland.com) 3 | // 2014-2019, PALANDesign Hannover, Germany 4 | // 5 | // \license The MIT License (MIT) 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | // \brief Tiny printf, sprintf and snprintf implementation, optimized for speed on 26 | // embedded systems with a very limited resources. 27 | // Use this instead of bloated standard/newlib printf. 28 | // These routines are thread safe and reentrant. 29 | // 30 | /////////////////////////////////////////////////////////////////////////////// 31 | 32 | #ifndef _KPRINTF_H_ 33 | #define _KPRINTF_H_ 34 | 35 | #include 36 | #include 37 | 38 | #include "console.h" 39 | 40 | #ifdef __cplusplus 41 | extern "C" { 42 | #endif 43 | 44 | /** 45 | * Tiny printf implementation 46 | * You have to implement _putchar if you use printf() 47 | * To avoid conflicts with the regular printf() API it is overridden by macro defines 48 | * and internal underscore-appended functions like printf_() are used 49 | * \param format A string that specifies the format of the output 50 | * \return The number of characters that are written into the array, not counting the terminating null character 51 | */ 52 | #define kprintf printf_ 53 | int printf_(const char* format, ...); 54 | 55 | 56 | /** 57 | * Tiny sprintf implementation 58 | * Due to security reasons (buffer overflow) YOU SHOULD CONSIDER USING (V)SNPRINTF INSTEAD! 59 | * \param buffer A pointer to the buffer where to store the formatted string. MUST be big enough to store the output! 60 | * \param format A string that specifies the format of the output 61 | * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character 62 | */ 63 | #define sprintf sprintf_ 64 | int sprintf_(char* buffer, const char* format, ...); 65 | 66 | 67 | /** 68 | * Tiny snprintf/vsnprintf implementation 69 | * \param buffer A pointer to the buffer where to store the formatted string 70 | * \param count The maximum number of characters to store in the buffer, including a terminating null character 71 | * \param format A string that specifies the format of the output 72 | * \param va A value identifying a variable arguments list 73 | * \return The number of characters that COULD have been written into the buffer, not counting the terminating 74 | * null character. A value equal or larger than count indicates truncation. Only when the returned value 75 | * is non-negative and less than count, the string has been completely written. 76 | */ 77 | #define snprintf snprintf_ 78 | #define vsnprintf vsnprintf_ 79 | int snprintf_(char* buffer, size_t count, const char* format, ...); 80 | int vsnprintf_(char* buffer, size_t count, const char* format, va_list va); 81 | 82 | 83 | /** 84 | * Tiny vprintf implementation 85 | * \param format A string that specifies the format of the output 86 | * \param va A value identifying a variable arguments list 87 | * \return The number of characters that are WRITTEN into the buffer, not counting the terminating null character 88 | */ 89 | #define kvprintf vprintf_ 90 | int vprintf_(const char* format, va_list va); 91 | 92 | 93 | /** 94 | * printf with output function 95 | * You may use this as dynamic alternative to printf() with its fixed _putchar() output 96 | * \param out An output function which takes one character and an argument pointer 97 | * \param arg An argument pointer for user data passed to output function 98 | * \param format A string that specifies the format of the output 99 | * \return The number of characters that are sent to the output function, not counting the terminating null character 100 | */ 101 | int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...); 102 | 103 | 104 | #ifdef __cplusplus 105 | } 106 | #endif 107 | 108 | 109 | #endif // _PRINTF_H_ 110 | -------------------------------------------------------------------------------- /kernel/include/mem/boot_alloc.h: -------------------------------------------------------------------------------- 1 | // 2 | // Guide OS 3 | // Copyright (c) 2022 Codetector 4 | // MIT License 5 | // 6 | 7 | #ifndef GUIDE_OS_BOOT_ALLOC_H 8 | #define GUIDE_OS_BOOT_ALLOC_H 9 | 10 | #include "types.h" 11 | 12 | struct boot_alloc_zone { 13 | void* begin_kva; 14 | void* end_kva; 15 | }; 16 | 17 | void boot_alloc_init(void* start_kva, size_t size); 18 | /** 19 | * Initial Allocation. Only support page sized allocations. 20 | * @param size n bytes, rounded up to nearest page size automatically 21 | * 22 | * @return null or ptr to the allocated region 23 | */ 24 | void* boot_alloc(size_t size); 25 | 26 | void* boot_alloc_disable(void); 27 | 28 | #endif //GUIDE_OS_BOOT_ALLOC_H 29 | -------------------------------------------------------------------------------- /kernel/include/mem/kmalloc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "types.h" 3 | 4 | void kmalloc_init(void); 5 | -------------------------------------------------------------------------------- /kernel/include/mem/memlayout.h: -------------------------------------------------------------------------------- 1 | // 2 | // Guide OS 3 | // Copyright (c) 2022 Codetector 4 | // MIT License 5 | // 6 | 7 | #ifndef GUIDE_OS_MEMLAYOUT_H 8 | #define GUIDE_OS_MEMLAYOUT_H 9 | 10 | #include "types.h" 11 | 12 | #define KERNBASE (0xFFFF800000000000) 13 | #define KERN_PHYMAP_TOP (KERNBASE + (512UL << 30U)) // 512 GB 14 | 15 | #define KV2P(VA) (((size_t)VA) - KERNBASE) 16 | #define P2KV(PA) ((void*)(((size_t)PA) + KERNBASE)) 17 | 18 | // Paging related defines 19 | #define NPTENTRIES (512) 20 | 21 | #define PG_SIZE (4096UL) 22 | #define L2_HUGE_SIZE (PG_SIZE * NPTENTRIES) 23 | #define L3_HUGE_SIZE (L2_HUGE_SIZE * NPTENTRIES) 24 | 25 | #define PGROUNDUP(sz) (((sz)+PG_SIZE-1) & ~(PG_SIZE-1)) 26 | #define PGROUNDDOWN(a) (((a)) & ~(PG_SIZE-1)) 27 | 28 | #define PG_INDEX(ADDR) ((ADDR) / PG_SIZE) 29 | 30 | 31 | extern size_t kern_end[]; 32 | 33 | #endif //GUIDE_OS_MEMLAYOUT_H 34 | -------------------------------------------------------------------------------- /kernel/include/mem/page_alloc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | void pgalloc_init(size_t max_mem_addr); 6 | /** 7 | * @brief free the selected range. Can be used to feed the allocator initially 8 | * 9 | * @param start_va pg aligned start address 10 | * @param end_va pg aligned end address 11 | */ 12 | void pgalloc_free_range(void *start_va, void *end_va); 13 | 14 | void* pgalloc_allocate(int order); 15 | void pgalloc_free(void* addr, int order); -------------------------------------------------------------------------------- /kernel/include/mem/vm.h: -------------------------------------------------------------------------------- 1 | // 2 | // Guide OS 3 | // Copyright (c) 2022 Codetector 4 | // MIT License 5 | // 6 | #pragma once 7 | 8 | /** 9 | * @brief setup initial page tables 10 | */ 11 | void vmm_init(void); 12 | void vmm_load_ktable(void); 13 | void* vmm_get_kernel_pgtable(void); -------------------------------------------------------------------------------- /kernel/include/param.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define NCPU 128 4 | #define NPROC 1024 5 | -------------------------------------------------------------------------------- /kernel/include/proc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "param.h" 4 | #include "types.h" 5 | #include "mem/vm.h" 6 | #include "arch/x86/vmm.h" 7 | #include "arch/x86/interrupt.h" 8 | #include "spinlock.h" 9 | 10 | enum proc_state { UNUSED, CREATION, SLEEPING, RUNNABLE, RUNNING, ZOMBIE}; 11 | enum proc_type { KERNEL, USER }; 12 | 13 | struct proc_context { 14 | uint64_t rbx; 15 | uint64_t rbp; 16 | uint64_t r12; 17 | uint64_t r13; 18 | uint64_t r14; 19 | uint64_t r15; 20 | uint64_t rip; 21 | }; 22 | 23 | struct proc { 24 | pml4e_t *pgtable; // Root Page Table 25 | trapframe_t *tf; 26 | struct proc_context *ctx; 27 | void *kstack; 28 | void *kstack_top; 29 | enum proc_state state; 30 | enum proc_type type; 31 | char name[32]; 32 | 33 | void* chan; 34 | 35 | uint32_t int_disable_layer; 36 | 37 | u16 pid; 38 | bool killed; 39 | bool int_enabled; 40 | }; 41 | 42 | extern struct proc idle_proc[NCPU]; 43 | 44 | void proc_init(void); 45 | struct proc* proc_alloc(void); 46 | void proc_kern_init(struct proc* p); 47 | 48 | void sched_init(void); 49 | void sched_add(struct proc* proc); 50 | void sched_start(void); 51 | void sched_create_kproc(struct proc* proc, void (*func)(void)); 52 | void sched_ctxsw(struct proc_context **old, const struct proc_context *new); 53 | void sched_kentry(void); 54 | void sched_switch_out(void); 55 | void sched_yield(void); 56 | void sched_sleep(void* chan, spinlock_t *lk); 57 | void sched_wakeup(void* chan); 58 | -------------------------------------------------------------------------------- /kernel/include/spinlock.h: -------------------------------------------------------------------------------- 1 | // 2 | // Guide OS 3 | // Copyright (c) 2022 Codetector 4 | // MIT License 5 | // 6 | 7 | #ifndef GUIDE_OS_SPINLOCK_H 8 | #define GUIDE_OS_SPINLOCK_H 9 | 10 | #include 11 | 12 | #include "types.h" 13 | 14 | 15 | typedef struct spinlock { 16 | u8 locked; 17 | const char* name; 18 | struct cpu* cpu; 19 | uptr locking_pc; 20 | } spinlock_t; 21 | 22 | void init_lock(spinlock_t *lk, const char* name); 23 | void acquire(spinlock_t *lk); 24 | void release(spinlock_t *lk); 25 | bool holding(spinlock_t *lk); 26 | 27 | #endif //GUIDE_OS_SPINLOCK_H 28 | -------------------------------------------------------------------------------- /kernel/include/string.h: -------------------------------------------------------------------------------- 1 | // 2 | // Guide OS 3 | // Copyright (c) 2022 Codetector 4 | // MIT License 5 | // 6 | 7 | #ifndef GUIDE_OS_STRING_H 8 | #define GUIDE_OS_STRING_H 9 | 10 | #include "types.h" 11 | 12 | int strlen(const char *s); 13 | size_t strnlen(const char *s, size_t size); 14 | char *strcpy(char *dst, const char *src); 15 | char *strcat(char *dst, const char *src); 16 | size_t strlcpy(char *dst, const char *src, size_t size); 17 | int strcmp(const char *s1, const char *s2); 18 | int strncmp(const char *s1, const char *s2, size_t size); 19 | char *strchr(const char *s, char c); 20 | char *strfind(const char *s, char c); 21 | 22 | void *memset(void *dst, int c, size_t len); 23 | void *memcpy(void *dst, const void *src, size_t len); 24 | void *memmove(void *dst, const void *src, size_t len); 25 | int memcmp(const void *s1, const void *s2, size_t len); 26 | void *memfind(const void *s, int c, size_t len); 27 | 28 | long strtol(const char *s, char **endptr, int base); 29 | 30 | char *safestrcpy(char *s, char *t, size_t n); 31 | char *strncpy(char *s, const char *t, size_t n); 32 | 33 | char *strtok(char* base, const char* delims); 34 | 35 | #endif //GUIDE_OS_STRING_H 36 | -------------------------------------------------------------------------------- /kernel/include/syscall.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | #include "arch/x86/interrupt.h" 5 | 6 | 7 | void handle_syscall(trapframe_t *); 8 | -------------------------------------------------------------------------------- /kernel/include/systick.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | uint64_t systick(void); 6 | void systick_init(void); 7 | void systick_increment(void); 8 | -------------------------------------------------------------------------------- /kernel/include/util/fifo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | #include 5 | 6 | typedef struct spsc_fifo { 7 | u8* buffer; 8 | size_t buffer_size; 9 | atomic_size_t read; 10 | atomic_size_t watermark; 11 | atomic_size_t write; 12 | } spsc_fifo_t; 13 | 14 | os_error_t spsc_fifo_init(spsc_fifo_t* f, u8* buffer, size_t buffer_size); 15 | os_error_t spsc_fifo_write(spsc_fifo_t* f, u8 byte); 16 | int spsc_fifo_read(spsc_fifo_t* f, u8* pOut); -------------------------------------------------------------------------------- /kernel/include/util/queue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | typedef struct dequeue_iterator { 6 | struct dequeue *q; 7 | struct dequeue_node* current_node; 8 | } dequeue_iterator_t; 9 | 10 | typedef struct dequeue { 11 | size_t size; 12 | struct dequeue_node* head; 13 | struct dequeue_node* tail; 14 | } dequeue_t; 15 | 16 | struct dequeue_node { 17 | void* data; 18 | struct dequeue_node* next; 19 | struct dequeue_node* prev; 20 | }; 21 | 22 | void dequeue_construct(dequeue_t* q); 23 | void dequeue_push_back(dequeue_t* q, void* item); 24 | void dequeue_push_front(dequeue_t* q, void* item); 25 | void* dequeue_peek_front(dequeue_t* q); 26 | void* dequeue_pop_front(dequeue_t* q); 27 | void* dequeue_pop_back(dequeue_t* q); 28 | 29 | void dequeue_iterator(dequeue_t* q, dequeue_iterator_t* iter); 30 | void* dequeue_iterator_next(dequeue_iterator_t* iter); 31 | bool dequeue_iterator_has_next(dequeue_iterator_t* iter); 32 | void dequeue_iterator_delete(dequeue_iterator_t* iter); 33 | -------------------------------------------------------------------------------- /kernel/kernel.ld: -------------------------------------------------------------------------------- 1 | /* Kernel Linker Script */ 2 | ENTRY(kentry) 3 | SECTIONS { 4 | . = 1M; 5 | raw_init : { 6 | KEEP(*(.raw_init)) 7 | } 8 | multiboot BLOCK(8) : { 9 | KEEP(*(.multiboot)) 10 | } 11 | bootstrap : { 12 | *(.bootstrap) 13 | } 14 | bootstrap.data BLOCK(4k) : { 15 | *(.bootstrap.data) 16 | } 17 | kernel_start_pa = .; 18 | 19 | kernel.text (0xFFFF800000000000 + kernel_start_pa) : AT (kernel_start_pa) { 20 | *(.text .text.*) 21 | } 22 | . = ALIGN(4k); 23 | kernel.bss : { 24 | *(.bss .bss.*) 25 | } =0 26 | kernel.data : { 27 | *(.data .data.*) 28 | } 29 | . = ALIGN(4k); 30 | kernel.rodata : { 31 | *(.rodata .rodata.*) 32 | } 33 | . = ALIGN(4k); 34 | kern_end = .; 35 | /DISCARD/ : { 36 | *(.eh_frame) 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /kernel/script/.gdbinit: -------------------------------------------------------------------------------- 1 | set $lastcs = -1 2 | set disassembly-flavor intel 3 | define hook-stop 4 | x/i $pc 5 | set $lastcs = $cs 6 | end 7 | 8 | echo + target remote localhost:1234\n 9 | target remote localhost:1234 10 | 11 | echo + symbol-file kernel/kernel\n 12 | symbol-file kernel/kernel.obj 13 | 14 | -------------------------------------------------------------------------------- /kernel/script/gen_vector.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | print('# Generated by gen_vector.py') 4 | print(''' 5 | .intel_syntax noprefix 6 | .section .text.vectors 7 | .code64 8 | ''') 9 | 10 | print('.extern trap_enter_all') 11 | for i in range(256): 12 | print(f''' 13 | vector_{i}:''') 14 | if i not in [8, 10, 11, 12, 13, 14, 17]: 15 | print(' push 0') 16 | print(f' push {i}') 17 | print(f' jmp trap_enter_all') 18 | 19 | print(''' 20 | # Vector Pointer Table 21 | .section .rodata.vectors 22 | .align 8 23 | vectors: 24 | ''') 25 | 26 | for i in range(256): 27 | print(f' .quad vector_{i}') 28 | -------------------------------------------------------------------------------- /kernel/script/qemu.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | qemu-system-x86_64 -m 512M -drive file=guideos.img,format=raw -nographic $@ 4 | -------------------------------------------------------------------------------- /kernel/src/arch/x86/asm/bsp_init.s: -------------------------------------------------------------------------------- 1 | .intel_syntax noprefix 2 | 3 | .extern kmain 4 | .globl kentry 5 | .globl raw_entry 6 | 7 | 8 | .code32 9 | .section .raw_init, "ax" 10 | raw_entry: 11 | mov eax, 0xb0bacafe 12 | mov ebx, 0 13 | jmp kentry 14 | 15 | .section .bootstrap, "ax" 16 | .align 8 17 | kentry: 18 | cli 19 | mov esp, 0x10000 20 | push ebx 21 | push eax 22 | 23 | # Build Page Tables 24 | mov eax, OFFSET pdp 25 | or eax, 0b11 26 | mov [pml4], eax 27 | mov [pml4 + (256 * 8)], eax 28 | 29 | # Enable Paging / Long Mode 30 | mov eax, OFFSET pml4 31 | mov cr3, eax 32 | 33 | mov eax, cr4 34 | or eax, 1 << 5 35 | mov cr4, eax 36 | 37 | mov ecx, 0xC0000080 38 | rdmsr 39 | or eax, 1 << 8 40 | wrmsr 41 | 42 | mov eax, cr0 43 | or eax, 1 << 31 44 | mov cr0, eax 45 | 46 | lgdt [gdtdesc] 47 | jmp 0x8:long_start 48 | 49 | # Long mode 50 | .code64 51 | 52 | long_start: 53 | xor ax, ax 54 | mov ds, ax 55 | mov es, ax 56 | mov ss, ax 57 | mov fs, ax 58 | mov gs, ax 59 | mov rax, 0xFFFF800000000000 60 | add rax, OFFSET gdt64 61 | mov [gdtdesc_addr], rax 62 | movabs rax, OFFSET gdtdesc 63 | mov rcx, 0xFFFF800000000000 64 | add rax, rcx 65 | lgdt [rax] 66 | 67 | mov rdi, DWORD [rsp] 68 | mov rsi, DWORD [rsp + 4] 69 | mov rbp, 0xFFFF800000000000 70 | mov rsp, 0xFFFF800000000000 + 0x10000 71 | movabs rax, OFFSET kmain 72 | call rax 73 | 74 | halt: 75 | hlt 76 | jmp halt 77 | 78 | gdt64: 79 | # Null Entry 80 | .quad 0 81 | 82 | .quad (1<<43) | (1<<44) | (1<<47) | (1<<53) 83 | 84 | .quad (1<<44) | (1<<47) | (1<<53) 85 | 86 | gdtdesc: 87 | .short (gdtdesc - gdt64 - 1) 88 | gdtdesc_addr: 89 | .quad gdt64 90 | 91 | .section .bootstrap.data, "wa" 92 | .align 4096 93 | pml4: 94 | .fill 512, 8, 0 95 | 96 | .align 4096 97 | pdp: 98 | .quad (0x80 | 0x2 | 0x1) 99 | .fill 511, 8, 0 100 | -------------------------------------------------------------------------------- /kernel/src/arch/x86/asm/multiboot.s: -------------------------------------------------------------------------------- 1 | .intel_syntax noprefix 2 | 3 | .section .multiboot, "a" 4 | .align 8 5 | multiboot_start: 6 | .long 0xE85250D6 7 | .long 0 8 | .long (multiboot_end - multiboot_start) 9 | .long 0x100000000 - (0xe85250d6 + 0 + (multiboot_end - multiboot_start)) 10 | 11 | # end tag 12 | .short 0 13 | .short 0 14 | .long 8 15 | 16 | multiboot_end: 17 | -------------------------------------------------------------------------------- /kernel/src/arch/x86/asm/swtch.s: -------------------------------------------------------------------------------- 1 | .intel_syntax noprefix 2 | 3 | .section .text 4 | .globl sched_ctxsw 5 | 6 | # void sched_ctxsw(struct proc_context **old, const struct proc_context *new); 7 | # rdi, rsi 8 | sched_ctxsw: 9 | push r15 10 | push r14 11 | push r13 12 | push r12 13 | push rbp 14 | push rbx 15 | 16 | mov [rdi], rsp 17 | mov rsp, rsi 18 | 19 | pop rbx 20 | pop rbp 21 | pop r12 22 | pop r13 23 | pop r14 24 | pop r15 25 | ret -------------------------------------------------------------------------------- /kernel/src/arch/x86/asm/trap.s: -------------------------------------------------------------------------------- 1 | .intel_syntax noprefix 2 | .section .text.vectors 3 | .code64 4 | 5 | .extern handle_interrupt 6 | .globl trap_enter_all 7 | .globl return_from_isr 8 | 9 | trap_enter_all: 10 | push r15 11 | push r14 12 | push r13 13 | push r12 14 | push r11 15 | push r10 16 | push r9 17 | push r8 18 | push rbp 19 | push rdi 20 | push rsi 21 | push rbx 22 | push rdx 23 | push rcx 24 | push rax 25 | # Setup Call 26 | mov rdi, rsp 27 | call handle_interrupt 28 | return_from_isr: 29 | pop rax 30 | pop rcx 31 | pop rdx 32 | pop rbx 33 | pop rsi 34 | pop rdi 35 | pop rbp 36 | pop r8 37 | pop r9 38 | pop r10 39 | pop r11 40 | pop r12 41 | pop r13 42 | pop r14 43 | pop r15 44 | add rsp, 16 # Pop trap_no and fake error_code 45 | iretq -------------------------------------------------------------------------------- /kernel/src/arch/x86/asm/vector.s: -------------------------------------------------------------------------------- 1 | # Generated by gen_vector.py 2 | 3 | .intel_syntax noprefix 4 | .section .text.vectors 5 | .code64 6 | 7 | .extern trap_enter_all 8 | 9 | vector_0: 10 | push 0 11 | push 0 12 | jmp trap_enter_all 13 | 14 | vector_1: 15 | push 0 16 | push 1 17 | jmp trap_enter_all 18 | 19 | vector_2: 20 | push 0 21 | push 2 22 | jmp trap_enter_all 23 | 24 | vector_3: 25 | push 0 26 | push 3 27 | jmp trap_enter_all 28 | 29 | vector_4: 30 | push 0 31 | push 4 32 | jmp trap_enter_all 33 | 34 | vector_5: 35 | push 0 36 | push 5 37 | jmp trap_enter_all 38 | 39 | vector_6: 40 | push 0 41 | push 6 42 | jmp trap_enter_all 43 | 44 | vector_7: 45 | push 0 46 | push 7 47 | jmp trap_enter_all 48 | 49 | vector_8: 50 | push 8 51 | jmp trap_enter_all 52 | 53 | vector_9: 54 | push 0 55 | push 9 56 | jmp trap_enter_all 57 | 58 | vector_10: 59 | push 10 60 | jmp trap_enter_all 61 | 62 | vector_11: 63 | push 11 64 | jmp trap_enter_all 65 | 66 | vector_12: 67 | push 12 68 | jmp trap_enter_all 69 | 70 | vector_13: 71 | push 13 72 | jmp trap_enter_all 73 | 74 | vector_14: 75 | push 14 76 | jmp trap_enter_all 77 | 78 | vector_15: 79 | push 0 80 | push 15 81 | jmp trap_enter_all 82 | 83 | vector_16: 84 | push 0 85 | push 16 86 | jmp trap_enter_all 87 | 88 | vector_17: 89 | push 17 90 | jmp trap_enter_all 91 | 92 | vector_18: 93 | push 0 94 | push 18 95 | jmp trap_enter_all 96 | 97 | vector_19: 98 | push 0 99 | push 19 100 | jmp trap_enter_all 101 | 102 | vector_20: 103 | push 0 104 | push 20 105 | jmp trap_enter_all 106 | 107 | vector_21: 108 | push 0 109 | push 21 110 | jmp trap_enter_all 111 | 112 | vector_22: 113 | push 0 114 | push 22 115 | jmp trap_enter_all 116 | 117 | vector_23: 118 | push 0 119 | push 23 120 | jmp trap_enter_all 121 | 122 | vector_24: 123 | push 0 124 | push 24 125 | jmp trap_enter_all 126 | 127 | vector_25: 128 | push 0 129 | push 25 130 | jmp trap_enter_all 131 | 132 | vector_26: 133 | push 0 134 | push 26 135 | jmp trap_enter_all 136 | 137 | vector_27: 138 | push 0 139 | push 27 140 | jmp trap_enter_all 141 | 142 | vector_28: 143 | push 0 144 | push 28 145 | jmp trap_enter_all 146 | 147 | vector_29: 148 | push 0 149 | push 29 150 | jmp trap_enter_all 151 | 152 | vector_30: 153 | push 0 154 | push 30 155 | jmp trap_enter_all 156 | 157 | vector_31: 158 | push 0 159 | push 31 160 | jmp trap_enter_all 161 | 162 | vector_32: 163 | push 0 164 | push 32 165 | jmp trap_enter_all 166 | 167 | vector_33: 168 | push 0 169 | push 33 170 | jmp trap_enter_all 171 | 172 | vector_34: 173 | push 0 174 | push 34 175 | jmp trap_enter_all 176 | 177 | vector_35: 178 | push 0 179 | push 35 180 | jmp trap_enter_all 181 | 182 | vector_36: 183 | push 0 184 | push 36 185 | jmp trap_enter_all 186 | 187 | vector_37: 188 | push 0 189 | push 37 190 | jmp trap_enter_all 191 | 192 | vector_38: 193 | push 0 194 | push 38 195 | jmp trap_enter_all 196 | 197 | vector_39: 198 | push 0 199 | push 39 200 | jmp trap_enter_all 201 | 202 | vector_40: 203 | push 0 204 | push 40 205 | jmp trap_enter_all 206 | 207 | vector_41: 208 | push 0 209 | push 41 210 | jmp trap_enter_all 211 | 212 | vector_42: 213 | push 0 214 | push 42 215 | jmp trap_enter_all 216 | 217 | vector_43: 218 | push 0 219 | push 43 220 | jmp trap_enter_all 221 | 222 | vector_44: 223 | push 0 224 | push 44 225 | jmp trap_enter_all 226 | 227 | vector_45: 228 | push 0 229 | push 45 230 | jmp trap_enter_all 231 | 232 | vector_46: 233 | push 0 234 | push 46 235 | jmp trap_enter_all 236 | 237 | vector_47: 238 | push 0 239 | push 47 240 | jmp trap_enter_all 241 | 242 | vector_48: 243 | push 0 244 | push 48 245 | jmp trap_enter_all 246 | 247 | vector_49: 248 | push 0 249 | push 49 250 | jmp trap_enter_all 251 | 252 | vector_50: 253 | push 0 254 | push 50 255 | jmp trap_enter_all 256 | 257 | vector_51: 258 | push 0 259 | push 51 260 | jmp trap_enter_all 261 | 262 | vector_52: 263 | push 0 264 | push 52 265 | jmp trap_enter_all 266 | 267 | vector_53: 268 | push 0 269 | push 53 270 | jmp trap_enter_all 271 | 272 | vector_54: 273 | push 0 274 | push 54 275 | jmp trap_enter_all 276 | 277 | vector_55: 278 | push 0 279 | push 55 280 | jmp trap_enter_all 281 | 282 | vector_56: 283 | push 0 284 | push 56 285 | jmp trap_enter_all 286 | 287 | vector_57: 288 | push 0 289 | push 57 290 | jmp trap_enter_all 291 | 292 | vector_58: 293 | push 0 294 | push 58 295 | jmp trap_enter_all 296 | 297 | vector_59: 298 | push 0 299 | push 59 300 | jmp trap_enter_all 301 | 302 | vector_60: 303 | push 0 304 | push 60 305 | jmp trap_enter_all 306 | 307 | vector_61: 308 | push 0 309 | push 61 310 | jmp trap_enter_all 311 | 312 | vector_62: 313 | push 0 314 | push 62 315 | jmp trap_enter_all 316 | 317 | vector_63: 318 | push 0 319 | push 63 320 | jmp trap_enter_all 321 | 322 | vector_64: 323 | push 0 324 | push 64 325 | jmp trap_enter_all 326 | 327 | vector_65: 328 | push 0 329 | push 65 330 | jmp trap_enter_all 331 | 332 | vector_66: 333 | push 0 334 | push 66 335 | jmp trap_enter_all 336 | 337 | vector_67: 338 | push 0 339 | push 67 340 | jmp trap_enter_all 341 | 342 | vector_68: 343 | push 0 344 | push 68 345 | jmp trap_enter_all 346 | 347 | vector_69: 348 | push 0 349 | push 69 350 | jmp trap_enter_all 351 | 352 | vector_70: 353 | push 0 354 | push 70 355 | jmp trap_enter_all 356 | 357 | vector_71: 358 | push 0 359 | push 71 360 | jmp trap_enter_all 361 | 362 | vector_72: 363 | push 0 364 | push 72 365 | jmp trap_enter_all 366 | 367 | vector_73: 368 | push 0 369 | push 73 370 | jmp trap_enter_all 371 | 372 | vector_74: 373 | push 0 374 | push 74 375 | jmp trap_enter_all 376 | 377 | vector_75: 378 | push 0 379 | push 75 380 | jmp trap_enter_all 381 | 382 | vector_76: 383 | push 0 384 | push 76 385 | jmp trap_enter_all 386 | 387 | vector_77: 388 | push 0 389 | push 77 390 | jmp trap_enter_all 391 | 392 | vector_78: 393 | push 0 394 | push 78 395 | jmp trap_enter_all 396 | 397 | vector_79: 398 | push 0 399 | push 79 400 | jmp trap_enter_all 401 | 402 | vector_80: 403 | push 0 404 | push 80 405 | jmp trap_enter_all 406 | 407 | vector_81: 408 | push 0 409 | push 81 410 | jmp trap_enter_all 411 | 412 | vector_82: 413 | push 0 414 | push 82 415 | jmp trap_enter_all 416 | 417 | vector_83: 418 | push 0 419 | push 83 420 | jmp trap_enter_all 421 | 422 | vector_84: 423 | push 0 424 | push 84 425 | jmp trap_enter_all 426 | 427 | vector_85: 428 | push 0 429 | push 85 430 | jmp trap_enter_all 431 | 432 | vector_86: 433 | push 0 434 | push 86 435 | jmp trap_enter_all 436 | 437 | vector_87: 438 | push 0 439 | push 87 440 | jmp trap_enter_all 441 | 442 | vector_88: 443 | push 0 444 | push 88 445 | jmp trap_enter_all 446 | 447 | vector_89: 448 | push 0 449 | push 89 450 | jmp trap_enter_all 451 | 452 | vector_90: 453 | push 0 454 | push 90 455 | jmp trap_enter_all 456 | 457 | vector_91: 458 | push 0 459 | push 91 460 | jmp trap_enter_all 461 | 462 | vector_92: 463 | push 0 464 | push 92 465 | jmp trap_enter_all 466 | 467 | vector_93: 468 | push 0 469 | push 93 470 | jmp trap_enter_all 471 | 472 | vector_94: 473 | push 0 474 | push 94 475 | jmp trap_enter_all 476 | 477 | vector_95: 478 | push 0 479 | push 95 480 | jmp trap_enter_all 481 | 482 | vector_96: 483 | push 0 484 | push 96 485 | jmp trap_enter_all 486 | 487 | vector_97: 488 | push 0 489 | push 97 490 | jmp trap_enter_all 491 | 492 | vector_98: 493 | push 0 494 | push 98 495 | jmp trap_enter_all 496 | 497 | vector_99: 498 | push 0 499 | push 99 500 | jmp trap_enter_all 501 | 502 | vector_100: 503 | push 0 504 | push 100 505 | jmp trap_enter_all 506 | 507 | vector_101: 508 | push 0 509 | push 101 510 | jmp trap_enter_all 511 | 512 | vector_102: 513 | push 0 514 | push 102 515 | jmp trap_enter_all 516 | 517 | vector_103: 518 | push 0 519 | push 103 520 | jmp trap_enter_all 521 | 522 | vector_104: 523 | push 0 524 | push 104 525 | jmp trap_enter_all 526 | 527 | vector_105: 528 | push 0 529 | push 105 530 | jmp trap_enter_all 531 | 532 | vector_106: 533 | push 0 534 | push 106 535 | jmp trap_enter_all 536 | 537 | vector_107: 538 | push 0 539 | push 107 540 | jmp trap_enter_all 541 | 542 | vector_108: 543 | push 0 544 | push 108 545 | jmp trap_enter_all 546 | 547 | vector_109: 548 | push 0 549 | push 109 550 | jmp trap_enter_all 551 | 552 | vector_110: 553 | push 0 554 | push 110 555 | jmp trap_enter_all 556 | 557 | vector_111: 558 | push 0 559 | push 111 560 | jmp trap_enter_all 561 | 562 | vector_112: 563 | push 0 564 | push 112 565 | jmp trap_enter_all 566 | 567 | vector_113: 568 | push 0 569 | push 113 570 | jmp trap_enter_all 571 | 572 | vector_114: 573 | push 0 574 | push 114 575 | jmp trap_enter_all 576 | 577 | vector_115: 578 | push 0 579 | push 115 580 | jmp trap_enter_all 581 | 582 | vector_116: 583 | push 0 584 | push 116 585 | jmp trap_enter_all 586 | 587 | vector_117: 588 | push 0 589 | push 117 590 | jmp trap_enter_all 591 | 592 | vector_118: 593 | push 0 594 | push 118 595 | jmp trap_enter_all 596 | 597 | vector_119: 598 | push 0 599 | push 119 600 | jmp trap_enter_all 601 | 602 | vector_120: 603 | push 0 604 | push 120 605 | jmp trap_enter_all 606 | 607 | vector_121: 608 | push 0 609 | push 121 610 | jmp trap_enter_all 611 | 612 | vector_122: 613 | push 0 614 | push 122 615 | jmp trap_enter_all 616 | 617 | vector_123: 618 | push 0 619 | push 123 620 | jmp trap_enter_all 621 | 622 | vector_124: 623 | push 0 624 | push 124 625 | jmp trap_enter_all 626 | 627 | vector_125: 628 | push 0 629 | push 125 630 | jmp trap_enter_all 631 | 632 | vector_126: 633 | push 0 634 | push 126 635 | jmp trap_enter_all 636 | 637 | vector_127: 638 | push 0 639 | push 127 640 | jmp trap_enter_all 641 | 642 | vector_128: 643 | push 0 644 | push 128 645 | jmp trap_enter_all 646 | 647 | vector_129: 648 | push 0 649 | push 129 650 | jmp trap_enter_all 651 | 652 | vector_130: 653 | push 0 654 | push 130 655 | jmp trap_enter_all 656 | 657 | vector_131: 658 | push 0 659 | push 131 660 | jmp trap_enter_all 661 | 662 | vector_132: 663 | push 0 664 | push 132 665 | jmp trap_enter_all 666 | 667 | vector_133: 668 | push 0 669 | push 133 670 | jmp trap_enter_all 671 | 672 | vector_134: 673 | push 0 674 | push 134 675 | jmp trap_enter_all 676 | 677 | vector_135: 678 | push 0 679 | push 135 680 | jmp trap_enter_all 681 | 682 | vector_136: 683 | push 0 684 | push 136 685 | jmp trap_enter_all 686 | 687 | vector_137: 688 | push 0 689 | push 137 690 | jmp trap_enter_all 691 | 692 | vector_138: 693 | push 0 694 | push 138 695 | jmp trap_enter_all 696 | 697 | vector_139: 698 | push 0 699 | push 139 700 | jmp trap_enter_all 701 | 702 | vector_140: 703 | push 0 704 | push 140 705 | jmp trap_enter_all 706 | 707 | vector_141: 708 | push 0 709 | push 141 710 | jmp trap_enter_all 711 | 712 | vector_142: 713 | push 0 714 | push 142 715 | jmp trap_enter_all 716 | 717 | vector_143: 718 | push 0 719 | push 143 720 | jmp trap_enter_all 721 | 722 | vector_144: 723 | push 0 724 | push 144 725 | jmp trap_enter_all 726 | 727 | vector_145: 728 | push 0 729 | push 145 730 | jmp trap_enter_all 731 | 732 | vector_146: 733 | push 0 734 | push 146 735 | jmp trap_enter_all 736 | 737 | vector_147: 738 | push 0 739 | push 147 740 | jmp trap_enter_all 741 | 742 | vector_148: 743 | push 0 744 | push 148 745 | jmp trap_enter_all 746 | 747 | vector_149: 748 | push 0 749 | push 149 750 | jmp trap_enter_all 751 | 752 | vector_150: 753 | push 0 754 | push 150 755 | jmp trap_enter_all 756 | 757 | vector_151: 758 | push 0 759 | push 151 760 | jmp trap_enter_all 761 | 762 | vector_152: 763 | push 0 764 | push 152 765 | jmp trap_enter_all 766 | 767 | vector_153: 768 | push 0 769 | push 153 770 | jmp trap_enter_all 771 | 772 | vector_154: 773 | push 0 774 | push 154 775 | jmp trap_enter_all 776 | 777 | vector_155: 778 | push 0 779 | push 155 780 | jmp trap_enter_all 781 | 782 | vector_156: 783 | push 0 784 | push 156 785 | jmp trap_enter_all 786 | 787 | vector_157: 788 | push 0 789 | push 157 790 | jmp trap_enter_all 791 | 792 | vector_158: 793 | push 0 794 | push 158 795 | jmp trap_enter_all 796 | 797 | vector_159: 798 | push 0 799 | push 159 800 | jmp trap_enter_all 801 | 802 | vector_160: 803 | push 0 804 | push 160 805 | jmp trap_enter_all 806 | 807 | vector_161: 808 | push 0 809 | push 161 810 | jmp trap_enter_all 811 | 812 | vector_162: 813 | push 0 814 | push 162 815 | jmp trap_enter_all 816 | 817 | vector_163: 818 | push 0 819 | push 163 820 | jmp trap_enter_all 821 | 822 | vector_164: 823 | push 0 824 | push 164 825 | jmp trap_enter_all 826 | 827 | vector_165: 828 | push 0 829 | push 165 830 | jmp trap_enter_all 831 | 832 | vector_166: 833 | push 0 834 | push 166 835 | jmp trap_enter_all 836 | 837 | vector_167: 838 | push 0 839 | push 167 840 | jmp trap_enter_all 841 | 842 | vector_168: 843 | push 0 844 | push 168 845 | jmp trap_enter_all 846 | 847 | vector_169: 848 | push 0 849 | push 169 850 | jmp trap_enter_all 851 | 852 | vector_170: 853 | push 0 854 | push 170 855 | jmp trap_enter_all 856 | 857 | vector_171: 858 | push 0 859 | push 171 860 | jmp trap_enter_all 861 | 862 | vector_172: 863 | push 0 864 | push 172 865 | jmp trap_enter_all 866 | 867 | vector_173: 868 | push 0 869 | push 173 870 | jmp trap_enter_all 871 | 872 | vector_174: 873 | push 0 874 | push 174 875 | jmp trap_enter_all 876 | 877 | vector_175: 878 | push 0 879 | push 175 880 | jmp trap_enter_all 881 | 882 | vector_176: 883 | push 0 884 | push 176 885 | jmp trap_enter_all 886 | 887 | vector_177: 888 | push 0 889 | push 177 890 | jmp trap_enter_all 891 | 892 | vector_178: 893 | push 0 894 | push 178 895 | jmp trap_enter_all 896 | 897 | vector_179: 898 | push 0 899 | push 179 900 | jmp trap_enter_all 901 | 902 | vector_180: 903 | push 0 904 | push 180 905 | jmp trap_enter_all 906 | 907 | vector_181: 908 | push 0 909 | push 181 910 | jmp trap_enter_all 911 | 912 | vector_182: 913 | push 0 914 | push 182 915 | jmp trap_enter_all 916 | 917 | vector_183: 918 | push 0 919 | push 183 920 | jmp trap_enter_all 921 | 922 | vector_184: 923 | push 0 924 | push 184 925 | jmp trap_enter_all 926 | 927 | vector_185: 928 | push 0 929 | push 185 930 | jmp trap_enter_all 931 | 932 | vector_186: 933 | push 0 934 | push 186 935 | jmp trap_enter_all 936 | 937 | vector_187: 938 | push 0 939 | push 187 940 | jmp trap_enter_all 941 | 942 | vector_188: 943 | push 0 944 | push 188 945 | jmp trap_enter_all 946 | 947 | vector_189: 948 | push 0 949 | push 189 950 | jmp trap_enter_all 951 | 952 | vector_190: 953 | push 0 954 | push 190 955 | jmp trap_enter_all 956 | 957 | vector_191: 958 | push 0 959 | push 191 960 | jmp trap_enter_all 961 | 962 | vector_192: 963 | push 0 964 | push 192 965 | jmp trap_enter_all 966 | 967 | vector_193: 968 | push 0 969 | push 193 970 | jmp trap_enter_all 971 | 972 | vector_194: 973 | push 0 974 | push 194 975 | jmp trap_enter_all 976 | 977 | vector_195: 978 | push 0 979 | push 195 980 | jmp trap_enter_all 981 | 982 | vector_196: 983 | push 0 984 | push 196 985 | jmp trap_enter_all 986 | 987 | vector_197: 988 | push 0 989 | push 197 990 | jmp trap_enter_all 991 | 992 | vector_198: 993 | push 0 994 | push 198 995 | jmp trap_enter_all 996 | 997 | vector_199: 998 | push 0 999 | push 199 1000 | jmp trap_enter_all 1001 | 1002 | vector_200: 1003 | push 0 1004 | push 200 1005 | jmp trap_enter_all 1006 | 1007 | vector_201: 1008 | push 0 1009 | push 201 1010 | jmp trap_enter_all 1011 | 1012 | vector_202: 1013 | push 0 1014 | push 202 1015 | jmp trap_enter_all 1016 | 1017 | vector_203: 1018 | push 0 1019 | push 203 1020 | jmp trap_enter_all 1021 | 1022 | vector_204: 1023 | push 0 1024 | push 204 1025 | jmp trap_enter_all 1026 | 1027 | vector_205: 1028 | push 0 1029 | push 205 1030 | jmp trap_enter_all 1031 | 1032 | vector_206: 1033 | push 0 1034 | push 206 1035 | jmp trap_enter_all 1036 | 1037 | vector_207: 1038 | push 0 1039 | push 207 1040 | jmp trap_enter_all 1041 | 1042 | vector_208: 1043 | push 0 1044 | push 208 1045 | jmp trap_enter_all 1046 | 1047 | vector_209: 1048 | push 0 1049 | push 209 1050 | jmp trap_enter_all 1051 | 1052 | vector_210: 1053 | push 0 1054 | push 210 1055 | jmp trap_enter_all 1056 | 1057 | vector_211: 1058 | push 0 1059 | push 211 1060 | jmp trap_enter_all 1061 | 1062 | vector_212: 1063 | push 0 1064 | push 212 1065 | jmp trap_enter_all 1066 | 1067 | vector_213: 1068 | push 0 1069 | push 213 1070 | jmp trap_enter_all 1071 | 1072 | vector_214: 1073 | push 0 1074 | push 214 1075 | jmp trap_enter_all 1076 | 1077 | vector_215: 1078 | push 0 1079 | push 215 1080 | jmp trap_enter_all 1081 | 1082 | vector_216: 1083 | push 0 1084 | push 216 1085 | jmp trap_enter_all 1086 | 1087 | vector_217: 1088 | push 0 1089 | push 217 1090 | jmp trap_enter_all 1091 | 1092 | vector_218: 1093 | push 0 1094 | push 218 1095 | jmp trap_enter_all 1096 | 1097 | vector_219: 1098 | push 0 1099 | push 219 1100 | jmp trap_enter_all 1101 | 1102 | vector_220: 1103 | push 0 1104 | push 220 1105 | jmp trap_enter_all 1106 | 1107 | vector_221: 1108 | push 0 1109 | push 221 1110 | jmp trap_enter_all 1111 | 1112 | vector_222: 1113 | push 0 1114 | push 222 1115 | jmp trap_enter_all 1116 | 1117 | vector_223: 1118 | push 0 1119 | push 223 1120 | jmp trap_enter_all 1121 | 1122 | vector_224: 1123 | push 0 1124 | push 224 1125 | jmp trap_enter_all 1126 | 1127 | vector_225: 1128 | push 0 1129 | push 225 1130 | jmp trap_enter_all 1131 | 1132 | vector_226: 1133 | push 0 1134 | push 226 1135 | jmp trap_enter_all 1136 | 1137 | vector_227: 1138 | push 0 1139 | push 227 1140 | jmp trap_enter_all 1141 | 1142 | vector_228: 1143 | push 0 1144 | push 228 1145 | jmp trap_enter_all 1146 | 1147 | vector_229: 1148 | push 0 1149 | push 229 1150 | jmp trap_enter_all 1151 | 1152 | vector_230: 1153 | push 0 1154 | push 230 1155 | jmp trap_enter_all 1156 | 1157 | vector_231: 1158 | push 0 1159 | push 231 1160 | jmp trap_enter_all 1161 | 1162 | vector_232: 1163 | push 0 1164 | push 232 1165 | jmp trap_enter_all 1166 | 1167 | vector_233: 1168 | push 0 1169 | push 233 1170 | jmp trap_enter_all 1171 | 1172 | vector_234: 1173 | push 0 1174 | push 234 1175 | jmp trap_enter_all 1176 | 1177 | vector_235: 1178 | push 0 1179 | push 235 1180 | jmp trap_enter_all 1181 | 1182 | vector_236: 1183 | push 0 1184 | push 236 1185 | jmp trap_enter_all 1186 | 1187 | vector_237: 1188 | push 0 1189 | push 237 1190 | jmp trap_enter_all 1191 | 1192 | vector_238: 1193 | push 0 1194 | push 238 1195 | jmp trap_enter_all 1196 | 1197 | vector_239: 1198 | push 0 1199 | push 239 1200 | jmp trap_enter_all 1201 | 1202 | vector_240: 1203 | push 0 1204 | push 240 1205 | jmp trap_enter_all 1206 | 1207 | vector_241: 1208 | push 0 1209 | push 241 1210 | jmp trap_enter_all 1211 | 1212 | vector_242: 1213 | push 0 1214 | push 242 1215 | jmp trap_enter_all 1216 | 1217 | vector_243: 1218 | push 0 1219 | push 243 1220 | jmp trap_enter_all 1221 | 1222 | vector_244: 1223 | push 0 1224 | push 244 1225 | jmp trap_enter_all 1226 | 1227 | vector_245: 1228 | push 0 1229 | push 245 1230 | jmp trap_enter_all 1231 | 1232 | vector_246: 1233 | push 0 1234 | push 246 1235 | jmp trap_enter_all 1236 | 1237 | vector_247: 1238 | push 0 1239 | push 247 1240 | jmp trap_enter_all 1241 | 1242 | vector_248: 1243 | push 0 1244 | push 248 1245 | jmp trap_enter_all 1246 | 1247 | vector_249: 1248 | push 0 1249 | push 249 1250 | jmp trap_enter_all 1251 | 1252 | vector_250: 1253 | push 0 1254 | push 250 1255 | jmp trap_enter_all 1256 | 1257 | vector_251: 1258 | push 0 1259 | push 251 1260 | jmp trap_enter_all 1261 | 1262 | vector_252: 1263 | push 0 1264 | push 252 1265 | jmp trap_enter_all 1266 | 1267 | vector_253: 1268 | push 0 1269 | push 253 1270 | jmp trap_enter_all 1271 | 1272 | vector_254: 1273 | push 0 1274 | push 254 1275 | jmp trap_enter_all 1276 | 1277 | vector_255: 1278 | push 0 1279 | push 255 1280 | jmp trap_enter_all 1281 | 1282 | # Vector Pointer Table 1283 | .section .rodata.vectors 1284 | .align 8 1285 | 1286 | .globl vectors 1287 | vectors: 1288 | .quad vector_0 1289 | .quad vector_1 1290 | .quad vector_2 1291 | .quad vector_3 1292 | .quad vector_4 1293 | .quad vector_5 1294 | .quad vector_6 1295 | .quad vector_7 1296 | .quad vector_8 1297 | .quad vector_9 1298 | .quad vector_10 1299 | .quad vector_11 1300 | .quad vector_12 1301 | .quad vector_13 1302 | .quad vector_14 1303 | .quad vector_15 1304 | .quad vector_16 1305 | .quad vector_17 1306 | .quad vector_18 1307 | .quad vector_19 1308 | .quad vector_20 1309 | .quad vector_21 1310 | .quad vector_22 1311 | .quad vector_23 1312 | .quad vector_24 1313 | .quad vector_25 1314 | .quad vector_26 1315 | .quad vector_27 1316 | .quad vector_28 1317 | .quad vector_29 1318 | .quad vector_30 1319 | .quad vector_31 1320 | .quad vector_32 1321 | .quad vector_33 1322 | .quad vector_34 1323 | .quad vector_35 1324 | .quad vector_36 1325 | .quad vector_37 1326 | .quad vector_38 1327 | .quad vector_39 1328 | .quad vector_40 1329 | .quad vector_41 1330 | .quad vector_42 1331 | .quad vector_43 1332 | .quad vector_44 1333 | .quad vector_45 1334 | .quad vector_46 1335 | .quad vector_47 1336 | .quad vector_48 1337 | .quad vector_49 1338 | .quad vector_50 1339 | .quad vector_51 1340 | .quad vector_52 1341 | .quad vector_53 1342 | .quad vector_54 1343 | .quad vector_55 1344 | .quad vector_56 1345 | .quad vector_57 1346 | .quad vector_58 1347 | .quad vector_59 1348 | .quad vector_60 1349 | .quad vector_61 1350 | .quad vector_62 1351 | .quad vector_63 1352 | .quad vector_64 1353 | .quad vector_65 1354 | .quad vector_66 1355 | .quad vector_67 1356 | .quad vector_68 1357 | .quad vector_69 1358 | .quad vector_70 1359 | .quad vector_71 1360 | .quad vector_72 1361 | .quad vector_73 1362 | .quad vector_74 1363 | .quad vector_75 1364 | .quad vector_76 1365 | .quad vector_77 1366 | .quad vector_78 1367 | .quad vector_79 1368 | .quad vector_80 1369 | .quad vector_81 1370 | .quad vector_82 1371 | .quad vector_83 1372 | .quad vector_84 1373 | .quad vector_85 1374 | .quad vector_86 1375 | .quad vector_87 1376 | .quad vector_88 1377 | .quad vector_89 1378 | .quad vector_90 1379 | .quad vector_91 1380 | .quad vector_92 1381 | .quad vector_93 1382 | .quad vector_94 1383 | .quad vector_95 1384 | .quad vector_96 1385 | .quad vector_97 1386 | .quad vector_98 1387 | .quad vector_99 1388 | .quad vector_100 1389 | .quad vector_101 1390 | .quad vector_102 1391 | .quad vector_103 1392 | .quad vector_104 1393 | .quad vector_105 1394 | .quad vector_106 1395 | .quad vector_107 1396 | .quad vector_108 1397 | .quad vector_109 1398 | .quad vector_110 1399 | .quad vector_111 1400 | .quad vector_112 1401 | .quad vector_113 1402 | .quad vector_114 1403 | .quad vector_115 1404 | .quad vector_116 1405 | .quad vector_117 1406 | .quad vector_118 1407 | .quad vector_119 1408 | .quad vector_120 1409 | .quad vector_121 1410 | .quad vector_122 1411 | .quad vector_123 1412 | .quad vector_124 1413 | .quad vector_125 1414 | .quad vector_126 1415 | .quad vector_127 1416 | .quad vector_128 1417 | .quad vector_129 1418 | .quad vector_130 1419 | .quad vector_131 1420 | .quad vector_132 1421 | .quad vector_133 1422 | .quad vector_134 1423 | .quad vector_135 1424 | .quad vector_136 1425 | .quad vector_137 1426 | .quad vector_138 1427 | .quad vector_139 1428 | .quad vector_140 1429 | .quad vector_141 1430 | .quad vector_142 1431 | .quad vector_143 1432 | .quad vector_144 1433 | .quad vector_145 1434 | .quad vector_146 1435 | .quad vector_147 1436 | .quad vector_148 1437 | .quad vector_149 1438 | .quad vector_150 1439 | .quad vector_151 1440 | .quad vector_152 1441 | .quad vector_153 1442 | .quad vector_154 1443 | .quad vector_155 1444 | .quad vector_156 1445 | .quad vector_157 1446 | .quad vector_158 1447 | .quad vector_159 1448 | .quad vector_160 1449 | .quad vector_161 1450 | .quad vector_162 1451 | .quad vector_163 1452 | .quad vector_164 1453 | .quad vector_165 1454 | .quad vector_166 1455 | .quad vector_167 1456 | .quad vector_168 1457 | .quad vector_169 1458 | .quad vector_170 1459 | .quad vector_171 1460 | .quad vector_172 1461 | .quad vector_173 1462 | .quad vector_174 1463 | .quad vector_175 1464 | .quad vector_176 1465 | .quad vector_177 1466 | .quad vector_178 1467 | .quad vector_179 1468 | .quad vector_180 1469 | .quad vector_181 1470 | .quad vector_182 1471 | .quad vector_183 1472 | .quad vector_184 1473 | .quad vector_185 1474 | .quad vector_186 1475 | .quad vector_187 1476 | .quad vector_188 1477 | .quad vector_189 1478 | .quad vector_190 1479 | .quad vector_191 1480 | .quad vector_192 1481 | .quad vector_193 1482 | .quad vector_194 1483 | .quad vector_195 1484 | .quad vector_196 1485 | .quad vector_197 1486 | .quad vector_198 1487 | .quad vector_199 1488 | .quad vector_200 1489 | .quad vector_201 1490 | .quad vector_202 1491 | .quad vector_203 1492 | .quad vector_204 1493 | .quad vector_205 1494 | .quad vector_206 1495 | .quad vector_207 1496 | .quad vector_208 1497 | .quad vector_209 1498 | .quad vector_210 1499 | .quad vector_211 1500 | .quad vector_212 1501 | .quad vector_213 1502 | .quad vector_214 1503 | .quad vector_215 1504 | .quad vector_216 1505 | .quad vector_217 1506 | .quad vector_218 1507 | .quad vector_219 1508 | .quad vector_220 1509 | .quad vector_221 1510 | .quad vector_222 1511 | .quad vector_223 1512 | .quad vector_224 1513 | .quad vector_225 1514 | .quad vector_226 1515 | .quad vector_227 1516 | .quad vector_228 1517 | .quad vector_229 1518 | .quad vector_230 1519 | .quad vector_231 1520 | .quad vector_232 1521 | .quad vector_233 1522 | .quad vector_234 1523 | .quad vector_235 1524 | .quad vector_236 1525 | .quad vector_237 1526 | .quad vector_238 1527 | .quad vector_239 1528 | .quad vector_240 1529 | .quad vector_241 1530 | .quad vector_242 1531 | .quad vector_243 1532 | .quad vector_244 1533 | .quad vector_245 1534 | .quad vector_246 1535 | .quad vector_247 1536 | .quad vector_248 1537 | .quad vector_249 1538 | .quad vector_250 1539 | .quad vector_251 1540 | .quad vector_252 1541 | .quad vector_253 1542 | .quad vector_254 1543 | .quad vector_255 1544 | -------------------------------------------------------------------------------- /kernel/src/arch/x86/console.c: -------------------------------------------------------------------------------- 1 | #include "console.h" 2 | #include "arch/x86.h" 3 | #include "arch/x86/interrupt.h" 4 | #include "defs.h" 5 | #include "device/uart.h" 6 | #include "mem/memlayout.h" 7 | #include "spinlock.h" 8 | #include "string.h" 9 | #include "util/fifo.h" 10 | #include "types.h" 11 | #include "proc.h" 12 | 13 | #define NUM_COL 80 14 | #define NUM_ROW 25 15 | 16 | #define CRTPORT 0x3d4 17 | 18 | static u16* crt = (u16*)P2KV(0xb8000); 19 | 20 | static spinlock_t console_lock; 21 | static uart_device_t con_uart; 22 | static bool uart_enable; 23 | 24 | // 25 | // console fifo is protected by two locks: 26 | // console_lock for reading operation and 27 | // console_fifo_write_lock for write operation. 28 | // 29 | static spinlock_t console_read_lock; 30 | static spsc_fifo_t console_fifo; 31 | 32 | #define CON_FIFO_SIZE 32 33 | 34 | void console_init() { 35 | init_lock(&console_lock, "console"); 36 | 37 | init_lock(&console_read_lock, "console read"); 38 | u8 *con_buffer = kmalloc(CON_FIFO_SIZE); // CON_FIFO_SIZE byte buffer is quite large for console 39 | if (!con_buffer) panic("console init oom"); 40 | spsc_fifo_init(&console_fifo, con_buffer, CON_FIFO_SIZE); 41 | if (!uart_pio_init(&con_uart, UART_COM1)) { 42 | ioapic_unmask(4, IDT_ENTRY_IRQ_COM1, lapic_id()); 43 | uart_enable = TRUE; 44 | } else { 45 | uart_enable = FALSE; 46 | } 47 | } 48 | 49 | void cga_putchar(int c) { 50 | int pos; 51 | 52 | // Cursor position: col + 80*row. 53 | outb(CRTPORT, 14); 54 | pos = inb(CRTPORT + 1) << 8; 55 | outb(CRTPORT, 15); 56 | pos |= inb(CRTPORT + 1); 57 | 58 | if (c == '\n') 59 | pos += 80 - pos % 80; 60 | else if (c == BACKSPACE) { 61 | if (pos > 0) 62 | --pos; 63 | } else { 64 | crt[pos++] = (c & 0xff) | 0x0700; // black on white 65 | } 66 | 67 | if (pos < 0 || pos > 25 * 80) { 68 | // panic("pos under/overflow"); 69 | } 70 | 71 | if ((pos / 80) >= 24) { // Scroll up. 72 | memcpy(crt, crt + 80, sizeof(crt[0]) * 23 * 80); 73 | pos -= 80; 74 | memset(crt + pos, 0, sizeof(crt[0]) * (24 * 80 - pos)); 75 | } 76 | 77 | outb(CRTPORT, 14); 78 | outb(CRTPORT + 1, pos >> 8); 79 | outb(CRTPORT, 15); 80 | outb(CRTPORT + 1, pos); 81 | crt[pos] = ' ' | 0x0700; 82 | } 83 | 84 | void putchar(int c) { 85 | acquire(&console_lock); 86 | if (uart_enable) { 87 | if (c == '\n') { 88 | uart_putc(&con_uart, '\r'); 89 | } 90 | uart_putc(&con_uart, c); 91 | } 92 | cga_putchar(c); 93 | release(&console_lock); 94 | } 95 | 96 | /** 97 | * @brief Console ISR handler. This function expects 98 | * to be called with interrupt disabled. 99 | * @todo Might consider adding a lock for the UART 100 | */ 101 | void console_isr_handler(void) { 102 | if (uart_enable) { 103 | int uartc; 104 | acquire(&console_read_lock); 105 | while ((uartc = uart_getc(&con_uart)) >= 0) { 106 | if (spsc_fifo_write(&console_fifo, (char)uartc)) { 107 | panic("uart buffer full\n"); 108 | } 109 | } 110 | sched_wakeup(&console_fifo); 111 | release(&console_read_lock); 112 | } 113 | } 114 | 115 | int console_getc(void) { 116 | int rtn; 117 | u8 val; 118 | acquire(&console_read_lock); 119 | while (spsc_fifo_read(&console_fifo, &val) < 0) { 120 | sched_sleep(&console_fifo, &console_read_lock); 121 | } 122 | // Filter Char 123 | rtn = val; 124 | if (val == 0x7F || val == 0x08) { 125 | rtn = BACKSPACE; 126 | } 127 | release(&console_read_lock); 128 | return rtn; 129 | } 130 | -------------------------------------------------------------------------------- /kernel/src/arch/x86/interrupt.c: -------------------------------------------------------------------------------- 1 | // 2 | // Guide OS 3 | // Copyright (c) 2022 Codetector 4 | // MIT License 5 | // 6 | 7 | #include "defs.h" 8 | #include "arch/x86.h" 9 | #include "arch/x86/interrupt.h" 10 | #include "arch/x86/system.h" 11 | #include "systick.h" 12 | #include "console.h" 13 | #include "proc.h" 14 | #include "syscall.h" 15 | 16 | #pragma pack(push, 1) 17 | typedef struct { 18 | uint16_t size; 19 | void *idt; 20 | } idtr_t; 21 | #pragma pack(pop) 22 | _Static_assert(sizeof(idtr_t) == 10, "lol"); 23 | 24 | __attribute__((aligned(8))) 25 | static idt64_t idt; 26 | 27 | extern const uint64_t vectors[]; 28 | 29 | void handle_interrupt(trapframe_t *tf) { 30 | if (tf->trap_no == IDT_ENTRY_DOUBLE_FAULT) { 31 | kprintf("DF rip = %p\n", tf->rip); 32 | panic("A double fault has occurred"); 33 | } 34 | if (tf->trap_no == IDT_ENTRY_GP) { 35 | kprintf("rip = %p\n", tf->rip); 36 | panic("GP"); 37 | } 38 | 39 | switch (tf->trap_no) { 40 | case IDT_ENTRY_IRQ_SPURIOUS: 41 | lapic_eoi(); 42 | break; 43 | case IDT_ENTRY_BP: 44 | kprintf("breakpoint at pc: %p\n", tf->rip); 45 | break; 46 | case IDT_ENTRY_IRQ_0: // LAPIC Timer 47 | if (cpu_id() == 0) { 48 | systick_increment(); 49 | } 50 | if (curproc() && curproc()->state == RUNNING) { 51 | curproc()->state = RUNNABLE; 52 | } 53 | lapic_eoi(); 54 | break; 55 | case IDT_ENTRY_IRQ_COM1: 56 | console_isr_handler(); 57 | lapic_eoi(); 58 | break; 59 | case VECTOR_SYSCALL: 60 | handle_syscall(tf); 61 | break; 62 | case IDT_ENTRY_PAGE_FAULT: 63 | size_t faulting_addr = rcr2(); 64 | kprintf("pg fault on %p at \nrip=%p\n", faulting_addr, tf->rip); 65 | panic("pgfault"); 66 | default: 67 | kprintf("unhandled %d\n", tf->trap_no); 68 | panic("interrupt_handler"); 69 | break; 70 | } 71 | 72 | if (curproc() && curproc()->state != RUNNING) { 73 | sched_yield(); 74 | } 75 | } 76 | 77 | void interrupt_init(void) { 78 | memset(&idt, 0, sizeof(idt)); 79 | for (int i = 0; i < 256; ++i) { 80 | idt.entries[i] = mk_idt_entry((int_handler_t) vectors[i], 81 | 0, 82 | IDT_GATE_FLAGS_P | IDT_GATE_FLAGS_DPL_KRNL | IDT_GATE_FLAGS_INT, 83 | GDT_KERNEL_CODE * 8); 84 | } 85 | idt.entries[VECTOR_SYSCALL] = mk_idt_entry((int_handler_t) vectors[VECTOR_SYSCALL], 86 | 0, 87 | IDT_GATE_FLAGS_P | IDT_GATE_FLAGS_DPL_USER | IDT_GATE_FLAGS_TRAP, 88 | GDT_KERNEL_CODE * 8); 89 | 90 | load_idt(&idt); 91 | } 92 | 93 | void load_idt(idt64_t *idt) { 94 | volatile idtr_t idtr = { 95 | sizeof(idt64_t) - 1, 96 | idt 97 | }; 98 | volatile idtr_t *pIDTR = &idtr; 99 | asm volatile("lidt (%0)" : : "r"(pIDTR)); 100 | } -------------------------------------------------------------------------------- /kernel/src/arch/x86/ioapic.c: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "defs.h" 3 | #include "arch/x86/interrupt.h" 4 | 5 | #define IOAPIC 0xFEC00000 6 | 7 | #define IOAPIC_REG_ID 0x00 8 | #define IOAPIC_REG_VER 0x01 9 | #define IOAPIC_REG_TABLE 0x10 10 | 11 | // 12 | // The redirection table starts at REG_TABLE and uses 13 | // two registers to configure each interrupt. 14 | // The first (low) register in a pair contains configuration bits. 15 | // The second (high) register contains a bitmask telling which 16 | // CPUs can serve that interrupt. 17 | // 18 | #define INT_DISABLED 0x00010000 // Interrupt disabled 19 | #define INT_LEVEL 0x00008000 // Level-triggered (vs edge-) 20 | #define INT_ACTIVELOW 0x00002000 // Active low (vs high) 21 | #define INT_LOGICAL 0x00000800 // Destination is CPU id (vs APIC ID) 22 | 23 | volatile struct ioapic *ioapic; 24 | 25 | // IO APIC MMIO structure: write reg, then read or write data. 26 | struct ioapic { 27 | u32 reg; 28 | u32 pad[3]; 29 | u32 data; 30 | }; 31 | 32 | static u32 33 | ioapicread(int reg) 34 | { 35 | ioapic->reg = reg; 36 | return ioapic->data; 37 | } 38 | 39 | static void 40 | ioapicwrite(int reg, u32 data) 41 | { 42 | ioapic->reg = reg; 43 | ioapic->data = data; 44 | } 45 | 46 | void 47 | ioapic_init(void) 48 | { 49 | int i, maxintr; 50 | 51 | ioapic = (volatile struct ioapic*)P2KV(IOAPIC); 52 | maxintr = (ioapicread(IOAPIC_REG_VER) >> 16) & 0xFF; 53 | 54 | // Mark all interrupts edge-triggered, active high, disabled, 55 | // and not routed to any CPUs. 56 | for(i = 0; i <= maxintr; i++){ 57 | ioapicwrite(IOAPIC_REG_TABLE+2*i, INT_DISABLED | (IDT_ENTRY_IRQ_0 + i)); 58 | ioapicwrite(IOAPIC_REG_TABLE+2*i+1, 0); 59 | } 60 | } 61 | 62 | void 63 | ioapic_unmask(u8 irq, u8 vector, u8 apicid) 64 | { 65 | // Mark interrupt edge-triggered, active high, 66 | // enabled, and routed to the given cpunum, 67 | // which happens to be that cpu's APIC ID. 68 | ioapicwrite(IOAPIC_REG_TABLE+2*irq, vector); 69 | ioapicwrite(IOAPIC_REG_TABLE+2*irq+1, (u32)apicid << 24); 70 | } 71 | 72 | void ioapic_mask(u8 irq) 73 | { 74 | ioapicwrite(IOAPIC_REG_TABLE+2*irq, INT_DISABLED | IDT_ENTRY_IRQ_SPURIOUS); 75 | ioapicwrite(IOAPIC_REG_TABLE+2*irq+1, 0); 76 | } -------------------------------------------------------------------------------- /kernel/src/arch/x86/lapic.c: -------------------------------------------------------------------------------- 1 | 2 | // Guide OS 3 | // Copyright (c) 2022 Codetector 4 | // MIT License 5 | // 6 | 7 | #include "defs.h" 8 | #include "types.h" 9 | #include "arch/x86/instructions.h" 10 | #include "arch/x86/msr.h" 11 | #include "arch/x86/interrupt.h" 12 | #include "arch/x86/interrupt_vectors.h" 13 | 14 | // Local APIC registers, divided by 4 for use as uint[] indices. 15 | #define ID (0x0020/4) // ID 16 | #define VER (0x0030/4) // Version 17 | #define TPR (0x0080/4) // Task Priority 18 | #define EOI (0x00B0/4) // EOI 19 | #define SVR (0x00F0/4) // Spurious Interrupt Vector 20 | #define ENABLE 0x00000100 // Unit Enable 21 | #define ESR (0x0280/4) // Error Status 22 | #define ICRLO (0x0300/4) // Interrupt Command 23 | #define INIT 0x00000500 // INIT/RESET 24 | #define STARTUP 0x00000600 // Startup IPI 25 | #define DELIVS 0x00001000 // Delivery status 26 | #define ASSERT 0x00004000 // Assert interrupt (vs deassert) 27 | #define DEASSERT 0x00000000 28 | #define LEVEL 0x00008000 // Level triggered 29 | #define BCAST 0x00080000 // Send to all APICs, including self. 30 | #define BUSY 0x00001000 31 | #define FIXED 0x00000000 32 | #define ICRHI (0x0310/4) // Interrupt Command [63:32] 33 | #define TIMER (0x0320/4) // Local Vector Table 0 (TIMER) 34 | #define X1 0x0000000B // divide counts by 1 35 | #define PERIODIC 0x00020000 // Periodic 36 | #define PCINT (0x0340/4) // Performance Counter LVT 37 | #define LINT0 (0x0350/4) // Local Vector Table 1 (LINT0) 38 | #define LINT1 (0x0360/4) // Local Vector Table 2 (LINT1) 39 | #define ERROR (0x0370/4) // Local Vector Table 3 (ERROR) 40 | #define MASKED 0x00010000 // Interrupt masked 41 | #define TICR (0x0380/4) // Timer Initial Count 42 | #define TCCR (0x0390/4) // Timer Current Count 43 | #define TDCR (0x03E0/4) // Timer Divide Configuration 44 | 45 | 46 | volatile u32 *lapic; 47 | 48 | static void 49 | lapicw(int index, int value) 50 | { 51 | lapic[index] = value; 52 | lapic[ID]; // wait for write to finish, by reading 53 | } 54 | 55 | u8 lapic_id(void) { 56 | return (lapic[ID] >> 24U); 57 | } 58 | 59 | void lapic_eoi(void) 60 | { 61 | if(lapic) 62 | lapicw(EOI, 0); 63 | } 64 | 65 | void lapic_init(void) { 66 | uint64_t apic_base_pa = rdmsr(IA32_APIC_BASE_MSR); 67 | if (!(apic_base_pa & IA32_APIC_BASE_MSR_ENABLED)) panic("apic disabled"); 68 | lapic = (volatile u32 *) P2KV(apic_base_pa & IA32_APIC_BASE_MSR_BASE_ADDR_MSK); 69 | 70 | // Enable local APIC; set spurious interrupt vector. 71 | lapicw(SVR, ENABLE | IDT_ENTRY_IRQ_SPURIOUS); 72 | 73 | // The timer repeatedly counts down at bus frequency 74 | // from lapic[TICR] and then issues an interrupt. 75 | // TODO: calibrate TICR with external time 76 | lapicw(TDCR, X1); 77 | lapicw(TIMER, PERIODIC | IDT_ENTRY_IRQ_TIMER); 78 | lapicw(TICR, 10000000); 79 | 80 | // Disable logical interrupt lines. 81 | lapicw(LINT0, MASKED); 82 | lapicw(LINT1, MASKED); 83 | 84 | // Disable performance counter overflow interrupts 85 | // on machines that provide that interrupt entry. 86 | if(((lapic[VER]>>16) & 0xFF) >= 4) 87 | lapicw(PCINT, MASKED); 88 | 89 | // Map error interrupt to IRQ_ERROR. 90 | lapicw(ERROR, IDT_ENTRY_IRQ_ERROR); 91 | 92 | // Clear error status register (requires back-to-back writes). 93 | lapicw(ESR, 0); 94 | lapicw(ESR, 0); 95 | 96 | // Ack any outstanding interrupts. 97 | lapicw(EOI, 0); 98 | 99 | // Send an Init Level De-Assert to synchronise arbitration ID's. 100 | lapicw(ICRHI, 0); 101 | lapicw(ICRLO, BCAST | INIT | LEVEL); 102 | while(lapic[ICRLO] & DELIVS) 103 | ; 104 | 105 | // Enable interrupts on the APIC (but not on the processor). 106 | lapicw(TPR, 0); 107 | } 108 | 109 | -------------------------------------------------------------------------------- /kernel/src/arch/x86/mem/vm.c: -------------------------------------------------------------------------------- 1 | // 2 | // Guide OS 3 | // Copyright (c) 2022 Codetector 4 | // MIT License 5 | // 6 | #include "mem/vm.h" 7 | #include "arch/x86/instructions.h" 8 | #include "arch/x86/vmm.h" 9 | #include "defs.h" 10 | #include "mem/boot_alloc.h" 11 | #include "mem/memlayout.h" 12 | 13 | // Kernel PML4 14 | static pml4e_t* kern_pml4; 15 | 16 | void vmm_init(void) { 17 | kern_pml4 = boot_alloc(PG_SIZE); 18 | if (!kern_pml4) 19 | panic("vmm_init oom"); 20 | if ((size_t)kern_pml4 % PG_SIZE != 0) 21 | panic("align"); 22 | memset(kern_pml4, 0, PG_SIZE); 23 | 24 | pdpe_t* kern_phys_map_pdp = 0; 25 | for (size_t va = KERNBASE; va < KERN_PHYMAP_TOP; va += L3_HUGE_SIZE) { 26 | if (PG_L3_IDX(va) == 0) { 27 | kern_phys_map_pdp = boot_alloc(PG_SIZE); 28 | if (!kern_phys_map_pdp) 29 | panic("vmm_init oom(l3)"); 30 | if ((size_t)kern_phys_map_pdp % PG_SIZE != 0) 31 | panic("align"); 32 | 33 | memset(kern_phys_map_pdp, 0, PG_SIZE); 34 | 35 | kern_pml4[PG_L4_IDX(va)] = 36 | PTE_FLAG_P | PTE_FLAG_WRITE | PTE_ADDR(KV2P(kern_phys_map_pdp)); 37 | } 38 | if (!kern_phys_map_pdp) 39 | panic("vmm_init nullptr"); 40 | kern_phys_map_pdp[PG_L3_IDX(va)] = 41 | PTE_FLAG_P | PTE_FLAG_WRITE | PTE_FLAG_SZ | PTE_ADDR(KV2P(va)); 42 | } 43 | vmm_load_ktable(); 44 | } 45 | 46 | void vmm_load_ktable() { lcr3(KV2P(kern_pml4)); } 47 | 48 | void* vmm_get_kernel_pgtable(void) { return (void*) kern_pml4; } 49 | -------------------------------------------------------------------------------- /kernel/src/arch/x86/system.c: -------------------------------------------------------------------------------- 1 | // 2 | // Guide OS 3 | // Copyright (c) 2022 Codetector 4 | // MIT License 5 | // 6 | 7 | #include "types.h" 8 | #include "defs.h" 9 | #include "arch/x86.h" 10 | #include "arch/x86/system.h" 11 | #include "cpu.h" 12 | 13 | bool disable_interrupt() 14 | { 15 | size_t flags = read_flags(); 16 | cli(); 17 | return (flags & RFLAGS_IF) > 0; 18 | } 19 | 20 | void enable_interrupt() { 21 | sti(); 22 | } 23 | 24 | void wait_for_interrupt() { 25 | hlt(); 26 | } 27 | 28 | #pragma pack(push, 1) 29 | struct gdtr { 30 | u16 size; 31 | struct gdt* gdt; 32 | }; 33 | _Static_assert(sizeof(struct gdtr) == 10, "gdtr size wrong"); 34 | #pragma pack(pop) 35 | 36 | void tss_setup(struct cpu* cpu) 37 | { 38 | memset(&cpu->tss, 0, sizeof(cpu->tss)); 39 | } 40 | 41 | void gdt_setup(struct cpu *cpu) 42 | { 43 | volatile struct gdtr gdtr; 44 | struct gdt* gdt = &cpu->gdt; 45 | memset(gdt, 0, sizeof(struct gdt)); 46 | // KCODE 47 | gdt->seg_descs[GDT_KERNEL_CODE].type = GDT_DESC_TYPE_CODE; 48 | gdt->seg_descs[GDT_KERNEL_CODE].dpl = 0; 49 | gdt->seg_descs[GDT_KERNEL_CODE].p = 1; 50 | gdt->seg_descs[GDT_KERNEL_CODE].flags = GDT_DESC_FLAGS_L | GDT_DESC_FLAGS_G; 51 | // KDATA 52 | gdt->seg_descs[GDT_KERNEL_DATA] = gdt->seg_descs[GDT_KERNEL_CODE]; 53 | gdt->seg_descs[GDT_KERNEL_DATA].type = GDT_DESC_TYPE_DATA; 54 | 55 | // UCODE 56 | gdt->seg_descs[GDT_USER_CODE] = gdt->seg_descs[GDT_KERNEL_CODE]; 57 | gdt->seg_descs[GDT_USER_CODE].dpl = 3; 58 | // UDATA 59 | gdt->seg_descs[GDT_USER_DATA] = gdt->seg_descs[GDT_KERNEL_DATA]; 60 | gdt->seg_descs[GDT_USER_DATA].dpl = 3; 61 | 62 | struct task_state_segment* tss = &cpu->tss; 63 | size_t tss_addr = (size_t) tss; 64 | gdt->tss_entry.type = GDT_DESC_TYPE_TSS; 65 | gdt->tss_entry.p = 1; 66 | gdt->tss_entry.dpl = 0; 67 | gdt->tss_entry.flags = GDT_DESC_FLAGS_L; 68 | gdt->tss_entry.limit_15_0 = sizeof(struct task_state_segment) & 0xFFFF; 69 | gdt->tss_entry.limit_19_16 = (sizeof(struct task_state_segment) >> 16U) & 0xF; 70 | gdt->tss_entry.base_15_0 = (tss_addr >> 0U ) & 0xFFFFU; 71 | gdt->tss_entry.base_23_16 = (tss_addr >> 16U) & 0xFFU; 72 | gdt->tss_entry.base_31_24 = (tss_addr >> 24U) & 0xFFU; 73 | gdt->tss_entry.base_63_32 = (tss_addr >> 32U) & 0xFFFFFFFFU; 74 | 75 | gdtr.gdt = gdt; 76 | gdtr.size = sizeof(struct gdt) - 1; 77 | asm volatile("lgdt (%0)" ::"r"(&gdtr)); 78 | } 79 | -------------------------------------------------------------------------------- /kernel/src/arch/x86/x86_pic.c: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "arch/x86/instructions.h" 3 | #include "arch/x86/interrupt.h" 4 | 5 | // I/O Addresses of the two programmable interrupt controllers 6 | #define IO_PIC1 0x20 // Master (IRQs 0-7) 7 | #define IO_PIC2 0xA0 // Slave (IRQs 8-15) 8 | 9 | // Don't use the 8259A interrupt controllers. assumes SMP hardware. 10 | void 11 | pic_init(void) 12 | { 13 | // mask all interrupts 14 | outb(IO_PIC1+1, 0xFF); 15 | outb(IO_PIC2+1, 0xFF); 16 | } 17 | -------------------------------------------------------------------------------- /kernel/src/cpu.c: -------------------------------------------------------------------------------- 1 | #include "defs.h" 2 | #include "arch/x86/instructions.h" 3 | #include "arch/x86/interrupt.h" 4 | #include "arch/x86/system.h" 5 | 6 | static struct cpu cpus[NCPU]; 7 | static uint16_t ncpu = 0; 8 | 9 | void cpu_bsp_init() 10 | { 11 | ncpu = 1; 12 | struct cpu *bsp = &cpus[0]; 13 | bsp->apicid = lapic_id(); 14 | bsp->started = 1; 15 | bsp->int_disable_layer = 0; 16 | gdt_setup(bsp); 17 | } 18 | 19 | u16 cpu_id() { 20 | return cur_cpu() - cpus; 21 | } 22 | 23 | struct cpu* cur_cpu(void) { 24 | u8 apicid; 25 | if (read_flags() & RFLAGS_IF) { 26 | panic("cur_cpu with IF"); 27 | } 28 | 29 | apicid = lapic_id(); 30 | 31 | for (size_t i = 0; i < ncpu; i++) 32 | { 33 | if (cpus[i].apicid == apicid) 34 | return &cpus[i]; 35 | } 36 | panic("unknown cpu"); 37 | return 0; 38 | } 39 | 40 | struct proc* curproc(void) { 41 | struct proc* c; 42 | push_int_disable(); 43 | c = cur_cpu()->proc; 44 | pop_int_disable(); 45 | return c; 46 | } 47 | 48 | void push_int_disable(void) 49 | { 50 | bool enabled = disable_interrupt(); 51 | struct cpu* c = cur_cpu(); 52 | if (c->int_disable_layer == 0) 53 | { 54 | c->int_enabled = enabled; 55 | } 56 | c->int_disable_layer++; 57 | } 58 | 59 | void pop_int_disable(void) 60 | { 61 | struct cpu* c = cur_cpu(); 62 | c->int_disable_layer--; 63 | if (c->int_disable_layer < 0) 64 | { 65 | panic("popcli"); 66 | } 67 | if (c->int_disable_layer == 0 && c->int_enabled) 68 | { 69 | enable_interrupt(); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /kernel/src/device/uart/uart.c: -------------------------------------------------------------------------------- 1 | // 2 | // Guide OS 3 | // Copyright (c) 2022 Codetector 4 | // MIT License 5 | // 6 | #include "device/uart.h" 7 | #include "arch/x86/instructions.h" 8 | #include "arch/x86/interrupt.h" 9 | #include "defs.h" 10 | #include "types.h" 11 | 12 | static void uart_write(uart_device_t* u, u8 offset, u8 value) { 13 | if (u->mmio_base) { 14 | ((volatile u32*)u->mmio_base)[offset] = value; 15 | (void)((volatile u32*)u->mmio_base)[offset]; 16 | } else { 17 | outb(u->pio_base + offset, value); 18 | } 19 | } 20 | 21 | static u8 uart_read(uart_device_t* u, u8 offset) { 22 | if (u->mmio_base) { 23 | return (u8)((volatile u32*)u->mmio_base)[offset]; 24 | } else { 25 | return inb(u->pio_base + offset); 26 | } 27 | } 28 | 29 | static int uart_init(uart_device_t* u) { 30 | uart_write(u, 3, 0x80); // Unlock divisor 31 | uart_write(u, 0, 115200 / 115200); // Baud = 115200 32 | uart_write(u, 1, 0); // Upper divisor (part of baud 115200) 33 | uart_write(u, 3, 0x3); // Lock divisor + 8 N 1 34 | uart_write(u, 1, 0); // Disable Interrupt 35 | uart_write(u, 2, 0x7); // Enable and reset TX RX FIFO 36 | 37 | uart_write(u, 7, 0x69); 38 | if (uart_read(u, 7) != 0x69) { 39 | return -1; 40 | } 41 | 42 | uart_write(u, 1, 0x1); // Enable Rx and Tx Interrupt 43 | 44 | { 45 | const char* init_string = "..uart..\n"; 46 | int i = 0; 47 | while(init_string[i] != '\0') 48 | uart_putc(u, init_string[i++]); 49 | } 50 | return 0; 51 | } 52 | 53 | int uart_pio_init(uart_device_t* u, u16 pio_base) { 54 | u->mmio_base = NULL; 55 | u->pio_base = pio_base; 56 | return uart_init(u); 57 | } 58 | 59 | int uart_mmio_init(uart_device_t* u, void* mmio_base) { return 1; } 60 | 61 | void s_uart_putc(uart_device_t *u, int c) { 62 | while ((uart_read(u, 5) & 0x20) == 0) 63 | ; 64 | uart_write(u, 0, c); 65 | } 66 | 67 | void uart_putc(uart_device_t* u, int c) { 68 | if (!u) 69 | return; 70 | if (c == BACKSPACE) { 71 | s_uart_putc(u, '\x08'); 72 | s_uart_putc(u, ' '); 73 | s_uart_putc(u, '\x08'); 74 | } else { 75 | s_uart_putc(u, c); 76 | } 77 | } 78 | 79 | bool uart_hasbyte(uart_device_t* u) { 80 | if (!u) 81 | return FALSE; 82 | 83 | return (uart_read(u, 5) & 0x1) != 0; 84 | } 85 | 86 | int uart_getc(uart_device_t* u) { 87 | if (!uart_hasbyte(u)) 88 | return -1; 89 | return uart_read(u, 0); 90 | } 91 | -------------------------------------------------------------------------------- /kernel/src/kmain.c: -------------------------------------------------------------------------------- 1 | #include "defs.h" 2 | #include "mem/boot_alloc.h" 3 | #include "mem/kmalloc.h" 4 | #include "mem/vm.h" 5 | #include "mem/page_alloc.h" 6 | #include "arch/x86/interrupt.h" 7 | #include "arch/x86/instructions.h" 8 | #include "systick.h" 9 | #include "cpu.h" 10 | #include "device/uart.h" 11 | #include "proc.h" 12 | 13 | __attribute__((noreturn)) void mpmain(void); 14 | 15 | __attribute__((noreturn)) 16 | void kmain(void) 17 | { 18 | boot_alloc_init(kern_end, 64 * 1024 * 1024); // Feed 64M into the boot_alloc 19 | vmm_init(); 20 | pgalloc_init(4UL * 1024 * 1024 * 1024); // TODO: remove hard code 4G 21 | 22 | // Interrupt related 23 | lapic_init(); // LAPIC 24 | cpu_bsp_init(); // We need to do this early so we can have locks 25 | interrupt_init(); // IDT 26 | pic_init(); // Disable PICs 27 | ioapic_init(); // Setup 1 IOAPIC 28 | 29 | // Locks should be ready by this point 30 | void *bootalloc_avail = boot_alloc_disable(); 31 | kmalloc_init(); 32 | pgalloc_free_range(bootalloc_avail, P2KV(64 * 1024 * 1024)); 33 | 34 | // System Devices 35 | console_init(); 36 | systick_init(); 37 | 38 | // Initialize pTable 39 | proc_init(); 40 | 41 | mpmain(); 42 | } 43 | 44 | void kshell_main(void); 45 | 46 | void mpmain() 47 | { 48 | struct proc* p = proc_alloc(); 49 | sched_create_kproc(p, kshell_main); 50 | sched_add(p); 51 | sched_start(); 52 | panic("sched failed to start"); 53 | for(;;); 54 | } 55 | -------------------------------------------------------------------------------- /kernel/src/kshell.c: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "defs.h" 3 | #include "arch/x86/instructions.h" 4 | #include "usys.h" 5 | #include "proc.h" 6 | 7 | #define CMD_MAX_LEN 1024 8 | #define CMD_MAX_PARTS 32 9 | 10 | void ksh_read_line(char* buf) { 11 | size_t input_len = 0; 12 | for(;;) { 13 | int c; 14 | c = console_getc(); 15 | if (c < 0) { 16 | panic("getc"); 17 | } 18 | if (c == BACKSPACE && input_len > 0) { 19 | input_len--; 20 | putchar(BACKSPACE); 21 | } else if (c == '\r' || c == '\n') { 22 | putchar('\n'); 23 | buf[input_len] = '\0'; 24 | break; 25 | } else if (input_len < CMD_MAX_LEN && c > 0 && c < 0xFF) { 26 | buf[input_len++] = (char)c; 27 | putchar(c); 28 | } 29 | } 30 | } 31 | 32 | int ksh_split_line(char* line, char** tokens) { 33 | int token_position = 0; 34 | int line_position = 0; 35 | if (line == NULL || tokens == NULL) { 36 | return 0; 37 | } 38 | 39 | while(line[line_position] != '\0' && line_position < CMD_MAX_LEN && token_position < CMD_MAX_LEN) { 40 | tokens[token_position++] = &line[line_position]; 41 | while(line[line_position] != ' ' && line[line_position] != '\0') { 42 | line_position++; 43 | } 44 | while(line[line_position] == ' ' && line[line_position] != '\0') { 45 | line[line_position++] = '\0'; 46 | } 47 | } 48 | tokens[token_position] = NULL; 49 | return token_position; 50 | } 51 | 52 | int echo(int argc, char** argv) { 53 | for (size_t i = 1; i < argc; i++) { 54 | kprintf("%s ", argv[i]); 55 | } 56 | kprintf("\n"); 57 | return 0; 58 | } 59 | 60 | struct sh_builtin { 61 | const char* cmd; 62 | int (*fn)(int argc, char** argv); 63 | }; 64 | 65 | static struct sh_builtin built_ins[] = { 66 | {"echo", echo}, 67 | }; 68 | 69 | void kshell_main(void) { 70 | char buffer[CMD_MAX_LEN]; 71 | char* parts[CMD_MAX_PARTS]; 72 | for(;;) { 73 | kprintf("$> "); 74 | ksh_read_line(buffer); 75 | int argc = ksh_split_line(buffer, parts); 76 | int (*fn)(int argc, char** argv) = NULL; 77 | if (argc == 0) { 78 | kprintf("\n"); 79 | continue; 80 | } 81 | for (size_t i = 0; i < sizeof(built_ins) / sizeof(built_ins[0]); i++) { 82 | if (strcmp(built_ins[i].cmd, parts[0]) == 0) { 83 | fn = built_ins[i].fn; 84 | break; 85 | } 86 | } 87 | if (fn != NULL) { 88 | fn(argc, parts); 89 | } else { 90 | kprintf("Command not found: %s\n", parts[0]); 91 | } 92 | } 93 | for(;;){} 94 | } 95 | -------------------------------------------------------------------------------- /kernel/src/mem/boot_alloc.c: -------------------------------------------------------------------------------- 1 | // 2 | // Guide OS 3 | // Copyright (c) 2022 Codetector 4 | // MIT License 5 | // 6 | 7 | #include "defs.h" 8 | #include "mem/boot_alloc.h" 9 | 10 | static struct boot_alloc_zone default_zone = { 11 | (void*) 0, 12 | (void*) 0 13 | }; 14 | 15 | static bool boot_alloc_initialized = FALSE; 16 | 17 | /** 18 | * Initialize the boot allocator with the given start kva and size 19 | * @param start_kva 20 | * @param size 21 | */ 22 | void boot_alloc_init(void *start_kva, size_t size) { 23 | if (boot_alloc_initialized) { 24 | return; 25 | } 26 | boot_alloc_initialized = TRUE; 27 | 28 | // Force native size alignment 29 | default_zone.begin_kva = (void*)ROUNDUP_PWR2((size_t)start_kva, PG_SIZE); 30 | default_zone.end_kva = (void*)((size_t)start_kva + size); 31 | } 32 | 33 | void *boot_alloc(size_t size) { 34 | size = ROUNDUP_PWR2(size, PG_SIZE); 35 | 36 | if (default_zone.begin_kva + size < default_zone.end_kva) { 37 | void* return_ptr = default_zone.begin_kva; 38 | default_zone.begin_kva += size; 39 | return return_ptr; 40 | } 41 | 42 | return NULL; 43 | } 44 | 45 | /** 46 | * @brief Disable boot allocator. This MUST be called before interrupt or SMP 47 | * is enabled. As the boot allocator is not thread safe. 48 | * 49 | * @return void* pointer to the first byte of availiable memory 50 | */ 51 | void *boot_alloc_disable() { 52 | void* rtn_ptr = default_zone.begin_kva; 53 | default_zone.begin_kva = 0; 54 | default_zone.end_kva = 0; 55 | return rtn_ptr; 56 | } 57 | -------------------------------------------------------------------------------- /kernel/src/mem/kmalloc.c: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "defs.h" 3 | #include "spinlock.h" 4 | #include "mem/page_alloc.h" 5 | 6 | #define TOTAL_METADATA_SIZE (sizeof(metadata_t)) 7 | #define MIN_BLOCK_SIZE (TOTAL_METADATA_SIZE + 8) 8 | 9 | typedef struct metadata { 10 | struct metadata *next; 11 | size_t size; // size of the user usable part of the block in number of bytes 12 | } metadata_t; 13 | 14 | spinlock_t kmalloc_lock; 15 | metadata_t *size_list; // Free List 16 | 17 | static metadata_t *merge_with_front(metadata_t *front, metadata_t *front_parent, size_t empty_Size) { 18 | if (front_parent == NULL) { 19 | size_list = front->next; 20 | } else { 21 | front_parent->next = front->next; 22 | } 23 | front->size += empty_Size; 24 | return front; 25 | } 26 | 27 | static metadata_t *merge_with_back(metadata_t *back, metadata_t *back_parent, metadata_t *original) { 28 | if (back_parent == NULL) { 29 | size_list = back->next; 30 | } else { 31 | back_parent->next = back->next; 32 | } 33 | original->size += back->size + TOTAL_METADATA_SIZE; 34 | return original; 35 | } 36 | 37 | static metadata_t *add_block(void *block, size_t raw_size) { 38 | if (raw_size < MIN_BLOCK_SIZE) { 39 | return NULL; 40 | } 41 | metadata_t *metaBlock = (metadata_t *) block; 42 | metaBlock->size = raw_size - TOTAL_METADATA_SIZE; 43 | void *endAddr = (uint8_t *) metaBlock + TOTAL_METADATA_SIZE + metaBlock->size; 44 | 45 | metadata_t *currentBlock = size_list; 46 | metadata_t *parentBlock = NULL; 47 | while (currentBlock) { 48 | if ((uint8_t *) currentBlock + currentBlock->size + TOTAL_METADATA_SIZE == block) { 49 | metaBlock = merge_with_front(currentBlock, parentBlock, metaBlock->size+TOTAL_METADATA_SIZE); 50 | } else if (endAddr == (uint8_t *) currentBlock) { 51 | metaBlock = merge_with_back(currentBlock, parentBlock, metaBlock); 52 | } else { 53 | parentBlock = currentBlock; 54 | } 55 | currentBlock = currentBlock->next; 56 | } 57 | if (size_list && size_list->size < metaBlock->size) { 58 | metadata_t *loopBlock = size_list; 59 | while (loopBlock && loopBlock->next) { 60 | if (loopBlock->next->size >= metaBlock->size) { 61 | metaBlock->next = loopBlock->next; 62 | loopBlock->next = metaBlock; 63 | return metaBlock; 64 | } 65 | loopBlock = loopBlock->next; 66 | } 67 | if (loopBlock) { 68 | metaBlock->next = loopBlock->next; 69 | loopBlock->next = metaBlock; 70 | } 71 | } else { 72 | metaBlock->next = size_list; 73 | size_list = metaBlock; 74 | } 75 | return metaBlock; 76 | } 77 | 78 | static void *remove_block(metadata_t *block, metadata_t *parent, size_t request_size) { 79 | if (parent) { 80 | parent->next = block->next; 81 | } else { 82 | size_list = block->next; 83 | } 84 | if (block->size == request_size) { 85 | return (block + 1); 86 | } else { 87 | size_t oldBlockSize = block->size - (request_size + TOTAL_METADATA_SIZE); 88 | add_block((void *) block, oldBlockSize + TOTAL_METADATA_SIZE); 89 | metadata_t *newBlock = (metadata_t *) (((uint8_t *) block) + TOTAL_METADATA_SIZE + oldBlockSize); 90 | newBlock->size = request_size; 91 | return (newBlock + 1); 92 | } 93 | } 94 | 95 | static void *find_fit_block(size_t request_size) { 96 | metadata_t *current_block = size_list; 97 | metadata_t *parent = NULL; 98 | while (current_block) { 99 | if (current_block->size == request_size || current_block->size >= request_size + MIN_BLOCK_SIZE) { 100 | return remove_block(current_block, parent, request_size); 101 | } 102 | parent = current_block; 103 | current_block = current_block->next; 104 | } 105 | return NULL; 106 | } 107 | 108 | void kmalloc_init(void) 109 | { 110 | size_list = NULL; 111 | init_lock(&kmalloc_lock, "kmalloc"); 112 | } 113 | 114 | /* MALLOC 115 | * See PDF for documentation 116 | */ 117 | void *kmalloc(size_t size) { 118 | void *rtn = NULL; 119 | acquire(&kmalloc_lock); 120 | 121 | if (size == 0) { 122 | goto kmalloc_exit; 123 | } 124 | if (size > (PG_SIZE - TOTAL_METADATA_SIZE)) { 125 | goto kmalloc_exit; 126 | } 127 | rtn = find_fit_block(size); 128 | if (rtn) 129 | { 130 | goto kmalloc_exit; 131 | } 132 | else 133 | { 134 | void *newRam = pgalloc_allocate(0); // 0th order allocates 1 page 135 | if (newRam) 136 | { 137 | add_block(newRam, PG_SIZE); 138 | rtn = find_fit_block(size); 139 | } 140 | else 141 | { 142 | panic("malloc: OOM"); 143 | } 144 | goto kmalloc_exit; 145 | } 146 | 147 | kmalloc_exit: 148 | release(&kmalloc_lock); 149 | return rtn; 150 | } 151 | 152 | void *krealloc(void *ptr, size_t size) { 153 | if (ptr == NULL) { 154 | return kmalloc(size); 155 | } 156 | if (size == 0) { 157 | kfree(ptr); 158 | return NULL; 159 | } 160 | metadata_t *block = ((metadata_t *) ptr) - 1; 161 | void* newBlk = kmalloc(size); 162 | memcpy(newBlk, ptr, MIN(size, block->size)); 163 | kfree(ptr); 164 | return newBlk; 165 | } 166 | 167 | /* CALLOC 168 | * See PDF for documentation 169 | */ 170 | void *kcalloc(size_t nmemb, size_t size) { 171 | void *memory = kmalloc(nmemb * size); 172 | if (memory) { 173 | memset(memory, 0, size * nmemb); 174 | } 175 | return memory; 176 | } 177 | 178 | void kfree(void *ptr) { 179 | if (ptr == NULL) { 180 | return; 181 | } 182 | metadata_t *block = ((metadata_t *) ptr) - 1; 183 | acquire(&kmalloc_lock); 184 | add_block((void *) block, block->size + TOTAL_METADATA_SIZE); 185 | release(&kmalloc_lock); 186 | } 187 | 188 | -------------------------------------------------------------------------------- /kernel/src/mem/memlayout.c: -------------------------------------------------------------------------------- 1 | // 2 | // Guide OS 3 | // Copyright (c) 2022 Codetector 4 | // MIT License 5 | // 6 | 7 | -------------------------------------------------------------------------------- /kernel/src/mem/page_alloc.c: -------------------------------------------------------------------------------- 1 | // 2 | // Guide OS 3 | // Copyright (c) 2022 Codetector 4 | // MIT License 5 | // 6 | 7 | #include "types.h" 8 | #include "defs.h" 9 | #include "mem/memlayout.h" 10 | #include "mem/boot_alloc.h" 11 | #include "spinlock.h" 12 | 13 | #define MAX_ORDER 10 14 | 15 | #define BITMAP_TOGGLE(bitmap, addr, order) 16 | 17 | struct free_page { 18 | struct free_page *next; 19 | }; 20 | 21 | struct free_page_list { 22 | struct free_page *head; 23 | size_t size; 24 | }; 25 | 26 | struct page_alloc_free_bin { 27 | struct free_page_list list; 28 | u32 *bitmap; 29 | }; 30 | 31 | static struct page_alloc_free_bin pgalloc_bins[MAX_ORDER + 1]; 32 | static spinlock_t pgalloc_lock; 33 | static size_t max_addr = 0; 34 | 35 | /** 36 | * Initialize the pgalloc page allocator 37 | * @param max_mem_addr the highest kva where memory still exists 38 | */ 39 | void pgalloc_init(size_t max_mem_addr) 40 | { 41 | if (max_addr != 0) 42 | { 43 | panic("pgalloc_init double init"); 44 | } 45 | init_lock(&pgalloc_lock, "pgalloc"); 46 | max_addr = PGROUNDUP((size_t)max_mem_addr); 47 | memset(pgalloc_bins, 0, sizeof(pgalloc_bins)); 48 | 49 | size_t num_pages = max_addr / PG_SIZE; 50 | size_t bitmap_size = num_pages / 8; 51 | for (int i = 0; i <= MAX_ORDER; ++i) 52 | { 53 | // For each bucket, we only need number of chunk / 2 bits. 54 | bitmap_size = (bitmap_size + 1) / 2; 55 | if ((pgalloc_bins[i].bitmap = boot_alloc(bitmap_size)) == NULL) 56 | { 57 | panic("pgalloc_init"); 58 | } 59 | } 60 | } 61 | 62 | /** 63 | * @brief free_block helper. Mark a block of memory 64 | * free and add it to the free list. 65 | * @note pgalloc_lock must be held before calling this function 66 | * 67 | * @param pgidx index of the PHYSICAL page to free 68 | * @param order 2^order pages to be freed 69 | */ 70 | static void s_free_block(size_t pgidx, int order) 71 | { 72 | if ((pgidx & ((1UL << order) - 1)) != 0) 73 | { 74 | kprintf("free alignment pgidx %lx, order %d\n", pgidx, order); 75 | panic("s_free_block"); 76 | } 77 | size_t bit_index = pgidx >> (order + 1); 78 | struct free_page *pg_va = (struct free_page*)(P2KV(pgidx * PG_SIZE)); 79 | struct page_alloc_free_bin* bin = &pgalloc_bins[order]; 80 | bool hasBuddy = (bin->bitmap[bit_index / (sizeof(u32) * 8)] & (1U << (bit_index % (sizeof(u32) * 8)))) != 0; 81 | if (order == MAX_ORDER) hasBuddy = 0; 82 | bin->bitmap[bit_index / (sizeof(u32) * 8)] ^= 1U << (bit_index % (sizeof(u32) * 8)); 83 | if (hasBuddy) 84 | { 85 | void* buddy_va = P2KV((pgidx ^ (1UL << order)) * PG_SIZE); 86 | struct free_page** pCurrent = &(bin->list.head); 87 | while(*pCurrent != NULL && *pCurrent != buddy_va) { 88 | pCurrent = &((*pCurrent)->next); 89 | } 90 | if (*pCurrent == buddy_va) { 91 | *pCurrent = (*pCurrent)->next; 92 | bin->list.size--; 93 | s_free_block(pgidx & ~((1UL << (order+1))-1), order+1); 94 | } else { 95 | kprintf("looking for buddy %p, self = %p\n", buddy_va, pg_va); 96 | struct free_page *pFree = bin->list.head; 97 | while(pFree != NULL) { 98 | kprintf("%p ->\n", pFree); 99 | pFree = pFree->next; 100 | } 101 | panic("has buddy but can't find it???"); 102 | } 103 | } else { 104 | pg_va->next = bin->list.head; 105 | bin->list.head = pg_va; 106 | bin->list.size++; 107 | } 108 | } 109 | 110 | static void* s_alloc_block(int order) 111 | { 112 | if (order < 0 || order > MAX_ORDER) 113 | { 114 | return NULL; 115 | } 116 | struct page_alloc_free_bin* bin = &pgalloc_bins[order]; 117 | if (bin->list.size) 118 | { 119 | bin->list.size--; 120 | struct free_page *pg = bin->list.head; 121 | bin->list.head = pg->next; 122 | size_t pgidx = PG_INDEX(KV2P(pg)); 123 | size_t bit_index = pgidx >> (order + 1); 124 | bin->bitmap[bit_index / (sizeof(u32) * 8)] ^= 1U << (bit_index % (sizeof(u32) * 8)); 125 | return (void*)pg; 126 | } 127 | else 128 | { 129 | void *large_page = s_alloc_block(order + 1); 130 | if (!large_page) 131 | { 132 | return NULL; 133 | } 134 | s_free_block(PG_INDEX(KV2P(large_page + (PG_SIZE << order))), order); 135 | return (void*) large_page; 136 | } 137 | } 138 | 139 | void pgalloc_free_range(void *start_va, void *end_va) 140 | { 141 | size_t start_pgidx = PGROUNDUP((size_t) KV2P(start_va)) / PG_SIZE; 142 | size_t end_pgidx = PGROUNDDOWN((size_t) KV2P(end_va)) / PG_SIZE; 143 | 144 | acquire(&pgalloc_lock); 145 | while(start_pgidx < end_pgidx) 146 | { 147 | for (int pg_order = MAX_ORDER; pg_order >= 0; pg_order--) 148 | { 149 | if (((start_pgidx & ((1UL << pg_order) - 1)) == 0) && 150 | (start_pgidx + (1UL << pg_order) <= end_pgidx)) 151 | { 152 | s_free_block(start_pgidx, pg_order); 153 | start_pgidx += (1UL << pg_order); 154 | break; 155 | } 156 | } 157 | } 158 | release(&pgalloc_lock); 159 | } 160 | 161 | void* pgalloc_allocate(int order) 162 | { 163 | void* rtn; 164 | acquire(&pgalloc_lock); 165 | rtn = s_alloc_block(order); 166 | release(&pgalloc_lock); 167 | return rtn; 168 | } 169 | 170 | void pgalloc_free(void* addr, int order) 171 | { 172 | acquire(&pgalloc_lock); 173 | s_free_block(PG_INDEX(KV2P(addr)), order); 174 | release(&pgalloc_lock); 175 | } 176 | -------------------------------------------------------------------------------- /kernel/src/proc/proc.c: -------------------------------------------------------------------------------- 1 | #include "proc.h" 2 | #include "defs.h" 3 | #include "mem/page_alloc.h" 4 | #include "mem/vm.h" 5 | #include "param.h" 6 | #include "spinlock.h" 7 | #include "arch/x86/interrupt.h" 8 | #include "arch/x86/instructions.h" 9 | 10 | struct ptable { 11 | spinlock_t lock; 12 | int next_pid; 13 | struct proc proc[NPROC]; 14 | } ptable; 15 | 16 | struct proc idle_proc[NCPU]; 17 | 18 | void proc_init(void) { 19 | // Initialize Process Table 20 | init_lock(&ptable.lock, "ptable"); 21 | memset(ptable.proc, 0, sizeof(ptable.proc)); 22 | memset(idle_proc, 0, sizeof(idle_proc)); 23 | ptable.next_pid = 1; 24 | 25 | sched_init(); 26 | } 27 | 28 | void proc_kern_init(struct proc* p) { 29 | if (p == NULL) { 30 | return; 31 | } 32 | void* kstack = pgalloc_allocate(0); 33 | void* kstack_top = (void*)(((size_t)kstack) + PG_SIZE); 34 | p->kstack = kstack; 35 | p->kstack_top = kstack_top; 36 | void* sp = kstack_top; 37 | 38 | sp -= sizeof(trapframe_t); 39 | p->tf = (trapframe_t *)sp; 40 | 41 | sp -= sizeof(size_t); 42 | *(size_t*)sp = (size_t)return_from_isr; 43 | 44 | sp -= sizeof(struct proc_context); 45 | p->ctx = (struct proc_context*)sp; 46 | memset(p->ctx, 0, sizeof(struct proc_context)); 47 | } 48 | 49 | struct proc* proc_alloc(void) { 50 | struct proc* selected = NULL; 51 | acquire(&ptable.lock); 52 | for(size_t i = 0; i < NPROC; i++) { 53 | if (ptable.proc[i].state == UNUSED) { 54 | selected = &ptable.proc[i]; 55 | memset(selected, 0, sizeof(struct proc)); 56 | selected->state = CREATION; 57 | selected->pid = (ptable.next_pid++); 58 | break; 59 | } 60 | } 61 | release(&ptable.lock); 62 | if (selected != NULL) { 63 | proc_kern_init(selected); 64 | } 65 | return selected; 66 | } 67 | -------------------------------------------------------------------------------- /kernel/src/proc/sched.c: -------------------------------------------------------------------------------- 1 | #include "proc.h" 2 | #include "defs.h" 3 | #include "mem/page_alloc.h" 4 | #include "mem/vm.h" 5 | #include "param.h" 6 | #include "spinlock.h" 7 | #include "arch/x86/interrupt.h" 8 | #include "arch/x86/instructions.h" 9 | #include "util/queue.h" 10 | 11 | 12 | struct scheduler { 13 | dequeue_t ready_queue; 14 | dequeue_t waiting_queue; 15 | 16 | spinlock_t lock; 17 | } sched; 18 | 19 | void sched_init(void) { 20 | // Initialize Scheduler 21 | init_lock(&sched.lock, "sched"); 22 | acquire(&sched.lock); 23 | dequeue_construct(&sched.ready_queue); 24 | dequeue_construct(&sched.waiting_queue); 25 | release(&sched.lock); 26 | } 27 | 28 | __attribute__((noreturn)) static void idle_function(void) { 29 | for (;;) { 30 | wait_for_interrupt(); 31 | } 32 | } 33 | 34 | 35 | void proc_kentry(void) { 36 | struct proc* p = curproc(); 37 | if (p == NULL) { 38 | panic("no curproc?"); 39 | } 40 | release(&sched.lock); 41 | // return to "caller" 42 | } 43 | 44 | void sched_create_kproc(struct proc* proc, void (*func)(void)) { 45 | memcpy(proc->name, "idle", 5); 46 | proc->killed = 0; 47 | proc->pgtable = vmm_get_kernel_pgtable(); 48 | proc->state = RUNNABLE; 49 | proc->type = KERNEL; 50 | proc->ctx->rip = (size_t)(proc_kentry); 51 | 52 | trapframe_t* tf = proc->tf; 53 | memset(tf, 0, sizeof(trapframe_t)); 54 | tf->rip = (size_t) func; 55 | tf->rsp = (size_t) proc->kstack_top; 56 | tf->cs = GDT_KERNEL_CODE * 8; 57 | tf->ss = GDT_KERNEL_DATA * 8; 58 | tf->flags = RFLAGS_IF; 59 | } 60 | 61 | static void sched_setup_idle_proc(struct proc* idleProc) { 62 | proc_kern_init(idleProc); 63 | idleProc->pid = 0; 64 | sched_create_kproc(idleProc, idle_function); 65 | } 66 | 67 | void sched_add(struct proc* proc) { 68 | if (proc->state != RUNNABLE) { 69 | panic("sched_add not ready"); 70 | } 71 | acquire(&sched.lock); 72 | dequeue_push_back(&sched.ready_queue, proc); 73 | release(&sched.lock); 74 | } 75 | 76 | void sched_start(void) { 77 | struct proc *p; 78 | struct cpu* c = cur_cpu(); 79 | c->proc = NULL; 80 | 81 | // Setup Idle proc 82 | int cpu_idx = cpu_id(); 83 | struct proc* this_idle_proc = &idle_proc[cpu_idx]; 84 | this_idle_proc->state = RUNNING; 85 | sched_setup_idle_proc(this_idle_proc); 86 | 87 | enable_interrupt(); 88 | 89 | acquire(&sched.lock); 90 | for(;;) { 91 | 92 | p = NULL; 93 | 94 | if (sched.ready_queue.size > 0) { 95 | p = dequeue_pop_front(&sched.ready_queue); 96 | } 97 | 98 | if (p == NULL) { 99 | p = &idle_proc[cpu_id()]; 100 | } 101 | 102 | // Picked the new process to run 103 | c->proc = p; 104 | p->state = RUNNING; 105 | // TODO: swap pgtable 106 | sched_ctxsw(&(c->scheduler_ctx), p->ctx); 107 | 108 | // Here when the proc done running 109 | vmm_load_ktable(); 110 | if ((c->proc != NULL) && 111 | (c->proc != &idle_proc[cpu_id()])) { 112 | // Add current proc to ready queue if it is marked runnable else goes in waiting queue 113 | if (c->proc->state == RUNNABLE) { 114 | dequeue_push_back(&sched.ready_queue, c->proc); 115 | } else { 116 | dequeue_push_back(&sched.waiting_queue, c->proc); 117 | } 118 | } 119 | c->proc = NULL; 120 | } 121 | release(&sched.lock); 122 | } 123 | 124 | void sched_switch_out(void) { 125 | int intena; 126 | struct proc* p = curproc(); 127 | 128 | if (!holding(&sched.lock)) { 129 | panic("sched_swtich_out lock"); 130 | } 131 | if (cur_cpu()->int_disable_layer != 1) { 132 | panic("switch_out lock count"); 133 | } 134 | if (p->state == RUNNING) { 135 | panic("switching out running"); 136 | } 137 | intena = cur_cpu()->int_enabled; 138 | sched_ctxsw(&p->ctx, cur_cpu()->scheduler_ctx); 139 | cur_cpu()->int_enabled = intena; 140 | } 141 | 142 | void sched_yield(void) { 143 | acquire(&sched.lock); 144 | if (curproc()->state == RUNNING) { 145 | curproc()->state = RUNNABLE; 146 | } 147 | sched_switch_out(); 148 | release(&sched.lock); 149 | } 150 | 151 | void sched_sleep(void* chan, spinlock_t *lk) { 152 | struct proc* p = curproc(); 153 | if (p == NULL) { 154 | panic("sched_sleep"); 155 | } 156 | if (lk == NULL) { 157 | panic("sleep w/o lock"); 158 | } 159 | 160 | if (lk != &sched.lock) { 161 | acquire(&sched.lock); 162 | release(lk); 163 | } 164 | 165 | p->chan = chan; 166 | p->state = SLEEPING; 167 | 168 | sched_switch_out(); 169 | 170 | p->chan = NULL; 171 | 172 | if (lk != &sched.lock) { 173 | acquire(lk); 174 | release(&sched.lock); 175 | } 176 | } 177 | 178 | void sched_wakeup(void* chan) { 179 | acquire(&sched.lock); 180 | dequeue_iterator_t iter; 181 | dequeue_iterator(&sched.waiting_queue, &iter); 182 | while(dequeue_iterator_has_next(&iter)) { 183 | struct proc* p = dequeue_iterator_next(&iter); 184 | if (p->chan == chan) { 185 | dequeue_iterator_delete(&iter); 186 | dequeue_push_back(&sched.ready_queue, p); 187 | } 188 | } 189 | release(&sched.lock); 190 | } 191 | -------------------------------------------------------------------------------- /kernel/src/spinlock.c: -------------------------------------------------------------------------------- 1 | // 2 | // Guide OS 3 | // Copyright (c) 2022 Codetector 4 | // MIT License 5 | // 6 | 7 | #include "defs.h" 8 | #include "spinlock.h" 9 | 10 | void init_lock(spinlock_t *lk, const char* name) 11 | { 12 | atomic_init(&lk->locked, 0); 13 | lk->cpu = NULL; 14 | lk->name = name; 15 | } 16 | 17 | bool holding(spinlock_t *lk) { 18 | bool r; 19 | push_int_disable(); 20 | r = lk->locked && lk->cpu == cur_cpu(); 21 | pop_int_disable(); 22 | return r; 23 | } 24 | 25 | void acquire(spinlock_t *lk) 26 | { 27 | push_int_disable(); 28 | if (holding(lk)) { 29 | panic("acquire"); 30 | } 31 | // Use c11 atomics to acquire the lock 32 | // Here we atomically exchange locked with 1. If locked was 0, then we've 33 | // just acquired the lock! 34 | // We use the acquire release semantics (orderings). We really only want 35 | // acquire semantics, but we are doing a read and modify operation at once 36 | // which requires acquire (write) and release (read) ordering semantics. 37 | while(atomic_exchange_explicit(&lk->locked, 1, memory_order_acq_rel) != 0) 38 | ; 39 | lk->cpu = cur_cpu(); 40 | } 41 | 42 | void release(spinlock_t *lk) 43 | { 44 | if (!holding(lk)) { 45 | panic("release"); 46 | } 47 | lk->cpu = NULL; 48 | atomic_store_explicit(&lk->locked, 0, memory_order_release); 49 | pop_int_disable(); 50 | } 51 | 52 | -------------------------------------------------------------------------------- /kernel/src/syscall.c: -------------------------------------------------------------------------------- 1 | #include "syscall.h" 2 | #include "syscall_number.h" 3 | #include "proc.h" 4 | #include "defs.h" 5 | 6 | 7 | static uint64_t sys_yield(trapframe_t *tf) { 8 | sched_yield(); 9 | return 0; 10 | } 11 | 12 | static uint64_t sys_con_read(trapframe_t *tf) { 13 | struct proc* p = curproc(); 14 | push_int_disable(); 15 | if (p->state == RUNNING) 16 | p->state = RUNNABLE; 17 | pop_int_disable(); 18 | return 0; 19 | } 20 | 21 | void handle_syscall(trapframe_t *tf) { 22 | u64 syscallno = tf->rax; 23 | switch(syscallno) { 24 | case SYS_YIELD: tf->rax = sys_yield(tf); break; 25 | case SYS_CON_READ: tf->rax = sys_con_read(tf); break; 26 | default: kprintf("unknown syscall %d\n", syscallno); break; 27 | } 28 | 29 | } 30 | -------------------------------------------------------------------------------- /kernel/src/time/systick.c: -------------------------------------------------------------------------------- 1 | #include "systick.h" 2 | #include "defs.h" 3 | #include "spinlock.h" 4 | #include "stdatomic.h" 5 | 6 | static uint64_t sys_tick; 7 | 8 | uint64_t systick(void) { 9 | uint64_t time = atomic_load_explicit(&sys_tick, memory_order_acquire); 10 | return time; 11 | } 12 | 13 | void systick_init(void) { 14 | atomic_store_explicit(&sys_tick, 0, memory_order_release); 15 | } 16 | 17 | void systick_increment(void) { 18 | atomic_fetch_add_explicit(&sys_tick, 1, memory_order_acq_rel); 19 | } 20 | 21 | void spin_sleep(uint64_t ticks) { 22 | uint64_t target = ticks + systick(); 23 | while(systick() < target) 24 | ; 25 | } 26 | -------------------------------------------------------------------------------- /kernel/src/usys.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Codetector1374/GuideOS/255c91632da6c5c05ec11649fbc250e4d338eff2/kernel/src/usys.c -------------------------------------------------------------------------------- /kernel/src/util/fifo.c: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "util/fifo.h" 3 | 4 | os_error_t spsc_fifo_init(spsc_fifo_t* f, u8* buffer, size_t buffer_size) { 5 | if (!f) return OSERR_INVALID_ARGUMENT; 6 | f->buffer = buffer; 7 | f->buffer_size = buffer_size; 8 | atomic_init(&f->read, 0); 9 | atomic_init(&f->write, 0); 10 | return OSERR_OK; 11 | } 12 | 13 | os_error_t spsc_fifo_write(spsc_fifo_t* f, u8 byte) { 14 | if (!f) return OSERR_INVALID_ARGUMENT; 15 | size_t cur_read = atomic_load_explicit(&f->read, memory_order_acquire); 16 | size_t cur_write = atomic_load_explicit(&f->write, memory_order_acquire); 17 | if ((cur_write + 1) % f->buffer_size == cur_read) { 18 | return OSERR_NO_MEMORY; 19 | } 20 | f->buffer[cur_write] = byte; 21 | atomic_store_explicit(&f->write, ((cur_write + 1) % f->buffer_size), memory_order_release); 22 | return OSERR_OK; 23 | } 24 | 25 | int spsc_fifo_read(spsc_fifo_t* f, u8* pOut) { 26 | if (!f || !pOut) return -1; 27 | size_t cur_read = atomic_load_explicit(&f->read, memory_order_acquire); 28 | size_t cur_write = atomic_load_explicit(&f->write, memory_order_acquire); 29 | if (cur_read == cur_write) return -1; 30 | *pOut = f->buffer[cur_read]; 31 | atomic_store_explicit(&f->read, (cur_read + 1) % f->buffer_size, memory_order_release); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /kernel/src/util/helpers.c: -------------------------------------------------------------------------------- 1 | // 2 | // Guide OS 3 | // Copyright (c) 2022 Codetector 4 | // MIT License 5 | // 6 | 7 | #include "defs.h" 8 | 9 | __attribute__((noreturn)) 10 | void 11 | panic(char *s) 12 | { 13 | disable_interrupt(); 14 | // cons.locking = 0; 15 | // kprintf("cpu with apicid %d: panic: ", lapicid()); 16 | kprintf("=====PANIC====\n"); 17 | kprintf(s); 18 | kprintf("\n"); 19 | for(;;) { 20 | wait_for_interrupt(); 21 | } 22 | } -------------------------------------------------------------------------------- /kernel/src/util/kprintf.c: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // \author (c) Marco Paland (info@paland.com) 3 | // 2014-2019, PALANDesign Hannover, Germany 4 | // 5 | // \license The MIT License (MIT) 6 | // 7 | // Permission is hereby granted, free of charge, to any person obtaining a copy 8 | // of this software and associated documentation files (the "Software"), to deal 9 | // in the Software without restriction, including without limitation the rights 10 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | // copies of the Software, and to permit persons to whom the Software is 12 | // furnished to do so, subject to the following conditions: 13 | // 14 | // The above copyright notice and this permission notice shall be included in 15 | // all copies or substantial portions of the Software. 16 | // 17 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 23 | // THE SOFTWARE. 24 | // 25 | // \brief Tiny printf, sprintf and (v)snprintf implementation, optimized for speed on 26 | // embedded systems with a very limited resources. These routines are thread 27 | // safe and reentrant! 28 | // Use this instead of the bloated standard/newlib printf cause these use 29 | // malloc for printf (and may not be thread safe). 30 | // 31 | /////////////////////////////////////////////////////////////////////////////// 32 | 33 | #include 34 | #include 35 | 36 | #include "kprintf.h" 37 | 38 | 39 | // define this globally (e.g. gcc -DPRINTF_INCLUDE_CONFIG_H ...) to include the 40 | // printf_config.h header file 41 | // default: undefined 42 | #ifdef PRINTF_INCLUDE_CONFIG_H 43 | #include "printf_config.h" 44 | #endif 45 | 46 | 47 | // 'ntoa' conversion buffer size, this must be big enough to hold one converted 48 | // numeric number including padded zeros (dynamically created on stack) 49 | // default: 32 byte 50 | #ifndef PRINTF_NTOA_BUFFER_SIZE 51 | #define PRINTF_NTOA_BUFFER_SIZE 32U 52 | #endif 53 | 54 | // 'ftoa' conversion buffer size, this must be big enough to hold one converted 55 | // float number including padded zeros (dynamically created on stack) 56 | // default: 32 byte 57 | #ifndef PRINTF_FTOA_BUFFER_SIZE 58 | #define PRINTF_FTOA_BUFFER_SIZE 32U 59 | #endif 60 | 61 | // support for the floating point type (%f) 62 | // default: activated 63 | #ifndef PRINTF_DISABLE_SUPPORT_FLOAT 64 | //#define PRINTF_SUPPORT_FLOAT 65 | #endif 66 | 67 | // support for exponential floating point notation (%e/%g) 68 | // default: activated 69 | #ifndef PRINTF_DISABLE_SUPPORT_EXPONENTIAL 70 | //#define PRINTF_SUPPORT_EXPONENTIAL 71 | #endif 72 | 73 | // define the default floating point precision 74 | // default: 6 digits 75 | #ifndef PRINTF_DEFAULT_FLOAT_PRECISION 76 | #define PRINTF_DEFAULT_FLOAT_PRECISION 6U 77 | #endif 78 | 79 | // define the largest float suitable to print with %f 80 | // default: 1e9 81 | #ifndef PRINTF_MAX_FLOAT 82 | #define PRINTF_MAX_FLOAT 1e9 83 | #endif 84 | 85 | // support for the long long types (%llu or %p) 86 | // default: activated 87 | #ifndef PRINTF_DISABLE_SUPPORT_LONG_LONG 88 | #define PRINTF_SUPPORT_LONG_LONG 89 | #endif 90 | 91 | // support for the ptrdiff_t type (%t) 92 | // ptrdiff_t is normally defined in as long or long long type 93 | // default: activated 94 | #ifndef PRINTF_DISABLE_SUPPORT_PTRDIFF_T 95 | #define PRINTF_SUPPORT_PTRDIFF_T 96 | #endif 97 | 98 | /////////////////////////////////////////////////////////////////////////////// 99 | 100 | // internal flag definitions 101 | #define FLAGS_ZEROPAD (1U << 0U) 102 | #define FLAGS_LEFT (1U << 1U) 103 | #define FLAGS_PLUS (1U << 2U) 104 | #define FLAGS_SPACE (1U << 3U) 105 | #define FLAGS_HASH (1U << 4U) 106 | #define FLAGS_UPPERCASE (1U << 5U) 107 | #define FLAGS_CHAR (1U << 6U) 108 | #define FLAGS_SHORT (1U << 7U) 109 | #define FLAGS_LONG (1U << 8U) 110 | #define FLAGS_LONG_LONG (1U << 9U) 111 | #define FLAGS_PRECISION (1U << 10U) 112 | #define FLAGS_ADAPT_EXP (1U << 11U) 113 | 114 | 115 | // output function type 116 | typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen); 117 | 118 | 119 | // wrapper (used as buffer) for output function type 120 | typedef struct { 121 | void (*fct)(char character, void* arg); 122 | void* arg; 123 | } out_fct_wrap_type; 124 | 125 | 126 | // internal buffer output 127 | static inline void _out_buffer(char character, void* buffer, size_t idx, size_t maxlen) 128 | { 129 | if (idx < maxlen) { 130 | ((char*)buffer)[idx] = character; 131 | } 132 | } 133 | 134 | 135 | // internal null output 136 | static inline void _out_null(char character, void* buffer, size_t idx, size_t maxlen) 137 | { 138 | (void)character; (void)buffer; (void)idx; (void)maxlen; 139 | } 140 | 141 | 142 | // internal _putchar wrapper 143 | static inline void _out_char(char character, void* buffer, size_t idx, size_t maxlen) 144 | { 145 | (void)buffer; (void)idx; (void)maxlen; 146 | if (character) { 147 | putchar(character); 148 | } 149 | } 150 | 151 | 152 | // internal output function wrapper 153 | static inline void _out_fct(char character, void* buffer, size_t idx, size_t maxlen) 154 | { 155 | (void)idx; (void)maxlen; 156 | if (character) { 157 | // buffer is the output fct pointer 158 | ((out_fct_wrap_type*)buffer)->fct(character, ((out_fct_wrap_type*)buffer)->arg); 159 | } 160 | } 161 | 162 | 163 | // internal secure strlen 164 | // \return The length of the string (excluding the terminating 0) limited by 'maxsize' 165 | static inline unsigned int _strnlen_s(const char* str, size_t maxsize) 166 | { 167 | const char* s; 168 | for (s = str; *s && maxsize--; ++s); 169 | return (unsigned int)(s - str); 170 | } 171 | 172 | 173 | // internal test if char is a digit (0-9) 174 | // \return true if char is a digit 175 | static inline bool _is_digit(char ch) 176 | { 177 | return (ch >= '0') && (ch <= '9'); 178 | } 179 | 180 | 181 | // internal ASCII string to unsigned int conversion 182 | static unsigned int _atoi(const char** str) 183 | { 184 | unsigned int i = 0U; 185 | while (_is_digit(**str)) { 186 | i = i * 10U + (unsigned int)(*((*str)++) - '0'); 187 | } 188 | return i; 189 | } 190 | 191 | 192 | // output the specified string in reverse, taking care of any zero-padding 193 | static size_t _out_rev(out_fct_type out, char* buffer, size_t idx, size_t maxlen, const char* buf, size_t len, unsigned int width, unsigned int flags) 194 | { 195 | const size_t start_idx = idx; 196 | 197 | // pad spaces up to given width 198 | if (!(flags & FLAGS_LEFT) && !(flags & FLAGS_ZEROPAD)) { 199 | for (size_t i = len; i < width; i++) { 200 | out(' ', buffer, idx++, maxlen); 201 | } 202 | } 203 | 204 | // reverse string 205 | while (len) { 206 | out(buf[--len], buffer, idx++, maxlen); 207 | } 208 | 209 | // append pad spaces up to given width 210 | if (flags & FLAGS_LEFT) { 211 | while (idx - start_idx < width) { 212 | out(' ', buffer, idx++, maxlen); 213 | } 214 | } 215 | 216 | return idx; 217 | } 218 | 219 | 220 | // internal itoa format 221 | static size_t _ntoa_format(out_fct_type out, char* buffer, size_t idx, size_t maxlen, char* buf, size_t len, bool negative, unsigned int base, unsigned int prec, unsigned int width, unsigned int flags) 222 | { 223 | // pad leading zeros 224 | if (!(flags & FLAGS_LEFT)) { 225 | if (width && (flags & FLAGS_ZEROPAD) && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { 226 | width--; 227 | } 228 | while ((len < prec) && (len < PRINTF_NTOA_BUFFER_SIZE)) { 229 | buf[len++] = '0'; 230 | } 231 | while ((flags & FLAGS_ZEROPAD) && (len < width) && (len < PRINTF_NTOA_BUFFER_SIZE)) { 232 | buf[len++] = '0'; 233 | } 234 | } 235 | 236 | // handle hash 237 | if (flags & FLAGS_HASH) { 238 | if (!(flags & FLAGS_PRECISION) && len && ((len == prec) || (len == width))) { 239 | len--; 240 | if (len && (base == 16U)) { 241 | len--; 242 | } 243 | } 244 | if ((base == 16U) && !(flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { 245 | buf[len++] = 'x'; 246 | } 247 | else if ((base == 16U) && (flags & FLAGS_UPPERCASE) && (len < PRINTF_NTOA_BUFFER_SIZE)) { 248 | buf[len++] = 'X'; 249 | } 250 | else if ((base == 2U) && (len < PRINTF_NTOA_BUFFER_SIZE)) { 251 | buf[len++] = 'b'; 252 | } 253 | if (len < PRINTF_NTOA_BUFFER_SIZE) { 254 | buf[len++] = '0'; 255 | } 256 | } 257 | 258 | if (len < PRINTF_NTOA_BUFFER_SIZE) { 259 | if (negative) { 260 | buf[len++] = '-'; 261 | } 262 | else if (flags & FLAGS_PLUS) { 263 | buf[len++] = '+'; // ignore the space if the '+' exists 264 | } 265 | else if (flags & FLAGS_SPACE) { 266 | buf[len++] = ' '; 267 | } 268 | } 269 | 270 | return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); 271 | } 272 | 273 | 274 | // internal itoa for 'long' type 275 | static size_t _ntoa_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long value, bool negative, unsigned long base, unsigned int prec, unsigned int width, unsigned int flags) 276 | { 277 | char buf[PRINTF_NTOA_BUFFER_SIZE]; 278 | size_t len = 0U; 279 | 280 | // no hash for 0 values 281 | if (!value) { 282 | flags &= ~FLAGS_HASH; 283 | } 284 | 285 | // write if precision != 0 and value is != 0 286 | if (!(flags & FLAGS_PRECISION) || value) { 287 | do { 288 | const char digit = (char)(value % base); 289 | buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; 290 | value /= base; 291 | } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); 292 | } 293 | 294 | return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); 295 | } 296 | 297 | 298 | // internal itoa for 'long long' type 299 | #if defined(PRINTF_SUPPORT_LONG_LONG) 300 | static size_t _ntoa_long_long(out_fct_type out, char* buffer, size_t idx, size_t maxlen, unsigned long long value, bool negative, unsigned long long base, unsigned int prec, unsigned int width, unsigned int flags) 301 | { 302 | char buf[PRINTF_NTOA_BUFFER_SIZE]; 303 | size_t len = 0U; 304 | 305 | // no hash for 0 values 306 | if (!value) { 307 | flags &= ~FLAGS_HASH; 308 | } 309 | 310 | // write if precision != 0 and value is != 0 311 | if (!(flags & FLAGS_PRECISION) || value) { 312 | do { 313 | const char digit = (char)(value % base); 314 | buf[len++] = digit < 10 ? '0' + digit : (flags & FLAGS_UPPERCASE ? 'A' : 'a') + digit - 10; 315 | value /= base; 316 | } while (value && (len < PRINTF_NTOA_BUFFER_SIZE)); 317 | } 318 | 319 | return _ntoa_format(out, buffer, idx, maxlen, buf, len, negative, (unsigned int)base, prec, width, flags); 320 | } 321 | #endif // PRINTF_SUPPORT_LONG_LONG 322 | 323 | 324 | #if defined(PRINTF_SUPPORT_FLOAT) 325 | 326 | #if defined(PRINTF_SUPPORT_EXPONENTIAL) 327 | // forward declaration so that _ftoa can switch to exp notation for values > PRINTF_MAX_FLOAT 328 | static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags); 329 | #endif 330 | 331 | 332 | // internal ftoa for fixed decimal floating point 333 | static size_t _ftoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) 334 | { 335 | char buf[PRINTF_FTOA_BUFFER_SIZE]; 336 | size_t len = 0U; 337 | double diff = 0.0; 338 | 339 | // powers of 10 340 | static const double pow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; 341 | 342 | // test for special values 343 | if (value != value) 344 | return _out_rev(out, buffer, idx, maxlen, "nan", 3, width, flags); 345 | if (value < -DBL_MAX) 346 | return _out_rev(out, buffer, idx, maxlen, "fni-", 4, width, flags); 347 | if (value > DBL_MAX) 348 | return _out_rev(out, buffer, idx, maxlen, (flags & FLAGS_PLUS) ? "fni+" : "fni", (flags & FLAGS_PLUS) ? 4U : 3U, width, flags); 349 | 350 | // test for very large values 351 | // standard printf behavior is to print EVERY whole number digit -- which could be 100s of characters overflowing your buffers == bad 352 | if ((value > PRINTF_MAX_FLOAT) || (value < -PRINTF_MAX_FLOAT)) { 353 | #if defined(PRINTF_SUPPORT_EXPONENTIAL) 354 | return _etoa(out, buffer, idx, maxlen, value, prec, width, flags); 355 | #else 356 | return 0U; 357 | #endif 358 | } 359 | 360 | // test for negative 361 | bool negative = false; 362 | if (value < 0) { 363 | negative = true; 364 | value = 0 - value; 365 | } 366 | 367 | // set default precision, if not set explicitly 368 | if (!(flags & FLAGS_PRECISION)) { 369 | prec = PRINTF_DEFAULT_FLOAT_PRECISION; 370 | } 371 | // limit precision to 9, cause a prec >= 10 can lead to overflow errors 372 | while ((len < PRINTF_FTOA_BUFFER_SIZE) && (prec > 9U)) { 373 | buf[len++] = '0'; 374 | prec--; 375 | } 376 | 377 | int whole = (int)value; 378 | double tmp = (value - whole) * pow10[prec]; 379 | unsigned long frac = (unsigned long)tmp; 380 | diff = tmp - frac; 381 | 382 | if (diff > 0.5) { 383 | ++frac; 384 | // handle rollover, e.g. case 0.99 with prec 1 is 1.0 385 | if (frac >= pow10[prec]) { 386 | frac = 0; 387 | ++whole; 388 | } 389 | } 390 | else if (diff < 0.5) { 391 | } 392 | else if ((frac == 0U) || (frac & 1U)) { 393 | // if halfway, round up if odd OR if last digit is 0 394 | ++frac; 395 | } 396 | 397 | if (prec == 0U) { 398 | diff = value - (double)whole; 399 | if ((!(diff < 0.5) || (diff > 0.5)) && (whole & 1)) { 400 | // exactly 0.5 and ODD, then round up 401 | // 1.5 -> 2, but 2.5 -> 2 402 | ++whole; 403 | } 404 | } 405 | else { 406 | unsigned int count = prec; 407 | // now do fractional part, as an unsigned number 408 | while (len < PRINTF_FTOA_BUFFER_SIZE) { 409 | --count; 410 | buf[len++] = (char)(48U + (frac % 10U)); 411 | if (!(frac /= 10U)) { 412 | break; 413 | } 414 | } 415 | // add extra 0s 416 | while ((len < PRINTF_FTOA_BUFFER_SIZE) && (count-- > 0U)) { 417 | buf[len++] = '0'; 418 | } 419 | if (len < PRINTF_FTOA_BUFFER_SIZE) { 420 | // add decimal 421 | buf[len++] = '.'; 422 | } 423 | } 424 | 425 | // do whole part, number is reversed 426 | while (len < PRINTF_FTOA_BUFFER_SIZE) { 427 | buf[len++] = (char)(48 + (whole % 10)); 428 | if (!(whole /= 10)) { 429 | break; 430 | } 431 | } 432 | 433 | // pad leading zeros 434 | if (!(flags & FLAGS_LEFT) && (flags & FLAGS_ZEROPAD)) { 435 | if (width && (negative || (flags & (FLAGS_PLUS | FLAGS_SPACE)))) { 436 | width--; 437 | } 438 | while ((len < width) && (len < PRINTF_FTOA_BUFFER_SIZE)) { 439 | buf[len++] = '0'; 440 | } 441 | } 442 | 443 | if (len < PRINTF_FTOA_BUFFER_SIZE) { 444 | if (negative) { 445 | buf[len++] = '-'; 446 | } 447 | else if (flags & FLAGS_PLUS) { 448 | buf[len++] = '+'; // ignore the space if the '+' exists 449 | } 450 | else if (flags & FLAGS_SPACE) { 451 | buf[len++] = ' '; 452 | } 453 | } 454 | 455 | return _out_rev(out, buffer, idx, maxlen, buf, len, width, flags); 456 | } 457 | 458 | 459 | #if defined(PRINTF_SUPPORT_EXPONENTIAL) 460 | // internal ftoa variant for exponential floating-point type, contributed by Martijn Jasperse 461 | static size_t _etoa(out_fct_type out, char* buffer, size_t idx, size_t maxlen, double value, unsigned int prec, unsigned int width, unsigned int flags) 462 | { 463 | // check for NaN and special values 464 | if ((value != value) || (value > DBL_MAX) || (value < -DBL_MAX)) { 465 | return _ftoa(out, buffer, idx, maxlen, value, prec, width, flags); 466 | } 467 | 468 | // determine the sign 469 | const bool negative = value < 0; 470 | if (negative) { 471 | value = -value; 472 | } 473 | 474 | // default precision 475 | if (!(flags & FLAGS_PRECISION)) { 476 | prec = PRINTF_DEFAULT_FLOAT_PRECISION; 477 | } 478 | 479 | // determine the decimal exponent 480 | // based on the algorithm by David Gay (https://www.ampl.com/netlib/fp/dtoa.c) 481 | union { 482 | uint64_t U; 483 | double F; 484 | } conv; 485 | 486 | conv.F = value; 487 | int exp2 = (int)((conv.U >> 52U) & 0x07FFU) - 1023; // effectively log2 488 | conv.U = (conv.U & ((1ULL << 52U) - 1U)) | (1023ULL << 52U); // drop the exponent so conv.F is now in [1,2) 489 | // now approximate log10 from the log2 integer part and an expansion of ln around 1.5 490 | int expval = (int)(0.1760912590558 + exp2 * 0.301029995663981 + (conv.F - 1.5) * 0.289529654602168); 491 | // now we want to compute 10^expval but we want to be sure it won't overflow 492 | exp2 = (int)(expval * 3.321928094887362 + 0.5); 493 | const double z = expval * 2.302585092994046 - exp2 * 0.6931471805599453; 494 | const double z2 = z * z; 495 | conv.U = (uint64_t)(exp2 + 1023) << 52U; 496 | // compute exp(z) using continued fractions, see https://en.wikipedia.org/wiki/Exponential_function#Continued_fractions_for_ex 497 | conv.F *= 1 + 2 * z / (2 - z + (z2 / (6 + (z2 / (10 + z2 / 14))))); 498 | // correct for rounding errors 499 | if (value < conv.F) { 500 | expval--; 501 | conv.F /= 10; 502 | } 503 | 504 | // the exponent format is "%+03d" and largest value is "307", so set aside 4-5 characters 505 | unsigned int minwidth = ((expval < 100) && (expval > -100)) ? 4U : 5U; 506 | 507 | // in "%g" mode, "prec" is the number of *significant figures* not decimals 508 | if (flags & FLAGS_ADAPT_EXP) { 509 | // do we want to fall-back to "%f" mode? 510 | if ((value >= 1e-4) && (value < 1e6)) { 511 | if ((int)prec > expval) { 512 | prec = (unsigned)((int)prec - expval - 1); 513 | } 514 | else { 515 | prec = 0; 516 | } 517 | flags |= FLAGS_PRECISION; // make sure _ftoa respects precision 518 | // no characters in exponent 519 | minwidth = 0U; 520 | expval = 0; 521 | } 522 | else { 523 | // we use one sigfig for the whole part 524 | if ((prec > 0) && (flags & FLAGS_PRECISION)) { 525 | --prec; 526 | } 527 | } 528 | } 529 | 530 | // will everything fit? 531 | unsigned int fwidth = width; 532 | if (width > minwidth) { 533 | // we didn't fall-back so subtract the characters required for the exponent 534 | fwidth -= minwidth; 535 | } else { 536 | // not enough characters, so go back to default sizing 537 | fwidth = 0U; 538 | } 539 | if ((flags & FLAGS_LEFT) && minwidth) { 540 | // if we're padding on the right, DON'T pad the floating part 541 | fwidth = 0U; 542 | } 543 | 544 | // rescale the float value 545 | if (expval) { 546 | value /= conv.F; 547 | } 548 | 549 | // output the floating part 550 | const size_t start_idx = idx; 551 | idx = _ftoa(out, buffer, idx, maxlen, negative ? -value : value, prec, fwidth, flags & ~FLAGS_ADAPT_EXP); 552 | 553 | // output the exponent part 554 | if (minwidth) { 555 | // output the exponential symbol 556 | out((flags & FLAGS_UPPERCASE) ? 'E' : 'e', buffer, idx++, maxlen); 557 | // output the exponent value 558 | idx = _ntoa_long(out, buffer, idx, maxlen, (expval < 0) ? -expval : expval, expval < 0, 10, 0, minwidth-1, FLAGS_ZEROPAD | FLAGS_PLUS); 559 | // might need to right-pad spaces 560 | if (flags & FLAGS_LEFT) { 561 | while (idx - start_idx < width) out(' ', buffer, idx++, maxlen); 562 | } 563 | } 564 | return idx; 565 | } 566 | #endif // PRINTF_SUPPORT_EXPONENTIAL 567 | #endif // PRINTF_SUPPORT_FLOAT 568 | 569 | 570 | // internal vsnprintf 571 | static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va) 572 | { 573 | unsigned int flags, width, precision, n; 574 | size_t idx = 0U; 575 | 576 | if (!buffer) { 577 | // use null output function 578 | out = _out_null; 579 | } 580 | 581 | while (*format) 582 | { 583 | // format specifier? %[flags][width][.precision][length] 584 | if (*format != '%') { 585 | // no 586 | out(*format, buffer, idx++, maxlen); 587 | format++; 588 | continue; 589 | } 590 | else { 591 | // yes, evaluate it 592 | format++; 593 | } 594 | 595 | // evaluate flags 596 | flags = 0U; 597 | do { 598 | switch (*format) { 599 | case '0': flags |= FLAGS_ZEROPAD; format++; n = 1U; break; 600 | case '-': flags |= FLAGS_LEFT; format++; n = 1U; break; 601 | case '+': flags |= FLAGS_PLUS; format++; n = 1U; break; 602 | case ' ': flags |= FLAGS_SPACE; format++; n = 1U; break; 603 | case '#': flags |= FLAGS_HASH; format++; n = 1U; break; 604 | default : n = 0U; break; 605 | } 606 | } while (n); 607 | 608 | // evaluate width field 609 | width = 0U; 610 | if (_is_digit(*format)) { 611 | width = _atoi(&format); 612 | } 613 | else if (*format == '*') { 614 | const int w = va_arg(va, int); 615 | if (w < 0) { 616 | flags |= FLAGS_LEFT; // reverse padding 617 | width = (unsigned int)-w; 618 | } 619 | else { 620 | width = (unsigned int)w; 621 | } 622 | format++; 623 | } 624 | 625 | // evaluate precision field 626 | precision = 0U; 627 | if (*format == '.') { 628 | flags |= FLAGS_PRECISION; 629 | format++; 630 | if (_is_digit(*format)) { 631 | precision = _atoi(&format); 632 | } 633 | else if (*format == '*') { 634 | const int prec = (int)va_arg(va, int); 635 | precision = prec > 0 ? (unsigned int)prec : 0U; 636 | format++; 637 | } 638 | } 639 | 640 | // evaluate length field 641 | switch (*format) { 642 | case 'l' : 643 | flags |= FLAGS_LONG; 644 | format++; 645 | if (*format == 'l') { 646 | flags |= FLAGS_LONG_LONG; 647 | format++; 648 | } 649 | break; 650 | case 'h' : 651 | flags |= FLAGS_SHORT; 652 | format++; 653 | if (*format == 'h') { 654 | flags |= FLAGS_CHAR; 655 | format++; 656 | } 657 | break; 658 | #if defined(PRINTF_SUPPORT_PTRDIFF_T) 659 | case 't' : 660 | flags |= (sizeof(ptrdiff_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); 661 | format++; 662 | break; 663 | #endif 664 | case 'j' : 665 | flags |= (sizeof(intmax_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); 666 | format++; 667 | break; 668 | case 'z' : 669 | flags |= (sizeof(size_t) == sizeof(long) ? FLAGS_LONG : FLAGS_LONG_LONG); 670 | format++; 671 | break; 672 | default : 673 | break; 674 | } 675 | 676 | // evaluate specifier 677 | switch (*format) { 678 | case 'd' : 679 | case 'i' : 680 | case 'u' : 681 | case 'x' : 682 | case 'X' : 683 | case 'o' : 684 | case 'b' : { 685 | // set the base 686 | unsigned int base; 687 | if (*format == 'x' || *format == 'X') { 688 | base = 16U; 689 | } 690 | else if (*format == 'o') { 691 | base = 8U; 692 | } 693 | else if (*format == 'b') { 694 | base = 2U; 695 | } 696 | else { 697 | base = 10U; 698 | flags &= ~FLAGS_HASH; // no hash for dec format 699 | } 700 | // uppercase 701 | if (*format == 'X') { 702 | flags |= FLAGS_UPPERCASE; 703 | } 704 | 705 | // no plus or space flag for u, x, X, o, b 706 | if ((*format != 'i') && (*format != 'd')) { 707 | flags &= ~(FLAGS_PLUS | FLAGS_SPACE); 708 | } 709 | 710 | // ignore '0' flag when precision is given 711 | if (flags & FLAGS_PRECISION) { 712 | flags &= ~FLAGS_ZEROPAD; 713 | } 714 | 715 | // convert the integer 716 | if ((*format == 'i') || (*format == 'd')) { 717 | // signed 718 | if (flags & FLAGS_LONG_LONG) { 719 | #if defined(PRINTF_SUPPORT_LONG_LONG) 720 | const long long value = va_arg(va, long long); 721 | idx = _ntoa_long_long(out, buffer, idx, maxlen, (unsigned long long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); 722 | #endif 723 | } 724 | else if (flags & FLAGS_LONG) { 725 | const long value = va_arg(va, long); 726 | idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); 727 | } 728 | else { 729 | const int value = (flags & FLAGS_CHAR) ? (char)va_arg(va, int) : (flags & FLAGS_SHORT) ? (short int)va_arg(va, int) : va_arg(va, int); 730 | idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned int)(value > 0 ? value : 0 - value), value < 0, base, precision, width, flags); 731 | } 732 | } 733 | else { 734 | // unsigned 735 | if (flags & FLAGS_LONG_LONG) { 736 | #if defined(PRINTF_SUPPORT_LONG_LONG) 737 | idx = _ntoa_long_long(out, buffer, idx, maxlen, va_arg(va, unsigned long long), false, base, precision, width, flags); 738 | #endif 739 | } 740 | else if (flags & FLAGS_LONG) { 741 | idx = _ntoa_long(out, buffer, idx, maxlen, va_arg(va, unsigned long), false, base, precision, width, flags); 742 | } 743 | else { 744 | const unsigned int value = (flags & FLAGS_CHAR) ? (unsigned char)va_arg(va, unsigned int) : (flags & FLAGS_SHORT) ? (unsigned short int)va_arg(va, unsigned int) : va_arg(va, unsigned int); 745 | idx = _ntoa_long(out, buffer, idx, maxlen, value, false, base, precision, width, flags); 746 | } 747 | } 748 | format++; 749 | break; 750 | } 751 | #if defined(PRINTF_SUPPORT_FLOAT) 752 | case 'f' : 753 | case 'F' : 754 | if (*format == 'F') flags |= FLAGS_UPPERCASE; 755 | idx = _ftoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); 756 | format++; 757 | break; 758 | #if defined(PRINTF_SUPPORT_EXPONENTIAL) 759 | case 'e': 760 | case 'E': 761 | case 'g': 762 | case 'G': 763 | if ((*format == 'g')||(*format == 'G')) flags |= FLAGS_ADAPT_EXP; 764 | if ((*format == 'E')||(*format == 'G')) flags |= FLAGS_UPPERCASE; 765 | idx = _etoa(out, buffer, idx, maxlen, va_arg(va, double), precision, width, flags); 766 | format++; 767 | break; 768 | #endif // PRINTF_SUPPORT_EXPONENTIAL 769 | #endif // PRINTF_SUPPORT_FLOAT 770 | case 'c' : { 771 | unsigned int l = 1U; 772 | // pre padding 773 | if (!(flags & FLAGS_LEFT)) { 774 | while (l++ < width) { 775 | out(' ', buffer, idx++, maxlen); 776 | } 777 | } 778 | // char output 779 | out((char)va_arg(va, int), buffer, idx++, maxlen); 780 | // post padding 781 | if (flags & FLAGS_LEFT) { 782 | while (l++ < width) { 783 | out(' ', buffer, idx++, maxlen); 784 | } 785 | } 786 | format++; 787 | break; 788 | } 789 | 790 | case 's' : { 791 | const char* p = va_arg(va, char*); 792 | unsigned int l = _strnlen_s(p, precision ? precision : (size_t)-1); 793 | // pre padding 794 | if (flags & FLAGS_PRECISION) { 795 | l = (l < precision ? l : precision); 796 | } 797 | if (!(flags & FLAGS_LEFT)) { 798 | while (l++ < width) { 799 | out(' ', buffer, idx++, maxlen); 800 | } 801 | } 802 | // string output 803 | while ((*p != 0) && (!(flags & FLAGS_PRECISION) || precision--)) { 804 | out(*(p++), buffer, idx++, maxlen); 805 | } 806 | // post padding 807 | if (flags & FLAGS_LEFT) { 808 | while (l++ < width) { 809 | out(' ', buffer, idx++, maxlen); 810 | } 811 | } 812 | format++; 813 | break; 814 | } 815 | 816 | case 'p' : { 817 | width = sizeof(void*) * 2U; 818 | flags |= FLAGS_ZEROPAD | FLAGS_UPPERCASE; 819 | #if defined(PRINTF_SUPPORT_LONG_LONG) 820 | const bool is_ll = sizeof(uintptr_t) == sizeof(long long); 821 | if (is_ll) { 822 | idx = _ntoa_long_long(out, buffer, idx, maxlen, (uintptr_t)va_arg(va, void*), false, 16U, precision, width, flags); 823 | } 824 | else { 825 | #endif 826 | idx = _ntoa_long(out, buffer, idx, maxlen, (unsigned long)((uintptr_t)va_arg(va, void*)), false, 16U, precision, width, flags); 827 | #if defined(PRINTF_SUPPORT_LONG_LONG) 828 | } 829 | #endif 830 | format++; 831 | break; 832 | } 833 | 834 | case '%' : 835 | out('%', buffer, idx++, maxlen); 836 | format++; 837 | break; 838 | 839 | default : 840 | out(*format, buffer, idx++, maxlen); 841 | format++; 842 | break; 843 | } 844 | } 845 | 846 | // termination 847 | out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen); 848 | 849 | // return written chars without terminating \0 850 | return (int)idx; 851 | } 852 | 853 | 854 | /////////////////////////////////////////////////////////////////////////////// 855 | 856 | int printf_(const char* format, ...) 857 | { 858 | va_list va; 859 | va_start(va, format); 860 | char buffer[1]; 861 | const int ret = _vsnprintf(_out_char, buffer, (size_t)-1, format, va); 862 | va_end(va); 863 | return ret; 864 | } 865 | 866 | 867 | int sprintf_(char* buffer, const char* format, ...) 868 | { 869 | va_list va; 870 | va_start(va, format); 871 | const int ret = _vsnprintf(_out_buffer, buffer, (size_t)-1, format, va); 872 | va_end(va); 873 | return ret; 874 | } 875 | 876 | 877 | int snprintf_(char* buffer, size_t count, const char* format, ...) 878 | { 879 | va_list va; 880 | va_start(va, format); 881 | const int ret = _vsnprintf(_out_buffer, buffer, count, format, va); 882 | va_end(va); 883 | return ret; 884 | } 885 | 886 | 887 | int vprintf_(const char* format, va_list va) 888 | { 889 | char buffer[1]; 890 | return _vsnprintf(_out_char, buffer, (size_t)-1, format, va); 891 | } 892 | 893 | 894 | int vsnprintf_(char* buffer, size_t count, const char* format, va_list va) 895 | { 896 | return _vsnprintf(_out_buffer, buffer, count, format, va); 897 | } 898 | 899 | 900 | int fctprintf(void (*out)(char character, void* arg), void* arg, const char* format, ...) 901 | { 902 | va_list va; 903 | va_start(va, format); 904 | const out_fct_wrap_type out_fct_wrap = { out, arg }; 905 | const int ret = _vsnprintf(_out_fct, (char*)(uintptr_t)&out_fct_wrap, (size_t)-1, format, va); 906 | va_end(va); 907 | return ret; 908 | } 909 | -------------------------------------------------------------------------------- /kernel/src/util/queue.c: -------------------------------------------------------------------------------- 1 | #include "defs.h" 2 | #include "util/queue.h" 3 | 4 | void dequeue_construct(dequeue_t *q) { 5 | if (q == NULL) { 6 | return; 7 | } 8 | memset(q, 0, sizeof(dequeue_t)); 9 | } 10 | 11 | void dequeue_push_back(dequeue_t *q, void* item) { 12 | struct dequeue_node* node = kmalloc(sizeof(struct dequeue_node)); 13 | node->data = item; 14 | node->next = NULL; 15 | if (q->size == 0) { 16 | node->prev = NULL; 17 | q->head = node; 18 | } else { 19 | node->prev = q->tail; 20 | q->tail->next = node; 21 | } 22 | q->tail = node; 23 | q->size++; 24 | } 25 | 26 | void dequeue_push_front(dequeue_t *q, void* item) { 27 | if (q->size == 0) { 28 | dequeue_push_front(q, item); 29 | return; 30 | } 31 | struct dequeue_node* node = kmalloc(sizeof(struct dequeue_node)); 32 | node->data = item; 33 | node->prev = NULL; 34 | node->next = q->head; 35 | q->head->prev = node; 36 | q->head = node; 37 | q->size++; 38 | } 39 | 40 | void* dequeue_peek_front(dequeue_t* q) { 41 | if (q->size == 0) { 42 | return NULL; 43 | } 44 | return q->head->data; 45 | } 46 | 47 | void* dequeue_pop_front(dequeue_t* q) { 48 | if (q->size == 0) { 49 | return NULL; 50 | } 51 | struct dequeue_node *node = q->head; 52 | q->head = q->head->next; 53 | 54 | if (--q->size == 0) { 55 | q->tail = NULL; 56 | } else { 57 | if (q->head == NULL) { 58 | panic("null head size > 0?"); 59 | } 60 | q->head->prev = NULL; 61 | } 62 | void* data = node->data; 63 | kfree(node); 64 | 65 | return data; 66 | } 67 | 68 | void* dequeue_pop_back(dequeue_t* q) { 69 | panic("not implemented"); 70 | return NULL; 71 | } 72 | 73 | void dequeue_iterator(dequeue_t* q, dequeue_iterator_t* iter) { 74 | iter->current_node = q->head; 75 | iter->q = q; 76 | } 77 | 78 | void* dequeue_iterator_next(dequeue_iterator_t* iter) { 79 | void* data = NULL; 80 | if (iter->current_node != NULL) { 81 | data = iter->current_node->data; 82 | iter->current_node = iter->current_node->next; 83 | } 84 | return data; 85 | } 86 | 87 | bool dequeue_iterator_has_next(dequeue_iterator_t* iter) { 88 | return iter->current_node != NULL; 89 | } 90 | 91 | void dequeue_iterator_delete(dequeue_iterator_t* iter) { 92 | if (iter->q->size == 0) { 93 | return; 94 | } 95 | if (iter->q->size == 1) { 96 | (void)dequeue_pop_front(iter->q); 97 | return; 98 | } 99 | struct dequeue_node* target_node = NULL; 100 | if (iter->current_node == NULL) { 101 | target_node = iter->q->tail; 102 | } else { 103 | target_node = iter->current_node->prev; 104 | } 105 | if (target_node != NULL) { 106 | // Not head 107 | if (target_node->prev != NULL) { 108 | target_node->prev->next = target_node->next; 109 | } else { 110 | iter->q->head = target_node->next; 111 | } 112 | 113 | // Not Tail 114 | if (target_node->next != NULL) { 115 | target_node->next->prev = target_node->prev; 116 | } else { 117 | iter->q->tail = target_node->prev; 118 | } 119 | target_node->next = NULL; 120 | target_node->prev = NULL; 121 | iter->q->size--; 122 | } 123 | if (iter->q->size == 0) { 124 | iter->current_node = NULL; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /kernel/src/util/string.c: -------------------------------------------------------------------------------- 1 | // 2 | // Guide OS 3 | // Copyright (c) 2022 Codetector 4 | // MIT License 5 | // 6 | 7 | #include "string.h" 8 | #include "arch/x86.h" 9 | 10 | void* 11 | memset(void *dst, int c, size_t n) 12 | { 13 | if ((size_t)dst%4 == 0 && n%4 == 0){ 14 | c &= 0xFF; 15 | stosl(dst, (c<<24)|(c<<16)|(c<<8)|c, n/4); 16 | } else 17 | stosb(dst, c, n); 18 | return dst; 19 | } 20 | 21 | int 22 | memcmp(const void *v1, const void *v2, size_t n) 23 | { 24 | const u8 *s1, *s2; 25 | 26 | s1 = v1; 27 | s2 = v2; 28 | while(n-- > 0){ 29 | if(*s1 != *s2) 30 | return *s1 - *s2; 31 | s1++, s2++; 32 | } 33 | 34 | return 0; 35 | } 36 | 37 | void* 38 | memmove(void *dst, const void *src, size_t n) 39 | { 40 | const char *s; 41 | char *d; 42 | 43 | s = src; 44 | d = dst; 45 | if(s < d && s + n > d){ 46 | s += n; 47 | d += n; 48 | while(n-- > 0) 49 | *--d = *--s; 50 | } else 51 | while(n-- > 0) 52 | *d++ = *s++; 53 | 54 | return dst; 55 | } 56 | 57 | // memcpy exists to placate GCC. Use memmove. 58 | void* 59 | memcpy(void *dst, const void *src, size_t n) 60 | { 61 | return memmove(dst, src, n); 62 | } 63 | 64 | int 65 | strncmp(const char *p, const char *q, size_t n) 66 | { 67 | while(n > 0 && *p && *p == *q) 68 | n--, p++, q++; 69 | if(n == 0) 70 | return 0; 71 | return (int)((size_t)*p - (size_t)*q); 72 | } 73 | 74 | char* 75 | strncpy(char *s, const char *t, size_t n) 76 | { 77 | char *os; 78 | 79 | os = s; 80 | while(n-- > 0 && (*s++ = *t++) != 0) 81 | ; 82 | while(n-- > 0) 83 | *s++ = 0; 84 | return os; 85 | } 86 | 87 | size_t 88 | strnlen(const char *s, size_t size) 89 | { 90 | size_t n; 91 | 92 | for (n = 0; size > 0 && *s != '\0'; s++, size--) 93 | n++; 94 | return n; 95 | } 96 | 97 | 98 | 99 | // Like strncpy but guaranteed to NUL-terminate. 100 | char* 101 | safestrcpy(char *s, char *t, size_t n) 102 | { 103 | char *os; 104 | 105 | os = s; 106 | if(n <= 0) 107 | return os; 108 | while(--n > 0 && (*s++ = *t++) != 0) 109 | ; 110 | *s = 0; 111 | return os; 112 | } 113 | 114 | int 115 | strlen(const char *s) 116 | { 117 | int n; 118 | 119 | for(n = 0; s[n]; n++) 120 | ; 121 | return n; 122 | } 123 | 124 | 125 | int 126 | strcmp(const char *p, const char *q) 127 | { 128 | while(*p && *p == *q) 129 | p++, q++; 130 | return (u8)*p - (u8)*q; 131 | } 132 | 133 | char* 134 | strchr(const char *s, char c) 135 | { 136 | for(; *s; s++) 137 | if(*s == c) 138 | return (char*)s; 139 | return 0; 140 | } 141 | 142 | // Return a pointer to the first occurrence of 'c' in 's', 143 | // or a pointer to the string-ending null character if the string has no 'c'. 144 | char * 145 | strfind(const char *s, char c) 146 | { 147 | for (; *s; s++) 148 | if (*s == c) 149 | break; 150 | return (char*)s; 151 | } 152 | 153 | char *strtok(char *base, const char *delims) 154 | { 155 | static char *copy; 156 | static int i; 157 | int j = 0, word_found = -1, blanks = 0; 158 | char *ret_str; 159 | 160 | if (base) 161 | { 162 | i = 0; 163 | copy = base; 164 | } 165 | while (copy[i]) 166 | { 167 | while (delims[j]) 168 | { 169 | if (copy[i] == delims[j]) 170 | { 171 | blanks = 1; 172 | if (word_found >= 0) 173 | { 174 | copy[i++] = '\0'; 175 | ret_str = copy + word_found; 176 | return (ret_str); 177 | } 178 | } 179 | j++; 180 | } 181 | j = 0; 182 | if (word_found == -1 && !blanks) 183 | { 184 | word_found = i; 185 | } 186 | blanks = 0; 187 | i++; 188 | } 189 | if (word_found == -1) 190 | return (0); 191 | ret_str = copy + word_found; 192 | return (ret_str); 193 | } 194 | 195 | -------------------------------------------------------------------------------- /lib/libsys/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(libsys C ASM) 2 | 3 | add_library(libsys STATIC 4 | src/syscall.c 5 | ) 6 | 7 | target_include_directories(libsys PUBLIC include) 8 | -------------------------------------------------------------------------------- /lib/libsys/include/syscall_number.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define SYS_YIELD 0x01 4 | 5 | #define SYS_CON_READ 0x10 -------------------------------------------------------------------------------- /lib/libsys/include/types.h: -------------------------------------------------------------------------------- 1 | // 2 | // Guide OS 3 | // Copyright (c) 2022 Codetector 4 | // MIT License 5 | // 6 | #pragma once 7 | 8 | #include 9 | #include 10 | #include "error.h" 11 | 12 | typedef uint64_t u64; 13 | typedef uint32_t u32; 14 | typedef uint16_t u16; 15 | typedef uint8_t u8; 16 | 17 | typedef u8 bool; 18 | 19 | typedef size_t uptr; 20 | 21 | #define FALSE 0 22 | #define TRUE 1 23 | 24 | 25 | #define BACKSPACE 0x100 26 | 27 | -------------------------------------------------------------------------------- /lib/libsys/include/usys.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "types.h" 4 | 5 | uint64_t syscall0(uint64_t); 6 | uint64_t syscall1(uint64_t, uint64_t); 7 | // uint64_t syscall2(uint64_t, uint64_t, uint64_t); 8 | // uint64_t syscall3(uint64_t, uint64_t, uint64_t, uint64_t); 9 | 10 | 11 | void yield(void); 12 | int con_read(void); 13 | -------------------------------------------------------------------------------- /lib/libsys/src/syscall.c: -------------------------------------------------------------------------------- 1 | #include "types.h" 2 | #include "usys.h" 3 | #include "syscall_number.h" 4 | 5 | uint64_t syscall0(uint64_t syscallNo) { 6 | uint64_t rtnval; 7 | asm volatile("int $0x80" : "=a"(rtnval) : "a"(syscallNo) : "cc", "memory"); 8 | return rtnval; 9 | } 10 | 11 | uint64_t syscall1(uint64_t syscallNo, uint64_t arg0) { 12 | uint64_t rtnval; 13 | asm volatile("int $0x80" : "=a"(rtnval) : "a"(syscallNo), "rdi"(arg0) : "cc", "rdi", "memory"); 14 | return rtnval; 15 | } 16 | 17 | // uint64_t syscall2(uint64_t, uint64_t, uint64_t); 18 | // uint64_t syscall3(uint64_t, uint64_t, uint64_t, uint64_t); 19 | 20 | void yield(void) { 21 | syscall0(SYS_YIELD); 22 | } 23 | 24 | int con_read(void) { 25 | return (int)syscall0(SYS_CON_READ); 26 | } 27 | 28 | -------------------------------------------------------------------------------- /stage1_bootloader/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | project(stage1_bootloader ASM) 3 | 4 | add_library(stage1Bootloader OBJECT 5 | src/asm/init.s) 6 | 7 | set(CMAKE_C_FLAGS "-static -fno-builtin -fno-pic -nostdinc -m16") 8 | set(CMAKE_ASM_FLAGS "-m32") 9 | 10 | set(CMAKE_C_FLAGS_RELEASE "-Os") 11 | set(CMAKE_C_FLAGS_DEBUG "-Os -ggdb3") 12 | 13 | 14 | add_custom_command( 15 | OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/stage1.obj 16 | COMMAND ${CMAKE_LINKER} -m elf_i386 -N -T ${CMAKE_CURRENT_SOURCE_DIR}/stage1.ld -o ${CMAKE_CURRENT_BINARY_DIR}/stage1.obj $ 17 | COMMAND ${CMAKE_OBJDUMP} -M intel -D ${CMAKE_CURRENT_BINARY_DIR}/stage1.obj > ${CMAKE_CURRENT_BINARY_DIR}/stage1.asm 18 | COMMAND ${CMAKE_OBJDUMP} -x ${CMAKE_CURRENT_BINARY_DIR}/stage1.obj > ${CMAKE_CURRENT_BINARY_DIR}/stage1.objdump 19 | COMMAND_EXPAND_LISTS 20 | BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/stage1.asm 21 | DEPENDS $ stage1Bootloader ${CMAKE_CURRENT_SOURCE_DIR}/stage1.ld) 22 | 23 | add_custom_command( 24 | OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/stage1.bin 25 | COMMAND ${CMAKE_OBJCOPY} -O binary ${CMAKE_CURRENT_BINARY_DIR}/stage1.obj ${CMAKE_CURRENT_BINARY_DIR}/stage1.bin 26 | DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/stage1.obj 27 | ) 28 | 29 | add_custom_target(stage1Binary 30 | DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/stage1.bin 31 | ) -------------------------------------------------------------------------------- /stage1_bootloader/src/asm/init.s: -------------------------------------------------------------------------------- 1 | # set intel syntax with no prefix on register nor immediate 2 | .intel_syntax noprefix 3 | 4 | # 5 | # We place the following code in the .text.init section so we can place 6 | # it at a location we want using the linker script (0x7c00) 7 | # 8 | .section .text.init 9 | 10 | # Set to 16-bit code mode. Since we are going to start in 16-bit real mode. 11 | .code16 12 | .globl start 13 | 14 | start: 15 | # 16 | # This jump is not strictly necessary, but some BIOS will start you at 0x07C0:0000 17 | # which is in fact the linear address as 0x0:7C00, but the range of jump will be 18 | # different. We will unify that with this long jump. 19 | # 20 | jmp 0:true_start 21 | 22 | .section .text 23 | 24 | true_start: 25 | cli # disable interrupts 26 | 27 | # We zero the segment registers 28 | xor ax, ax 29 | mov ds, ax 30 | mov es, ax 31 | mov ss, ax 32 | 33 | mov sp, 0x7C00 # SP is loaded with 0x7C00, we can use all that memory below code as stack. 34 | 35 | seta20.1: 36 | in al, 0x64 # Wait for not busy 37 | test al, 0x2 38 | jnz seta20.1 39 | 40 | mov al, 0xd1 # 0xd1 -> port 0x64 41 | out 0x64, al 42 | 43 | seta20.2: 44 | in al, 0x64 # Wait for not busy 45 | test al, 0x2 46 | jnz seta20.2 47 | 48 | mov al, 0xdf # 0xdf -> port 0x60 49 | out 0x60, al 50 | 51 | # We need to store our drive number onto the stack (DL) 52 | push dx # Let's just push the entire DX register 53 | 54 | # Clear Screen and set video mode to 2 55 | mov ah, 0 56 | mov al, 2 57 | int 0x10 58 | 59 | mov si, OFFSET loading_string 60 | call print_string 61 | 62 | # 63 | # Now that we are done printing, we can restore our DX register 64 | # and prepare for the BIOS call to load the next few sectors to 65 | # memory. 66 | # 67 | # First test to make sure LBA addressing mode is supported. This 68 | # is generally not supported on floppy drives 69 | # 70 | mov ah, 0x41 71 | mov bx, 0x55aa 72 | int 0x13 73 | jc error_no_ext_load 74 | cmp bx, 0xaa55 75 | jnz error_no_ext_load 76 | 77 | # If all is well, we will load the first 64x(512B) blocks to 0x7E00 78 | 79 | mov si, offset disk_address_block 80 | mov ah, 0x42 81 | int 0x13 82 | jc error_load # Carry is set if there is error while loading 83 | mov si, offset success_str 84 | call print_string 85 | 86 | # goto stage 2 87 | jmp 0:0x7E00 88 | end: 89 | hlt 90 | jmp end 91 | 92 | error_no_ext_load: 93 | mov si, offset error_str_no_ext 94 | call print_string 95 | jmp end 96 | 97 | error_load: 98 | mov si, offset error_str_load 99 | call print_string 100 | jmp end 101 | 102 | # Print string pointed to by DS:SI using 103 | # BIOS TTY output via int 10h/AH=0eh 104 | 105 | print_string: 106 | push ax 107 | push si 108 | push bx 109 | xor bx, bx 110 | mov ah, 0xe # int 10h 'print char' function 111 | 112 | repeat: 113 | lods al, [si] # Get character from string 114 | test al, al 115 | je done # If char is zero, end of string 116 | int 0x10 # Otherwise, print it 117 | jmp repeat 118 | done: 119 | pop bx 120 | pop si 121 | pop ax 122 | ret 123 | 124 | loading_string: 125 | .ascii "Loading Stage 2\r\n" 126 | .byte 0 127 | error_str_no_ext: 128 | .ascii "no EXT load\r\n" 129 | .byte 0 130 | error_str_load: 131 | .ascii "Failed to load sectors\r\n" 132 | .byte 0 133 | success_str: 134 | .ascii "Stage 2 Loaded. Now starting Stage2\r\n" 135 | .byte 0 136 | 137 | disk_address_block: 138 | .byte 0x10 # length of this block 139 | .byte 0x0 # reserved 140 | .short 64 # number of blocks = 32k/512b = 64 141 | .long 0x07E00000 # Target memory address 142 | .quad 1 # Starting Disk block 1, since we just need to skip the boot sector. 143 | 144 | -------------------------------------------------------------------------------- /stage1_bootloader/stage1.ld: -------------------------------------------------------------------------------- 1 | /* Linker Script for the Stage 1 Bootloader */ 2 | 3 | /* 4 | * we use this "boot" memory region to make sure we throw an 5 | * error if we ever go over 512 bytes in the 1 stage binary 6 | */ 7 | MEMORY { 8 | boot : ORIGIN = 0x7C00, LENGTH = 512 9 | } 10 | 11 | ENTRY(start) 12 | SECTIONS { 13 | text 0x7C00 : { 14 | *(.text.init) 15 | *(.text .text*) 16 | } >boot 17 | .rodata : { 18 | *(.rodata) 19 | } >boot 20 | 21 | .bss : { 22 | *(.bss) 23 | } >boot 24 | .data : { 25 | *(.data) 26 | } >boot 27 | .bootsign (0x7C00 + 510) : { 28 | BYTE(0x55) 29 | BYTE(0xAA) 30 | } >boot 31 | /DISCARD/ : { 32 | *(.debug*) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /stage2_bootloader/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | project(stage2_bootloader ASM C) 2 | 3 | add_library(stage2Bootloader OBJECT 4 | src/asm/stage2.s 5 | src/asm/protected_mode.s 6 | 7 | src/stage2_loader.c 8 | ) 9 | 10 | set(CMAKE_C_FLAGS "-static -fno-builtin -fno-pic -nostdinc -m32") 11 | set(CMAKE_ASM_FLAGS "-m32") 12 | 13 | set(CMAKE_C_FLAGS_RELEASE "-Os") 14 | set(CMAKE_C_FLAGS_DEBUG "-Os -ggdb3") 15 | 16 | 17 | add_custom_command( 18 | OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/stage2.obj 19 | COMMAND ${CMAKE_LINKER} -m elf_i386 -T ${CMAKE_CURRENT_SOURCE_DIR}/stage2.ld -o ${CMAKE_CURRENT_BINARY_DIR}/stage2.obj $ 20 | COMMAND ${CMAKE_OBJDUMP} -M intel -D ${CMAKE_CURRENT_BINARY_DIR}/stage2.obj > ${CMAKE_CURRENT_BINARY_DIR}/stage2.asm 21 | COMMAND ${CMAKE_OBJDUMP} -x ${CMAKE_CURRENT_BINARY_DIR}/stage2.obj > ${CMAKE_CURRENT_BINARY_DIR}/stage2.objdump 22 | COMMAND_EXPAND_LISTS 23 | BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/stage2.asm 24 | DEPENDS $ stage2Bootloader ${CMAKE_CURRENT_SOURCE_DIR}/stage2.ld 25 | ) 26 | 27 | add_custom_command( 28 | OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/stage2.bin 29 | COMMAND ${CMAKE_OBJCOPY} -O binary ${CMAKE_CURRENT_BINARY_DIR}/stage2.obj ${CMAKE_CURRENT_BINARY_DIR}/stage2.bin 30 | DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/stage2.obj 31 | ) 32 | 33 | add_custom_target(stage2Binary 34 | DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/stage2.bin 35 | ) -------------------------------------------------------------------------------- /stage2_bootloader/src/asm/protected_mode.s: -------------------------------------------------------------------------------- 1 | # set intel syntax with no prefix on register nor immediate 2 | .intel_syntax noprefix 3 | 4 | # Set to 16-bit code mode. We will prepare for protected mode here 5 | 6 | .extern stage2_cmain 7 | 8 | .code16 9 | .globl stage2_enter_protected 10 | 11 | stage2_enter_protected: 12 | lgdt gdtdesc 13 | mov eax, cr0 14 | or eax, 0x1 # PE bit 15 | mov cr0, eax 16 | 17 | jmp (1<<3):start32 # (1 << 3): code segment index * 8 bytes per segment descriptor 18 | 19 | .code32 20 | start32: 21 | 22 | mov ax, (2 << 3) 23 | mov ds, ax 24 | mov es, ax 25 | mov ss, ax 26 | 27 | xor ax, ax 28 | mov fs, ax 29 | mov gs, ax 30 | 31 | call stage2_cmain 32 | 33 | halt: 34 | hlt 35 | jmp halt 36 | 37 | .align 4 38 | gdt: 39 | # Null Entry 40 | .short 0, 0 41 | .byte 0,0,0,0 42 | 43 | # Code Segment 44 | .short 0xFFFF, 0 45 | .byte 0 46 | .byte 0b10011010 47 | .byte 0b11001111 48 | .byte 0 49 | 50 | # Data Segment 51 | .short 0xFFFF, 0 52 | .byte 0 53 | .byte 0b10010010 54 | .byte 0b11001111 55 | .byte 0 56 | 57 | gdtdesc: 58 | .short (gdtdesc - gdt - 1) 59 | .long gdt 60 | 61 | -------------------------------------------------------------------------------- /stage2_bootloader/src/asm/stage2.s: -------------------------------------------------------------------------------- 1 | # set intel syntax with no prefix on register nor immediate 2 | .intel_syntax noprefix 3 | 4 | # Set to 16-bit code mode. Since we are going to start in 16-bit real mode. 5 | .code16 6 | .globl stage2 7 | 8 | .extern stage2_enter_protected 9 | 10 | .section .text.start 11 | 12 | stage2: 13 | cli # disable interrupts 14 | 15 | # We zero the segment registers 16 | xor ax, ax 17 | mov ds, ax 18 | mov es, ax 19 | mov ss, ax 20 | 21 | mov sp, OFFSET stage2 # SP is loaded with 0x7E00, we can use all that memory below code as stack. 22 | 23 | # We need to store our drive number 24 | mov [drive_number], edx 25 | 26 | lea si, loading_string 27 | call print_string 28 | 29 | mov eax, 0x10000 30 | mov ebx, 512 31 | mov ecx, (1 + 64) 32 | call load_sector 33 | jc error 34 | 35 | mov si, OFFSET load_done_string 36 | call print_string 37 | jmp stage2_enter_protected 38 | 39 | error: 40 | mov si, OFFSET load_fail_string 41 | call print_string 42 | 43 | end: 44 | hlt 45 | jmp end 46 | 47 | # EAX: Base address of the load target 48 | # EBX: Number of sector to load 49 | # ECX: Start Sector 50 | .globl load_sector 51 | load_sector: 52 | push ebp 53 | mov bp, sp 54 | push esi 55 | push edx 56 | 57 | push eax # bp - 12 58 | push ebx # bp - 16 59 | push ecx # bp - 20 60 | 61 | loop: 62 | # load ebx 63 | test ebx, 64 64 | jae more_than64 65 | mov DWORD PTR [bp - 16], 0 66 | jmp calc_start_sector 67 | 68 | more_than64: 69 | mov ebx, 64 70 | sub DWORD PTR [bp - 16], 64 71 | 72 | calc_start_sector: 73 | mov ecx, DWORD PTR [bp - 20] 74 | add DWORD PTR [bp - 20], ebx 75 | 76 | # Store info into dab 77 | mov WORD PTR [dab_num_sectors], bx 78 | mov DWORD PTR [dab_start_block], ecx 79 | 80 | # calculate target address 81 | mov eax, DWORD PTR [bp - 12] 82 | mov ecx, ebx 83 | shl ecx, 9 # ecx * 512 84 | add DWORD PTR [bp - 12], ecx 85 | shr eax, 4 86 | mov WORD PTR [dab_target_seg], ax 87 | 88 | magic: 89 | mov dx, [drive_number] 90 | mov si, offset disk_address_block 91 | mov ah, 0x42 92 | int 0x13 93 | jc load_sector_end # fail 94 | 95 | mov ebx, DWORD PTR [bp - 16] 96 | test ebx, ebx 97 | jnz loop 98 | xor eax, eax # success 99 | 100 | load_sector_end: 101 | pop ecx 102 | add sp, 4 # skip eax 103 | pop ebx 104 | pop edx 105 | pop esi 106 | pop ebp 107 | ret 108 | 109 | print_string: 110 | push ax 111 | push si 112 | push bx 113 | xor bx, bx 114 | mov ah, 0xe # int 10h 'print char' function 115 | 116 | repeat: 117 | lods al, [si] # Get character from string 118 | test al, al 119 | je done # If char is zero, end of string 120 | int 0x10 # Otherwise, print it 121 | jmp repeat 122 | done: 123 | pop bx 124 | pop si 125 | pop ax 126 | ret 127 | 128 | .align 8 129 | disk_address_block: 130 | .byte 0x10 # length of this block 131 | .byte 0x0 # reserved 132 | dab_num_sectors: 133 | .short 0 # max 64 134 | dab_target_addr: 135 | .short 0 # Target memory address 136 | dab_target_seg: 137 | .short 0 138 | dab_start_block: 139 | .quad 0 # Starting Disk block 1, since we just need to skip the boot sector. 140 | 141 | loading_string: 142 | .ascii "In Stage 2\r\n" 143 | .byte 0 144 | 145 | load_fail_string: 146 | .ascii "Failed to load kernel" 147 | .byte 0 148 | 149 | load_done_string: 150 | .ascii "Done" 151 | .byte 0 152 | 153 | .align 4 154 | drive_number: 155 | .long 0 156 | -------------------------------------------------------------------------------- /stage2_bootloader/src/stage2_loader.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by user on 2/14/2022. 3 | // 4 | 5 | unsigned char* current_binary = ((unsigned char*) 0x10000); 6 | unsigned char* target_binary = ((unsigned char*) 0x100000); 7 | 8 | void (*entry) (void) = (void (*) (void))0x100000; 9 | 10 | __attribute__((noreturn)) 11 | void stage2_cmain(void) { 12 | for (unsigned int i = 0; i < 256 * 1024; ++i) { 13 | target_binary[i] = current_binary[i]; 14 | } 15 | entry(); 16 | for(;;) { 17 | } 18 | } -------------------------------------------------------------------------------- /stage2_bootloader/stage2.ld: -------------------------------------------------------------------------------- 1 | /* Linker Script for the Stage 2 Bootloader */ 2 | 3 | MEMORY { 4 | stage2 : ORIGIN = 0x7E00, LENGTH = 32k 5 | } 6 | 7 | ENTRY(stage2) 8 | SECTIONS { 9 | text : { 10 | *(.text.start) 11 | *(.text .text*) 12 | } >stage2 13 | .rodata : { 14 | *(.rodata .rodata.*) 15 | } >stage2 16 | 17 | .bss : { 18 | *(.bss .bss.*) 19 | } >stage2 20 | .data : { 21 | *(.data .data.*) 22 | } >stage2 23 | /DISCARD/ : { 24 | *(.debug*) 25 | } 26 | } 27 | --------------------------------------------------------------------------------