├── .gitignore ├── Makefile ├── README.md ├── asm.c ├── asm.h ├── bochsrc ├── bochsrcgrub ├── boot.h ├── bootloader └── cdrom │ ├── Makefile │ ├── bios.c │ ├── bios.h │ ├── bios_function.inc │ ├── blmain.c │ ├── config.h │ ├── elf.c │ ├── elf.h │ ├── iso9660.c │ ├── iso9660.h │ ├── linker.ld │ ├── stage1.asm │ ├── stage2.asm │ ├── util.c │ ├── util.h │ ├── vesa.c │ ├── vesa.h │ └── vesa_types.h ├── cmdline.txt ├── descriptor.inc ├── driver ├── keyboard.c ├── keyboard.h ├── pic8259a.c ├── pic8259a.h ├── pit8253.c ├── pit8253.h ├── vesa.c ├── vesa.h ├── vga.c ├── vga.h ├── vga_font.c └── vga_font.h ├── dwm.c ├── dwm.h ├── gdb_remote ├── idle.c ├── idle.h ├── interrupt.c ├── interrupt.h ├── io.c ├── io.h ├── iso └── boot │ ├── cmdline.txt │ └── grub │ └── grub.cfg ├── kmain.c ├── linker.ld ├── loader.asm ├── mm ├── README.md ├── buddy.c ├── buddy.h ├── mm.c ├── mm.h ├── page_fault.c ├── page_fault.h ├── page_list.c ├── page_list.h ├── paging.c └── paging.h ├── multiboot.h ├── paging.inc ├── pm.c ├── pm.h ├── runtime └── types.h ├── stdlib ├── bits.c ├── bits.h ├── memory.c ├── memory.h ├── string.c └── string.h ├── syscall.c ├── syscall.h ├── syscall_impl.c ├── syscall_impl.h ├── test ├── Makefile ├── test_buddy.c └── test_page_list.c ├── thread.c ├── thread.h ├── tty.c └── tty.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Assembler source code files 2 | *.s 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | *.elf 34 | *.iso 35 | *.bin 36 | 37 | # Makefile Dependencies files 38 | *.d 39 | 40 | stage1 41 | bochsout.txt 42 | *~ 43 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | AS = nasm 3 | LD = ld 4 | 5 | CFLAGS = -g -m32 -fno-stack-protector -fno-builtin -fno-asynchronous-unwind-tables \ 6 | -nostdlib -nostdinc -fno-PIC -fno-PIE -Wall -Wextra -I. 7 | ASFLAGS = -felf32 8 | LDFLAGS = -z max-page-size=0x1000 -melf_i386 -T linker.ld 9 | 10 | .PHONY: all 11 | all: os.iso grub.iso 12 | 13 | 14 | .PHONY: bootloader/cdrom/stage2.bin 15 | bootloader/cdrom/stage2.bin: bootloader/cdrom/stage2.asm stdlib/memory.o stdlib/string.o 16 | cd bootloader/cdrom && make stage2.bin 17 | 18 | .PHONY: bootloader/cdrom/stage1 19 | bootloader/cdrom/stage1: bootloader/cdrom/stage1.asm 20 | cd bootloader/cdrom && make stage1 21 | 22 | os.iso: kernel.elf bootloader/cdrom/stage1 bootloader/cdrom/stage2.bin cmdline.txt 23 | cp kernel.elf iso/boot 24 | cp cmdline.txt iso/boot 25 | cp bootloader/cdrom/stage1 iso/boot 26 | cp bootloader/cdrom/stage2.bin iso/boot 27 | mkisofs -R -b boot/stage1 -no-emul-boot -V WDOS -v -o os.iso iso 28 | 29 | loader.o: loader.asm 30 | $(AS) $(ASFLAGS) $^ -o $@ 31 | 32 | kmain.o: kmain.c 33 | $(CC) $(CFLAGS) -c $^ -o $@ 34 | 35 | asm.o: asm.c 36 | $(CC) $(CFLAGS) -c $^ -o $@ 37 | 38 | tty.o: tty.c 39 | $(CC) $(CFLAGS) -c $^ -o $@ 40 | 41 | pm.o: pm.c 42 | $(CC) $(CFLAGS) -c $^ -o $@ 43 | 44 | interrupt.o: interrupt.c 45 | $(CC) $(CFLAGS) -c $^ -o $@ 46 | 47 | syscall.o: syscall.c 48 | $(CC) $(CFLAGS) -c $^ -o $@ 49 | 50 | io.o: io.c 51 | $(CC) $(CFLAGS) -c $^ -o $@ 52 | 53 | syscall_impl.o: syscall_impl.c 54 | $(CC) $(CFLAGS) -c $^ -o $@ 55 | 56 | thread.o: thread.c 57 | $(CC) $(CFLAGS) -c $^ -o $@ 58 | 59 | idle.o: idle.c 60 | $(CC) $(CFLAGS) -c $^ -o $@ 61 | 62 | dwm.o: dwm.c 63 | $(CC) $(CFLAGS) -c $^ -o $@ 64 | 65 | driver/pic8259a.o: driver/pic8259a.c 66 | $(CC) $(CFLAGS) -c $^ -o $@ 67 | 68 | driver/pit8253.o: driver/pit8253.c 69 | $(CC) $(CFLAGS) -c $^ -o $@ 70 | 71 | driver/keyboard.o: driver/keyboard.c 72 | $(CC) $(CFLAGS) -c $^ -o $@ 73 | 74 | driver/vga.o: driver/vga.c 75 | $(CC) $(CFLAGS) -c $^ -o $@ 76 | 77 | driver/vesa.o: driver/vesa.c 78 | $(CC) $(CFLAGS) -c $^ -o $@ 79 | 80 | driver/vga_font.o: driver/vga_font.c 81 | $(CC) $(CFLAGS) -c $^ -o $@ 82 | 83 | stdlib/memory.o: stdlib/memory.c 84 | $(CC) $(CFLAGS) -c $^ -o $@ 85 | 86 | stdlib/string.o: stdlib/string.c 87 | $(CC) $(CFLAGS) -c $^ -o $@ 88 | 89 | stdlib/bits.o: stdlib/bits.c 90 | $(CC) $(CFLAGS) -c $^ -o $@ 91 | 92 | mm/page_list.o: mm/page_list.c 93 | $(CC) $(CFLAGS) -c $^ -o $@ 94 | 95 | mm/buddy.o: mm/buddy.c 96 | $(CC) $(CFLAGS) -c $^ -o $@ 97 | 98 | mm/mm.o: mm/mm.c 99 | $(CC) $(CFLAGS) -c $^ -o $@ 100 | 101 | mm/page_fault.o: mm/page_fault.c 102 | $(CC) $(CFLAGS) -c $^ -o $@ 103 | 104 | mm/paging.o: mm/paging.c 105 | $(CC) $(CFLAGS) -c $^ -o $@ 106 | 107 | kernel.elf: linker.ld loader.o kmain.o asm.o tty.o pm.o interrupt.o syscall.o io.o syscall_impl.o thread.o idle.o dwm.o driver/pic8259a.o driver/pit8253.o driver/keyboard.o driver/vga.o driver/vesa.o driver/vga_font.o stdlib/memory.o stdlib/string.o stdlib/bits.o mm/page_list.o mm/buddy.o mm/mm.o mm/page_fault.o mm/paging.o 108 | $(LD) $(LDFLAGS) $^ -o $@ 109 | 110 | grub.iso: kernel.elf iso/boot/grub/grub.cfg 111 | cp kernel.elf iso/boot 112 | grub-mkrescue --fonts=ascii --locales=en_GB --modules= \ 113 | --product-name=WDOS --product-version=1.0 -o grub.iso iso 114 | 115 | .PHONY: run 116 | run: os.iso 117 | qemu-system-x86_64 -s -cdrom os.iso -m 1024 118 | 119 | .PHONY: debug 120 | debug: os.iso 121 | bochs -f bochsrc 122 | 123 | .PHONY: rungrub 124 | rungrub: grub.iso 125 | qemu-system-x86_64 -s -cdrom grub.iso -m 1024 126 | 127 | .PHONY: debuggrub 128 | debuggrub: grub.iso 129 | bochs -f bochsrcgrub 130 | 131 | .PHONY: gdb 132 | gdb: 133 | gdb -x gdb_remote 134 | 135 | .PHONY: clean 136 | clean: 137 | -rm *.d 138 | -rm *.o 139 | -rm *.elf 140 | -rm *.iso 141 | -rm driver/*.o 142 | -rm mm/*.o 143 | -rm stdlib/*.o 144 | cd bootloader/cdrom && make clean 145 | 146 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # osdev 2 | os dev 3 | -------------------------------------------------------------------------------- /asm.c: -------------------------------------------------------------------------------- 1 | #include "asm.h" 2 | 3 | #include 4 | 5 | inline bool test_and_set(bool *x) 6 | { 7 | bool ret; 8 | asm volatile ("lock bts $0, %1\n" 9 | "adc $0, %0" // use setc instead? 10 | : "=g"(ret) 11 | : "m"(*x), "0"(0)); 12 | return ret; 13 | } 14 | 15 | inline bool test_and_reset(bool *x) 16 | { 17 | bool ret; 18 | asm volatile ("lock btr $0, %1\n" 19 | "adc $0, %0" 20 | : "=g"(ret) 21 | : "m"(*x), "0"(0)); 22 | return ret; 23 | } 24 | 25 | // returns old (*x) 26 | inline ureg_t compare_and_swap(ureg_t *x, ureg_t compare_value, ureg_t swap_value) 27 | { 28 | ureg_t ret; 29 | asm volatile ("lock cmpxchg %3, %1" 30 | : "=a"(ret) 31 | : "m"(*x), "a"(compare_value), "r"(swap_value)); 32 | return ret; 33 | } 34 | 35 | inline void spinlock_init(spinlock_t *l) 36 | { 37 | l->lock = false; 38 | } 39 | 40 | inline bool spinlock_try_lock(spinlock_t *l) 41 | { 42 | return !test_and_set(&l->lock); // if old value is 0, we get the lock 43 | } 44 | 45 | void spinlock_wait_and_lock(spinlock_t *l) 46 | { 47 | while (!spinlock_try_lock(l)) // loop until we get the lock 48 | { 49 | asm volatile ("pause"); 50 | } 51 | } 52 | 53 | void spinlock_release(spinlock_t *l) 54 | { 55 | l->lock = false; 56 | } 57 | -------------------------------------------------------------------------------- /asm.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_KERNEL_ASM_H_ 2 | #define _WDOS_KERNEL_ASM_H_ 3 | 4 | #include 5 | #include 6 | 7 | extern descriptor_entry_t gdt32_tss; 8 | extern gate_entry_t idt_ptr[256]; 9 | // unused: extern descriptor_entry_t gdt32_ptr[5]; 10 | extern const uint16_t SELECTOR_KERNEL_CODE; 11 | extern const uint16_t SELECTOR_KERNEL_DATA; 12 | extern const uint16_t SELECTOR_USER_CODE; 13 | extern const uint16_t SELECTOR_USER_DATA; 14 | extern const uint16_t SELECTOR_TSS; 15 | extern const uint32_t TSS_LENGTH; 16 | 17 | // loader.asm 18 | void enter_ring3(); 19 | uint32_t get_eflags(); 20 | 21 | bool test_and_set(bool *x); 22 | bool test_and_reset(bool *x); 23 | ureg_t compare_and_swap(ureg_t *x, ureg_t compare_value, ureg_t swap_value); 24 | 25 | typedef struct spinlock 26 | { 27 | volatile bool lock; 28 | } spinlock_t; 29 | 30 | void spinlock_init(spinlock_t *l); 31 | bool spinlock_try_lock(spinlock_t *l); 32 | void spinlock_wait_and_lock(spinlock_t *l); 33 | void spinlock_release(spinlock_t *l); 34 | 35 | #define save_flags(flags) \ 36 | do \ 37 | { \ 38 | asm volatile ("pushf\n" \ 39 | "pop %0" \ 40 | : "=g"(flags) \ 41 | : \ 42 | : "memory"); \ 43 | } \ 44 | while (0) 45 | 46 | #define restore_flags(flags) \ 47 | do \ 48 | { \ 49 | asm volatile ("push %0\n" \ 50 | "popf" \ 51 | : \ 52 | : "g"(flags) \ 53 | : "memory"); \ 54 | } \ 55 | while (0) 56 | 57 | #define cli() asm volatile ("cli") 58 | #define sti() asm volatile ("sti") 59 | 60 | #endif // _WDOS_KERNEL_ASM_H_ 61 | -------------------------------------------------------------------------------- /bochsrc: -------------------------------------------------------------------------------- 1 | megs: 16 2 | 3 | romimage: file=$BXSHARE/BIOS-bochs-latest 4 | vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest 5 | 6 | ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 7 | ata0-master: type=cdrom, path=os.iso, status=inserted 8 | 9 | boot: cdrom 10 | 11 | log: bochsout.txt 12 | 13 | mouse: enabled=0 14 | keyboard_mapping: enabled=1, map=$BXSHARE/keymaps/x11-pc-us.map 15 | -------------------------------------------------------------------------------- /bochsrcgrub: -------------------------------------------------------------------------------- 1 | megs: 16 2 | 3 | romimage: file=$BXSHARE/BIOS-bochs-latest 4 | vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest 5 | 6 | ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14 7 | ata0-master: type=cdrom, path=grub.iso, status=inserted 8 | 9 | boot: cdrom 10 | 11 | log: bochsout.txt 12 | 13 | mouse: enabled=0 14 | keyboard_mapping: enabled=1, map=$BXSHARE/keymaps/x11-pc-us.map 15 | -------------------------------------------------------------------------------- /boot.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_KERNEL_BOOT_H_ 2 | #define _WDOS_KERNEL_BOOT_H_ 3 | 4 | #include 5 | #include 6 | 7 | #define MULTIBOOT_NEEDED_FLAGS (MULTIBOOT_INFO_MEMORY | MULTIBOOT_INFO_BOOTDEV | \ 8 | MULTIBOOT_INFO_CMDLINE | MULTIBOOT_INFO_MEM_MAP) 9 | #define MEMORY_TYPE_USABLE 1 10 | #define MEMORY_TYPE_RESERVED 2 11 | 12 | typedef struct memory_map_long 13 | { 14 | union 15 | { 16 | struct 17 | { 18 | uint32_t base_low; 19 | uint32_t base_high; 20 | }; 21 | uint64_t base; 22 | }; 23 | union 24 | { 25 | struct 26 | { 27 | uint32_t length_low; 28 | uint32_t length_high; 29 | }; 30 | uint64_t length; 31 | }; 32 | } memory_map_long_t; 33 | 34 | #endif // _WDOS_KERNEL_BOOT_H_ 35 | -------------------------------------------------------------------------------- /bootloader/cdrom/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | AS = nasm 3 | LD = ld 4 | 5 | CFLAGS = -O2 -m32 -fno-stack-protector -fno-builtin -fno-asynchronous-unwind-tables \ 6 | -nostdlib -nostdinc -fno-PIC -fno-PIE -Wall -Wextra -I. -I../../ 7 | ASFLAGS = -felf32 8 | LDFLAGS = -z max-page-size=0x1000 -melf_i386 -T linker.ld 9 | 10 | .PHONY: all 11 | all: stage1 stage2.bin 12 | 13 | 14 | stage1: stage1.asm 15 | $(AS) $^ -o $@ 16 | 17 | stage2.bin: stage2.elf 18 | objcopy -j .text -O binary stage2.elf stage2.bin 19 | 20 | stage2.elf: linker.ld stage2.o blmain.o bios.o iso9660.o vesa.o elf.o util.o ../../stdlib/memory.o ../../stdlib/string.o 21 | $(LD) $(LDFLAGS) $^ -o $@ 22 | 23 | stage2.o: stage2.asm bios_function.inc 24 | $(AS) $(ASFLAGS) $< -o $@ 25 | 26 | blmain.o: blmain.c 27 | $(CC) $(CFLAGS) -c $^ -o $@ 28 | 29 | bios.o: bios.c 30 | $(CC) $(CFLAGS) -c $^ -o $@ 31 | 32 | iso9660.o: iso9660.c 33 | $(CC) $(CFLAGS) -c $^ -o $@ 34 | 35 | vesa.o: vesa.c 36 | $(CC) $(CFLAGS) -c $^ -o $@ 37 | 38 | elf.o: elf.c 39 | $(CC) $(CFLAGS) -c $^ -o $@ 40 | 41 | util.o: util.c 42 | $(CC) $(CFLAGS) -c $^ -o $@ 43 | 44 | .PHONY: clean 45 | clean: 46 | -rm *.bin 47 | -rm stage1 48 | -rm *.o 49 | -rm *.elf 50 | -rm *.iso 51 | 52 | -------------------------------------------------------------------------------- /bootloader/cdrom/bios.c: -------------------------------------------------------------------------------- 1 | #include "bios.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "util.h" 7 | 8 | #define FUNCTION_PRINT 1 9 | #define FUNCTION_GETCHAR 2 10 | #define FUNCTION_READ_SECTOR 3 11 | #define FUNCTION_MEMORY_MAP 4 12 | #define FUNCTION_DRIVE_PARAMS 5 13 | #define FUNCTION_VESA_CONTROL_INFO 6 14 | #define FUNCTION_VESA_MODE_INFO 7 15 | #define FUNCTION_SET_VESA_MODE 8 16 | 17 | // bios_function.inc 18 | int bios_function(uint32_t arg1, uint32_t arg2, uint32_t arg3); 19 | 20 | inline void *logic_to_linear(uint16_t seg, uint16_t offset) 21 | { 22 | return (void *)(((uint32_t)seg << 4) + (uint32_t)offset); 23 | } 24 | 25 | inline void linear_to_logic(void *addr, uint16_t *out_seg, uint16_t *out_offset) 26 | { 27 | // linear to seg:offset 28 | // 0x8abcd -> 0x8abc:000d 29 | *out_seg = ((uintptr_t)addr & 0xFFFFFFF0) >> 4; 30 | *out_offset = (uintptr_t)addr & 0x000F; 31 | } 32 | 33 | int print(const char *str) 34 | { 35 | if (!(0x10000 <= (uintptr_t)str && (uintptr_t)str <= 0x1ffff)) 36 | { 37 | die("Argument for str is out of range.\r\n"); 38 | } 39 | return bios_function(FUNCTION_PRINT, (uint32_t)str, 0); 40 | } 41 | 42 | int print_hex(uint32_t x) 43 | { 44 | static char buffer[sizeof(x) * 2 + 3] = { '0', 'x', 0 }; 45 | utoh(x, &buffer[2]); 46 | return print(buffer); 47 | } 48 | 49 | int print_bin(uint32_t x) 50 | { 51 | static char buffer[sizeof(x) * 8 + 3] = { '0', 'b', 0 }; 52 | utob(x, &buffer[2]); 53 | return print(buffer); 54 | } 55 | 56 | int print_int(int32_t x) 57 | { 58 | static char buffer[12] = { 0 }; // -2 147 483 647, 11 chars 59 | itos(x, buffer); 60 | return print(buffer); 61 | } 62 | 63 | int print_byte(uint8_t x) 64 | { 65 | static char buffer[sizeof(x) * 2 + 1] = { 0 }; 66 | btoh(x, buffer); 67 | return print(buffer); 68 | } 69 | 70 | int print_hex_long(uint64_t x) 71 | { 72 | static char buffer[sizeof(x) * 2 + 3] = { '0', 'x', 0 }; 73 | ultoh(x, &buffer[2]); 74 | return print(buffer); 75 | } 76 | 77 | uint8_t getchar() 78 | { 79 | static uint8_t buffer[2]; 80 | bios_function(FUNCTION_GETCHAR, (uint32_t)buffer, 0); 81 | return buffer[0]; 82 | } 83 | 84 | // buffer must be in [0x00000, 0xfffff] 85 | // count must be less than or equal to BIOS_DMA_MAX_LENGTH / sector_size. 86 | inline static int _read_sector(uint8_t dev, uint32_t lba, void *buffer, uint16_t count) 87 | { 88 | if (!count) 89 | { 90 | return OK; 91 | } 92 | static dap_t dap; 93 | dap.size = sizeof(dap); 94 | dap.reserved = 0; 95 | dap.count = count; 96 | dap.lba_low = lba; 97 | dap.lba_high = 0; 98 | linear_to_logic(buffer, &dap.dest_seg, &dap.dest_offset); 99 | return bios_function(FUNCTION_READ_SECTOR, dev, (uint32_t)&dap); 100 | } 101 | 102 | // buffer must be in [0x00000, 0xfffff] 103 | // count must be less than or equal to BIOS_DMA_MAX_LENGTH / sector_size. 104 | inline static int _read_sector_high_memory(uint8_t dev, uint32_t lba, void *dest, uint16_t count, 105 | void *buffer) 106 | { 107 | const uint16_t sector_size = get_sector_size(dev); 108 | 109 | int ret = _read_sector(dev, lba, buffer, count); 110 | if (ret != OK) 111 | { 112 | return ret; 113 | } 114 | memcpy(dest, buffer, count * sector_size); // copy to high memory 115 | return OK; 116 | } 117 | 118 | int read_sector(uint8_t dev, uint32_t lba, void *buffer, uint16_t count) 119 | { 120 | if ((uintptr_t)buffer > 0xfffff) 121 | { 122 | die("Argument for buffer is out of range.\r\n"); 123 | } 124 | 125 | const uint16_t sector_size = get_sector_size(dev); 126 | // how many sectors can we read at most at once? 127 | const uint16_t block_count = (uint16_t)(BIOS_DMA_MAX_LENGTH / (uint32_t)sector_size); 128 | assert(is_power_of_2(block_count)); 129 | 130 | uint8_t *buffer8 = buffer; 131 | for (int i = 0; i < (count / block_count); ++i) 132 | { 133 | int ret = _read_sector(dev, lba, buffer8, block_count); 134 | if (ret != OK) 135 | { 136 | return ret; 137 | } 138 | lba += block_count; 139 | buffer8 += block_count * sector_size; 140 | } 141 | // the last several sectors 142 | return _read_sector(dev, lba, buffer8, count & (block_count - 1)); 143 | } 144 | 145 | int read_sector_high_memory(uint8_t dev, uint32_t lba, void *dest, uint16_t count, void *buffer) 146 | { 147 | if ((uintptr_t)buffer > 0xfffff) 148 | { 149 | die("Argument for buffer is out of range.\r\n"); 150 | } 151 | 152 | const uint16_t sector_size = get_sector_size(dev); 153 | // how many sectors can we read at most at once? 154 | const uint16_t block_count = (uint16_t)(BIOS_DMA_MAX_LENGTH / (uint32_t)sector_size); 155 | assert(is_power_of_2(block_count)); 156 | 157 | uint8_t *dest8 = dest; 158 | for (int i = 0; i < (count / block_count); ++i) 159 | { 160 | int ret = _read_sector_high_memory(dev, lba, dest8, block_count, buffer); 161 | if (ret != OK) 162 | { 163 | return ret; 164 | } 165 | lba += block_count; 166 | dest8 += block_count * sector_size; 167 | print("."); 168 | } 169 | // the last several sectors 170 | return _read_sector_high_memory(dev, lba, dest8, count & (block_count - 1), buffer); 171 | } 172 | 173 | int read_memory_map(bios_memory_map_t *buffer) 174 | { 175 | if (!(0x10000 <= (uintptr_t)buffer && (uintptr_t)buffer <= 0x1ffff)) 176 | { 177 | die("Argument for buffer is out of range.\r\n"); 178 | } 179 | 180 | static uint32_t size; 181 | size = sizeof(bios_memory_map_t); // in size, out count 182 | if (bios_function(FUNCTION_MEMORY_MAP, (uint32_t)buffer, (uint32_t)&size) != OK) 183 | { 184 | return 0; 185 | } 186 | return size; 187 | } 188 | 189 | int get_drive_params(uint8_t dev, drive_params_t *buffer) 190 | { 191 | buffer->size = sizeof(drive_params_t); 192 | buffer->flags = 0; 193 | return bios_function(FUNCTION_DRIVE_PARAMS, dev, (uint32_t)buffer); 194 | } 195 | 196 | uint16_t get_boot_device_sector_size() 197 | { 198 | static drive_params_t dp; 199 | if (dp.size == 0) // not initialized 200 | { 201 | if (get_drive_params(boot_device, &dp) != OK) 202 | { 203 | dp.size = 0; 204 | return 0; 205 | } 206 | } 207 | return dp.sector_size; 208 | } 209 | 210 | uint16_t get_sector_size(uint8_t dev) 211 | { 212 | static drive_params_t dp; 213 | 214 | if (dev == boot_device) 215 | { 216 | return get_boot_device_sector_size(); 217 | } 218 | 219 | if (get_drive_params(dev, &dp) != OK) 220 | { 221 | return 0; 222 | } 223 | return dp.sector_size; 224 | } 225 | 226 | int get_vesa_control_info(vesa_control_info_t *buffer) 227 | { 228 | if (!(0x10000 <= (uintptr_t)buffer && (uintptr_t)buffer <= 0x1ffff)) 229 | { 230 | die("Argument for buffer is out of range.\r\n"); 231 | } 232 | return bios_function(FUNCTION_VESA_CONTROL_INFO, (uint32_t)buffer, 0); 233 | } 234 | 235 | int get_vesa_mode_info(uint16_t mode, vesa_mode_info_t *buffer) 236 | { 237 | if (!(0x10000 <= (uintptr_t)buffer && (uintptr_t)buffer <= 0x1ffff)) 238 | { 239 | die("Argument for buffer is out of range.\r\n"); 240 | } 241 | return bios_function(FUNCTION_VESA_MODE_INFO, mode, (uint32_t)buffer); 242 | } 243 | 244 | int set_vesa_mode(uint16_t mode) 245 | { 246 | return bios_function(FUNCTION_SET_VESA_MODE, (uint32_t)mode, 0); 247 | } 248 | -------------------------------------------------------------------------------- /bootloader/cdrom/bios.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_BOOTLOADER_CDROM_STAGE2_BIOS_H_ 2 | #define _WDOS_BOOTLOADER_CDROM_STAGE2_BIOS_H_ 3 | 4 | #include 5 | 6 | #include "vesa_types.h" 7 | 8 | #define BIOS_DMA_MAX_LENGTH 0x10000 9 | 10 | #define OK 0 11 | #define ERROR_UNKNOWN_FUNCTION 0xffff 12 | // ERROR_BIOS_ERROR: OTHER 13 | 14 | typedef struct dap 15 | { 16 | uint8_t size; 17 | uint8_t reserved; 18 | uint16_t count; 19 | uint16_t dest_offset; 20 | uint16_t dest_seg; 21 | union 22 | { 23 | struct 24 | { 25 | uint32_t lba_low; 26 | uint32_t lba_high; 27 | }; 28 | uint64_t lba; 29 | }; 30 | } dap_t; 31 | 32 | #define MEMORY_TYPE_USABLE 1 33 | #define MEMORY_TYPE_RESERVED 2 34 | // MEMORY_TYPE_UNUSABLE: OTHER 35 | 36 | typedef struct bios_memory_map 37 | { 38 | union 39 | { 40 | struct 41 | { 42 | uint32_t base_low; 43 | uint32_t base_high; 44 | }; 45 | uint64_t base; 46 | }; 47 | union 48 | { 49 | struct 50 | { 51 | uint32_t length_low; 52 | uint32_t length_high; 53 | }; 54 | uint64_t length; 55 | }; 56 | uint32_t type; 57 | } bios_memory_map_t; 58 | 59 | typedef struct drive_params 60 | { 61 | uint16_t size; 62 | uint16_t flags; 63 | uint32_t cylinders; 64 | uint32_t heads; 65 | uint32_t sectors_per_track; 66 | union 67 | { 68 | struct 69 | { 70 | uint32_t sector_count_low; 71 | uint32_t sector_count_high; 72 | }; 73 | uint64_t sector_count; 74 | }; 75 | uint16_t sector_size; 76 | } __attribute__((packed)) drive_params_t; 77 | 78 | extern uint8_t boot_device; // stage2.asm 79 | 80 | void *logic_to_linear(uint16_t seg, uint16_t offset); 81 | void linear_to_logic(void *addr, uint16_t *out_seg, uint16_t *out_offset); 82 | int print(const char *str); // str must be in [0x10000, 0x1ffff] 83 | int print_hex(uint32_t x); 84 | int print_bin(uint32_t x); 85 | int print_int(int32_t x); 86 | int print_byte(uint8_t x); 87 | int print_hex_long(uint64_t x); 88 | uint8_t getchar(); 89 | 90 | // buffer must be in [0x00000, 0xfffff] 91 | int read_sector(uint8_t dev, uint32_t lba, void *buffer, uint16_t count); 92 | 93 | // buffer must be in [0x00000, 0xfffff] 94 | int read_sector_high_memory(uint8_t dev, uint32_t lba, void *dest, uint16_t count, void *buffer); 95 | 96 | int read_memory_map(bios_memory_map_t *buffer); // buffer must be in [0x10000, 0x1ffff] 97 | int get_drive_params(uint8_t dev, drive_params_t *buffer); 98 | uint16_t get_boot_device_sector_size(); 99 | uint16_t get_sector_size(uint8_t dev); 100 | int get_vesa_control_info(vesa_control_info_t *buffer); 101 | int get_vesa_mode_info(uint16_t mode, vesa_mode_info_t *buffer); 102 | int set_vesa_mode(uint16_t mode); 103 | 104 | #endif // _WDOS_BOOTLOADER_CDROM_STAGE2_BIOS_H_ 105 | -------------------------------------------------------------------------------- /bootloader/cdrom/bios_function.inc: -------------------------------------------------------------------------------- 1 | bios_function: 2 | push ebp 3 | mov ebp, esp 4 | push ebx 5 | push edi 6 | push esi 7 | 8 | mov ebx, [ebp + 8] ; first argument: function 9 | mov edi, [ebp + 12] ; second argument 10 | mov esi, [ebp + 16] ; third argument 11 | 12 | jmp selector_code16:_prepare_go_to_16 - $$ 13 | 14 | [bits 16] 15 | _prepare_go_to_16: 16 | mov ax, selector_data16 17 | mov ds, ax 18 | mov es, ax 19 | mov fs, ax 20 | mov gs, ax 21 | mov ss, ax 22 | 23 | ; disable protect mode 24 | mov eax, cr0 25 | and al, 0b11111110 26 | mov cr0, eax 27 | 28 | jmp 0x1000:_start16 - $$ 29 | _start16: 30 | 31 | cli 32 | 33 | mov ax, cs 34 | mov ds, ax 35 | mov es, ax 36 | mov fs, ax 37 | mov gs, ax 38 | xor ax, ax 39 | mov ss, ax 40 | 41 | ; A20 42 | in al, 0x92 43 | and al, 0b11111101 44 | out 0x92, al 45 | 46 | ; do function 47 | cmp bx, 1 48 | je function_print 49 | 50 | cmp bx, 2 51 | je function_getchar 52 | 53 | cmp bx, 3 54 | je function_read_sector 55 | 56 | cmp bx, 4 57 | je function_memory_map 58 | 59 | cmp bx, 5 60 | je function_drive_params 61 | 62 | cmp bx, 6 63 | je function_vesa_control_info 64 | 65 | cmp bx, 7 66 | je function_vesa_mode_info 67 | 68 | cmp bx, 8 69 | je function_set_vesa_mode 70 | 71 | function_default: 72 | xor bx, bx 73 | not bx ; error 0xffff: unknown function 74 | jmp function_end 75 | 76 | function_print: 77 | xor bx, bx ; bx = 0 78 | mov si, di ; high 16 bits of edi are ignored 79 | print_loop: 80 | cld 81 | lodsb 82 | test al, al 83 | jz print_return 84 | mov ah, 0x0e ; print 85 | int 0x10 ; bios print 86 | jc bios_error 87 | jmp print_loop 88 | print_return: 89 | jmp function_end 90 | 91 | function_getchar: 92 | xor bx, bx ; bx = 0 93 | xor ah, ah ; ah = 0 94 | int 0x16 ; bios get char 95 | jc bios_error 96 | mov [di], ax ; high 16 bits of edi are ignored 97 | jmp function_end 98 | 99 | function_read_sector: 100 | xor bx, bx ; bx = 0 101 | mov dx, di 102 | mov ah, 0x42 ; extended read sector 103 | ; dap is at ds:si 104 | int 0x13 ; bios function 105 | jc bios_error 106 | jmp function_end 107 | 108 | memory_map_count dd 0 109 | function_memory_map: 110 | xor ebx, ebx ; first record 111 | mov dword [memory_map_count - $$], ebx ; memory_map_count = 0 112 | memory_map_loop: 113 | mov eax, 0xe820 ; read memory info 114 | mov ecx, [si] ; in sizeof(memory_map_t) 115 | mov edx, 0x534d4150 ; "SMAP" 116 | ; destination = es:di 117 | int 0x15 ; bios function 118 | jc bios_error 119 | cmp eax, 0x534d4150 120 | jne bios_error 121 | inc dword [memory_map_count - $$] ; ++memory_map_count 122 | test ebx, ebx ; is last record? 123 | jz memory_map_return 124 | add di, [si] ; next memory_map_t 125 | jmp memory_map_loop 126 | memory_map_return: 127 | mov eax, dword [memory_map_count - $$] 128 | mov [si], eax ; out count 129 | jmp function_end 130 | 131 | function_drive_params: 132 | xor bx, bx ; bx = 0 133 | mov dx, di 134 | mov ah, 0x48 ; extended get drive parameters 135 | ; data struct is at ds:si 136 | int 0x13 ; bios function 137 | jc bios_error 138 | jmp function_end 139 | 140 | function_vesa_control_info: 141 | ; buffer = es:di 142 | mov ax, 0x4f00 ; get SuperVGA info 143 | int 0x10 ; bios function 144 | jc bios_error 145 | cmp ax, 0x004f 146 | jne bios_error 147 | xor bx, bx 148 | jmp function_end 149 | 150 | function_vesa_mode_info: 151 | mov cx, di 152 | mov di, si 153 | mov ax, 0x4f01 ; get SuperVGA mode info 154 | int 0x10 ; bios function 155 | jc bios_error 156 | cmp ax, 0x004f 157 | jne bios_error 158 | xor bx, bx 159 | jmp function_end 160 | 161 | function_set_vesa_mode: 162 | mov bx, di 163 | mov di, si 164 | mov ax, 0x4f02 ; set SuperVGA video mode 165 | int 0x10 ; bios function 166 | jc bios_error 167 | cmp ax, 0x004f 168 | jne bios_error 169 | xor bx, bx 170 | jmp function_end 171 | 172 | bios_error: 173 | mov bx, ax ; bx = bios error = ax 174 | 175 | function_end: 176 | 177 | lgdt [ds:gdt32_reg - $$] 178 | 179 | ; A20 180 | in al, 0x92 181 | or al, 0b00000010 182 | out 0x92, al 183 | 184 | ; enable protect mode 185 | mov eax, cr0 186 | or eax, 1 187 | mov cr0, eax 188 | 189 | ; return to protect mode 190 | xor eax, eax 191 | mov ax, cs 192 | shl eax, 4 193 | add eax, _return_to32 - $$ 194 | mov [ds:ljmp_address2 - $$], eax ; logical address cs:_return_to32 to physical address 195 | 196 | ; ljmp dword selector_code:_return_to32 197 | db 0x66 ; operand-size override 198 | db 0xea ; ljmp 199 | ljmp_address2 dd 0xdeadbeef ; will be changed 200 | dw selector_code 201 | 202 | [bits 32] 203 | 204 | _return_to32: 205 | cli 206 | 207 | mov ax, selector_data 208 | mov ds, ax 209 | mov es, ax 210 | mov fs, ax 211 | mov gs, ax 212 | mov ss, ax 213 | 214 | and ebx, 0x0000ffff 215 | mov eax, ebx ; return bx 216 | pop esi 217 | pop edi 218 | pop ebx 219 | leave 220 | ret 221 | -------------------------------------------------------------------------------- /bootloader/cdrom/blmain.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | #include "config.h" 8 | #include "util.h" 9 | #include "bios.h" 10 | #include "iso9660.h" 11 | #include "vesa.h" 12 | #include "elf.h" 13 | 14 | extern uint8_t _bss_begin, _bss_end; 15 | void *bss_begin = &_bss_begin, *bss_end = &_bss_end; 16 | 17 | const char *const cmdline_file = "/boot/cmdline.txt"; 18 | const char *const kernel_file = "/boot/kernel.elf"; 19 | 20 | void *const sector_buffer = (void *)0x20000; // length: 64 KiB 21 | 22 | char kernel_cmdline[256]; 23 | 24 | uint32_t memory_map_count; 25 | bios_memory_map_t memory_map[32]; 26 | 27 | multiboot_info_t mb_info; 28 | vesa_control_info_t vesa_control_info; 29 | vesa_mode_info_t vesa_mode_info; 30 | 31 | 32 | void load_memory_map() 33 | { 34 | print("Loading system memory map... "); 35 | memory_map_count = read_memory_map(memory_map); 36 | if (!memory_map_count) 37 | { 38 | die("\r\nLoad system memory map failed.\r\n"); 39 | } 40 | print_int(memory_map_count); 41 | print(" entries.\r\n"); 42 | print("+----------------------------------------------------+\r\n" 43 | "| SYSTEM MEMORY MAP |\r\n" 44 | "+----------------------------------------------------+\r\n" 45 | " BASE LIMIT TYPE USABLE?\r\n"); 46 | mb_info.mem_lower = mb_info.mem_upper = 0; 47 | #ifndef X86_64 48 | bool has_warning = false; 49 | #endif 50 | for (uint32_t i = 0; i < memory_map_count; ++i) 51 | { 52 | uint64_t limit = memory_map[i].base - 1 + memory_map[i].length; 53 | uint32_t limit_low = memory_map[i].base_low - 1 + memory_map[i].length_low; 54 | print_byte((uint8_t)i); 55 | print(": "); 56 | print_hex_long(memory_map[i].base); 57 | print("~"); 58 | print_hex_long(memory_map[i].base - 1 + memory_map[i].length); 59 | print(" "); 60 | print_int(memory_map[i].type); 61 | if (memory_map[i].type == MEMORY_TYPE_USABLE) 62 | { 63 | #ifndef X86_64 64 | if (!memory_map[i].base_high && !(limit & 0xFFFFFFFF00000000ULL)) 65 | { 66 | #endif 67 | print(" YES"); 68 | if (limit_low <= LOW_MEMORY_LIMIT) // in 640 KiB 69 | { 70 | mb_info.mem_lower = (limit_low + 1) >> 10; 71 | } 72 | else if (!mb_info.mem_upper && memory_map[i].base_low >= HIGH_MEMORY_BASE) 73 | { 74 | // first upper memory hole 75 | mb_info.mem_upper = memory_map[i].length_low >> 10; 76 | } 77 | #ifndef X86_64 78 | } 79 | else 80 | { 81 | has_warning = true; 82 | print(" NO*"); 83 | } 84 | #endif 85 | } 86 | else 87 | { 88 | print(" NO"); 89 | } 90 | print("\r\n"); 91 | if ((i & 0xf) == 0xf) 92 | { 93 | debug_pause(); 94 | } 95 | } 96 | #ifndef X86_64 97 | if (has_warning) 98 | { 99 | print("* Warning: High memory is not usable for 32-bit system.\r\n"); 100 | } 101 | #endif 102 | print("mem_lower="); 103 | print_int(mb_info.mem_lower); 104 | print(" KiB, mem_upper="); 105 | print_int(mb_info.mem_upper); 106 | print(" KiB\r\n"); 107 | } 108 | 109 | void fill_multiboot_info() 110 | { 111 | mb_info.flags = MULTIBOOT_INFO_FLAGS; 112 | // mem_lower and mem_upper are filled by load_memory_map() 113 | mb_info.boot_device = MKBOOT_DEVICE(boot_device, UNUSED_PARTITION, 114 | UNUSED_PARTITION, UNUSED_PARTITION); 115 | mb_info.cmdline = (uint32_t)kernel_cmdline; 116 | 117 | // copy memory_map 118 | assert(memory_map_count); 119 | mb_info.mmap_length = memory_map_count * sizeof(multiboot_memory_map_t); 120 | multiboot_memory_map_t *mb_mmap = 121 | (multiboot_memory_map_t *)palloc(mb_info.mmap_length); 122 | for (uint32_t i = 0; i < memory_map_count; ++i) 123 | { 124 | mb_mmap[i].size = sizeof(mb_mmap[i]) - sizeof(mb_mmap[i].size); 125 | mb_mmap[i].addr = memory_map[i].base; 126 | mb_mmap[i].len = memory_map[i].length; 127 | mb_mmap[i].type = memory_map[i].type; 128 | } 129 | mb_info.mmap_addr = (uint32_t)mb_mmap; 130 | 131 | // vbe_control_info, vbe_mode_info and vbe_mode will be filled by init_vesa() 132 | } 133 | 134 | void *read_all_extent(directory_record_t *file, void *buffer) 135 | { 136 | const uint16_t sector_size = get_boot_device_sector_size(); 137 | const uint32_t file_lba = file->extent_location, file_length = file->data_length; 138 | 139 | if (read_sector(boot_device, file_lba, buffer, 140 | ((file_length - 1 + sector_size) / sector_size)) != OK) 141 | { 142 | die("\r\nRead error.\r\n"); 143 | } 144 | return (void *)((uint8_t *)buffer + file_length); 145 | } 146 | 147 | directory_record_t *find_file(const char *path) 148 | { 149 | if (strlen(path) > 255) 150 | { 151 | die("\r\nPath is too long.\r\n"); 152 | } 153 | 154 | // load root directory 155 | vd_primary_t *pvd = (vd_primary_t *)sector_buffer; 156 | for (uint32_t lba = FIRST_LBA; ; ++lba) 157 | { 158 | read_sector(boot_device, lba, sector_buffer, 1); // might fail 159 | print("."); 160 | 161 | // check magic "CD001" 162 | if (memcmp(pvd->std_ident, ISO9660_MAGIC, ISO9660_MAGIC_LENGTH)) 163 | { 164 | die("\r\nInvalid CD-ROM.\r\n"); 165 | } 166 | 167 | if (pvd->type == VD_TYPE_PRIMARY) 168 | { 169 | // found 170 | break; 171 | } 172 | else if (pvd->type == VD_TYPE_TERMINATOR) 173 | { 174 | die("\r\nNo primary volume descriptor.\r\n"); 175 | } 176 | } 177 | 178 | const char *iter = path; 179 | if (*iter == '/') 180 | { 181 | ++iter; 182 | } 183 | else 184 | { 185 | die("\r\nRelative path is not supported.\r\n"); 186 | } 187 | 188 | if (!*iter) // path == "/" 189 | { 190 | // "/" is not a file. 191 | return NULL; 192 | } 193 | 194 | directory_record_t *end = read_all_extent(&pvd->root_directory, sector_buffer); 195 | directory_record_t *begin = sector_buffer; 196 | print("."); 197 | 198 | static char ident[256]; 199 | while (iter) 200 | { 201 | iter = strsplit(iter, '/', ident); 202 | to_ident(ident); 203 | 204 | directory_record_t *rec = find_record(ident, begin, end); 205 | if (!rec) // not found 206 | { 207 | return NULL; 208 | } 209 | 210 | if (!iter) // is last 211 | { 212 | if (rec->flags & ISO9660_FLAG_DIRECTORY) 213 | { 214 | // not a file 215 | return NULL; 216 | } 217 | return rec; 218 | } 219 | 220 | if (!(rec->flags & ISO9660_FLAG_DIRECTORY)) 221 | { 222 | // not a directory 223 | return NULL; 224 | } 225 | end = read_all_extent(rec, sector_buffer); // next level 226 | begin = sector_buffer; 227 | print("."); 228 | } 229 | 230 | return NULL; 231 | } 232 | 233 | void load_cmdline() 234 | { 235 | print("Loading cmdline file "); 236 | print(cmdline_file); 237 | print("."); 238 | directory_record_t *rec = find_file(cmdline_file); 239 | if (!rec) 240 | { 241 | die("\r\nFile not found.\r\n"); 242 | } 243 | if (rec->data_length >= sizeof(kernel_cmdline)) 244 | { 245 | die("\r\nCmdline is too long.\r\n"); 246 | } 247 | uint32_t length = rec->data_length; 248 | read_all_extent(rec, sector_buffer); 249 | memcpy(kernel_cmdline, sector_buffer, length); 250 | for (char *p = kernel_cmdline; *p; ++p) 251 | { 252 | if (*p == '\r' || *p == '\n') 253 | { 254 | *p = 0; 255 | break; 256 | } 257 | } 258 | print(" "); 259 | print_int(strlen(kernel_cmdline)); 260 | print(" bytes read.\r\n"); 261 | } 262 | 263 | int load_segment(uint32_t lba, uint32_t offset, void *dest, uint32_t length) 264 | { 265 | const uint16_t sector_size = get_boot_device_sector_size(); 266 | assert(offset < sector_size); 267 | int ret; 268 | 269 | // |......***.|..........|..........|..........| 270 | // |......****|***.......|..........|..........| 271 | /// first mid last 272 | // |......****|**********|***.......|..........| 273 | 274 | ret = read_sector(boot_device, lba, sector_buffer, 1); // first sector 275 | if (ret != OK) 276 | { 277 | return ret; 278 | } 279 | print("."); 280 | 281 | if (length <= sector_size - offset) 282 | { 283 | memcpy(dest, sector_buffer, length); 284 | return OK; 285 | // done 286 | } 287 | else 288 | { 289 | memcpy(dest, sector_buffer, sector_size - offset); 290 | ++lba; 291 | dest = (void *)((uint8_t *)dest + sector_size - offset); 292 | length -= sector_size - offset; 293 | } 294 | 295 | // mid 296 | ret = read_sector_high_memory(boot_device, lba, dest, length / sector_size, sector_buffer); 297 | if (ret != OK) 298 | { 299 | return ret; 300 | } 301 | print("."); 302 | lba += length / sector_size; 303 | dest = (void *)((uint8_t *)dest + (length - length % sector_size)); 304 | length = length % sector_size; 305 | 306 | ret = read_sector(boot_device, lba, sector_buffer, 1); // last sector 307 | if (ret != OK) 308 | { 309 | return ret; 310 | } 311 | print("."); 312 | memcpy(dest, sector_buffer, length % sector_size); 313 | 314 | return OK; 315 | } 316 | 317 | kernel_entry_t load_kernel(multiboot_header_t *out_mb_header) 318 | { 319 | const uint16_t sector_size = get_boot_device_sector_size(); 320 | print("Loading kernel "); 321 | print(kernel_file); 322 | print("."); 323 | directory_record_t *rec = find_file(kernel_file); 324 | if (!rec) 325 | { 326 | die("\r\nFile not found.\r\n"); 327 | } 328 | 329 | uint32_t elf_lba = rec->extent_location, elf_length = rec->data_length; 330 | 331 | print(" "); 332 | print_int(elf_length); 333 | print(" bytes.\r\n"); 334 | 335 | Elf32_Ehdr elf_header; 336 | assert(read_sector(boot_device, elf_lba, sector_buffer, 1) == OK); 337 | print("."); 338 | memcpy(&elf_header, sector_buffer, sizeof(Elf32_Ehdr)); 339 | 340 | if (memcmp(elf_header.e_ident, ELFMAG, SELFMAG)) 341 | { 342 | die("\r\nNot an ELF file.\r\n"); 343 | } 344 | 345 | if (elf_header.e_type != ET_EXEC) 346 | { 347 | die("\r\nNot an executable ELF file.\r\n"); 348 | } 349 | 350 | kernel_entry_t kernel_entry = (kernel_entry_t)elf_header.e_entry; 351 | uint8_t code[] = { 0xeb, 0xfe /* jmp $ */, 0xcc /* int3 */ }; // default kernel code 352 | memcpy(kernel_entry, code, sizeof(code)); 353 | 354 | print("kernel_entry="); 355 | print_hex(kernel_entry); 356 | print("\r\n"); 357 | 358 | assert(elf_header.e_phnum); 359 | assert(elf_header.e_phentsize == sizeof(Elf32_Phdr)); 360 | 361 | Elf32_Phdr *program_header = 362 | (Elf32_Phdr *)palloc(elf_header.e_phentsize * elf_header.e_phnum); 363 | memcpy(program_header, (uint8_t *)sector_buffer + elf_header.e_phoff, 364 | elf_header.e_phentsize * elf_header.e_phnum); 365 | 366 | print("+-------------------------------------------------------------+\r\n" 367 | "| PROGRAM HEADERS |\r\n" 368 | "+-------------------------------------------------------------+\r\n" 369 | " TYPE OFFSET VIRT ADDR PHY ADDR FILE SIZE MEM SIZE \r\n"); 370 | for (int i = 0; i < elf_header.e_phnum; ++i) 371 | { 372 | print_byte((uint8_t)i); 373 | print(": "); 374 | if (program_header[i].p_type == PT_LOAD) 375 | { 376 | print("LOAD"); 377 | } 378 | else 379 | { 380 | print("????"); 381 | } 382 | print(" "); 383 | print_hex(program_header[i].p_offset); 384 | print(" "); 385 | print_hex(program_header[i].p_vaddr); 386 | print(" "); 387 | print_hex(program_header[i].p_paddr); 388 | print(" "); 389 | print_hex(program_header[i].p_filesz); 390 | print(" "); 391 | print_hex(program_header[i].p_memsz); 392 | print("\r\n"); 393 | 394 | if (program_header[i].p_type == PT_LOAD && 395 | program_header[i].p_paddr - 1 + program_header[i].p_memsz >= 396 | (HIGH_MEMORY_BASE + (mb_info.mem_upper << 10))) 397 | { 398 | die("\r\nNo memory.\r\n"); 399 | } 400 | } 401 | 402 | // compatible with multiboot 403 | // check multiboot header 404 | uint32_t ph0_offset = program_header[0].p_offset; 405 | assert(read_sector(boot_device, elf_lba + ph0_offset / sector_size, sector_buffer, 1) == OK); 406 | 407 | multiboot_header_t *mb_header = 408 | (multiboot_header_t *)((uint8_t *)sector_buffer + ph0_offset % sector_size); 409 | 410 | if (mb_header->magic != MULTIBOOT_HEADER_MAGIC) 411 | { 412 | die("\r\nELF file is not multiboot compatible.\r\n"); 413 | } 414 | 415 | if (-(mb_header->magic + mb_header->flags) != mb_header->checksum) 416 | { 417 | die("\r\nChecksum is incorrect.\r\n"); 418 | } 419 | 420 | memcpy(out_mb_header, mb_header, sizeof(multiboot_header_t)); 421 | 422 | print("flags="); 423 | print_bin(mb_header->flags); 424 | print("\r\n"); 425 | 426 | if (mb_header->flags & MULTIBOOT_UNSUPPORTED_FLAGS) 427 | { 428 | die("\r\nUnsupported flag(s) found.\r\n"); 429 | } 430 | 431 | for (int i = 0; i < elf_header.e_phnum; ++i) 432 | { 433 | if (program_header[i].p_type == PT_LOAD) 434 | { 435 | print("Loading "); 436 | print_byte((uint8_t)i); 437 | print("."); 438 | int ret = load_segment(elf_lba + program_header[i].p_offset / sector_size, 439 | program_header[i].p_offset % sector_size, 440 | (void *)program_header[i].p_paddr, 441 | program_header[i].p_filesz); 442 | if (ret != OK) 443 | { 444 | die("\r\nRead error.\r\n"); 445 | } 446 | if (program_header[i].p_filesz < program_header[i].p_memsz) 447 | { 448 | memset((void *)(program_header[i].p_paddr + program_header[i].p_filesz), 449 | 0, program_header[i].p_memsz - program_header[i].p_filesz); 450 | print("init .bss"); 451 | } 452 | print("\r\n"); 453 | } 454 | } 455 | 456 | return kernel_entry; 457 | } 458 | 459 | void print_vesa_mode_info(vesa_mode_info_t *info) 460 | { 461 | print_int(info->x_res); 462 | print("x"); 463 | print_int(info->y_res); 464 | print(", "); 465 | print_int(info->bpp); 466 | print("bpp, linear fb: "); 467 | print((info->attr & VESA_MODE_ATTR_LINEAR_FRAMEBUFFER) ? "YES" : "NO"); 468 | print(", graphics: "); 469 | print((info->attr & VESA_MODE_ATTR_GRAPHICS) ? "YES" : "NO"); 470 | print(", mem_model="); 471 | print_int(info->memory_model); 472 | } 473 | 474 | bool init_vesa(multiboot_header_t *mb_header) 475 | { 476 | print("kernel requires video mode: "); 477 | print_int(mb_header->width); 478 | print("x"); 479 | print_int(mb_header->height); 480 | print(", "); 481 | print_int(mb_header->depth); 482 | print("bpp\r\n"); 483 | 484 | memset(&vesa_control_info, 0, sizeof(vesa_control_info)); 485 | #ifdef USE_VBE2 486 | memcpy(vesa_control_info.magic, "VBE2", 4); 487 | #endif 488 | 489 | if (get_vesa_control_info(&vesa_control_info) != OK) 490 | { 491 | print("Warning: Get VESA control info failed.\r\n"); 492 | return false; 493 | } 494 | 495 | static char buffer[256] = {0}; 496 | 497 | memcpy(buffer, vesa_control_info.magic, 4); 498 | if (memcmp(buffer, VESA_MAGIC, VESA_MAGIC_LENGTH)) 499 | { 500 | print("Warning: Get VESA control info failed.\r\n"); 501 | return false; 502 | } 503 | 504 | print("+--------------+\r\n" 505 | "| VESA INFO |\r\n" 506 | "+--------------+\r\n"); 507 | print("magic="); 508 | print(buffer); 509 | print(", version="); 510 | print_int(vesa_control_info.version >> 8); 511 | print("."); 512 | print_int(vesa_control_info.version & 0xff); 513 | print("\r\n"); 514 | strcpy(buffer, logic_to_linear(vesa_control_info.oem_string_seg, 515 | vesa_control_info.oem_string_offset)); 516 | print("OEM string=\r\n "); 517 | print(buffer); 518 | print("\r\ntotal_memory="); 519 | print_int((uint32_t)vesa_control_info.total_memory * 64); 520 | print(" KiB, supported modes:\r\n"); 521 | 522 | debug_pause(); 523 | 524 | uint16_t *modes = 525 | (uint16_t *)(logic_to_linear(vesa_control_info.video_mode_seg, 526 | vesa_control_info.video_mode_offset)); 527 | 528 | uint16_t vesa_mode_selected = VESA_MODE_INVALID; 529 | uint32_t vesa_mode_diff = (uint32_t)-1; 530 | 531 | for (size_t i = 0; modes[i] != VESA_MODE_TERMINATOR; ++i) 532 | { 533 | #ifndef NDEBUG 534 | print(" "); 535 | print_byte(modes[i] >> 8); 536 | print_byte(modes[i] & 0xff); 537 | print(": "); 538 | #endif 539 | memset(&vesa_mode_info, 0, sizeof(vesa_mode_info)); 540 | if (get_vesa_mode_info(modes[i], &vesa_mode_info) == OK) 541 | { 542 | #ifndef NDEBUG 543 | print_vesa_mode_info(&vesa_mode_info); 544 | #endif 545 | if ((vesa_mode_info.attr & VESA_MODE_ATTR_LINEAR_FRAMEBUFFER) && 546 | (vesa_mode_info.attr & VESA_MODE_ATTR_GRAPHICS) && 547 | vesa_mode_info.memory_model == VESA_MODE_MEMORY_MODEL_DIRECTCOLOR) 548 | { 549 | uint32_t diff = 550 | mode_diff(mb_header->width, mb_header->height, mb_header->depth, 551 | vesa_mode_info.x_res, vesa_mode_info.y_res, vesa_mode_info.bpp); 552 | if (!diff) 553 | { 554 | vesa_mode_selected = modes[i]; 555 | vesa_mode_diff = diff; 556 | // break; 557 | } 558 | else if (diff < vesa_mode_diff) 559 | { 560 | vesa_mode_selected = modes[i]; 561 | vesa_mode_diff = diff; 562 | } 563 | } 564 | } 565 | else 566 | { 567 | print("Warning: Set VESA mode info failed."); 568 | } 569 | print("\r\n"); 570 | if ((i & 0xf) == 0xf) 571 | { 572 | debug_pause(); 573 | } 574 | } 575 | print("END\r\n"); 576 | debug_pause(); 577 | 578 | if (vesa_mode_selected == 0xffff || vesa_mode_diff == (uint32_t)-1) 579 | { 580 | print("Warning: No satisfied mode.\r\n"); 581 | return false; 582 | } 583 | else 584 | { 585 | memset(&vesa_mode_info, 0, sizeof(vesa_mode_info)); 586 | assert(get_vesa_mode_info(vesa_mode_selected, &vesa_mode_info) == OK); 587 | print("Selected mode:\r\n "); 588 | print_byte(vesa_mode_selected >> 8); 589 | print_byte(vesa_mode_selected & 0xff); 590 | print(": "); 591 | print_vesa_mode_info(&vesa_mode_info); 592 | print("\r\n"); 593 | print("base="); 594 | print_hex(vesa_mode_info.base); 595 | print("\r\n"); 596 | print("Going to graphics mode... "); 597 | debug_pause(); 598 | } 599 | 600 | if (set_vesa_mode(vesa_mode_selected | VESA_MODE_LINEAR_FRAMEBUFFER) != OK) 601 | { 602 | print("Warning: Set VESA mode failed.\r\n"); 603 | return false; 604 | } 605 | 606 | mb_info.flags |= MULTIBOOT_INFO_VIDEO_INFO; 607 | mb_info.vbe_control_info = (uint32_t)&vesa_control_info; 608 | mb_info.vbe_mode_info = (uint32_t)&vesa_mode_info; 609 | mb_info.vbe_mode = vesa_mode_selected | VESA_MODE_LINEAR_FRAMEBUFFER; 610 | return true; 611 | } 612 | 613 | void jmp_kernel(kernel_entry_t kernel_entry, uint32_t mb_magic, multiboot_info_t *mb_info) 614 | { 615 | asm volatile ("jmp *%%ecx" 616 | : 617 | : "c"(kernel_entry), "a"(mb_magic), "b"(mb_info)); 618 | } 619 | 620 | void blmain() 621 | { 622 | print("Stage 1 booted successfully.\r\n"); 623 | 624 | if ((uintptr_t)bss_end - STAGE2_LOAD_ADDRESS > SEGMENT_LIMIT) 625 | { 626 | die("Section .bss is too long.\r\n"); 627 | } 628 | memset(bss_begin, 0, bss_end - bss_begin); // init .bss 629 | 630 | print("boot_device="); 631 | print_byte(boot_device); 632 | print(", sector size is "); 633 | print_int(get_boot_device_sector_size()); 634 | print(" bytes.\r\n"); 635 | 636 | load_memory_map(); 637 | 638 | debug_pause(); 639 | 640 | load_cmdline(); 641 | fill_multiboot_info(); 642 | 643 | debug_pause(); 644 | 645 | multiboot_header_t mb_header; 646 | kernel_entry_t kernel_entry = load_kernel(&mb_header); 647 | assert(kernel_entry); 648 | 649 | debug_pause(); 650 | 651 | if ((mb_header.flags & MULTIBOOT_VIDEO_MODE) && 652 | mb_header.mode_type == MULTIBOOT_MODE_TYPE_GRAPHICS) 653 | { 654 | print("Calling kernel(at "); 655 | print_hex(kernel_entry); 656 | print(") with cmdline=\""); 657 | print(kernel_cmdline); 658 | print("\"...\r\n"); 659 | if (!init_vesa(&mb_header)) 660 | { 661 | debug_pause(); 662 | } 663 | } 664 | else 665 | { 666 | print("Calling kernel(at "); 667 | print_hex(kernel_entry); 668 | print(") with cmdline=\""); 669 | print(kernel_cmdline); 670 | print("\"...\r\n"); 671 | debug_pause(); 672 | } 673 | 674 | jmp_kernel(kernel_entry, MULTIBOOT_BOOTLOADER_MAGIC, &mb_info); 675 | 676 | die("Unknown error."); 677 | } 678 | -------------------------------------------------------------------------------- /bootloader/cdrom/config.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_BOOTLOADER_CDROM_STAGE2_CONFIG_H_ 2 | #define _WDOS_BOOTLOADER_CDROM_STAGE2_CONFIG_H_ 3 | 4 | #include 5 | #include 6 | 7 | #define NDEBUG 1 8 | // #define USE_VBE2 1 9 | #define STAGE2_LOAD_ADDRESS 0x10000 10 | #define SEGMENT_LIMIT 0xffff 11 | #define LOW_MEMORY_BASE 0 12 | #define LOW_MEMORY_LIMIT (0xa0000 - 1) 13 | #define HIGH_MEMORY_BASE 0x100000 14 | #define MULTIBOOT_UNSUPPORTED_FLAGS (~(MULTIBOOT_MEMORY_INFO | MULTIBOOT_VIDEO_MODE)) 15 | #define MULTIBOOT_INFO_FLAGS (MULTIBOOT_INFO_MEMORY | MULTIBOOT_INFO_BOOTDEV | \ 16 | MULTIBOOT_INFO_CMDLINE | MULTIBOOT_INFO_MEM_MAP) 17 | #define MULTIBOOT_MODE_TYPE_GRAPHICS 0 18 | 19 | #define MKBOOT_DEVICE(dev, part1, part2, part3) \ 20 | ((((uint32_t)(dev) & 0xff) << 24) | (((uint32_t)(part1) & 0xff) << 16) | \ 21 | (((uint32_t)(part2) & 0xff) << 8) | ((uint32_t)(part2) & 0xff)) 22 | #define UNUSED_PARTITION 0xff 23 | 24 | typedef void (*kernel_entry_t)(); 25 | 26 | #endif // _WDOS_BOOTLOADER_CDROM_STAGE2_CONFIG_H_ 27 | -------------------------------------------------------------------------------- /bootloader/cdrom/elf.c: -------------------------------------------------------------------------------- 1 | #include "elf.h" 2 | 3 | 4 | -------------------------------------------------------------------------------- /bootloader/cdrom/elf.h: -------------------------------------------------------------------------------- 1 | /* This file defines standard ELF types, structures, and macros. 2 | Copyright (C) 1995-2016 Free Software Foundation, Inc. 3 | This file is part of the GNU C Library. 4 | 5 | The GNU C Library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | The GNU C Library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with the GNU C Library; if not, see 17 | . */ 18 | 19 | #ifndef _WDOS_BOOTLOADER_CDROM_STAGE2_ELF_H_ 20 | #define _WDOS_BOOTLOADER_CDROM_STAGE2_ELF_H_ 21 | 22 | #include 23 | 24 | /* Type for a 16-bit quantity. */ 25 | typedef uint16_t Elf32_Half; 26 | typedef uint16_t Elf64_Half; 27 | 28 | /* Types for signed and unsigned 32-bit quantities. */ 29 | typedef uint32_t Elf32_Word; 30 | typedef int32_t Elf32_Sword; 31 | typedef uint32_t Elf64_Word; 32 | typedef int32_t Elf64_Sword; 33 | 34 | /* Types for signed and unsigned 64-bit quantities. */ 35 | typedef uint64_t Elf32_Xword; 36 | typedef int64_t Elf32_Sxword; 37 | typedef uint64_t Elf64_Xword; 38 | typedef int64_t Elf64_Sxword; 39 | 40 | /* Type of addresses. */ 41 | typedef uint32_t Elf32_Addr; 42 | typedef uint64_t Elf64_Addr; 43 | 44 | /* Type of file offsets. */ 45 | typedef uint32_t Elf32_Off; 46 | typedef uint64_t Elf64_Off; 47 | 48 | /* Type for section indices, which are 16-bit quantities. */ 49 | typedef uint16_t Elf32_Section; 50 | typedef uint16_t Elf64_Section; 51 | 52 | /* Type for version symbol information. */ 53 | typedef Elf32_Half Elf32_Versym; 54 | typedef Elf64_Half Elf64_Versym; 55 | 56 | /* The ELF file header. This appears at the start of every ELF file. */ 57 | 58 | #define EI_NIDENT (16) 59 | 60 | typedef struct 61 | { 62 | unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ 63 | Elf32_Half e_type; /* Object file type */ 64 | Elf32_Half e_machine; /* Architecture */ 65 | Elf32_Word e_version; /* Object file version */ 66 | Elf32_Addr e_entry; /* Entry point virtual address */ 67 | Elf32_Off e_phoff; /* Program header table file offset */ 68 | Elf32_Off e_shoff; /* Section header table file offset */ 69 | Elf32_Word e_flags; /* Processor-specific flags */ 70 | Elf32_Half e_ehsize; /* ELF header size in bytes */ 71 | Elf32_Half e_phentsize; /* Program header table entry size */ 72 | Elf32_Half e_phnum; /* Program header table entry count */ 73 | Elf32_Half e_shentsize; /* Section header table entry size */ 74 | Elf32_Half e_shnum; /* Section header table entry count */ 75 | Elf32_Half e_shstrndx; /* Section header string table index */ 76 | } Elf32_Ehdr; 77 | 78 | typedef struct 79 | { 80 | unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */ 81 | Elf64_Half e_type; /* Object file type */ 82 | Elf64_Half e_machine; /* Architecture */ 83 | Elf64_Word e_version; /* Object file version */ 84 | Elf64_Addr e_entry; /* Entry point virtual address */ 85 | Elf64_Off e_phoff; /* Program header table file offset */ 86 | Elf64_Off e_shoff; /* Section header table file offset */ 87 | Elf64_Word e_flags; /* Processor-specific flags */ 88 | Elf64_Half e_ehsize; /* ELF header size in bytes */ 89 | Elf64_Half e_phentsize; /* Program header table entry size */ 90 | Elf64_Half e_phnum; /* Program header table entry count */ 91 | Elf64_Half e_shentsize; /* Section header table entry size */ 92 | Elf64_Half e_shnum; /* Section header table entry count */ 93 | Elf64_Half e_shstrndx; /* Section header string table index */ 94 | } Elf64_Ehdr; 95 | 96 | /* Fields in the e_ident array. The EI_* macros are indices into the 97 | array. The macros under each EI_* macro are the values the byte 98 | may have. */ 99 | 100 | #define EI_MAG0 0 /* File identification byte 0 index */ 101 | #define ELFMAG0 0x7f /* Magic number byte 0 */ 102 | 103 | #define EI_MAG1 1 /* File identification byte 1 index */ 104 | #define ELFMAG1 'E' /* Magic number byte 1 */ 105 | 106 | #define EI_MAG2 2 /* File identification byte 2 index */ 107 | #define ELFMAG2 'L' /* Magic number byte 2 */ 108 | 109 | #define EI_MAG3 3 /* File identification byte 3 index */ 110 | #define ELFMAG3 'F' /* Magic number byte 3 */ 111 | 112 | /* Conglomeration of the identification bytes, for easy testing as a word. */ 113 | #define ELFMAG "\177ELF" 114 | #define SELFMAG 4 115 | 116 | #define ET_EXEC 2 /* Executable file */ 117 | 118 | #define EM_386 3 /* Intel 80386 */ 119 | 120 | #define EV_NONE 0 /* Invalid ELF version */ 121 | #define EV_CURRENT 1 /* Current version */ 122 | #define EV_NUM 2 123 | 124 | /* Program segment header. */ 125 | 126 | typedef struct 127 | { 128 | Elf32_Word p_type; /* Segment type */ 129 | Elf32_Off p_offset; /* Segment file offset */ 130 | Elf32_Addr p_vaddr; /* Segment virtual address */ 131 | Elf32_Addr p_paddr; /* Segment physical address */ 132 | Elf32_Word p_filesz; /* Segment size in file */ 133 | Elf32_Word p_memsz; /* Segment size in memory */ 134 | Elf32_Word p_flags; /* Segment flags */ 135 | Elf32_Word p_align; /* Segment alignment */ 136 | } Elf32_Phdr; 137 | 138 | typedef struct 139 | { 140 | Elf64_Word p_type; /* Segment type */ 141 | Elf64_Word p_flags; /* Segment flags */ 142 | Elf64_Off p_offset; /* Segment file offset */ 143 | Elf64_Addr p_vaddr; /* Segment virtual address */ 144 | Elf64_Addr p_paddr; /* Segment physical address */ 145 | Elf64_Xword p_filesz; /* Segment size in file */ 146 | Elf64_Xword p_memsz; /* Segment size in memory */ 147 | Elf64_Xword p_align; /* Segment alignment */ 148 | } Elf64_Phdr; 149 | 150 | #define PT_LOAD 1 /* Loadable program segment */ 151 | 152 | #endif // _WDOS_BOOTLOADER_CDROM_STAGE2_ELF_H_ 153 | -------------------------------------------------------------------------------- /bootloader/cdrom/iso9660.c: -------------------------------------------------------------------------------- 1 | #include "iso9660.h" 2 | 3 | #include 4 | #include 5 | 6 | directory_record_t *next_record(directory_record_t *ptr) 7 | { 8 | return (directory_record_t *)(((uint8_t *)ptr) + ptr->length); 9 | } 10 | 11 | directory_record_t *find_record(const char *pattern, directory_record_t *begin, directory_record_t *end) 12 | { 13 | for (directory_record_t *iter = begin; iter->length && iter < end; iter = next_record(iter)) 14 | { 15 | if (ident_cmp(pattern, iter->ident_length, iter->ident)) 16 | { 17 | return iter; 18 | } 19 | } 20 | return NULL; 21 | } 22 | 23 | bool ident_cmp(const char *pattern, uint32_t ident_length, const char *ident) 24 | { 25 | uint32_t length = strlen(pattern); 26 | if (ident_length < length) 27 | { 28 | return false; 29 | } 30 | if (memcmp(pattern, ident, length)) 31 | { 32 | return false; 33 | } 34 | // FILENAME.EXT;version 35 | if (ident_length > length && ident[length] != ';' && ident[length] != 0) 36 | { 37 | return false; 38 | } 39 | return true; 40 | } 41 | 42 | void to_ident(char *pattern) 43 | { 44 | while (*pattern) 45 | { 46 | if (*pattern >= 'a' && *pattern <= 'z') 47 | { 48 | *pattern = *pattern - 'a' + 'A'; 49 | } 50 | ++pattern; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /bootloader/cdrom/iso9660.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_BOOTLOADER_CDROM_STAGE2_ISO9660_H_ 2 | #define _WDOS_BOOTLOADER_CDROM_STAGE2_ISO9660_H_ 3 | 4 | #include 5 | 6 | #define FIRST_LBA 16 7 | 8 | #define ISO9660_MAGIC "CD001" 9 | #define ISO9660_MAGIC_LENGTH 5 10 | 11 | #define VD_TYPE_PRIMARY 0x01 12 | #define VD_TYPE_TERMINATOR 0xff 13 | 14 | #define ISO9660_FLAG_DIRECTORY 0b10 15 | 16 | typedef struct directory_record 17 | { 18 | uint8_t length; 19 | uint8_t ear_length; 20 | uint32_t extent_location; 21 | uint32_t extent_location_be; // big-endian, unused 22 | uint32_t data_length; 23 | uint32_t data_length_be; // big-endian, unused 24 | uint8_t datetime[7]; 25 | uint8_t flags; 26 | uint8_t unit_size; 27 | uint8_t gap_size; 28 | uint16_t vol_seq_number; 29 | uint16_t vol_seq_number_be; // big-endian, unused 30 | uint8_t ident_length; 31 | char ident[0]; 32 | } __attribute__((packed)) directory_record_t; 33 | 34 | typedef struct vd_primary 35 | { 36 | uint8_t type; 37 | char std_ident[5]; 38 | uint8_t version; 39 | uint8_t reserved1; 40 | char sys_ident[32]; 41 | char vol_ident[32]; 42 | uint8_t reserved2[8]; 43 | uint8_t unused1[76]; 44 | directory_record_t root_directory; 45 | uint8_t unused2[1858]; 46 | } __attribute__((packed)) vd_primary_t; 47 | 48 | directory_record_t *next_record(directory_record_t *ptr); 49 | directory_record_t *find_record(const char *pattern, directory_record_t *begin, directory_record_t *end); 50 | bool ident_cmp(const char *pattern, uint32_t ident_length, const char *ident); 51 | void to_ident(char *pattern); 52 | 53 | #endif // _WDOS_BOOTLOADER_CDROM_STAGE2_ISO9660_H_ 54 | -------------------------------------------------------------------------------- /bootloader/cdrom/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(_start) 2 | 3 | SECTIONS 4 | { 5 | . = 0x00010000; 6 | 7 | .text ALIGN(4K): 8 | { 9 | *(.text) 10 | *(.rodata*) 11 | *(.data) 12 | _bss_begin = (. + 4095) & (~ 4095); /* 4K align */ 13 | } 14 | 15 | .bss ALIGN(4K): 16 | { 17 | *(COMMON) 18 | *(.bss) 19 | _bss_end = (. + 4095) & (~ 4095); /* 4K align */ 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /bootloader/cdrom/stage1.asm: -------------------------------------------------------------------------------- 1 | ; boot from cdrom 2 | ; use bios function 0x42 3 | ; compatible with ISO-9660 4 | 5 | org 0x7c00 6 | bits 16 7 | 8 | _start: 9 | cli 10 | 11 | ;cmp dl, 0xe0 ; is cdrom? 12 | ;jnz die 13 | 14 | xor ax, ax 15 | mov ds, ax 16 | mov es, ax 17 | mov ss, ax 18 | mov sp, 0x7c00 ; init stack 19 | 20 | lea si, [loading_str] 21 | call print 22 | 23 | mov ah, 0x41 ; check extension present 24 | mov bx, 0x55aa ; magic 25 | int 0x13 ; bios function 26 | jc not_present 27 | cmp bx, 0xaa55 ; magic again 28 | jne not_present ; if not present... 29 | 30 | ; find primary volume descriptor 31 | mov ebx, 16 ; starts at sector 16 32 | mov ecx, 1 ; descriptors are one sector size. 33 | mov ax, 0x1000 34 | mov es, ax 35 | xor di, di ; buffer = es:di = 1000:0000 = 0x10000 36 | find_primary_volume_descriptor_loop: 37 | call read_sector 38 | cmp byte [es:di + volume_descriptor_type], type_primary_volume_descriptor 39 | je found_primary_volume_descriptor ; is primary volume descriptor? 40 | inc ebx ; try next sector 41 | jmp find_primary_volume_descriptor_loop 42 | 43 | found_primary_volume_descriptor: 44 | mov ebx, [es:di + primary_volume_descriptor_root_dir_rec + dir_rec_extent_sector_no] 45 | mov ecx, [es:di + primary_volume_descriptor_root_dir_rec + dir_rec_data_length] 46 | shr ecx, 11 ; length to sector count 47 | ; es:di is still 1000:0000 = 0x10000 48 | call read_sector ; read root directory record 49 | 50 | ; find boot dir 51 | mov ax, es 52 | mov ds, ax 53 | mov si, di ; buffer = ds:si = es:di 54 | mov bx, cx 55 | shl bx, 11 ; limit + 1 = buffer size 56 | lea ax, [boot_dir_name] 57 | call find_entry 58 | test ax, ax ; found? 59 | jz path_not_found 60 | 61 | mov ebx, [ds:si + dir_rec_extent_sector_no] 62 | mov ecx, [ds:si + dir_rec_data_length] 63 | shr ecx, 11 ; length to sector count 64 | ; es:di is still 1000:0000 = 0x10000 65 | call read_sector ; read `boot' directory record 66 | 67 | ; find stage2 file 68 | mov ax, es 69 | mov ds, ax 70 | mov si, di ; buffer = ds:si = es:di 71 | mov bx, cx 72 | shl bx, 11 ; limit + 1 = buffer size 73 | lea ax, [stage2_file_name] 74 | call find_entry 75 | test ax, ax ; found? 76 | jz stage2_not_found 77 | 78 | ; found stage2 79 | mov ebx, [ds:si + dir_rec_extent_sector_no] 80 | mov ecx, [ds:si + dir_rec_data_length] 81 | add ecx, 2047 82 | shr ecx, 11 ; length to sector count = ceiling(length / 2048) 83 | ; es:di is still 1000:0000 = 0x10000 84 | call read_sector ; load stage2 file 85 | jmp word 0x1000:0000 ; go! 86 | 87 | bios_error: 88 | xor ax, ax 89 | mov ds, ax 90 | lea si, [bios_error_str] 91 | jmp print_and_die 92 | 93 | not_present: 94 | xor ax, ax 95 | mov ds, ax 96 | lea si, [not_present_str] 97 | jmp print_and_die 98 | 99 | path_not_found: 100 | xor ax, ax 101 | mov ds, ax 102 | lea si, [path_not_found_str] 103 | jmp print_and_die 104 | 105 | stage2_not_found: 106 | xor ax, ax 107 | mov ds, ax 108 | lea si, [stage2_not_found_str] 109 | jmp print_and_die 110 | 111 | print_and_die: 112 | call print 113 | ; ... and die ... 114 | 115 | die: 116 | cli 117 | hlt 118 | jmp die 119 | 120 | ; print a string 121 | ; buffer = ds:si 122 | print: 123 | lodsb 124 | or al, al 125 | jz print_return 126 | mov ah, 0x0e ; print 127 | mov bh, 0 128 | mov bl, 0 129 | int 0x10 ; bios print 130 | jmp print 131 | print_return: 132 | ret 133 | 134 | ; print a '.' 135 | print_dot: 136 | mov al, '.' 137 | mov ah, 0x0e ; print 138 | mov bh, 0 139 | mov bl, 0 140 | int 0x10 ; bios print 141 | ret 142 | 143 | ; read one or more sectors 144 | ; sector LBA = ebx, count = ecx, destination = es:di 145 | read_sector: 146 | xor ax, ax 147 | mov ds, ax 148 | mov [dap_ptr + dap_lba_low], ebx 149 | mov [dap_ptr + dap_count], ecx 150 | lea si, [dap_ptr] ; ds:si = dap_ptr 151 | mov ax, es 152 | mov [dap_ptr + dap_seg], ax 153 | mov [dap_ptr + dap_offset], di ; dap_ptr->seg:offset = es:di 154 | mov ah, 0x42 ; extended read sector 155 | int 0x13 ; bios function 156 | jc bios_error 157 | push ax ; save ax (set by int 0x13) 158 | call print_dot 159 | pop ax 160 | ret 161 | 162 | ; find a directory record 163 | ; buffer = ds:si, buffer size = limit + 1 = bx, name_ptr = ax 164 | find_entry: 165 | push di 166 | push es 167 | push bx 168 | mov di, ax 169 | xor ax, ax 170 | mov es, ax ; es = 0 171 | add bx, si 172 | find_entry_loop: 173 | cmp si, bx ; buffer > limit? 174 | jae find_entry_return0 175 | cmp byte [ds:si + dir_rec_length], 0 ; buffer->dir_rec_length == 0? 176 | je find_entry_return0 177 | 178 | xor cx, cx 179 | mov cl, [ds:si + dir_rec_ident_length] 180 | cmp cl, name_min_size ; buffer->dir_rec_ident_length < name_min_size? 181 | jb find_entry_loop_continue 182 | 183 | xor bp, bp ; i = 0 184 | strcmp_loop: 185 | mov cl, [es:bp + di] ; pattern char 186 | mov ch, [ds:bp + si + dir_rec_ident] ; text char 187 | test cl, cl ; is last pattern char? 188 | jz strcmp_last 189 | cmp cl, ch ; pattern char == text char? 190 | jne find_entry_loop_continue ; != 191 | inc bp ; next char 192 | jmp strcmp_loop 193 | 194 | strcmp_last: 195 | ; (ch == ';' || ch == '\0') || bp == dir_rec_ident_length 196 | cmp ch, ';' 197 | je find_entry_return1 198 | test ch, ch 199 | jz find_entry_return1 200 | cmp bp, dir_rec_ident_length 201 | je find_entry_return1 202 | 203 | ; else 204 | 205 | find_entry_loop_continue: 206 | ; next entry 207 | xor cx, cx 208 | mov cl, [ds:si + dir_rec_length] 209 | add si, cx ; buffer += buffer->dir_rec_length 210 | jmp find_entry_loop 211 | 212 | find_entry_return0: 213 | xor ax, ax 214 | jmp find_entry_return 215 | 216 | find_entry_return1: 217 | mov ax, 1 218 | find_entry_return: 219 | pop bx 220 | pop es 221 | pop di 222 | ret 223 | 224 | dap_ptr: 225 | db 16 ; dap size = 16 226 | db 0 ; reserved 227 | dw 1 ; count 228 | dd 0 ; destination 229 | dd 0 ; sector LBA low 230 | dd 0 ; sector LBA high 231 | 232 | dap_count equ 2 233 | dap_offset equ 4 234 | dap_seg equ 6 235 | dap_lba_low equ 8 236 | dap_lba_high equ 12 237 | 238 | volume_descriptor_type equ 0 239 | type_primary_volume_descriptor equ 0x01 240 | 241 | ; data struct offset 242 | primary_volume_descriptor_root_dir_rec equ 156 243 | dir_rec_length equ 0 244 | dir_rec_extent_sector_no equ 2 245 | dir_rec_data_length equ 10 246 | dir_rec_ident_length equ 32 247 | dir_rec_ident equ 33 248 | 249 | ; constant strings 250 | loading_str db "Loading.", 0 251 | bios_error_str db "BIOS error.", 0 252 | not_present_str db "Extensions not present.", 0 253 | path_not_found_str db "Path not found.", 0 254 | stage2_not_found_str db "Stage2 not found.", 0 255 | 256 | ; /BOOT/STAGE2.BIN 257 | name_min_size equ 4 ; length of "BOOT" 258 | boot_dir_name db "BOOT", 0 259 | stage2_file_name db "STAGE2.BIN", 0 260 | 261 | times 510 - ($ - $$) db 0 262 | db 0x55 263 | db 0xaa 264 | -------------------------------------------------------------------------------- /bootloader/cdrom/stage2.asm: -------------------------------------------------------------------------------- 1 | %include "../../descriptor.inc" 2 | 3 | ; Assume this code was loaded at 0x1000:0000 = 0x10000. 4 | ; (see stage1.asm, "jmp word 0x1000:0000") 5 | ; All 16-bit codes are linked manually (" - $$"s). 6 | 7 | extern blmain 8 | 9 | global _start 10 | global boot_device 11 | global bios_function 12 | 13 | ; everything's in .text. 14 | [section .text] 15 | 16 | [bits 16] 17 | _start: 18 | cli 19 | 20 | mov ax, cs 21 | mov ds, ax 22 | mov es, ax 23 | mov fs, ax 24 | mov gs, ax 25 | 26 | xor ax, ax 27 | mov ss, ax 28 | mov sp, 0xffff 29 | 30 | mov [boot_device - $$], dl ; save boot device 31 | 32 | ; prepare GDTR 33 | xor eax, eax 34 | mov ax, cs 35 | shl eax, 4 36 | add eax, gdt32_ptr - $$ 37 | mov [ds:gdt32_reg - $$ + 2], eax ; logical address cs:gdt32_ptr to physical address 38 | lgdt [ds:gdt32_reg - $$] 39 | 40 | ; A20 41 | in al, 0x92 42 | or al, 0b00000010 43 | out 0x92, al 44 | 45 | ; enable protect mode 46 | mov eax, cr0 47 | or eax, 1 48 | mov cr0, eax 49 | 50 | ; go to protect mode 51 | xor eax, eax 52 | mov ax, cs 53 | shl eax, 4 54 | add eax, _start32 - $$ 55 | mov [ds:ljmp_address - $$], eax ; logical address cs:_start32 to physical address 56 | 57 | ; ljmp dword selector_code:_start32 58 | db 0x66 ; operand-size override 59 | db 0xea ; ljmp 60 | ljmp_address dd 0xdeadbeef ; will be changed 61 | dw selector_code 62 | 63 | ; variables 64 | boot_device db 0 65 | 66 | gdt32_ptr: descriptor 0, 0, 0 ; none 67 | gdt32_code: descriptor 0, 0xFFFFF, DESCRIPTOR_ATTR_CODE32 | DESCRIPTOR_ATTR_DPL0 68 | gdt32_data: descriptor 0, 0xFFFFF, DESCRIPTOR_ATTR_DATA32 | DESCRIPTOR_ATTR_DPL0 69 | gdt32_code16: descriptor 0x10000, 0x0FFFF, DESCRIPTOR_ATTR_CODE16 | DESCRIPTOR_ATTR_DPL0 70 | gdt32_data16: descriptor 0, 0x0FFFF, DESCRIPTOR_ATTR_DATA16 | DESCRIPTOR_ATTR_DPL0 71 | 72 | gdt32_length equ $ - gdt32_ptr 73 | gdt32_reg: 74 | dw gdt32_length - 1 ; GDT limit 75 | dd 0 ; GDT base, will be filled later 76 | 77 | selector_code equ ((gdt32_code - gdt32_ptr) | SELECTOR_GDT | SELECTOR_RPL0) 78 | selector_data equ ((gdt32_data - gdt32_ptr) | SELECTOR_GDT | SELECTOR_RPL0) 79 | selector_code16 equ ((gdt32_code16 - gdt32_ptr) | SELECTOR_GDT | SELECTOR_RPL0) 80 | selector_data16 equ ((gdt32_data16 - gdt32_ptr) | SELECTOR_GDT | SELECTOR_RPL0) 81 | 82 | [bits 32] 83 | _start32: 84 | cli 85 | 86 | mov ax, selector_data 87 | mov ds, ax 88 | mov es, ax 89 | mov fs, ax 90 | mov gs, ax 91 | mov ss, ax 92 | 93 | call blmain 94 | 95 | die: 96 | cli 97 | hlt 98 | jmp die 99 | 100 | %include "bios_function.inc" 101 | -------------------------------------------------------------------------------- /bootloader/cdrom/util.c: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | 3 | #include "bios.h" 4 | 5 | #ifndef NDEBUG 6 | void debug_pause() 7 | { 8 | print("Press any key to continue...\r\n"); 9 | getchar(); 10 | } 11 | #endif 12 | 13 | void *palloc(uint32_t size) 14 | { 15 | static uint8_t *buffer = (void *)0x30000; 16 | uint8_t *old_buffer = buffer; 17 | buffer += size; 18 | return (void *)old_buffer; 19 | } 20 | 21 | void die(const char *str) 22 | { 23 | print(str); 24 | while (true) 25 | { 26 | asm("cli\n" 27 | "hlt"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /bootloader/cdrom/util.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_BOOTLOADER_CDROM_STAGE2_UTIL_H_ 2 | #define _WDOS_BOOTLOADER_CDROM_STAGE2_UTIL_H_ 3 | 4 | #include 5 | 6 | #define assert(x) do { if (!(x)) die("\r\nAssertion failed.\r\n"); } while (0) 7 | 8 | #ifndef NDEBUG 9 | void debug_pause(); 10 | #else 11 | #define debug_pause() do { } while (0) 12 | #endif 13 | 14 | void *palloc(uint32_t size); // p means physical, permanent 15 | void die(const char *str); 16 | 17 | #define is_power_of_2(x) (!((x) & ((x) - 1))) 18 | 19 | #endif // _WDOS_BOOTLOADER_CDROM_STAGE2_UTIL_H_ 20 | -------------------------------------------------------------------------------- /bootloader/cdrom/vesa.c: -------------------------------------------------------------------------------- 1 | #include "vesa.h" 2 | 3 | static inline uint32_t abs(int x) 4 | { 5 | return x > 0 ? x : -x; 6 | } 7 | 8 | uint32_t mode_diff(uint16_t target_width, uint16_t target_height, uint8_t target_depth, 9 | uint16_t width, uint16_t height, uint8_t depth) 10 | { 11 | uint32_t diff = 0; 12 | diff += abs(target_width - width) * 100000 / target_width; 13 | diff += abs(target_height - height) * 100000 / target_height; 14 | diff += abs(target_depth - depth) * 1000000 / target_depth; 15 | 16 | if (!(target_width == width && target_height == height)) 17 | { 18 | diff += 0x10000000; // resolution first 19 | } 20 | return diff; 21 | } 22 | -------------------------------------------------------------------------------- /bootloader/cdrom/vesa.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_BOOTLOADER_CDROM_STAGE2_VESA_H_ 2 | #define _WDOS_BOOTLOADER_CDROM_STAGE2_VESA_H_ 3 | 4 | #include 5 | 6 | #include "vesa_types.h" 7 | 8 | #define VESA_MAGIC "VESA" 9 | #define VESA_MAGIC_LENGTH 4 10 | #define VESA_MODE_INVALID 0xffff 11 | #define VESA_MODE_TERMINATOR 0xffff 12 | #define VESA_MODE_LINEAR_FRAMEBUFFER 0x4000 13 | #define VESA_MODE_ATTR_GRAPHICS 0x10 14 | #define VESA_MODE_ATTR_LINEAR_FRAMEBUFFER 0x80 15 | #define VESA_MODE_MEMORY_MODEL_DIRECTCOLOR 0x6 16 | 17 | uint32_t mode_diff(uint16_t target_width, uint16_t target_height, uint8_t target_depth, 18 | uint16_t width, uint16_t height, uint8_t depth); 19 | 20 | #endif // _WDOS_BOOTLOADER_CDROM_STAGE2_VESA_H_ 21 | -------------------------------------------------------------------------------- /bootloader/cdrom/vesa_types.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_BOOTLOADER_CDROM_STAGE2_VESA_TYPES_H_ 2 | #define _WDOS_BOOTLOADER_CDROM_STAGE2_VESA_TYPES_H_ 3 | 4 | #include 5 | 6 | typedef struct vesa_control_info 7 | { 8 | char magic[4]; // "VESA" 9 | uint16_t version; // == 0x0300 for VBE 3.0 10 | uint16_t oem_string_offset; 11 | uint16_t oem_string_seg; 12 | uint32_t capabilities; 13 | uint16_t video_mode_offset; 14 | uint16_t video_mode_seg; 15 | uint16_t total_memory; // x 64KB 16 | uint8_t reserved[492]; 17 | } __attribute__((packed)) vesa_control_info_t; 18 | 19 | typedef struct vesa_mode_info 20 | { 21 | uint16_t attr; 22 | uint8_t win_a, win_b; 23 | uint16_t win_granularity; 24 | uint16_t win_size; 25 | uint16_t seg_a, seg_b; 26 | uint32_t real_mode_func_ptr; 27 | uint16_t pitch; // bytes per scanline 28 | 29 | uint16_t x_res, y_res; // width, height 30 | uint8_t w_char, y_char, planes, bpp, banks; 31 | uint8_t memory_model, bank_size, image_pages; 32 | uint8_t reserved0; 33 | 34 | uint8_t red_mask, red_position; 35 | uint8_t green_mask, green_position; 36 | uint8_t blue_mask, blue_position; 37 | uint8_t rsv_mask, rsv_position; 38 | uint8_t directcolor_attr; 39 | 40 | uint32_t base; // framebuffer physical address 41 | uint32_t reserved1; 42 | uint16_t reserved2; 43 | uint8_t reserved[206]; 44 | } __attribute__((packed)) vesa_mode_info_t; 45 | 46 | #endif // _WDOS_BOOTLOADER_CDROM_STAGE2_VESA_TYPES_H_ 47 | -------------------------------------------------------------------------------- /cmdline.txt: -------------------------------------------------------------------------------- 1 | cmdline test 2 | -------------------------------------------------------------------------------- /descriptor.inc: -------------------------------------------------------------------------------- 1 | DESCRIPTOR_ATTR_4K equ (1 << 15) 2 | DESCRIPTOR_ATTR_DB equ (1 << 14) 3 | DESCRIPTOR_ATTR_L equ (1 << 13) 4 | DESCRIPTOR_ATTR_PRESENT equ (1 << 7) 5 | DESCRIPTOR_ATTR_DPL0 equ (0 << 5) 6 | DESCRIPTOR_ATTR_DPL3 equ (3 << 5) 7 | DESCRIPTOR_ATTR_SEG equ (1 << 4) 8 | DESCRIPTOR_ATTR_EX equ (1 << 3) 9 | DESCRIPTOR_ATTR_DC equ (1 << 2) 10 | DESCRIPTOR_ATTR_RW equ (1 << 1) 11 | DESCRIPTOR_ATTR_AC equ (1 << 0) 12 | 13 | SELECTOR_GDT equ (0 << 2) 14 | SELECTOR_LDT equ (1 << 2) 15 | SELECTOR_RPL0 equ (0 << 0) 16 | SELECTOR_RPL3 equ (3 << 0) 17 | SELECTOR_RPL_MASK equ (0b11) 18 | 19 | DESCRIPTOR_ATTR_CODE32 equ (DESCRIPTOR_ATTR_PRESENT | DESCRIPTOR_ATTR_DB | \ 20 | DESCRIPTOR_ATTR_SEG | DESCRIPTOR_ATTR_EX | \ 21 | DESCRIPTOR_ATTR_RW | DESCRIPTOR_ATTR_4K) 22 | DESCRIPTOR_ATTR_DATA32 equ (DESCRIPTOR_ATTR_PRESENT | DESCRIPTOR_ATTR_DB | \ 23 | DESCRIPTOR_ATTR_SEG | DESCRIPTOR_ATTR_RW | \ 24 | DESCRIPTOR_ATTR_4K) 25 | 26 | ; for bootloader 27 | DESCRIPTOR_ATTR_CODE16 equ (DESCRIPTOR_ATTR_PRESENT | DESCRIPTOR_ATTR_SEG | \ 28 | DESCRIPTOR_ATTR_EX | DESCRIPTOR_ATTR_RW) 29 | DESCRIPTOR_ATTR_DATA16 equ (DESCRIPTOR_ATTR_PRESENT | DESCRIPTOR_ATTR_SEG | \ 30 | DESCRIPTOR_ATTR_RW) 31 | 32 | DESCRIPTOR_ATTR_TSS equ (DESCRIPTOR_ATTR_PRESENT | 0x9) ; type 0x9 free 386 tss 33 | GATE_ATTR_INTERRUPT equ (DESCRIPTOR_ATTR_PRESENT | 0xE) ; type 0xE 386 interrupt gate 34 | 35 | ; descriptor base, limit, attr 36 | %macro descriptor 3 37 | dw %2 & 0xFFFF ; limit 1 38 | dw %1 & 0xFFFF ; base 1 39 | db (%1 >> 16) & 0xFF ; base 1 40 | dw ((%2 >> 8) & 0x0F00) | (%3 & 0xF0FF) ; attr 1, limit 2, attr 2 41 | db (%1 >> 24) & 0xFF ; base 2 42 | %endmacro 43 | 44 | ; gate selector, offset, attr 45 | %macro gate 3 46 | dw %2 & 0xFFFF ; offset 1 47 | dw %1 ; selector 48 | db 0 ; zero 49 | db %3 ; attr 50 | dw (%2 >> 16) & 0xFFFF ; offset 2 51 | %endmacro 52 | -------------------------------------------------------------------------------- /driver/keyboard.c: -------------------------------------------------------------------------------- 1 | #include "keyboard.h" 2 | #include 3 | #include 4 | 5 | static uint8_t left_shift_down_count = 0; 6 | static uint8_t right_shift_down_count = 0; 7 | static uint8_t left_ctrl_down_count = 0; 8 | static uint8_t right_ctrl_down_count = 0; 9 | static uint8_t left_alt_down_count = 0; 10 | static uint8_t right_alt_down_count = 0; 11 | 12 | void init_keyboard() 13 | { 14 | register_irq_handler(IRQ_KEYBOARD, keyboard_irq_handler); 15 | keyboard_read(); // eat 16 | } 17 | 18 | inline uint8_t keyboard_read() 19 | { 20 | uint8_t b = inb(KEYBOARD_BUFFER); 21 | io_delay(); 22 | return b; 23 | } 24 | 25 | void keyboard_irq_handler(uint8_t irq, interrupt_frame_t *frame) 26 | { 27 | uint8_t scancode = keyboard_read(); 28 | /*tty_set_current(default_tty); 29 | kprint("[KEYBOARD] "); 30 | kprint_hex(scancode); 31 | kprint("\n"); 32 | tty_set_current(NULL);*/ 33 | // TODO: extend code 34 | switch (scancode) 35 | { 36 | case 0x1d: // ctrl make 37 | ++left_ctrl_down_count; 38 | break; 39 | case 0x9d: // ctrl break 40 | --left_ctrl_down_count; 41 | break; 42 | case 0x2a: // shift make 43 | ++left_shift_down_count; 44 | break; 45 | case 0xaa: // shift break 46 | --left_shift_down_count; 47 | break; 48 | case 0x38: // alt make 49 | ++left_alt_down_count; 50 | break; 51 | case 0xb8: // alt break 52 | --left_alt_down_count; 53 | break; 54 | case 0x36: // right shift make 55 | ++right_shift_down_count; 56 | break; 57 | case 0xb6: // right shift break 58 | --right_shift_down_count; 59 | break; 60 | case 0x53: // delete make 61 | if (left_ctrl_down_count && left_alt_down_count) 62 | { 63 | asm("ud2"); 64 | } 65 | break; 66 | default: 67 | if (0x3b <= scancode && scancode <= 0x3b + 7) 68 | { 69 | tty_switch(default_tty + scancode - 0x3b); 70 | } 71 | break; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /driver/keyboard.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_KERNEL_DRIVER_KEYBOARD_H_ 2 | #define _WDOS_KERNEL_DRIVER_KEYBOARD_H_ 3 | 4 | #include 5 | #include 6 | 7 | #define KEYBOARD_BUFFER 0x60 8 | 9 | void init_keyboard(); 10 | uint8_t keyboard_read(); 11 | void keyboard_irq_handler(uint8_t, interrupt_frame_t*); 12 | 13 | #endif // _WDOS_KERNEL_DRIVER_KEYBOARD_H_ 14 | -------------------------------------------------------------------------------- /driver/pic8259a.c: -------------------------------------------------------------------------------- 1 | #include "pic8259a.h" 2 | #include 3 | #include 4 | 5 | void init_pic8259a() 6 | { 7 | outb(PIC8259A_MASTER_COMMAND, 0b00010001); // ICW1: PC, is ICW1, edge, 8B vec, cascade, has ICW4 8 | io_delay(); 9 | outb(PIC8259A_SLAVE_COMMAND, 0b00010001); 10 | io_delay(); 11 | 12 | outb(PIC8259A_MASTER_DATA, INTERRUPT_VECTOR_IRQ0); // ICW2: IRQ0, 80x86 13 | io_delay(); 14 | outb(PIC8259A_SLAVE_DATA, INTERRUPT_VECTOR_IRQ8); // ICW2: IRQ8, 80x86 15 | io_delay(); 16 | 17 | outb(PIC8259A_MASTER_DATA, 0b00000100); // ICW3: IR2 cascade 18 | io_delay(); 19 | outb(PIC8259A_SLAVE_DATA, 2); // ICW3: IR2 cascade 20 | io_delay(); 21 | 22 | outb(PIC8259A_MASTER_DATA, 1); // ICW4: 80x86 23 | io_delay(); 24 | outb(PIC8259A_SLAVE_DATA, 1); 25 | io_delay(); 26 | 27 | outb(PIC8259A_MASTER_DATA, 0); // OCW1: enable all interrupts(no mask) 28 | io_delay(); 29 | outb(PIC8259A_SLAVE_DATA, 0); 30 | io_delay(); 31 | } 32 | 33 | void send_eoi(uint8_t irq) 34 | { 35 | uint16_t port = PIC8259A_MASTER_COMMAND; 36 | if (irq >= 8) 37 | { 38 | port = PIC8259A_SLAVE_COMMAND; 39 | } 40 | outb(port, PIC8259A_EOI); 41 | io_delay(); 42 | } 43 | -------------------------------------------------------------------------------- /driver/pic8259a.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_KERNEL_PIC8259A_H_ 2 | #define _WDOS_KERNEL_PIC8259A_H_ 3 | 4 | #include 5 | 6 | #define PIC8259A_MASTER_ADDRESS 0x20 7 | #define PIC8259A_SLAVE_ADDRESS 0xA0 8 | #define PIC8259A_MASTER_COMMAND PIC8259A_MASTER_ADDRESS 9 | #define PIC8259A_MASTER_DATA (PIC8259A_MASTER_ADDRESS + 1) 10 | #define PIC8259A_SLAVE_COMMAND PIC8259A_SLAVE_ADDRESS 11 | #define PIC8259A_SLAVE_DATA (PIC8259A_SLAVE_ADDRESS + 1) 12 | #define PIC8259A_EOI 0x20 13 | 14 | void init_pic8259a(); 15 | void send_eoi(uint8_t irq); 16 | 17 | #endif // _WDOS_KERNEL_PIC8259A_H_ 18 | -------------------------------------------------------------------------------- /driver/pit8253.c: -------------------------------------------------------------------------------- 1 | #include "pit8253.h" 2 | #include 3 | 4 | void init_pit8253() 5 | { 6 | set_clock_freq(IRQ_FREQ); 7 | } 8 | 9 | inline void set_clock_freq(uint32_t freq) 10 | { 11 | uint16_t counter = (uint16_t)(CLOCK_FREQ / freq); 12 | outb(PIT8253_MCR, 13 | PIT8253_MCR_BINARY | PIT8253_MCR_MODE2 | PIT8253_MCR_COUNTER0 | PIT8253_MCR_WRITE_LH); 14 | io_delay(); 15 | outb(PIT8253_COUNTER0, counter & 0xFF); 16 | io_delay(); 17 | outb(PIT8253_COUNTER0, (counter >> 8) & 0xFF); 18 | io_delay(); 19 | } 20 | -------------------------------------------------------------------------------- /driver/pit8253.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_KERNEL_DRIVER_PIT8253_H_ 2 | #define _WDOS_KERNEL_DRIVER_PIT8253_H_ 3 | 4 | #include 5 | 6 | #define CLOCK_FREQ 1193180 7 | #define PIT8253_COUNTER0 0x40 8 | #define PIT8253_COUNTER1 0x41 9 | #define PIT8253_COUNTER2 0x42 10 | #define PIT8253_MCR 0x43 11 | 12 | #define PIT8253_MCR_BINARY 0 13 | #define PIT8253_MCR_MODE2 (2 << 1) 14 | #define PIT8253_MCR_COUNTER0 (0 << 6) 15 | #define PIT8253_MCR_COUNTER1 (1 << 6) 16 | #define PIT8253_MCR_COUNTER2 (2 << 6) 17 | #define PIT8253_MCR_WRITE_LH (3 << 4) 18 | 19 | #define IRQ_FREQ 500 // Hz 20 | 21 | void init_pit8253(); 22 | void set_clock_freq(uint32_t interval); 23 | 24 | #endif // _WDOS_KERNEL_DRIVER_PIT8253_H_ 25 | -------------------------------------------------------------------------------- /driver/vesa.c: -------------------------------------------------------------------------------- 1 | #include "vesa.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | bool vesa_available = false; 9 | 10 | vesa_control_info_t vesa_control_info; 11 | uint16_t vesa_mode; 12 | vesa_mode_info_t vesa_mode_info; 13 | void *vesa_framebuffer_va; 14 | 15 | static uint32_t vesa_tty_color[16]; 16 | 17 | static spinlock_t vesa_lock; 18 | static volatile uint32_t vesa_revision = 0; 19 | 20 | static tty_driver_t vesa_tty_driver = 21 | { 22 | .width = 0, // filled by init_vesa() 23 | .height = 0, // filled by init_vesa() 24 | .init = &vesa_tty_init, 25 | .rerender = &vesa_tty_rerender, 26 | .switch_handler = &vesa_tty_switch_handler, 27 | .update_cursor_location = &vesa_tty_update_cursor_location, 28 | .set_char = &vesa_tty_set_char 29 | }; 30 | 31 | void init_vesa(multiboot_info_t *mb_info) 32 | { 33 | if (mb_info->flags & MULTIBOOT_INFO_VIDEO_INFO) 34 | { 35 | vesa_control_info_t *mb_control_info = 36 | (vesa_control_info_t *)__VA((void *)mb_info->vbe_control_info); 37 | memcpy(&vesa_control_info, mb_control_info, sizeof(vesa_control_info_t)); 38 | 39 | vesa_mode = mb_info->vbe_mode; 40 | 41 | vesa_mode_info_t *mb_mode_info = 42 | (vesa_mode_info_t *)__VA((void *)mb_info->vbe_mode_info); 43 | memcpy(&vesa_mode_info, mb_mode_info, sizeof(vesa_mode_info_t)); 44 | 45 | vesa_available = 46 | (vesa_mode_info.attr & VESA_MODE_ATTR_LINEAR_FRAMEBUFFER) && 47 | (vesa_mode_info.attr & VESA_MODE_ATTR_GRAPHICS) && 48 | vesa_mode_info.memory_model == VESA_MODE_MEMORY_MODEL_DIRECTCOLOR; 49 | 50 | // TODO: paging: if vesa_available, map vesa_mode_info.base 51 | vesa_framebuffer_va = (void *)vesa_mode_info.base; 52 | 53 | vesa_clear(COLOR_BLACK); 54 | 55 | // for tty driver 56 | vesa_init_tty_color(); 57 | vesa_tty_driver.width = vesa_mode_info.x_res / VESA_CHAR_WIDTH; 58 | vesa_tty_driver.height = vesa_mode_info.y_res / VESA_CHAR_HEIGHT; 59 | 60 | spinlock_init(&vesa_lock); 61 | } 62 | else 63 | { 64 | vesa_available = false; 65 | } 66 | } 67 | 68 | inline uint32_t vesa_device_color(color_t color) 69 | { 70 | uint32_t r, g, b; 71 | COLOR_RGB(color, r, g, b); 72 | r = ((r << vesa_mode_info.red_mask) >> 8) << vesa_mode_info.red_position; 73 | g = ((g << vesa_mode_info.green_mask) >> 8) << vesa_mode_info.green_position; 74 | b = ((b << vesa_mode_info.blue_mask) >> 8) << vesa_mode_info.blue_position; 75 | return r | g | b; 76 | } 77 | 78 | #define OFFSET(fb, x0, y0) \ 79 | ((uint8_t *)fb + vesa_mode_info.pitch * (y0) + vesa_mode_info.bpp * (x0) / 8) 80 | 81 | #define SET_COLOR(lfb, color) \ 82 | do \ 83 | { \ 84 | if (vesa_mode_info.bpp == 32) \ 85 | { \ 86 | uint32_t *lfb32 = (uint32_t *)lfb; \ 87 | *lfb32 = color; \ 88 | lfb += 4; \ 89 | } \ 90 | else if (vesa_mode_info.bpp == 24) \ 91 | { \ 92 | uint32_t *lfb32 = (uint32_t *)lfb; \ 93 | *lfb32 = (*lfb32 & 0xff000000) | (color & 0xffffff); \ 94 | lfb += 3; \ 95 | } \ 96 | else /* 15, 16 */ \ 97 | { \ 98 | uint16_t *lfb16 = (uint16_t *)lfb; \ 99 | *lfb16 = (uint16_t)(color & 0xffff); \ 100 | lfb += 2; \ 101 | } \ 102 | } while (0) 103 | 104 | #define KEEP_COLOR(lfb) \ 105 | do \ 106 | { \ 107 | lfb += vesa_mode_info.bpp >> 3; \ 108 | } while (0) 109 | 110 | #define RECTANGLE_FOR_EACH_PIXEL_BEGIN(fb, lfb, width, height, x, y) \ 111 | for (size_t y = 0; y < (height); ++y) \ 112 | { \ 113 | uint8_t *lfb = fb; \ 114 | for (size_t x = 0; x < (width); ++x) \ 115 | { 116 | 117 | #define RECTANGLE_FOR_EACH_PIXEL_END() \ 118 | } \ 119 | fb += vesa_mode_info.pitch; \ 120 | } 121 | 122 | void vesa_clear(color_t color) 123 | { 124 | if (!vesa_available) 125 | { 126 | return; 127 | } 128 | uint8_t *fb = vesa_framebuffer_va; 129 | uint32_t device_color = vesa_device_color(color); 130 | 131 | RECTANGLE_FOR_EACH_PIXEL_BEGIN(fb, lfb, vesa_mode_info.x_res, vesa_mode_info.y_res, 132 | x, y) 133 | SET_COLOR(lfb, device_color); 134 | RECTANGLE_FOR_EACH_PIXEL_END() 135 | } 136 | 137 | inline void vesa_fill_char(size_t x0, size_t y0, uint8_t ch, color_t fc, color_t bc) 138 | { 139 | if (!vesa_available) 140 | { 141 | return; 142 | } 143 | uint8_t *fb = OFFSET(vesa_framebuffer_va, x0, y0); 144 | uint8_t *font = vga_font_get(ch); 145 | uint32_t device_fc = vesa_device_color(fc), 146 | device_bc = vesa_device_color(bc); 147 | 148 | RECTANGLE_FOR_EACH_PIXEL_BEGIN(fb, lfb, VESA_CHAR_WIDTH, VESA_CHAR_HEIGHT, x, y) 149 | uint32_t c; 150 | if (x < VGA_FONT_WIDTH && y < VGA_FONT_HEIGHT && ((font[y] << x) & 0x80)) // MSB, left 151 | { 152 | c = device_fc; 153 | } 154 | else 155 | { 156 | c = device_bc; 157 | } 158 | SET_COLOR(lfb, c); 159 | RECTANGLE_FOR_EACH_PIXEL_END() 160 | } 161 | 162 | inline void vesa_fill_char_scale(size_t x0, size_t y0, uint8_t ch, 163 | size_t scale, color_t fc, color_t bc) 164 | { 165 | if (!vesa_available) 166 | { 167 | return; 168 | } 169 | uint8_t *fb = OFFSET(vesa_framebuffer_va, x0, y0); 170 | uint8_t *font = vga_font_get(ch); 171 | uint32_t device_fc = vesa_device_color(fc), 172 | device_bc = vesa_device_color(bc); 173 | size_t char_width = scale / 2, 174 | char_height = scale; 175 | 176 | RECTANGLE_FOR_EACH_PIXEL_BEGIN(fb, lfb, char_width, char_height, x, y) 177 | uint32_t c; 178 | // MSB, left 179 | if ((font[y * VGA_FONT_HEIGHT / scale] << (x * 2 * VGA_FONT_WIDTH / scale)) & 0x80) 180 | { 181 | c = device_fc; 182 | } 183 | else 184 | { 185 | c = device_bc; 186 | } 187 | SET_COLOR(lfb, c); 188 | RECTANGLE_FOR_EACH_PIXEL_END() 189 | } 190 | 191 | inline void vesa_fill_char_transparent(size_t x0, size_t y0, uint8_t ch, color_t fc) 192 | { 193 | if (!vesa_available) 194 | { 195 | return; 196 | } 197 | uint8_t *fb = OFFSET(vesa_framebuffer_va, x0, y0); 198 | uint8_t *font = vga_font_get(ch); 199 | uint32_t device_fc = vesa_device_color(fc); 200 | 201 | RECTANGLE_FOR_EACH_PIXEL_BEGIN(fb, lfb, VGA_FONT_WIDTH, VGA_FONT_HEIGHT, x, y) 202 | if (x < VGA_FONT_WIDTH && y < VGA_FONT_HEIGHT && ((font[y] << x) & 0x80)) // MSB, left 203 | { 204 | SET_COLOR(lfb, device_fc); 205 | } 206 | else 207 | { 208 | KEEP_COLOR(lfb); 209 | } 210 | RECTANGLE_FOR_EACH_PIXEL_END() 211 | } 212 | 213 | inline void vesa_fill_char_scale_transparent(size_t x0, size_t y0, uint8_t ch, 214 | size_t scale, color_t fc) 215 | { 216 | if (!vesa_available) 217 | { 218 | return; 219 | } 220 | uint8_t *fb = OFFSET(vesa_framebuffer_va, x0, y0); 221 | uint8_t *font = vga_font_get(ch); 222 | uint32_t device_fc = vesa_device_color(fc); 223 | size_t char_width = scale / 2, 224 | char_height = scale; 225 | 226 | RECTANGLE_FOR_EACH_PIXEL_BEGIN(fb, lfb, char_width, char_height, x, y) 227 | // MSB, left 228 | if ((font[y * VGA_FONT_HEIGHT / scale] << (x * 2 * VGA_FONT_WIDTH / scale)) & 0x80) 229 | { 230 | SET_COLOR(lfb, device_fc); 231 | } 232 | else 233 | { 234 | KEEP_COLOR(lfb); 235 | } 236 | RECTANGLE_FOR_EACH_PIXEL_END() 237 | } 238 | 239 | inline void vesa_fill_rect(size_t x0, size_t y0, size_t width, size_t height, color_t color) 240 | { 241 | if (!vesa_available) 242 | { 243 | return; 244 | } 245 | uint8_t *fb = OFFSET(vesa_framebuffer_va, x0, y0); 246 | uint32_t device_color = vesa_device_color(color); 247 | 248 | RECTANGLE_FOR_EACH_PIXEL_BEGIN(fb, lfb, width, height, x, y) 249 | SET_COLOR(lfb, device_color); 250 | RECTANGLE_FOR_EACH_PIXEL_END() 251 | } 252 | 253 | inline void vesa_draw_hline(size_t x0, size_t y0, size_t width, color_t color) 254 | { 255 | vesa_fill_rect(x0, y0, width, 1, color); 256 | } 257 | inline void vesa_draw_vline(size_t x0, size_t y0, size_t height, color_t color) 258 | { 259 | vesa_fill_rect(x0, y0, 1, height, color); 260 | } 261 | 262 | void vesa_draw_button_rect(size_t x0, size_t y0, size_t width, size_t height, bool pushed) 263 | { 264 | if (!pushed) 265 | { 266 | vesa_draw_hline(x0, y0, width, 0xe0e0e0); 267 | vesa_draw_vline(x0, y0, height - 1, 0xe0e0e0); 268 | vesa_draw_hline(x0, y0 + height - 1, width, 0x303030); 269 | vesa_draw_vline(x0 + width - 1, y0 + 1, height - 1, 0x303030); 270 | vesa_fill_rect(x0 + 1, y0 + 1, width - 2, height - 2, 0x909090); 271 | } 272 | else 273 | { 274 | vesa_draw_hline(x0, y0, width, 0x303030); 275 | vesa_draw_vline(x0, y0, height - 1, 0x303030); 276 | vesa_draw_hline(x0, y0 + height - 1, width, 0xe0e0e0); 277 | vesa_draw_vline(x0 + width - 1, y0, height, 0xe0e0e0); 278 | vesa_fill_rect(x0 + 1, y0 + 1, width - 2, height - 2, 0x808080); 279 | } 280 | } 281 | 282 | void vesa_fill_string(size_t x0, size_t y0, size_t width, const char *str, color_t fc) 283 | { 284 | if (width != (size_t)-1) 285 | { 286 | for (int i = 0; str[i] != '\0'; ++i) 287 | { 288 | vesa_fill_char_transparent(x0 + i % width * 9, y0 + i / width * 16, 289 | str[i], fc); 290 | } 291 | } 292 | else 293 | { 294 | for (int i = 0; str[i] != '\0'; ++i) 295 | { 296 | vesa_fill_char_transparent(x0 + i * 9, y0, str[i], fc); 297 | } 298 | } 299 | } 300 | 301 | void vesa_init_tty_color() 302 | { 303 | vesa_tty_color[TTY_COLOR_BLACK] = vesa_device_color(MKCOLOR(0, 0, 0)); 304 | vesa_tty_color[TTY_COLOR_BLUE] = vesa_device_color(MKCOLOR(0, 0, 168)); 305 | vesa_tty_color[TTY_COLOR_GREEN] = vesa_device_color(MKCOLOR(0, 168, 0)); 306 | vesa_tty_color[TTY_COLOR_CYAN] = vesa_device_color(MKCOLOR(0, 168, 168)); 307 | vesa_tty_color[TTY_COLOR_RED] = vesa_device_color(MKCOLOR(168, 0, 0)); 308 | vesa_tty_color[TTY_COLOR_MAGENTA] = vesa_device_color(MKCOLOR(168, 0, 168)); 309 | vesa_tty_color[TTY_COLOR_BROWN] = vesa_device_color(MKCOLOR(168, 87, 0)); 310 | vesa_tty_color[TTY_COLOR_LIGHTGREY] = vesa_device_color(MKCOLOR(168, 168, 168)); 311 | vesa_tty_color[TTY_COLOR_DARKGREY] = vesa_device_color(MKCOLOR(87, 87, 87)); 312 | vesa_tty_color[TTY_COLOR_LIGHTBLUE] = vesa_device_color(MKCOLOR(87, 87, 255)); 313 | vesa_tty_color[TTY_COLOR_LIGHTGREEN] = vesa_device_color(MKCOLOR(87, 255, 87)); 314 | vesa_tty_color[TTY_COLOR_LIGHTCYAN] = vesa_device_color(MKCOLOR(87, 255, 255)); 315 | vesa_tty_color[TTY_COLOR_LIGHTRED] = vesa_device_color(MKCOLOR(255, 87, 87)); 316 | vesa_tty_color[TTY_COLOR_LIGHTMAGENTA] = vesa_device_color(MKCOLOR(255, 87, 255)); 317 | vesa_tty_color[TTY_COLOR_LIGHTBROWN] = vesa_device_color(MKCOLOR(255, 255, 87)); 318 | vesa_tty_color[TTY_COLOR_WHITE] = vesa_device_color(MKCOLOR(255, 255, 255)); 319 | } 320 | 321 | void vesa_tty_init(tty_t *tty, size_t i) 322 | { 323 | // allocate colored chars buffer 324 | tty->mem = (tty_colored_char_t *)mm_palloc(vesa_tty_driver.width * 325 | vesa_tty_driver.height * 326 | sizeof(tty_colored_char_t)); 327 | memset(tty->mem, 0, vesa_tty_driver.width * vesa_tty_driver.height * 328 | sizeof(tty_colored_char_t)); 329 | } 330 | 331 | void vesa_tty_rerender(tty_t *tty) 332 | { 333 | // inc and get? 334 | ++vesa_revision; 335 | uint32_t current_revision = vesa_revision; 336 | 337 | uint8_t *fb = (uint8_t *)vesa_framebuffer_va; 338 | 339 | // clear 340 | /*uint32_t device_color = vesa_device_color(COLOR_BLACK); 341 | RECTANGLE_FOR_EACH_PIXEL_BEGIN(fb, lfb, vesa_mode_info.x_res, vesa_mode_info.y_res, 342 | x, y) 343 | if (vesa_revision != current_revision) 344 | { 345 | return; 346 | } 347 | SET_COLOR(lfb, device_color); 348 | RECTANGLE_FOR_EACH_PIXEL_END()*/ 349 | 350 | // reset 351 | fb = (uint8_t *)vesa_framebuffer_va; 352 | //size_t width = vesa_tty_driver.width * VESA_CHAR_WIDTH, 353 | // height = vesa_tty_driver.height * VESA_CHAR_HEIGHT; 354 | tty_colored_char_t *lcch = tty->mem; 355 | for (size_t y = 0; y < vesa_tty_driver.height; ++y) 356 | { 357 | for (size_t y_font = 0; y_font < VESA_CHAR_HEIGHT; ++y_font) 358 | { 359 | uint8_t *lfb = fb; 360 | tty_colored_char_t *cch = lcch; 361 | for (size_t x = 0; x < vesa_tty_driver.width; ++x) 362 | { 363 | tty_color_t color = *cch >> 8; 364 | char ch = *cch & 0xff; 365 | uint8_t *font = vga_font_get(ch); 366 | ++cch; 367 | for (size_t x_font = 0; x_font < VESA_CHAR_WIDTH; ++x_font) 368 | { 369 | if (vesa_revision != current_revision) 370 | { 371 | return; 372 | } 373 | uint32_t c; 374 | // MSB, left 375 | if (x_font < VGA_FONT_WIDTH && y_font < VGA_FONT_HEIGHT && 376 | ((font[y_font] << x_font) & 0x80)) 377 | { 378 | c = vesa_tty_color[color & 0xf]; 379 | } 380 | else 381 | { 382 | c = vesa_tty_color[color >> 4]; 383 | } 384 | SET_COLOR(lfb, c); 385 | } 386 | } 387 | fb += vesa_mode_info.pitch; 388 | } 389 | lcch += vesa_tty_driver.width; 390 | } 391 | } 392 | 393 | void vesa_tty_switch_handler(tty_t *tty) 394 | { 395 | vesa_tty_rerender(tty); 396 | } 397 | 398 | void vesa_tty_update_cursor_location(tty_t *tty) 399 | { 400 | // TODO 401 | } 402 | 403 | void vesa_tty_set_char(tty_t *tty, size_t x, size_t y, char ch, tty_color_t color) 404 | { 405 | size_t x0 = x * VESA_CHAR_WIDTH, y0 = y * VESA_CHAR_HEIGHT; 406 | uint8_t *fb = OFFSET(vesa_framebuffer_va, x0, y0); 407 | uint8_t *font = vga_font_get(ch); 408 | uint32_t device_fc = vesa_tty_color[color & 0xf], 409 | device_bc = vesa_tty_color[color >> 4]; 410 | 411 | RECTANGLE_FOR_EACH_PIXEL_BEGIN(fb, lfb, VESA_CHAR_WIDTH, VESA_CHAR_HEIGHT, x_font, y_font) 412 | uint32_t c; 413 | if (x_font < VGA_FONT_WIDTH && y_font < VGA_FONT_HEIGHT && 414 | (font[y_font] << x_font) & 0x80) // MSB, left 415 | { 416 | c = device_fc; 417 | } 418 | else 419 | { 420 | c = device_bc; 421 | } 422 | SET_COLOR(lfb, c); 423 | RECTANGLE_FOR_EACH_PIXEL_END() 424 | } 425 | 426 | const tty_driver_t *vesa_get_tty_driver() 427 | { 428 | return (const tty_driver_t *)&vesa_tty_driver; 429 | } 430 | -------------------------------------------------------------------------------- /driver/vesa.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_KERNEL_DRIVER_VESA_H_ 2 | #define _WDOS_KERNEL_DRIVER_VESA_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define VESA_MAGIC "VESA" 9 | #define VESA_MAGIC_LENGTH 4 10 | #define VESA_MODE_INVALID 0xffff 11 | #define VESA_MODE_TERMINATOR 0xffff 12 | #define VESA_MODE_LINEAR_FRAMEBUFFER 0x4000 13 | #define VESA_MODE_ATTR_GRAPHICS 0x10 14 | #define VESA_MODE_ATTR_LINEAR_FRAMEBUFFER 0x80 15 | #define VESA_MODE_MEMORY_MODEL_DIRECTCOLOR 0x6 16 | 17 | typedef struct vesa_control_info 18 | { 19 | char magic[4]; // "VESA" 20 | uint16_t version; // == 0x0300 for VBE 3.0 21 | uint16_t oem_string_offset; 22 | uint16_t oem_string_seg; 23 | uint32_t capabilities; 24 | uint16_t video_mode_offset; 25 | uint16_t video_mode_seg; 26 | uint16_t total_memory; // x 64KB 27 | uint8_t reserved[492]; 28 | } __attribute__((packed)) vesa_control_info_t; 29 | 30 | typedef struct vesa_mode_info 31 | { 32 | uint16_t attr; 33 | uint8_t win_a, win_b; 34 | uint16_t win_granularity; 35 | uint16_t win_size; 36 | uint16_t seg_a, seg_b; 37 | uint32_t real_mode_func_ptr; 38 | uint16_t pitch; // bytes per scanline 39 | 40 | uint16_t x_res, y_res; // width, height 41 | uint8_t w_char, y_char, planes, bpp, banks; 42 | uint8_t memory_model, bank_size, image_pages; 43 | uint8_t reserved0; 44 | 45 | uint8_t red_mask, red_position; 46 | uint8_t green_mask, green_position; 47 | uint8_t blue_mask, blue_position; 48 | uint8_t rsv_mask, rsv_position; 49 | uint8_t directcolor_attr; 50 | 51 | uint32_t base; // framebuffer physical address 52 | uint32_t reserved1; 53 | uint16_t reserved2; 54 | uint8_t reserved[206]; 55 | } __attribute__((packed)) vesa_mode_info_t; 56 | 57 | typedef uint32_t color_t; 58 | #define MKCOLOR(r, g, b) (((color_t)((r) & 0xff) << 16) | ((color_t)((g) & 0xff) << 8) | \ 59 | ((color_t)((b) & 0xff))) 60 | #define COLOR_BLACK MKCOLOR(0, 0, 0) 61 | #define COLOR_WHITE MKCOLOR(0xff, 0xff, 0xff) 62 | #define COLOR_R(color) (((color) >> 16) & 0xff) 63 | #define COLOR_G(color) (((color) >> 8) & 0xff) 64 | #define COLOR_B(color) (((color)) & 0xff) 65 | #define COLOR_RGB(color, r, g, b) \ 66 | do \ 67 | { \ 68 | r = COLOR_R(color); \ 69 | g = COLOR_G(color); \ 70 | b = COLOR_B(color); \ 71 | } \ 72 | while (0) 73 | #define VESA_CHAR_WIDTH (VGA_FONT_WIDTH + 1) 74 | #define VESA_CHAR_HEIGHT (VGA_FONT_HEIGHT) 75 | 76 | extern bool vesa_available; 77 | 78 | void init_vesa(multiboot_info_t *mb_info); 79 | uint32_t vesa_device_color(color_t color); 80 | void vesa_clear(color_t color); 81 | void vesa_fill_char(size_t x0, size_t y0, uint8_t ch, color_t fc, color_t bc); 82 | void vesa_fill_char_scale(size_t x0, size_t y0, uint8_t ch, 83 | size_t scale, color_t fc, color_t bc); 84 | void vesa_fill_char_transparent(size_t x0, size_t y0, uint8_t ch, color_t fc); 85 | void vesa_fill_char_scale_transparent(size_t x0, size_t y0, uint8_t ch, 86 | size_t scale, color_t fc); 87 | void vesa_fill_rect(size_t x0, size_t y0, size_t width, size_t height, color_t color); 88 | void vesa_draw_hline(size_t x0, size_t y0, size_t width, color_t color); 89 | void vesa_draw_vline(size_t x0, size_t y0, size_t height, color_t color); 90 | void vesa_draw_button_rect(size_t x0, size_t y0, size_t width, size_t height, bool pushed); 91 | void vesa_fill_string(size_t x0, size_t y0, size_t width, const char *str, color_t fc); 92 | 93 | // for tty driver 94 | void vesa_init_tty_color(); 95 | void vesa_tty_init(tty_t *tty, size_t i); 96 | void vesa_tty_rerender(tty_t *tty); 97 | void vesa_tty_switch_handler(tty_t *tty); 98 | void vesa_tty_update_cursor_location(tty_t *tty); 99 | void vesa_tty_set_char(tty_t *tty, size_t x, size_t y, char ch, tty_color_t color); 100 | const tty_driver_t *vesa_get_tty_driver(); 101 | 102 | #endif // _WDOS_KERNEL_DRIVER_VESA_H_ 103 | -------------------------------------------------------------------------------- /driver/vga.c: -------------------------------------------------------------------------------- 1 | #include "vga.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | static tty_driver_t vga_tty_driver = 8 | { 9 | .width = VGA_WIDTH, 10 | .height = VGA_HEIGHT, 11 | .init = &vga_tty_init, 12 | .rerender = NULL, 13 | .switch_handler = &vga_tty_switch_handler, 14 | .update_cursor_location = &vga_tty_update_cursor_location, 15 | .set_char = NULL 16 | }; 17 | 18 | void init_vga() 19 | { 20 | 21 | } 22 | 23 | void vga_set_start_address(uint16_t *gm) 24 | { 25 | uint16_t start_address = 26 | (uint16_t)(((uintptr_t)gm - (uintptr_t)VGA_GRAPHICS_MEMORY_START_ADDRESS) >> 1); 27 | 28 | ureg_t flags; 29 | save_flags(flags); 30 | cli(); 31 | 32 | outb(CRTC_ADDRESS, CRTC_START_ADDRESS_HIGH); 33 | io_delay(); 34 | outb(CRTC_DATA, (start_address >> 8) & 0xFF); 35 | io_delay(); 36 | outb(CRTC_ADDRESS, CRTC_START_ADDRESS_LOW); 37 | io_delay(); 38 | outb(CRTC_DATA, start_address & 0xFF); 39 | io_delay(); 40 | 41 | restore_flags(flags); 42 | } 43 | 44 | void vga_set_cursor_location(uint8_t x, uint8_t y) 45 | { 46 | uint16_t location = y * VGA_WIDTH + x; 47 | 48 | ureg_t flags; 49 | save_flags(flags); 50 | cli(); 51 | 52 | outb(CRTC_ADDRESS, CRTC_CURSOR_LOCATION_HIGH); 53 | io_delay(); 54 | outb(CRTC_DATA, (location >> 8) & 0xFF); 55 | io_delay(); 56 | outb(CRTC_ADDRESS, CRTC_CURSOR_LOCATION_LOW); 57 | io_delay(); 58 | outb(CRTC_DATA, location & 0xFF); 59 | io_delay(); 60 | 61 | restore_flags(flags); 62 | } 63 | 64 | void vga_tty_init(tty_t *tty, size_t i) 65 | { 66 | tty->mem = (tty_colored_char_t *)(VGA_GRAPHICS_MEMORY_START_ADDRESS + (i << 12)); // 4K 67 | } 68 | 69 | void vga_tty_switch_handler(tty_t *tty) 70 | { 71 | vga_set_start_address(tty->mem); 72 | } 73 | 74 | void vga_tty_update_cursor_location(tty_t *tty) 75 | { 76 | // TODO 77 | // vga_set_cursor_location(tty->x, tty->y); 78 | } 79 | 80 | const tty_driver_t *vga_get_tty_driver() 81 | { 82 | return (const tty_driver_t *)&vga_tty_driver; 83 | } 84 | -------------------------------------------------------------------------------- /driver/vga.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_KERNEL_DRIVER_VGA_H_ 2 | #define _WDOS_KERNEL_DRIVER_VGA_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define CRTC_ADDRESS 0x3D4 9 | #define CRTC_DATA 0x3D5 10 | #define CRTC_START_ADDRESS_HIGH 0xC 11 | #define CRTC_START_ADDRESS_LOW 0xD 12 | #define CRTC_CURSOR_LOCATION_HIGH 0xE 13 | #define CRTC_CURSOR_LOCATION_LOW 0xF 14 | 15 | #define VGA_GRAPHICS_MEMORY_START_ADDRESS __VA((void *)0xb8000) 16 | #define VGA_WIDTH 80 17 | #define VGA_HEIGHT 25 18 | 19 | void init_vga(); 20 | void vga_set_start_address(uint16_t *gm); 21 | void vga_set_cursor_location(uint8_t x, uint8_t y); 22 | 23 | // for tty driver 24 | void vga_tty_init(tty_t *tty, size_t i); 25 | void vga_tty_switch_handler(tty_t *tty); 26 | void vga_tty_update_cursor_location(tty_t *tty); 27 | const tty_driver_t *vga_get_tty_driver(); 28 | 29 | #endif // _WDOS_KERNEL_DRIVER_VGA_H_ 30 | -------------------------------------------------------------------------------- /driver/vga_font.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_KERNEL_DRIVER_VGA_FONT_H_ 2 | #define _WDOS_KERNEL_DRIVER_VGA_FONT_H_ 3 | 4 | #include 5 | 6 | #define VGA_FONT_WIDTH 8 7 | #define VGA_FONT_HEIGHT 16 8 | 9 | extern uint8_t vga_font[256 * 16]; 10 | 11 | #define vga_font_get(ch) (&vga_font[(ch) * 16]) 12 | 13 | #endif // _WDOS_KERNEL_DRIVER_VGA_FONT_H_ 14 | -------------------------------------------------------------------------------- /dwm.c: -------------------------------------------------------------------------------- 1 | #include "dwm.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | static uint8_t dwm_stack[0x1000]; 10 | 11 | uint32_t dwm_pid; 12 | 13 | void init_dwm() 14 | { 15 | dwm_pid = thread_create_kernel("dwm", &dwm_entry, &dwm_stack[sizeof(dwm_stack)]); 16 | kprint_ok_fail("[KDEBUG] create windows manager thread", dwm_pid != (uint32_t)-1); 17 | } 18 | 19 | void dwm_entry() 20 | { 21 | if (!vesa_available) 22 | { 23 | thread_set_priority(THREAD_PRIORITY_MIN); 24 | kprint("[DWM] No GUI available :(\n"); 25 | while (true) 26 | { 27 | sys_yield(); 28 | } 29 | } 30 | thread_set_priority(THREAD_PRIORITY_MAX); 31 | kprint("[DWM] Initialized, press F8 to enter GUI.\n"); 32 | while (true) 33 | { 34 | if (tty_current_screen() != tty_select(7)) 35 | { 36 | while (tty_current_screen() != tty_select(7)) 37 | { 38 | sys_yield(); 39 | } 40 | vesa_clear(0x00a8a8); 41 | //vesa_clear(0x6060ff); 42 | } 43 | kprint("[DWM] Rendering...\n"); 44 | for (int i = 0; i < 26; ++i) 45 | { 46 | vesa_fill_char(100 + i * 9, 160, 'a' + i, 0xa8a8a8, 0); 47 | } 48 | for (int i = 0; i < 26; ++i) 49 | { 50 | vesa_fill_char(100 + i * 9, 176, 'A' + i, 0xa8a8a8, 0); 51 | } 52 | for (int i = 0; i < 26; ++i) 53 | { 54 | vesa_fill_char_transparent(100 + i * 9, 192, 'a' + i, 0); 55 | } 56 | for (int i = 0; i < 26; ++i) 57 | { 58 | vesa_fill_char_transparent(100 + i * 9, 208, 'A' + i, 0); 59 | } 60 | /*for (int y = 1; y <= 256; ++y) 61 | { 62 | for (int i = 0; i < 6; ++i) 63 | { 64 | vesa_fill_char_scale_transparent(i * (y / 2 + 1), 0, '1' + i, y, 0xa8a8a8); 65 | } 66 | }*/ 67 | for (int i = 0; i < 0x100; ++i) 68 | { 69 | vesa_draw_vline(10 + i, 10, 30, 0xff0000 | i); 70 | } 71 | for (int i = 0; i < 0xff; ++i) 72 | { 73 | vesa_draw_vline(265 + i, 10, 30, 0xff00ff - (i << 16)); 74 | } 75 | for (int i = 0; i < 0xff; ++i) 76 | { 77 | vesa_draw_vline(520 + i, 10, 30, 0x0000ff | (i << 8)); 78 | } 79 | vesa_fill_rect(50, 50, 50, 50, 0xff0000); 80 | vesa_fill_rect(105, 50, 50, 50, 0x00ff00); 81 | vesa_fill_rect(160, 50, 50, 50, 0x0000ff); 82 | vesa_fill_rect(50, 105, 50, 50, 0x00ffff); 83 | vesa_fill_rect(105, 105, 50, 50, 0xff00ff); 84 | vesa_fill_rect(160, 105, 50, 50, 0xffff00); 85 | /*vesa_draw_hline(0, 570, 800, 0xffffff); 86 | vesa_draw_vline(0, 570, 29, 0xffffff); 87 | vesa_draw_hline(0, 599, 800, 0); 88 | vesa_draw_vline(799, 570, 30, 0); 89 | vesa_fill_rect(1, 571, 798, 28, 0x808080);*/ 90 | vesa_draw_button_rect(0, 570, 800, 30, false); 91 | vesa_draw_button_rect(5, 575, 50, 20, false); 92 | vesa_fill_string(9, 578, -1, "Start", 0); 93 | vesa_draw_button_rect(744, 575, 50, 20, true); 94 | vesa_fill_string(748, 578, -1, "23:17", 0); 95 | vesa_fill_string(328, 284, -1, "Welcome to WDOS!", 0); 96 | vesa_fill_string(296, 300, -1, "GUI is not implemented.", 0); 97 | vesa_fill_string(287, 316, -1, "Press F1~F7 to enter TTY.", 0); 98 | delay(1000); 99 | vesa_draw_button_rect(5, 575, 50, 20, true); 100 | vesa_fill_string(10, 579, -1, "Start", 0); 101 | delay(1000); 102 | vesa_draw_button_rect(5, 575, 50, 20, false); 103 | vesa_fill_string(9, 578, -1, "Start", 0); 104 | while (tty_current_screen() == tty_select(7)) 105 | { 106 | sys_yield(); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /dwm.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_KERNEL_DWM_H_ 2 | #define _WDOS_KERNEL_DWM_H_ 3 | 4 | void init_dwm(); 5 | void dwm_entry(); 6 | 7 | #endif // _WDOS_KERNEL_DWM_H_ 8 | -------------------------------------------------------------------------------- /gdb_remote: -------------------------------------------------------------------------------- 1 | set architecture i386 2 | file kernel.elf 3 | target remote tcp::1234 4 | -------------------------------------------------------------------------------- /idle.c: -------------------------------------------------------------------------------- 1 | #include "idle.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | static uint8_t idle_stack[0x1000]; 8 | 9 | uint32_t idle_pid; 10 | 11 | void init_idle() 12 | { 13 | idle_pid = thread_create_kernel("IDLE", &idle_entry, &idle_stack[sizeof(idle_stack)]); 14 | kprint_ok_fail("[KDEBUG] create system idle process", idle_pid != (uint32_t)-1); 15 | } 16 | 17 | void idle_entry() 18 | { 19 | thread_set_priority(THREAD_PRIORITY_MIN); 20 | kprint("[IDLE] I am system IDLE!\n"); 21 | kprint("[IDLE] My PID="); 22 | kprint_int(get_pid()); 23 | kprint("\n"); 24 | while (true) 25 | { 26 | sys_yield(); 27 | // asm volatile ("hlt"); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /idle.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_KERNEL_IDLE_H_ 2 | #define _WDOS_KERNEL_IDLE_H_ 3 | 4 | void init_idle(); 5 | void idle_entry(); 6 | 7 | #endif // _WDOS_KERNEL_IDLE_H_ 8 | -------------------------------------------------------------------------------- /interrupt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | const char *const cpu_exception_strings[INTERRUPT_EXCEPTION_COUNT] = 8 | { 9 | "#DE Divide-by-zero Error", 10 | "#DB Debug", 11 | "--- Non-maskable Interrupt", 12 | "#BP Breakpoint", 13 | "#OF Overflow", 14 | "#BR Bound Range Exceeded", 15 | "#UD Invalid Opcode", 16 | "#NM Device Not Available", 17 | "#DF Double Fault", 18 | "--- Coprocessor Segment Overrun", 19 | "#TS Invalid TSS", 20 | "#NP Segment Not Present", 21 | "#SS Stack-Segment Fault", 22 | "#GP General Protection Fault", 23 | "#PF Page Fault", 24 | "--- [Reserved]", 25 | "#MF x87 Floating-Point Exception", 26 | "#AC Alignment Check", 27 | "#MC Machine Check", 28 | "#XM/#XF SIMD Floating-Point Exception", 29 | "#VE Virtualization Exception", 30 | "--- [Reserved]", 31 | "--- [Reserved]", 32 | "--- [Reserved]", 33 | "--- [Reserved]", 34 | "--- [Reserved]", 35 | "--- [Reserved]", 36 | "--- [Reserved]", 37 | "--- [Reserved]", 38 | "--- [Reserved]", 39 | "#SX Security Exception", 40 | "--- [Reserved]", 41 | }; 42 | 43 | static irq_handler_t irq_handlers[INTERRUPT_VECTOR_IRQ_COUNT] = { NULL }; 44 | 45 | void interrupt_handler(uint8_t vec, interrupt_frame_t frame) 46 | { 47 | if (vec == INTERRUPT_VECTOR_SYSCALL) 48 | { 49 | syscall_dispatch(frame.eax, &frame); 50 | /* TODO 51 | { 52 | frame.eax = 0xdeadbeef; 53 | tty_set_current(default_tty); 54 | kprint("[KDEBUG] Interrupt: system call #"); 55 | kprint_int(frame.eax); 56 | kprint("\n"); 57 | tty_set_current(NULL); 58 | }*/ 59 | } 60 | else if (vec < INTERRUPT_EXCEPTION_COUNT) // cpu exception 61 | { 62 | tty_switch(default_tty); 63 | tty_set_current(default_tty); 64 | kfill_color(TTY_MKCOLOR(TTY_COLOR_LIGHTGREY, TTY_COLOR_RED)); 65 | kset_color(TTY_MKCOLOR(TTY_COLOR_LIGHTGREY, TTY_COLOR_RED)); 66 | kprint("[pid="); 67 | kprint_int(get_pid()); 68 | kprint("] Exception #"); 69 | kprint_int(vec); 70 | kprint(": "); 71 | kprint(cpu_exception_strings[vec]); 72 | kprint("\n"); 73 | if (vec == 14) // page fault 74 | { 75 | uintptr_t pfla = (uintptr_t)mm_page_fault_va(); 76 | kprint("-> page fault linear address="); 77 | kprint_hex(pfla); 78 | kprint(", flags="); 79 | kprint_hex(frame.errorcode); 80 | kprint("\n"); 81 | } 82 | kprint("-> errorcode="); 83 | kprint_hex(frame.errorcode); 84 | kprint(", frame="); 85 | kprint_hex(&frame); 86 | kprint("\n-> cs:eip="); 87 | kprint_hex(frame.cs); 88 | kprint(":"); 89 | kprint_hex(frame.eip); 90 | kprint(", eflags="); 91 | kprint_hex(frame.eflags); 92 | if ((frame.cs & 0b11) != 0) 93 | { 94 | kprint("\n-> ss:esp="); 95 | kprint_hex(frame.ss); 96 | kprint(":"); 97 | kprint_hex(frame.esp); 98 | } 99 | kprint("\n-> eax="); 100 | kprint_hex(frame.eax); 101 | kprint(", ebx="); 102 | kprint_hex(frame.ebx); 103 | kprint(", ecx="); 104 | kprint_hex(frame.ecx); 105 | kprint(", edx="); 106 | kprint_hex(frame.edx); 107 | kprint("\n-> ebp="); 108 | kprint_hex(frame.ebp); 109 | kprint(", esi="); 110 | kprint_hex(frame.esi); 111 | kprint(", edi="); 112 | kprint_hex(frame.edi); 113 | kprint(", isr_esp="); 114 | kprint_hex(frame.isr_esp); 115 | kprint("\n"); 116 | for (;;) 117 | { 118 | asm("cli"); 119 | asm("hlt"); 120 | } 121 | } 122 | else if (vec >= INTERRUPT_VECTOR_IRQ0 && vec <= INTERRUPT_VECTOR_IRQ7) 123 | { 124 | irq_dispatch(vec - INTERRUPT_VECTOR_IRQ0, &frame); 125 | } 126 | else if (vec >= INTERRUPT_VECTOR_IRQ8 && vec <= INTERRUPT_VECTOR_IRQ15) 127 | { 128 | irq_dispatch(vec - INTERRUPT_VECTOR_IRQ8, &frame); 129 | } 130 | } 131 | 132 | inline void irq_dispatch(uint8_t irq, interrupt_frame_t *frame) 133 | { 134 | if (irq_handlers[irq]) 135 | { 136 | irq_handlers[irq](irq, frame); 137 | } 138 | else 139 | { 140 | if (irq >= 1) 141 | { 142 | tty_set_current(default_tty); 143 | kprint("[KDEBUG] No handler for IRQ #"); 144 | kprint_int(irq); 145 | kprint("\n"); 146 | tty_set_current(NULL); 147 | } 148 | } 149 | send_eoi(irq); 150 | } 151 | 152 | void register_irq_handler(uint8_t irq, irq_handler_t handler) 153 | { 154 | irq_handlers[irq] = handler; 155 | } 156 | -------------------------------------------------------------------------------- /interrupt.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_KERNEL_INTERRUPT_H_ 2 | #define _WDOS_KERNEL_INTERRUPT_H_ 3 | 4 | #include 5 | 6 | typedef struct interrupt_frame 7 | { 8 | uint32_t isr_esp; // esp of interrupt_wrapper 9 | uint32_t gs; 10 | uint32_t fs; 11 | uint32_t es; 12 | uint32_t ds; 13 | uint32_t edi; 14 | uint32_t esi; 15 | uint32_t ebp; 16 | uint32_t _; // unused 17 | uint32_t ebx; 18 | uint32_t edx; 19 | uint32_t ecx; 20 | uint32_t eax; 21 | uint32_t errorcode; 22 | uint32_t eip; 23 | uint32_t cs; 24 | uint32_t eflags; 25 | uint32_t esp; 26 | uint32_t ss; 27 | } __attribute__((packed)) interrupt_frame_t; 28 | 29 | #define SECOND_REGISTER gs 30 | 31 | #define INTERRUPT_VECTOR_IRQ0 (0x20) 32 | #define INTERRUPT_VECTOR_IRQ1 (INTERRUPT_VECTOR_IRQ0 + 1) 33 | #define INTERRUPT_VECTOR_IRQ2 (INTERRUPT_VECTOR_IRQ0 + 2) 34 | #define INTERRUPT_VECTOR_IRQ3 (INTERRUPT_VECTOR_IRQ0 + 3) 35 | #define INTERRUPT_VECTOR_IRQ4 (INTERRUPT_VECTOR_IRQ0 + 4) 36 | #define INTERRUPT_VECTOR_IRQ5 (INTERRUPT_VECTOR_IRQ0 + 5) 37 | #define INTERRUPT_VECTOR_IRQ6 (INTERRUPT_VECTOR_IRQ0 + 6) 38 | #define INTERRUPT_VECTOR_IRQ7 (INTERRUPT_VECTOR_IRQ0 + 7) 39 | #define INTERRUPT_VECTOR_IRQ8 (0x28) 40 | #define INTERRUPT_VECTOR_IRQ9 (INTERRUPT_VECTOR_IRQ8 + 1) 41 | #define INTERRUPT_VECTOR_IRQ10 (INTERRUPT_VECTOR_IRQ8 + 2) 42 | #define INTERRUPT_VECTOR_IRQ11 (INTERRUPT_VECTOR_IRQ8 + 3) 43 | #define INTERRUPT_VECTOR_IRQ12 (INTERRUPT_VECTOR_IRQ8 + 4) 44 | #define INTERRUPT_VECTOR_IRQ13 (INTERRUPT_VECTOR_IRQ8 + 5) 45 | #define INTERRUPT_VECTOR_IRQ14 (INTERRUPT_VECTOR_IRQ8 + 6) 46 | #define INTERRUPT_VECTOR_IRQ15 (INTERRUPT_VECTOR_IRQ8 + 7) 47 | #define INTERRUPT_VECTOR_IRQ_COUNT 16 48 | 49 | #define INTERRUPT_EXCEPTION_COUNT 32 50 | #define INTERRUPT_VECTOR_SYSCALL 0x80 51 | 52 | #define IRQ_CLOCK 0 53 | #define IRQ_KEYBOARD 1 54 | #define IRQ_COM2 3 55 | #define IRQ_COM1 4 56 | #define IRQ_LPT1 5 57 | #define IRQ_FDD 6 58 | #define IRQ_LPT2 7 59 | #define IRQ_CMOS_ALTER 8 60 | #define IRQ_MOUSE 12 61 | #define IRQ_FPU 13 62 | #define IRQ_IDE0 14 63 | #define IRQ_IDE1 15 64 | 65 | // loader.asm 66 | void interrupt_wrapper_0(); 67 | void interrupt_wrapper_1(); 68 | void interrupt_wrapper_2(); 69 | void interrupt_wrapper_3(); 70 | void interrupt_wrapper_4(); 71 | void interrupt_wrapper_5(); 72 | void interrupt_wrapper_6(); 73 | void interrupt_wrapper_7(); 74 | void interrupt_wrapper_8(); 75 | void interrupt_wrapper_9(); 76 | void interrupt_wrapper_10(); 77 | void interrupt_wrapper_11(); 78 | void interrupt_wrapper_12(); 79 | void interrupt_wrapper_13(); 80 | void interrupt_wrapper_14(); 81 | void interrupt_wrapper_15(); 82 | void interrupt_wrapper_16(); 83 | void interrupt_wrapper_17(); 84 | void interrupt_wrapper_18(); 85 | void interrupt_wrapper_19(); 86 | void interrupt_wrapper_20(); 87 | void interrupt_wrapper_21(); 88 | void interrupt_wrapper_22(); 89 | void interrupt_wrapper_23(); 90 | void interrupt_wrapper_24(); 91 | void interrupt_wrapper_25(); 92 | void interrupt_wrapper_26(); 93 | void interrupt_wrapper_27(); 94 | void interrupt_wrapper_28(); 95 | void interrupt_wrapper_29(); 96 | void interrupt_wrapper_30(); 97 | void interrupt_wrapper_31(); 98 | 99 | void interrupt_wrapper_32(); 100 | void interrupt_wrapper_33(); 101 | void interrupt_wrapper_34(); 102 | void interrupt_wrapper_35(); 103 | void interrupt_wrapper_36(); 104 | void interrupt_wrapper_37(); 105 | void interrupt_wrapper_38(); 106 | void interrupt_wrapper_39(); 107 | void interrupt_wrapper_40(); 108 | void interrupt_wrapper_41(); 109 | void interrupt_wrapper_42(); 110 | void interrupt_wrapper_43(); 111 | void interrupt_wrapper_44(); 112 | void interrupt_wrapper_45(); 113 | void interrupt_wrapper_46(); 114 | void interrupt_wrapper_47(); 115 | 116 | void interrupt_wrapper_128(); 117 | 118 | extern const char *const cpu_exception_strings[INTERRUPT_EXCEPTION_COUNT]; 119 | 120 | typedef void (*irq_handler_t)(uint8_t, interrupt_frame_t*); 121 | 122 | void interrupt_handler(uint8_t vec, interrupt_frame_t frame); 123 | void irq_dispatch(uint8_t irq, interrupt_frame_t *frame); 124 | void register_irq_handler(uint8_t irq, irq_handler_t handler); 125 | #define enable_interrupt() asm volatile ("sti") 126 | #define disable_interrupt() asm volatile ("cli") 127 | 128 | #endif // _WDOS_KERNEL_INTERRUPT_H_ 129 | -------------------------------------------------------------------------------- /io.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void outb(uint16_t port, uint8_t value) 4 | { 5 | asm volatile ("out %%al, %%dx" 6 | : 7 | : "d"(port), "a"(value) 8 | ); 9 | } 10 | 11 | void outw(uint16_t port, uint16_t value) 12 | { 13 | asm volatile ("out %%ax, %%dx" 14 | : 15 | : "d"(port), "a"(value) 16 | ); 17 | } 18 | 19 | void outdw(uint16_t port, uint32_t value) 20 | { 21 | asm volatile ("out %%eax, %%dx" 22 | : 23 | : "d"(port), "a"(value) 24 | ); 25 | } 26 | 27 | uint8_t inb(uint16_t port) 28 | { 29 | uint8_t ret; 30 | asm volatile ("xor %%eax, %%eax\n" 31 | "in %%dx, %%al" 32 | : "=a"(ret) 33 | : "d"(port) 34 | ); 35 | return ret; 36 | } 37 | 38 | uint16_t inw(uint16_t port) 39 | { 40 | uint16_t ret; 41 | asm volatile ("xor %%eax, %%eax\n" 42 | "in %%dx, %%ax" 43 | : "=a"(ret) 44 | : "d"(port) 45 | ); 46 | return ret; 47 | } 48 | 49 | uint32_t indw(uint16_t port) 50 | { 51 | uint32_t ret; 52 | asm volatile ("in %%dx, %%eax" 53 | : "=a"(ret) 54 | : "d"(port) 55 | ); 56 | return ret; 57 | } 58 | 59 | void io_delay() 60 | { 61 | asm volatile ("nop\nnop\nnop\nnop"); 62 | } 63 | -------------------------------------------------------------------------------- /io.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_KERNEL_IO_H_ 2 | #define _WDOS_KERNEL_IO_H_ 3 | 4 | #include 5 | 6 | void outb(uint16_t port, uint8_t value); 7 | void outw(uint16_t port, uint16_t value); 8 | void outdw(uint16_t port, uint32_t value); 9 | 10 | uint8_t inb(uint16_t port); 11 | uint16_t inw(uint16_t port); 12 | uint32_t indw(uint16_t port); 13 | 14 | void io_delay(); 15 | 16 | #endif // _WDOS_KERNEL_IO_H_ 17 | -------------------------------------------------------------------------------- /iso/boot/cmdline.txt: -------------------------------------------------------------------------------- 1 | cmdline test 2 | -------------------------------------------------------------------------------- /iso/boot/grub/grub.cfg: -------------------------------------------------------------------------------- 1 | default=0 2 | timeout=0 3 | 4 | menuentry 'wdos' --class gnu --class os { 5 | multiboot /boot/kernel.elf cmd_test 6 | } 7 | -------------------------------------------------------------------------------- /kmain.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | static uint8_t thread_stack[0x8000]; 18 | 19 | void delay(int x) 20 | { 21 | int i = 10000; 22 | while (--i) 23 | { 24 | int j = 10 * x; 25 | while (--j); 26 | } 27 | } 28 | 29 | void thread1() 30 | { 31 | thread_set_priority(THREAD_PRIORITY_MAX); 32 | kset_color(TTY_MKCOLOR(TTY_COLOR_LIGHTCYAN, TTY_COLOR_BLACK)); 33 | kprint("My PID="); 34 | kprint_int(get_pid()); 35 | kprint("\n"); 36 | kprint("calling sys_test()..."); 37 | kprint_hex(sys_test()); 38 | kprint("\n"); 39 | kprint("calling sys_add(123, 654)..."); 40 | kprint_int(sys_add(123, 654)); 41 | kprint("\n"); 42 | uint32_t i = 0; 43 | while (true) 44 | { 45 | ktty_enter(); 46 | kprint("My PID="); 47 | kprint_int(get_pid()); 48 | kprint(" A"); 49 | kprint_int(++i); 50 | kprint(" "); 51 | kprint_hex(&i); 52 | kprint("\n"); 53 | ktty_leave(); 54 | //kprint("calling sys_delay(1)..."); 55 | //sys_delay(1); 56 | //delay(1); 57 | } 58 | // TODO: sys_exit 59 | } 60 | 61 | void thread2() 62 | { 63 | kset_color(TTY_MKCOLOR(TTY_COLOR_WHITE, TTY_COLOR_BLACK)); 64 | kprint("My PID="); 65 | kprint_int(get_pid()); 66 | kprint("\n"); 67 | kprint("calling sys_test()..."); 68 | kprint_hex(sys_test()); 69 | kprint("\n"); 70 | kprint("calling sys_add(135, 531)..."); 71 | kprint_int(sys_add(135, 531)); 72 | kprint("\n"); 73 | uint32_t i = 0; 74 | while (true) 75 | { 76 | ktty_enter(); 77 | kprint("My PID="); 78 | kprint_int(get_pid()); 79 | kprint(" B"); 80 | kprint_int(++i); 81 | kprint(" "); 82 | kprint_hex(&i); 83 | kprint("\n"); 84 | ktty_leave(); 85 | //kprint("calling sys_delay(2)..."); 86 | //sys_delay(2); 87 | //delay(2); 88 | } 89 | // TODO: sys_exit 90 | } 91 | 92 | void thread3() 93 | { 94 | kprint("My PID="); 95 | kprint_int(get_pid()); 96 | kprint("\nThis is tty "); 97 | kprint_int(get_ttyid() + 1); 98 | kprint(".\n"); 99 | thread_set_priority(THREAD_PRIORITY_MIN); 100 | while (true) 101 | { 102 | sys_yield(); 103 | } 104 | } 105 | 106 | void print_multiboot_info(int mb_magic, multiboot_info_t *mb_info) 107 | { 108 | kprint("[KDEBUG] ====multiboot header====\n"); 109 | kprint("-> magic="); 110 | kprint_hex(mb_magic); 111 | kprint(", mb_info at "); 112 | kprint_hex(mb_info); 113 | kprint(",\n-> flags="); 114 | kprint_bin(mb_info->flags); 115 | kprint(",\n-> mem_lower="); 116 | kprint_int(mb_info->mem_lower); 117 | kprint(" KiB, mem_upper="); 118 | kprint_int(mb_info->mem_upper); 119 | kprint(" KiB, boot_device="); 120 | kprint_hex(mb_info->boot_device); 121 | kprint(", \n-> mmap_addr="); 122 | kprint_hex((uintptr_t)__VA((void *)mb_info->mmap_addr)); 123 | kprint(", mmap_length="); 124 | kprint_int(mb_info->mmap_length); 125 | kprint(" bytes,\n-> cmdline at "); 126 | kprint_hex((uintptr_t)__VA((void *)mb_info->cmdline)); 127 | kprint(", cmdline=\""); 128 | kprint((char *)__VA((void *)mb_info->cmdline)); 129 | kprint("\"\n"); 130 | } 131 | 132 | void print_mem_info() 133 | { 134 | kprint("[KDEBUG] ====system memory info====\n"); 135 | kprint("-> free_mem_start="); 136 | kprint_hex(free_mem_start); 137 | kprint(", free_mem_end="); 138 | kprint_hex(free_mem_end); 139 | kprint(", bios_mem_map_count="); 140 | kprint_int(bios_mem_map_count); 141 | kprint("\n"); 142 | memory_map_long_t *mmap = bios_mem_map; 143 | for (uint32_t i = 0; i < bios_mem_map_count; ++i) 144 | { 145 | kprint("[KDEBUG] "); 146 | kprint_int(i); 147 | kprint(": base="); 148 | kprint_hex_long(mmap[i].base); 149 | kprint(", limit="); 150 | kprint_hex_long(mmap[i].base - 1 + mmap[i].length); 151 | kprint("\n"); 152 | } 153 | } 154 | 155 | int kmain(int mb_magic, multiboot_info_t *mb_info) 156 | { 157 | mb_info = __VA(mb_info); 158 | 159 | if (mb_magic != MULTIBOOT_BOOTLOADER_MAGIC) 160 | { 161 | // not multiboot 162 | /*init_tty(); 163 | kclear(); 164 | kprint("WDOS [version 0.0]\nMust boot from a multiboot bootloader.\n");*/ 165 | return 0xdeadbeef; 166 | } 167 | 168 | init_pm(); 169 | 170 | init_vesa(mb_info); 171 | if (vesa_available) 172 | { 173 | init_tty(vesa_get_tty_driver()); 174 | } 175 | else 176 | { 177 | init_vga(); 178 | init_tty(vga_get_tty_driver()); 179 | } 180 | 181 | kclear(); 182 | kprint_ok_fail("[KDEBUG] check VESA availability", vesa_available); 183 | 184 | kprint_ok_fail("[KDEBUG] system booted successfully.", true); 185 | print_multiboot_info(mb_magic, mb_info); 186 | 187 | bool flags_satisified = (mb_info->flags & MULTIBOOT_NEEDED_FLAGS) == MULTIBOOT_NEEDED_FLAGS; 188 | kprint_ok_fail("[KDEBUG] check multiboot header flags", flags_satisified); 189 | if (!flags_satisified) 190 | { 191 | return 0xdeadbeef; 192 | } 193 | 194 | init_mm(mb_info); 195 | print_mem_info(); 196 | 197 | kprint_ok_fail("[KDEBUG] init PIC8259A", true); 198 | init_pic8259a(); 199 | 200 | kprint_ok_fail("[KDEBUG] init PIT8253", true); 201 | init_pit8253(); 202 | 203 | kprint_ok_fail("[KDEBUG] init keyboard", true); 204 | init_keyboard(); 205 | 206 | init_syscall_impl(); 207 | 208 | kprint_ok_fail("[KDEBUG] init thread scheduler", true); 209 | init_thread(); 210 | 211 | init_idle(); 212 | init_dwm(); 213 | 214 | tty_switch(default_tty + 1); 215 | uint32_t kpid = thread_create_kernel("kernel", &thread1, &thread_stack[0x1000]); 216 | kprint_ok_fail("[KDEBUG] create kernel thread", kpid != (uint32_t)-1); 217 | tty_switch(default_tty + 2); 218 | uint32_t ipid = thread_create("init", &thread2, &thread_stack[0x3000], 219 | &thread_stack[0x4000]); 220 | kprint_ok_fail("[KDEBUG] create init thread", ipid != (uint32_t)-1); 221 | tty_switch(default_tty + 3); 222 | uint32_t spid = thread_create("shell", &thread3, &thread_stack[0x5000], 223 | &thread_stack[0x6000]); 224 | tty_switch(default_tty + 4); 225 | uint32_t s2pid = thread_create("shell", &thread3, &thread_stack[0x7000], 226 | &thread_stack[0x8000]); 227 | tty_switch(default_tty); 228 | 229 | kprint(TTY_SET_COLOR "\013hello, world\b\b\b\b\btwd2.\n" TTY_SET_COLOR TTY_DEFAULT_COLOR); 230 | 231 | kprint( " \001\0011\001\0022\001\0033\001\0044\001\0055\001\0066\001\0077" 232 | "\001\0108\001\0119\001\012A\001\013B\001\014C\001\015D\001\016E\001\017F\r\n" 233 | TTY_SET_COLOR TTY_DEFAULT_COLOR); 234 | kprint("[KDEBUG] thread stack "); 235 | kprint_hex(thread_stack); 236 | kprint("\n"); 237 | enable_interrupt(); 238 | kprint_ok_fail("[KDEBUG] enable interrupt", true); 239 | 240 | // will not reach here 241 | for (;;) 242 | { 243 | asm("hlt"); 244 | } 245 | return 0; 246 | } 247 | -------------------------------------------------------------------------------- /linker.ld: -------------------------------------------------------------------------------- 1 | /* OUTPUT_FORMAT("elf64-x86-64") 2 | OUTPUT_ARCH(i386:x86-64) */ 3 | ENTRY(_start) 4 | 5 | _kernel_load_address = 0x00100000; 6 | _kernel_virtual_base = 0xC0000000; 7 | 8 | SECTIONS 9 | { 10 | . = _kernel_load_address; 11 | 12 | .init32.text ALIGN(4K): 13 | { 14 | *(.init32.text) 15 | } 16 | 17 | . += _kernel_virtual_base; 18 | 19 | .text ALIGN(4K) : AT(ADDR(.text) - _kernel_virtual_base) 20 | { 21 | *(.text) 22 | } 23 | 24 | .rodata ALIGN(4K): AT(ADDR(.rodata) - _kernel_virtual_base) 25 | { 26 | *(.rodata*) 27 | } 28 | 29 | .data ALIGN(4K): AT(ADDR(.data) - _kernel_virtual_base) 30 | { 31 | *(.data) 32 | } 33 | 34 | .bss ALIGN(4K): AT(ADDR(.bss) - _kernel_virtual_base) 35 | { 36 | *(COMMON) 37 | *(.bss) 38 | } 39 | 40 | .pm ALIGN(4K): AT(ADDR(.pm) - _kernel_virtual_base) 41 | { 42 | *(.pm) 43 | } 44 | 45 | .pd ALIGN(4K): AT(ADDR(.pd) - _kernel_virtual_base) 46 | { 47 | *(.pd) 48 | _end_of_kernel = (. + 4095) & (~ 4095); /* 4K align */ 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /loader.asm: -------------------------------------------------------------------------------- 1 | %include "descriptor.inc" 2 | 3 | global _start 4 | global gdt32_tss 5 | global idt_ptr 6 | global enter_ring3 7 | global get_eflags 8 | 9 | ; paging 10 | global pd_ptr 11 | global pt0_ptr 12 | global pt1_ptr 13 | 14 | ; global constants 15 | global SELECTOR_KERNEL_CODE 16 | global SELECTOR_KERNEL_DATA 17 | global SELECTOR_USER_CODE 18 | global SELECTOR_USER_DATA 19 | global SELECTOR_TSS 20 | 21 | extern kmain 22 | extern prepare_tss_gdt_entry 23 | extern prepare_idt 24 | extern interrupt_handler 25 | extern _kernel_load_address 26 | extern _kernel_virtual_base 27 | 28 | MULTIBOOT_HEADER_MAGIC equ 0x1BADB002 29 | MULTIBOOT_HEADER_FLAGS equ 0b110 ; mem_*, mmap_*, vesa 30 | MULTIBOOT_HEADER_CHECKSUM equ -(MULTIBOOT_HEADER_MAGIC + MULTIBOOT_HEADER_FLAGS) 31 | MULTIBOOT_HEADER_MODE_TYPE equ 1 ; 0=graphics, 1=text 32 | MULTIBOOT_HEADER_WIDTH equ 800 33 | MULTIBOOT_HEADER_HEIGHT equ 600 34 | MULTIBOOT_HEADER_DEPTH equ 32 35 | KERNEL_STACK_SIZE equ 0x4000 ; 16KiB 36 | 37 | section .bss 38 | align 4 39 | kernel_stack_base: 40 | resb KERNEL_STACK_SIZE 41 | isr_stack_base: 42 | resb KERNEL_STACK_SIZE 43 | user_stack_base: 44 | resb KERNEL_STACK_SIZE 45 | 46 | section .init32.text progbits alloc exec nowrite 47 | align 4 48 | bits 32 49 | 50 | ; multiboot headers 51 | dd MULTIBOOT_HEADER_MAGIC 52 | dd MULTIBOOT_HEADER_FLAGS 53 | dd MULTIBOOT_HEADER_CHECKSUM 54 | dd 0 55 | dd 0 56 | dd 0 57 | dd 0 58 | dd 0 59 | dd MULTIBOOT_HEADER_MODE_TYPE 60 | dd MULTIBOOT_HEADER_WIDTH 61 | dd MULTIBOOT_HEADER_HEIGHT 62 | dd MULTIBOOT_HEADER_DEPTH 63 | 64 | nop 65 | nop 66 | nop 67 | nop 68 | 69 | ; at 0x1xxxxx 70 | _start: 71 | cli 72 | 73 | ; times 0x400000 nop ; makes kernel bigger 74 | 75 | ; save eax=MULTIBOOT_BOOTLOADER_MAGIC and ebx=multiboot_info_t* 76 | mov edi, eax 77 | mov esi, ebx 78 | 79 | ; init paging 80 | lea eax, [pd_ptr] 81 | lea ebx, [_kernel_virtual_base] 82 | sub eax, ebx 83 | lea ecx, [pt0_ptr] 84 | sub ecx, ebx 85 | or dword [eax], ecx 86 | or dword [eax + 768 * 4], ecx 87 | lea ecx, [pt1_ptr] 88 | sub ecx, ebx 89 | or dword [eax + 1 * 4], ecx 90 | or dword [eax + (768 + 1) * 4], ecx 91 | mov cr3, eax ; cr3 = pd_ptr (this is virtual address) - _kernel_virtual_base 92 | 93 | ; enable paging 94 | mov eax, cr0 95 | or eax, 0x80000000 96 | mov cr0, eax 97 | 98 | jmp _start_va 99 | 100 | section .text 101 | align 4 102 | bits 32 103 | 104 | ; at 0xc01xxxxx 105 | _start_va: 106 | ; gdt 107 | lgdt [gdt32_reg] 108 | ; use new gdt 109 | jmp selector_kernel_code:_start_kernel 110 | 111 | _start_kernel: 112 | mov ax, selector_kernel_data 113 | mov ds, ax 114 | mov es, ax 115 | mov fs, ax 116 | mov gs, ax 117 | ; prepare kernel stack 118 | mov ss, ax 119 | mov esp, kernel_stack_base + KERNEL_STACK_SIZE 120 | 121 | ; remove 0 ~ 8M-1 -> 0 ~ 8M-1 122 | lea eax, [pd_ptr] 123 | xor ebx, ebx 124 | mov [eax], ebx 125 | mov [eax + 1 * 4], ebx 126 | lea ebx, [_kernel_virtual_base] 127 | sub eax, ebx 128 | mov cr3, eax 129 | ; mov [0], eax test 130 | ; idt 131 | call prepare_idt 132 | lidt [idt_reg] 133 | 134 | push esi 135 | push edi 136 | call kmain 137 | add esp, 8 138 | 139 | cli 140 | hlt 141 | 142 | enter_ring3: 143 | ; avoid reenter 144 | mov ax, ss 145 | and ax, SELECTOR_RPL_MASK 146 | test ax, ax 147 | jnz _start_user 148 | 149 | mov eax, esp 150 | push selector_user_data ; ss 151 | push eax ; esp 152 | push selector_user_code ; cs 153 | push _start_user ; eip 154 | retf ; enter ring3 155 | _start_user: 156 | ret 157 | 158 | get_eflags: 159 | pushf 160 | pop eax 161 | ret 162 | 163 | ; interrupt_wrapper_macro i 164 | %macro interrupt_wrapper_macro 1 165 | global interrupt_wrapper_%1 166 | interrupt_wrapper_%1: 167 | %if !(%1 == 8 || (%1 >= 10 && %1 <= 14) || %1 == 17 || %1 == 30) 168 | push 0xFFFFFFFF ; dummy errorcode 169 | %endif 170 | pushad 171 | push ds 172 | push es 173 | push fs 174 | push gs 175 | push esp 176 | cld 177 | push %1 178 | jmp interrupt_wrapper_common 179 | %endmacro 180 | 181 | interrupt_wrapper_common: 182 | call interrupt_handler 183 | add esp, 4 ; pop %1 184 | pop esp 185 | pop gs 186 | pop fs 187 | pop es 188 | pop ds 189 | popad 190 | add esp, 4 ; pop errorcode 191 | iret 192 | 193 | ; interrupt wrappers 194 | %assign i 0 195 | %rep 256 196 | interrupt_wrapper_macro i 197 | %assign i i + 1 198 | %endrep 199 | 200 | ; protected mode related 201 | section .pm progbits alloc noexec write 202 | align 4 203 | 204 | gdt32_ptr: descriptor 0, 0, 0 ; none 205 | gdt32_kernel_code: descriptor 0, 0xFFFFF, DESCRIPTOR_ATTR_CODE32 | DESCRIPTOR_ATTR_DPL0 206 | gdt32_kernel_data: descriptor 0, 0xFFFFF, DESCRIPTOR_ATTR_DATA32 | DESCRIPTOR_ATTR_DPL0 207 | gdt32_user_code: descriptor 0, 0xFFFFF, DESCRIPTOR_ATTR_CODE32 | DESCRIPTOR_ATTR_DPL3 208 | gdt32_user_data: descriptor 0, 0xFFFFF, DESCRIPTOR_ATTR_DATA32 | DESCRIPTOR_ATTR_DPL3 209 | gdt32_tss: descriptor 0, 0, 0 ; will be filled later, see pm.c 210 | 211 | gdt32_length equ $ - gdt32_ptr 212 | gdt32_reg: 213 | dw gdt32_length - 1 ; GDT limit 214 | dd gdt32_ptr ; GDT base 215 | 216 | selector_kernel_code equ ((gdt32_kernel_code - gdt32_ptr) | SELECTOR_GDT | SELECTOR_RPL0) 217 | selector_kernel_data equ ((gdt32_kernel_data - gdt32_ptr) | SELECTOR_GDT | SELECTOR_RPL0) 218 | selector_user_code equ ((gdt32_user_code - gdt32_ptr) | SELECTOR_GDT | SELECTOR_RPL3) 219 | selector_user_data equ ((gdt32_user_data - gdt32_ptr) | SELECTOR_GDT | SELECTOR_RPL3) 220 | selector_tss equ ((gdt32_tss - gdt32_ptr) | SELECTOR_GDT | SELECTOR_RPL3) 221 | 222 | idt_ptr: 223 | %rep 256 224 | gate 0, 0, 0 ; will be filled later, see pm.c 225 | %endrep 226 | 227 | idt_length equ $ - idt_ptr 228 | idt_reg: 229 | dw idt_length - 1 230 | dd idt_ptr 231 | 232 | section .pd progbits alloc noexec write 233 | align 4 234 | 235 | %include "paging.inc" 236 | 237 | pd_ptr: ; page directory 238 | ; 0 ~ 8M-1 -> 0 ~ 8M-1 239 | dd 0 | PAGING_PXE_P | PAGING_PXE_RW 240 | dd 0 | PAGING_PXE_P | PAGING_PXE_RW 241 | times 766 dd 0 242 | ; 768 = 0xc0000000 / 4096 / 1024 243 | ; C0000000 ~ C0000000 + 8M-1 -> 0 ~ 8M-1 244 | dd 0 | PAGING_PXE_P | PAGING_PXE_RW | PAGING_PXE_US ; TODO 245 | dd 0 | PAGING_PXE_P | PAGING_PXE_RW | PAGING_PXE_US 246 | times 254 dd 0 247 | 248 | %assign i 0 249 | pt0_ptr: ; page table 0 250 | %rep 1024 251 | dd (i << 12) | PAGING_PXE_P | PAGING_PXE_RW | PAGING_PXE_G | PAGING_PXE_US ; TODO 252 | %assign i i + 1 253 | %endrep 254 | pt1_ptr: ; page table 1 255 | %rep 1024 256 | dd (i << 12) | PAGING_PXE_P | PAGING_PXE_RW | PAGING_PXE_G | PAGING_PXE_US ; TODO 257 | %assign i i + 1 258 | %endrep 259 | 260 | ; global constants 261 | section .rodata 262 | align 4 263 | 264 | SELECTOR_KERNEL_CODE dw selector_kernel_code 265 | SELECTOR_KERNEL_DATA dw selector_kernel_data 266 | SELECTOR_USER_CODE dw selector_user_code 267 | SELECTOR_USER_DATA dw selector_user_data 268 | SELECTOR_TSS dw selector_tss 269 | 270 | -------------------------------------------------------------------------------- /mm/README.md: -------------------------------------------------------------------------------- 1 | # Memory Layout 2 | 3 | ``` 4 | +-----------------------------+ 5 | | kernel space | 6 | | | 7 | | | 8 | | | 9 | | | 10 | | | 11 | | | 12 | | | 0xC0000000 / 0xFFFF800000000000 + 13 | +-----------------------------+ 14 | | non-canonical addresses | 0xFFFF800000000000 - 1 ~ 15 | | | 16 | | for amd64 systems impl.48b | 0x00007FFFFFFFFFFF + 1 17 | +-----------------------------+ 18 | | user space | 0xC0000000 - 1 / 0x00007FFFFFFFFFFF ~ 19 | | | 0x00000000 / 0x0000000000000000 20 | | | 21 | | | 22 | | | 23 | | | 24 | | | 25 | | | 26 | | | 27 | | | 28 | | | 29 | | | 30 | | | 31 | +-----------------------------+ 32 | ``` 33 | -------------------------------------------------------------------------------- /mm/buddy.c: -------------------------------------------------------------------------------- 1 | #include "buddy.h" 2 | 3 | #include 4 | #include 5 | 6 | void buddy_init(buddy_t *b, bucket_t *buckets, size_t bucket_count, 7 | page_node_t *nodes, size_t node_count, size_t page_size) 8 | { 9 | b->buckets = buckets; 10 | b->bucket_count = bucket_count; 11 | b->nodes = nodes; 12 | b->node_count = node_count; 13 | b->page_size = page_size; 14 | // assert is_power_of_2(page_size) 15 | b->page_size_log2 = bits_log2(page_size); 16 | 17 | // init buckets 18 | for (size_t i = 0; i < bucket_count; ++i) 19 | { 20 | page_list_init(&(buckets[i].list), NULL); 21 | } 22 | } 23 | 24 | inline page_node_t *buddy_page_node(buddy_t *b, void *page) 25 | { 26 | return &b->nodes[((uintptr_t)page >> b->page_size_log2)]; 27 | } 28 | 29 | inline page_node_t *buddy_pfn_node(buddy_t *b, uintptr_t pfn) 30 | { 31 | return &b->nodes[pfn]; 32 | } 33 | 34 | inline void *buddy_align(buddy_t *b, void *ptr) 35 | { 36 | // t / b->page_size == ceiling((uintptr_t)page / b->page_size) 37 | uintptr_t t = (uintptr_t)ptr - 1 + b->page_size; 38 | // t - t % b->page_size == int(t / b->page_size) * b->page_size 39 | return (void *)(t & ~(b->page_size - 1)); 40 | // ceiling((uintptr_t)page / b->page_size) * b->page_size 41 | } 42 | 43 | void buddy_init_pages(buddy_t *b, void *begin, size_t length) 44 | { 45 | // assert (uintptr_t)begin % b->page_size == 0 46 | uint8_t *page = buddy_align(b, begin); 47 | length -= page - (uint8_t *)begin; 48 | // length % b->page_size bytes ignored 49 | size_t page_count = length >> b->page_size_log2; 50 | for (ptrdiff_t bucket = b->bucket_count - 1; bucket >= 0; --bucket) 51 | { 52 | const size_t pages_per_item = 1 << bucket; 53 | const size_t bucket_item_count = page_count >> bucket; // page_count / pages_per_item 54 | for (size_t item = 0; item < bucket_item_count; ++item) 55 | { 56 | page_node_t *node = buddy_page_node(b, page); 57 | node->page = page; 58 | node->used = false; 59 | node->count = pages_per_item; 60 | 61 | page_list_t *list = &(b->buckets[bucket].list); 62 | page_list_insert_as_prev(list, node, list->tail); 63 | 64 | page += pages_per_item << b->page_size_log2; 65 | } 66 | page_count -= bucket_item_count << bucket; // bucket_item_count * pages_per_item 67 | } 68 | // assert page_count == 0 69 | } 70 | 71 | void *buddy_alloc_pages(buddy_t *b, size_t count) 72 | { 73 | if (count > (1 << (b->bucket_count - 1))) 74 | { 75 | return NULL; 76 | } 77 | 78 | count = next_power_of_2(count); 79 | size_t bucket = bits_log2(count); 80 | 81 | ptrdiff_t available_bucket = -1; 82 | for (size_t i = bucket; i < b->bucket_count; ++i) 83 | { 84 | page_list_t *list = &(b->buckets[i].list); 85 | if (list->head->next != list->tail && !list->head->next->used) 86 | { 87 | available_bucket = i; 88 | break; 89 | } 90 | } 91 | 92 | if (available_bucket == -1) 93 | { 94 | return NULL; 95 | } 96 | 97 | for (ptrdiff_t i = available_bucket; i > bucket; --i) 98 | { 99 | page_list_t *list = &(b->buckets[i].list); 100 | page_list_t *list_smaller = &(b->buckets[i - 1].list); 101 | 102 | page_node_t *node1 = list->head->next; 103 | // assert !node1->used 104 | // split 105 | // TODO: flags 106 | page_list_take_node(list, node1); 107 | node1->count >>= 1; 108 | 109 | void *page2 = (void *)((uintptr_t)node1->page + (node1->count << b->page_size_log2)); 110 | page_node_t *node2 = buddy_page_node(b, page2); 111 | node2->page = page2; 112 | node2->used = false; 113 | node2->count = node1->count; 114 | 115 | page_list_insert_as_prev(list_smaller, node2, list_smaller->head->next); 116 | page_list_insert_as_prev(list_smaller, node1, node2); 117 | } 118 | 119 | page_list_t *list = &(b->buckets[bucket].list); 120 | page_node_t *node = list->head->next; 121 | node->used = true; 122 | // just move to last 123 | page_list_take_node(list, node); 124 | page_list_insert_as_prev(list, node, list->tail); 125 | return node->page; 126 | } 127 | 128 | void buddy_free_pages(buddy_t *b, void *page) 129 | { 130 | void *page_aligned = buddy_align(b, page); 131 | if (page_aligned != page) 132 | { 133 | // assert false 134 | } 135 | 136 | page_node_t *node = buddy_page_node(b, page_aligned); 137 | // assert node->used 138 | 139 | ptrdiff_t bucket = bits_log2(node->count); 140 | 141 | // assert bucket != -1 142 | page_list_t *list = &(b->buckets[bucket].list); 143 | node->used = false; 144 | // just move to first 145 | page_list_take_node(list, node); 146 | page_list_insert_as_prev(list, node, list->head->next); 147 | 148 | // TODO: combine 149 | } 150 | -------------------------------------------------------------------------------- /mm/buddy.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_KERNEL_MM_BUDDY_H_ 2 | #define _WDOS_KERNEL_MM_BUDDY_H_ 3 | 4 | #include 5 | #include 6 | 7 | typedef struct bucket 8 | { 9 | page_list_t list; 10 | } bucket_t; 11 | 12 | typedef struct buddy 13 | { 14 | bucket_t *buckets; 15 | size_t bucket_count; 16 | page_node_t *nodes; 17 | size_t node_count; 18 | size_t page_size; 19 | uint8_t page_size_log2; 20 | uint8_t reserved[sizeof(ureg_t) - 1]; 21 | } buddy_t; 22 | 23 | void buddy_init(buddy_t *b, bucket_t *buckets, size_t bucket_count, 24 | page_node_t *nodes, size_t node_count, size_t page_size); 25 | page_node_t *buddy_page_node(buddy_t *b, void *page); 26 | page_node_t *buddy_pfn_node(buddy_t *b, uintptr_t pfn); 27 | void *buddy_align(buddy_t *b, void *ptr); 28 | void buddy_init_pages(buddy_t *b, void *begin, size_t length); 29 | void *buddy_alloc_pages(buddy_t *b, size_t count); 30 | void buddy_free_pages(buddy_t *b, void *page); 31 | 32 | #endif // _WDOS_KERNEL_MM_BUDDY_H_ 33 | -------------------------------------------------------------------------------- /mm/mm.c: -------------------------------------------------------------------------------- 1 | #include "mm.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | static bool mm_inited = false; 11 | 12 | // loader.asm 13 | extern uint8_t _kernel_load_address; 14 | extern uint8_t _kernel_virtual_base; 15 | void *const kernel_load_address = &_kernel_load_address; 16 | void *const kernel_virtual_base = &_kernel_virtual_base; 17 | 18 | extern uint8_t _end_of_kernel; 19 | void *palloc_mem_start = NULL; 20 | void *free_mem_start = NULL; 21 | void *free_mem_end = NULL; // [free_mem_start, free_mem_end) 22 | 23 | uint32_t bios_mem_map_count; 24 | memory_map_long_t bios_mem_map[BIOS_MEM_MAP_MAX_COUNT]; 25 | 26 | static buddy_t buddy; 27 | 28 | inline void *mm_align(void *ptr) 29 | { 30 | uintptr_t t = (uintptr_t)ptr - 1 + PAGE_SIZE; 31 | return (void *)(t & ~(PAGE_SIZE - 1)); 32 | } 33 | 34 | inline void *mm_palloc(size_t size) 35 | { 36 | if (mm_inited) 37 | { 38 | // assert false 39 | return NULL; 40 | } 41 | void *old_free_mem_start = free_mem_start; 42 | free_mem_start = (void *)((uint8_t *)free_mem_start + size); 43 | return __VA(old_free_mem_start); 44 | } 45 | 46 | static inline void copy_mem_map(multiboot_info_t *mb_info) 47 | { 48 | memory_map_long_t *const mmap = bios_mem_map; 49 | multiboot_memory_map_t *mb_mmap = 50 | (multiboot_memory_map_t *)__VA((void *)mb_info->mmap_addr); 51 | multiboot_memory_map_t *mb_mmap_end = 52 | (multiboot_memory_map_t *)((uint8_t *)mb_mmap + mb_info->mmap_length); 53 | 54 | bios_mem_map_count = 0; 55 | while (mb_mmap != mb_mmap_end) 56 | { 57 | if (mb_mmap->type == MEMORY_TYPE_USABLE) 58 | { 59 | mmap[bios_mem_map_count].base = mb_mmap->addr; 60 | mmap[bios_mem_map_count].length = mb_mmap->len; 61 | ++bios_mem_map_count; 62 | } 63 | 64 | // next 65 | mb_mmap = (multiboot_memory_map_t *)((uint8_t *)mb_mmap + mb_mmap->size + 66 | sizeof(mb_mmap->size)); 67 | } 68 | } 69 | 70 | static void print_bucket(bucket_t *b) 71 | { 72 | page_list_t *list = &b->list; 73 | for (page_node_t *iter = list->head->next; iter != list->tail; iter = iter->next) 74 | { 75 | kprint(" ["); 76 | kprint_hex(iter); 77 | kprint("]"); 78 | kprint_hex(iter->page); 79 | kprint(","); 80 | kprint_byte(iter->used); 81 | kprint(" "); 82 | } 83 | kprint("\n"); 84 | } 85 | 86 | static void print_buddy(buddy_t *b) 87 | { 88 | kprint("======\n"); 89 | for (size_t i = 0; i < b->bucket_count; ++i) 90 | { 91 | kprint("[BUCKET #"); 92 | kprint_uint(i); 93 | kprint(" "); 94 | kprint_uint(1 << i); 95 | kprint(" pages] "); 96 | print_bucket(&b->buckets[i]); 97 | } 98 | kprint("======\n"); 99 | } 100 | 101 | void init_mm(multiboot_info_t *mb_info) 102 | { 103 | copy_mem_map(mb_info); 104 | palloc_mem_start = __PA(&_end_of_kernel); 105 | free_mem_start = __PA(&_end_of_kernel); 106 | free_mem_end = (void *)((mb_info->mem_upper << 10) + 0x100000); 107 | 108 | // paging: map [0, free_mem_end) 109 | init_mm_paging(); 110 | 111 | bucket_t *buckets = (bucket_t *)mm_palloc(BUCKET_COUNT * sizeof(bucket_t)); 112 | 113 | const size_t node_count = (uintptr_t)free_mem_end / PAGE_SIZE; 114 | page_node_t *nodes = (page_node_t *)mm_palloc(node_count * sizeof(page_node_t)); 115 | 116 | mm_inited = true; // forbid mm_palloc 117 | free_mem_start = mm_align(free_mem_start); 118 | buddy_init(&buddy, buckets, BUCKET_COUNT, nodes, node_count, PAGE_SIZE); 119 | buddy_init_pages(&buddy, free_mem_start, free_mem_end - free_mem_start); 120 | print_buddy(&buddy); 121 | for (;;); 122 | } 123 | 124 | void *mm_alloc_pages(size_t count) 125 | { 126 | return buddy_alloc_pages(&buddy, count); 127 | } 128 | 129 | void mm_free_pages(void *page) 130 | { 131 | buddy_free_pages(&buddy, page); 132 | } 133 | -------------------------------------------------------------------------------- /mm/mm.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_KERNEL_MM_MM_H_ 2 | #define _WDOS_KERNEL_MM_MM_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define PAGE_SIZE 0x1000 9 | #define PAGE_SIZE_LOG2 12 10 | #ifndef X86_64 11 | #define BUCKET_COUNT 20 // 32 - 12 12 | #else 13 | #define BUCKET_COUNT 36 // 48 - 12 14 | #endif 15 | 16 | #define BIOS_MEM_MAP_MAX_COUNT 16 17 | 18 | #define __VA(ptr) ((void *)((uintptr_t)(ptr) + (uintptr_t)(kernel_virtual_base))) 19 | #define __PA(ptr) ((void *)((uintptr_t)(ptr) - (uintptr_t)(kernel_virtual_base))) 20 | 21 | void *mm_align(void *ptr); 22 | void *mm_palloc(size_t size); 23 | void mm_init_mem(void *begin, void *end); 24 | void init_mm(multiboot_info_t *mb_info); 25 | void *mm_alloc_pages(size_t count); 26 | void mm_free_pages(void *page); 27 | 28 | extern void *const kernel_load_address; 29 | extern void *const kernel_virtual_base; 30 | extern void *palloc_mem_start; 31 | extern void *free_mem_start; 32 | extern void *free_mem_end; 33 | extern uint32_t bios_mem_map_count; 34 | extern memory_map_long_t bios_mem_map[BIOS_MEM_MAP_MAX_COUNT]; 35 | 36 | #endif // _WDOS_KERNEL_MM_MM_H_ 37 | -------------------------------------------------------------------------------- /mm/page_fault.c: -------------------------------------------------------------------------------- 1 | #include "page_fault.h" 2 | 3 | static size_t page_fault_count = 0; 4 | 5 | inline void *mm_page_fault_va() 6 | { 7 | void *ret; 8 | asm volatile ("mov %%cr2, %0" 9 | : "=r"(ret) 10 | :); 11 | return ret; 12 | } 13 | 14 | size_t mm_page_fault_count() 15 | { 16 | return page_fault_count; 17 | } 18 | -------------------------------------------------------------------------------- /mm/page_fault.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_KERNEL_MM_PAGE_FAULT_H_ 2 | #define _WDOS_KERNEL_MM_PAGE_FAULT_H_ 3 | 4 | #include 5 | 6 | void *mm_page_fault_va(); 7 | size_t mm_page_fault_count(); 8 | 9 | #endif // _WDOS_KERNEL_MM_PAGE_FAULT_H_ 10 | -------------------------------------------------------------------------------- /mm/page_list.c: -------------------------------------------------------------------------------- 1 | #include "page_list.h" 2 | 3 | void page_list_init(page_list_t *list, page_node_t *nodes) 4 | { 5 | page_node_t *head, *tail; 6 | 7 | head = &list->_head; 8 | tail = &list->_tail; 9 | 10 | head->prev = NULL; 11 | head->next = tail; 12 | tail->prev = head; 13 | tail->next = NULL; 14 | 15 | list->size = 0; 16 | list->head = head; 17 | list->tail = tail; 18 | list->nodes = nodes; 19 | } 20 | 21 | page_node_t *page_list_alloc_node(page_list_t *list) 22 | { 23 | page_node_t *n = &list->nodes[list->size]; 24 | ++list->size; 25 | return n; 26 | } 27 | 28 | inline void page_list_insert_as_prev(page_list_t *list, page_node_t *node, page_node_t *next) 29 | { 30 | node->next = next; 31 | node->prev = next->prev; 32 | next->prev->next = node; 33 | next->prev = node; 34 | } 35 | 36 | inline void page_list_take_node(page_list_t *list, page_node_t *node) 37 | { 38 | node->prev->next = node->next; 39 | node->next->prev = node->prev; 40 | node->prev = node->next = NULL; 41 | } 42 | 43 | inline page_node_t *page_list_last_node(page_list_t *list) 44 | { 45 | if (list->tail->prev == list->head) 46 | { 47 | return NULL; 48 | } 49 | return list->tail->prev; 50 | } 51 | 52 | inline page_node_t *page_list_last_phy_node(page_list_t *list) 53 | { 54 | return &list->nodes[list->size - 1]; 55 | } 56 | 57 | inline void page_list_swap_nodes(page_list_t *list, 58 | page_node_t *node1, page_node_t *node2) 59 | { 60 | if (node1 == node2) 61 | { 62 | return; 63 | } 64 | 65 | // swap data 66 | void *t = node1->page; 67 | node1->page = node2->page; 68 | node2->page = t; 69 | 70 | // swap links 71 | if (node1->next == node2) // node1 is next to node2 72 | { 73 | node1->prev->next = node2; 74 | node2->prev = node1->prev; 75 | 76 | node2->next->prev = node1; 77 | node1->next = node2->next; 78 | 79 | node2->next = node1; 80 | node1->prev = node2; 81 | } 82 | else if (node2->next == node1) 83 | { 84 | node2->prev->next = node1; 85 | node1->prev = node2->prev; 86 | 87 | node1->next->prev = node2; 88 | node2->next = node1->next; 89 | 90 | node1->next = node2; 91 | node2->prev = node1; 92 | } 93 | else 94 | { 95 | node1->prev->next = node2; 96 | node1->next->prev = node2; 97 | 98 | node2->prev->next = node1; 99 | node2->next->prev = node1; 100 | 101 | page_node_t *tmp; 102 | 103 | tmp = node1->prev; 104 | node1->prev = node2->prev; 105 | node2->prev = tmp; 106 | tmp = node1->next; 107 | node1->next = node2->next; 108 | node2->next = tmp; 109 | } 110 | } 111 | 112 | inline void *page_list_remove_last_phy_node(page_list_t *list) 113 | { 114 | page_node_t *node = page_list_last_phy_node(list); 115 | if (!node) 116 | { 117 | return NULL; 118 | } 119 | void *page = node->page; 120 | page_list_take_node(list, node); 121 | --list->size; 122 | return page; 123 | } 124 | 125 | void *page_list_remove_node(page_list_t *list, page_node_t *node) 126 | { 127 | void *page = node->page; 128 | page_list_swap_nodes(list, node, page_list_last_phy_node(list)); // make node last phy. 129 | node = page_list_last_phy_node(list); 130 | page_list_remove_last_phy_node(list); 131 | return page; 132 | } 133 | 134 | static inline bool page_list_comparator_gt(page_list_t *list, page_node_t *a, page_node_t *b) 135 | { 136 | // guard tail is greater than everything 137 | return (a == list->tail) || (a->page > b->page); // TODO: used > unused 138 | } 139 | 140 | inline page_node_t *page_list_find_gt(page_list_t *list, page_node_t *node) 141 | { 142 | for (page_node_t *iter = list->head->next; iter != NULL; iter = iter->next) 143 | { 144 | if (page_list_comparator_gt(list, iter, node)) 145 | { 146 | return iter; 147 | } 148 | } 149 | // should not be here 150 | return NULL; 151 | } 152 | 153 | // page changed or used/unused flag changed 154 | void page_list_update_position(page_list_t *list, page_node_t *node) 155 | { 156 | page_list_take_node(list, node); 157 | page_list_insert_as_prev(list, node, page_list_find_gt(list, node)); 158 | } 159 | -------------------------------------------------------------------------------- /mm/page_list.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_KERNEL_MM_PAGE_LIST_H_ 2 | #define _WDOS_KERNEL_MM_PAGE_LIST_H_ 3 | 4 | #include 5 | 6 | struct page_node; 7 | typedef struct page_node page_node_t; 8 | struct page_node 9 | { 10 | page_node_t *prev, *next; 11 | void *page; // physical address 12 | size_t count; // how many pages does this node have? 13 | bool used : 1; 14 | uintptr_t flags : sizeof(uintptr_t) * 8 - 1; // rest unused bits 15 | }; 16 | 17 | typedef struct page_list 18 | { 19 | page_node_t _head, _tail; // guard instances 20 | page_node_t *head, *tail; // guards 21 | size_t size; 22 | // size_t capacity; 23 | page_node_t *nodes; // fixed-size array 24 | } page_list_t; 25 | 26 | void page_list_init(page_list_t *list, page_node_t *nodes); 27 | page_node_t *page_list_alloc_node(page_list_t *list); 28 | void page_list_insert_as_prev(page_list_t *list, page_node_t *node, page_node_t *next); 29 | void page_list_take_node(page_list_t *list, page_node_t *node); // breaks links 30 | page_node_t *page_list_last_node(page_list_t *list); // logic 31 | page_node_t *page_list_last_phy_node(page_list_t *list); // phy 32 | void *page_list_remove_last_phy_node(page_list_t *list); // returns page 33 | void page_list_swap_nodes(page_list_t *list, page_node_t *node1, page_node_t *node2); 34 | void *page_list_remove_node(page_list_t *list, page_node_t *node); // returns page 35 | page_node_t *page_list_find_gt(page_list_t *list, page_node_t *node); // first greater than 36 | void page_list_update_position(page_list_t *list, page_node_t *node); 37 | 38 | #endif // _WDOS_KERNEL_MM_PAGE_LIST_H_ 39 | -------------------------------------------------------------------------------- /mm/paging.c: -------------------------------------------------------------------------------- 1 | #include "paging.h" 2 | 3 | #include 4 | #include 5 | 6 | // loader.asm, for x86 7 | extern pml2_t pd_ptr; 8 | extern pml1_t pt0_ptr; 9 | extern pml1_t pt1_ptr; 10 | static pml1_t *pt_rest; 11 | 12 | inline void mm_enable_page_global() 13 | { 14 | asm volatile ("movl %%cr4, %%eax\n" 15 | "or $0x80, %%eax\n" 16 | "movl %%eax, %%cr4" 17 | : 18 | : 19 | : "eax"); 20 | } 21 | 22 | inline void mm_load_pml4(void *pml4) 23 | { 24 | asm volatile ("movl %0, %%cr3" 25 | : 26 | : "r"(__PA(pml4)) 27 | :); 28 | } 29 | 30 | void init_mm_paging() 31 | { 32 | // map [0, min(512MiB, free_mem_end)) 33 | uintptr_t hi = (uintptr_t)free_mem_end; 34 | if (hi > MM_PAGING_DIRECT_MAP_MAX) 35 | { 36 | hi = MM_PAGING_DIRECT_MAP_MAX; 37 | } 38 | size_t pml1e_count = (hi + PAGE_SIZE - 1) / PAGE_SIZE; 39 | size_t pml1_count = (pml1e_count + MM_PML1_MASK + 1 - 1) / (MM_PML1_MASK + 1); 40 | if (pml1_count <= 2) 41 | { 42 | return; // already mapped, loader.asm 43 | } 44 | pt_rest = (pml1_t *)mm_palloc((pml1_count - 2) * PAGE_SIZE); // -2 : pt0, pt1 45 | if ((uintptr_t)pt_rest & 0xfff) 46 | { 47 | // not aligned! 48 | kprint("[KDEBUG] Assertion failed.\n"); 49 | while (true); 50 | } 51 | 52 | // fill pml1 53 | pml1e_t pml1e = 2048 * 4096; // loader.asm 54 | for (size_t i = 2; i < pml1_count; ++i) 55 | { 56 | // for each pml1... 57 | for (size_t j = 0; j < MM_PML1_MASK + 1; ++j) 58 | { 59 | pt_rest[i - 2].entries[j] = pml1e | MM_PAGING_PXE_P | MM_PAGING_PXE_RW | 60 | MM_PAGING_PXE_G | MM_PAGING_PXE_US; // TODO 61 | pml1e += PAGE_SIZE; 62 | } 63 | } 64 | 65 | // fill pml2 66 | for (size_t i = 2; i < pml1_count; ++i) 67 | { 68 | pd_ptr.entries[768 + i] = (uintptr_t)__PA(&pt_rest[i - 2]) | MM_PAGING_PXE_P | 69 | MM_PAGING_PXE_RW | MM_PAGING_PXE_US; // TODO 70 | } 71 | 72 | kprint("[KDEBUG] mapped 0x00000000~"); 73 | kprint_hex(hi); 74 | kprint("\n"); 75 | 76 | mm_enable_page_global(); 77 | } 78 | 79 | inline void mm_invalidate_tlb(void *va) 80 | { 81 | asm volatile ("invlpg %0" 82 | : 83 | : "m"(*(uint8_t *)va) 84 | : "memory"); 85 | } 86 | -------------------------------------------------------------------------------- /mm/paging.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_KERNEL_MM_PAGING_H_ 2 | #define _WDOS_KERNEL_MM_PAGING_H_ 3 | 4 | #include 5 | 6 | #ifdef X86_64 7 | #error Not Implemented. 8 | #endif 9 | 10 | #ifndef X86_64 11 | #define MM_PML4_SHIFT 0 12 | #define MM_PML4_MASK 0 13 | #define MM_PML3_SHIFT 0 14 | #define MM_PML3_MASK 0 15 | #define MM_PML2_SHIFT 22 16 | #define MM_PML2_MASK 0b1111111111 17 | #define MM_PML1_SHIFT 12 18 | #define MM_PML1_MASK 0b1111111111 19 | #else 20 | #define MM_PML4_SHIFT 39 21 | #define MM_PML4_MASK 0b111111111 22 | #define MM_PML3_SHIFT 30 23 | #define MM_PML3_MASK 0b111111111 24 | #define MM_PML2_SHIFT 21 25 | #define MM_PML2_MASK 0b111111111 26 | #define MM_PML1_SHIFT 12 27 | #define MM_PML1_MASK 0b111111111 28 | #endif 29 | 30 | // X = ML4, ML3, ML2, ML1 (ML4, DPT, D, T for x86, x86-64) 31 | #define MM_PAGING_PXE_P 0x1 32 | #define MM_PAGING_PXE_RW 0x2 33 | #define MM_PAGING_PXE_US 0x4 34 | #define MM_PAGING_PXE_PWT 0x8 35 | #define MM_PAGING_PXE_PCD 0x10 36 | #define MM_PAGING_PXE_A 0x20 37 | #define MM_PAGING_PXE_D 0x40 38 | #define MM_PAGING_PXE_PS 0x80 39 | #define MM_PAGING_PXE_PAT 0x80 40 | #define MM_PAGING_PXE_G 0x100 41 | 42 | #ifdef X86_64 43 | #define MM_PAGING_PXE_NX (1UL << 63) 44 | #endif 45 | 46 | typedef uintptr_t pml4e_t; 47 | typedef uintptr_t pml3e_t; 48 | typedef uintptr_t pml2e_t; 49 | typedef uintptr_t pml1e_t; 50 | 51 | typedef struct pml4 52 | { 53 | pml4e_t entries[MM_PML4_MASK + 1]; 54 | } pml4_t; 55 | 56 | typedef struct pml3 57 | { 58 | pml3e_t entries[MM_PML3_MASK + 1]; 59 | } pml3_t; 60 | 61 | typedef struct pml2 62 | { 63 | pml2e_t entries[MM_PML2_MASK + 1]; 64 | } pml2_t; 65 | 66 | typedef struct pml1 67 | { 68 | pml1e_t entries[MM_PML1_MASK + 1]; 69 | } pml1_t; 70 | 71 | #define MM_PAGING_DIRECT_MAP_MAX 0x20000000 // max 512MiB 72 | 73 | void mm_enable_page_global(); 74 | void mm_load_pml4(void *pml4); 75 | void init_mm_paging(); 76 | void mm_invalidate_tlb(void *va); 77 | 78 | #endif // _WDOS_KERNEL_MM_PAGING_H_ 79 | -------------------------------------------------------------------------------- /multiboot.h: -------------------------------------------------------------------------------- 1 | /* multiboot.h - Multiboot header file. */ 2 | /* Copyright (C) 1999,2003,2007,2008,2009 Free Software Foundation, Inc. 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a copy 5 | * of this software and associated documentation files (the "Software"), to 6 | * deal in the Software without restriction, including without limitation the 7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 | * sell copies of the Software, and to permit persons to whom the Software is 9 | * furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY 17 | * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 19 | * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | */ 21 | 22 | #ifndef MULTIBOOT_HEADER 23 | #define MULTIBOOT_HEADER 1 24 | 25 | /* How many bytes from the start of the file we search for the header. */ 26 | #define MULTIBOOT_SEARCH 8192 27 | 28 | /* The magic field should contain this. */ 29 | #define MULTIBOOT_HEADER_MAGIC 0x1BADB002 30 | 31 | /* This should be in %eax. */ 32 | #define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 33 | 34 | /* The bits in the required part of flags field we don't support. */ 35 | #define MULTIBOOT_UNSUPPORTED 0x0000fffc 36 | 37 | /* Alignment of multiboot modules. */ 38 | #define MULTIBOOT_MOD_ALIGN 0x00001000 39 | 40 | /* Alignment of the multiboot info structure. */ 41 | #define MULTIBOOT_INFO_ALIGN 0x00000004 42 | 43 | /* Flags set in the 'flags' member of the multiboot header. */ 44 | 45 | /* Align all boot modules on i386 page (4KB) boundaries. */ 46 | #define MULTIBOOT_PAGE_ALIGN 0x00000001 47 | 48 | /* Must pass memory information to OS. */ 49 | #define MULTIBOOT_MEMORY_INFO 0x00000002 50 | 51 | /* Must pass video information to OS. */ 52 | #define MULTIBOOT_VIDEO_MODE 0x00000004 53 | 54 | /* This flag indicates the use of the address fields in the header. */ 55 | #define MULTIBOOT_AOUT_KLUDGE 0x00010000 56 | 57 | /* Flags to be set in the 'flags' member of the multiboot info structure. */ 58 | 59 | /* is there basic lower/upper memory information? */ 60 | #define MULTIBOOT_INFO_MEMORY 0x00000001 61 | /* is there a boot device set? */ 62 | #define MULTIBOOT_INFO_BOOTDEV 0x00000002 63 | /* is the command-line defined? */ 64 | #define MULTIBOOT_INFO_CMDLINE 0x00000004 65 | /* are there modules to do something with? */ 66 | #define MULTIBOOT_INFO_MODS 0x00000008 67 | 68 | /* These next two are mutually exclusive */ 69 | 70 | /* is there a symbol table loaded? */ 71 | #define MULTIBOOT_INFO_AOUT_SYMS 0x00000010 72 | /* is there an ELF section header table? */ 73 | #define MULTIBOOT_INFO_ELF_SHDR 0X00000020 74 | 75 | /* is there a full memory map? */ 76 | #define MULTIBOOT_INFO_MEM_MAP 0x00000040 77 | 78 | /* Is there drive info? */ 79 | #define MULTIBOOT_INFO_DRIVE_INFO 0x00000080 80 | 81 | /* Is there a config table? */ 82 | #define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100 83 | 84 | /* Is there a boot loader name? */ 85 | #define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200 86 | 87 | /* Is there a APM table? */ 88 | #define MULTIBOOT_INFO_APM_TABLE 0x00000400 89 | 90 | /* Is there video information? */ 91 | #define MULTIBOOT_INFO_VIDEO_INFO 0x00000800 92 | 93 | #ifndef ASM_FILE 94 | 95 | typedef unsigned short multiboot_uint16_t; 96 | typedef unsigned int multiboot_uint32_t; 97 | typedef unsigned long long multiboot_uint64_t; 98 | 99 | struct multiboot_header 100 | { 101 | /* Must be MULTIBOOT_MAGIC - see above. */ 102 | multiboot_uint32_t magic; 103 | 104 | /* Feature flags. */ 105 | multiboot_uint32_t flags; 106 | 107 | /* The above fields plus this one must equal 0 mod 2^32. */ 108 | multiboot_uint32_t checksum; 109 | 110 | /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */ 111 | multiboot_uint32_t header_addr; 112 | multiboot_uint32_t load_addr; 113 | multiboot_uint32_t load_end_addr; 114 | multiboot_uint32_t bss_end_addr; 115 | multiboot_uint32_t entry_addr; 116 | 117 | /* These are only valid if MULTIBOOT_VIDEO_MODE is set. */ 118 | multiboot_uint32_t mode_type; 119 | multiboot_uint32_t width; 120 | multiboot_uint32_t height; 121 | multiboot_uint32_t depth; 122 | }; 123 | typedef struct multiboot_header multiboot_header_t; 124 | 125 | /* The symbol table for a.out. */ 126 | struct multiboot_aout_symbol_table 127 | { 128 | multiboot_uint32_t tabsize; 129 | multiboot_uint32_t strsize; 130 | multiboot_uint32_t addr; 131 | multiboot_uint32_t reserved; 132 | }; 133 | typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t; 134 | 135 | /* The section header table for ELF. */ 136 | struct multiboot_elf_section_header_table 137 | { 138 | multiboot_uint32_t num; 139 | multiboot_uint32_t size; 140 | multiboot_uint32_t addr; 141 | multiboot_uint32_t shndx; 142 | }; 143 | typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t; 144 | 145 | struct multiboot_info 146 | { 147 | /* Multiboot info version number */ 148 | multiboot_uint32_t flags; 149 | 150 | /* Available memory from BIOS */ 151 | multiboot_uint32_t mem_lower; 152 | multiboot_uint32_t mem_upper; 153 | 154 | /* "root" partition */ 155 | multiboot_uint32_t boot_device; 156 | 157 | /* Kernel command line */ 158 | multiboot_uint32_t cmdline; 159 | 160 | /* Boot-Module list */ 161 | multiboot_uint32_t mods_count; 162 | multiboot_uint32_t mods_addr; 163 | 164 | union 165 | { 166 | multiboot_aout_symbol_table_t aout_sym; 167 | multiboot_elf_section_header_table_t elf_sec; 168 | } u; 169 | 170 | /* Memory Mapping buffer */ 171 | multiboot_uint32_t mmap_length; 172 | multiboot_uint32_t mmap_addr; 173 | 174 | /* Drive Info buffer */ 175 | multiboot_uint32_t drives_length; 176 | multiboot_uint32_t drives_addr; 177 | 178 | /* ROM configuration table */ 179 | multiboot_uint32_t config_table; 180 | 181 | /* Boot Loader Name */ 182 | multiboot_uint32_t boot_loader_name; 183 | 184 | /* APM table */ 185 | multiboot_uint32_t apm_table; 186 | 187 | /* Video */ 188 | multiboot_uint32_t vbe_control_info; 189 | multiboot_uint32_t vbe_mode_info; 190 | multiboot_uint16_t vbe_mode; 191 | multiboot_uint16_t vbe_interface_seg; 192 | multiboot_uint16_t vbe_interface_off; 193 | multiboot_uint16_t vbe_interface_len; 194 | }; 195 | typedef struct multiboot_info multiboot_info_t; 196 | 197 | struct multiboot_mmap_entry 198 | { 199 | multiboot_uint32_t size; 200 | multiboot_uint64_t addr; 201 | multiboot_uint64_t len; 202 | #define MULTIBOOT_MEMORY_AVAILABLE 1 203 | #define MULTIBOOT_MEMORY_RESERVED 2 204 | multiboot_uint32_t type; 205 | } __attribute__((packed)); 206 | typedef struct multiboot_mmap_entry multiboot_memory_map_t; 207 | 208 | struct multiboot_mod_list 209 | { 210 | /* the memory used goes from bytes 'mod_start' to 'mod_end-1' inclusive */ 211 | multiboot_uint32_t mod_start; 212 | multiboot_uint32_t mod_end; 213 | 214 | /* Module command line */ 215 | multiboot_uint32_t cmdline; 216 | 217 | /* padding to take it to 16 bytes (must be zero) */ 218 | multiboot_uint32_t pad; 219 | }; 220 | typedef struct multiboot_mod_list multiboot_module_t; 221 | 222 | #endif /* ! ASM_FILE */ 223 | 224 | #endif /* ! MULTIBOOT_HEADER */ 225 | -------------------------------------------------------------------------------- /paging.inc: -------------------------------------------------------------------------------- 1 | PAGING_PXE_P equ 0x1 2 | PAGING_PXE_RW equ 0x2 3 | PAGING_PXE_US equ 0x4 4 | PAGING_PXE_PWT equ 0x8 5 | PAGING_PXE_PCD equ 0x10 6 | PAGING_PXE_A equ 0x20 7 | PAGING_PXE_D equ 0x40 8 | PAGING_PXE_PS equ 0x80 9 | PAGING_PXE_PAT equ 0x80 10 | PAGING_PXE_G equ 0x100 11 | PAGING_PXE_NX equ (1 << 63) 12 | -------------------------------------------------------------------------------- /pm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | static tss_entry_t tss_entry; 6 | 7 | inline void fill_descriptor(descriptor_entry_t *ptr, uint32_t base, uint32_t limit, uint32_t attr) 8 | { 9 | ptr->limit1 = limit & 0xFFFF; 10 | ptr->base1 = base & 0xFFFF; 11 | ptr->base2 = (base >> 16) & 0xFF; 12 | ptr->attr1_limit2_attr2 = ((limit >> 8) & 0x0F00) | (attr & 0xF0FF); 13 | ptr->base3 = (base >> 24) & 0xFF; 14 | } 15 | 16 | inline void fill_gate(gate_entry_t *ptr, uint16_t selector, uint32_t offset, uint8_t attr) 17 | { 18 | ptr->offset1 = offset & 0xFFFF; 19 | ptr->selector = selector; 20 | ptr->zero = 0; 21 | ptr->type_attr = attr; 22 | ptr->offset2 = (offset >> 16) & 0xFFFF; 23 | } 24 | 25 | inline void prepare_tss_gdt_entry() 26 | { 27 | fill_descriptor(&gdt32_tss, (uintptr_t)&tss_entry, sizeof(tss_entry) - 1, 28 | DESCRIPTOR_ATTR_TSS | DESCRIPTOR_ATTR_DPL3); 29 | } 30 | 31 | void init_pm() 32 | { 33 | tss_entry.iomap_base = sizeof(tss_entry_t); 34 | prepare_tss_gdt_entry(); 35 | } 36 | 37 | inline void reset_tss_busy(descriptor_entry_t *ptr) 38 | { 39 | ptr->attr1_limit2_attr2 &= ~DESCRIPTOR_ATTR_BUSY; 40 | } 41 | 42 | inline void flush_tss() 43 | { 44 | reset_tss_busy(&gdt32_tss); 45 | asm volatile ("ltr %0" 46 | : 47 | : "r"((uint16_t)SELECTOR_TSS)); 48 | } 49 | 50 | void set_tss_stack0(ureg_t stack) 51 | { 52 | tss_entry.ss0 = SELECTOR_KERNEL_DATA; 53 | tss_entry.esp0 = stack; 54 | flush_tss(); 55 | } 56 | 57 | void prepare_idt() 58 | { 59 | fill_gate(&idt_ptr[0], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_0, 60 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 61 | fill_gate(&idt_ptr[1], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_1, 62 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 63 | fill_gate(&idt_ptr[2], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_2, 64 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 65 | fill_gate(&idt_ptr[3], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_3, 66 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 67 | fill_gate(&idt_ptr[4], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_4, 68 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 69 | fill_gate(&idt_ptr[5], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_5, 70 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 71 | fill_gate(&idt_ptr[6], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_6, 72 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 73 | fill_gate(&idt_ptr[7], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_7, 74 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 75 | fill_gate(&idt_ptr[8], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_8, 76 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 77 | fill_gate(&idt_ptr[9], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_9, 78 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 79 | fill_gate(&idt_ptr[10], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_10, 80 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 81 | fill_gate(&idt_ptr[11], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_11, 82 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 83 | fill_gate(&idt_ptr[12], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_12, 84 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 85 | fill_gate(&idt_ptr[13], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_13, 86 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 87 | fill_gate(&idt_ptr[14], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_14, 88 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 89 | fill_gate(&idt_ptr[15], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_15, 90 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 91 | fill_gate(&idt_ptr[16], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_16, 92 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 93 | fill_gate(&idt_ptr[17], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_17, 94 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 95 | fill_gate(&idt_ptr[18], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_18, 96 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 97 | fill_gate(&idt_ptr[19], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_19, 98 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 99 | fill_gate(&idt_ptr[20], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_20, 100 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 101 | fill_gate(&idt_ptr[21], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_21, 102 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 103 | fill_gate(&idt_ptr[22], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_22, 104 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 105 | fill_gate(&idt_ptr[23], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_23, 106 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 107 | fill_gate(&idt_ptr[24], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_24, 108 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 109 | fill_gate(&idt_ptr[25], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_25, 110 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 111 | fill_gate(&idt_ptr[26], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_26, 112 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 113 | fill_gate(&idt_ptr[27], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_27, 114 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 115 | fill_gate(&idt_ptr[28], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_28, 116 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 117 | fill_gate(&idt_ptr[29], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_29, 118 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 119 | fill_gate(&idt_ptr[30], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_30, 120 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 121 | fill_gate(&idt_ptr[31], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_31, 122 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 123 | fill_gate(&idt_ptr[32], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_32, 124 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 125 | fill_gate(&idt_ptr[33], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_33, 126 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 127 | fill_gate(&idt_ptr[34], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_34, 128 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 129 | fill_gate(&idt_ptr[35], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_35, 130 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 131 | fill_gate(&idt_ptr[36], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_36, 132 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 133 | fill_gate(&idt_ptr[37], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_37, 134 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 135 | fill_gate(&idt_ptr[38], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_38, 136 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 137 | fill_gate(&idt_ptr[39], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_39, 138 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 139 | fill_gate(&idt_ptr[40], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_40, 140 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 141 | fill_gate(&idt_ptr[41], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_41, 142 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 143 | fill_gate(&idt_ptr[42], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_42, 144 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 145 | fill_gate(&idt_ptr[43], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_43, 146 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 147 | fill_gate(&idt_ptr[44], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_44, 148 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 149 | fill_gate(&idt_ptr[45], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_45, 150 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 151 | fill_gate(&idt_ptr[46], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_46, 152 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 153 | fill_gate(&idt_ptr[47], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_47, 154 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL0); 155 | 156 | fill_gate(&idt_ptr[128], SELECTOR_KERNEL_CODE, (uintptr_t)&interrupt_wrapper_128, 157 | GATE_ATTR_INTERRUPT | DESCRIPTOR_ATTR_DPL3); 158 | } 159 | -------------------------------------------------------------------------------- /pm.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_KERNEL_PM_H_ 2 | #define _WDOS_KERNEL_PM_H_ 3 | 4 | #include 5 | 6 | #define DESCRIPTOR_ATTR_4K (1 << 15) 7 | #define DESCRIPTOR_ATTR_DB (1 << 14) 8 | #define DESCRIPTOR_ATTR_L (1 << 13) 9 | #define DESCRIPTOR_ATTR_PRESENT (1 << 7) 10 | #define DESCRIPTOR_ATTR_DPL0 (0 << 5) 11 | #define DESCRIPTOR_ATTR_DPL3 (3 << 5) 12 | #define DESCRIPTOR_ATTR_SEG (1 << 4) 13 | #define DESCRIPTOR_ATTR_EX (1 << 3) 14 | #define DESCRIPTOR_ATTR_DC (1 << 2) 15 | #define DESCRIPTOR_ATTR_RW (1 << 1) 16 | #define DESCRIPTOR_ATTR_AC (1 << 0) 17 | 18 | #define DESCRIPTOR_ATTR_BUSY (1 << 1) 19 | 20 | #define SELECTOR_GDT (0 << 2) 21 | #define SELECTOR_LDT (1 << 2) 22 | #define SELECTOR_RPL0 (0 << 0) 23 | #define SELECTOR_RPL3 (3 << 0) 24 | #define SELECTOR_RPL_MASK (0b11) 25 | 26 | #define DESCRIPTOR_ATTR_CODE32 (DESCRIPTOR_ATTR_PRESENT | DESCRIPTOR_ATTR_DB | \ 27 | DESCRIPTOR_ATTR_SEG | DESCRIPTOR_ATTR_EX | \ 28 | DESCRIPTOR_ATTR_RW | DESCRIPTOR_ATTR_4K) 29 | #define DESCRIPTOR_ATTR_DATA32 (DESCRIPTOR_ATTR_PRESENT | DESCRIPTOR_ATTR_DB | \ 30 | DESCRIPTOR_ATTR_SEG | DESCRIPTOR_ATTR_RW | \ 31 | DESCRIPTOR_ATTR_4K) 32 | #define DESCRIPTOR_ATTR_TSS (DESCRIPTOR_ATTR_PRESENT | 0x9) 33 | #define GATE_ATTR_INTERRUPT (DESCRIPTOR_ATTR_PRESENT | 0xE) 34 | 35 | typedef struct descriptor_entry 36 | { 37 | uint16_t limit1; 38 | uint16_t base1; 39 | uint8_t base2; 40 | uint16_t attr1_limit2_attr2; 41 | uint8_t base3; 42 | } __attribute__((packed)) descriptor_entry_t; 43 | 44 | typedef struct gate_entry 45 | { 46 | uint16_t offset1; // offset bits 0..15 47 | uint16_t selector; // a code segment selector in GDT or LDT 48 | uint8_t zero; // unused, set to 0 49 | uint8_t type_attr; // type and attributes, see below 50 | uint16_t offset2; // offset bits 16..31 51 | } __attribute__((packed)) gate_entry_t; 52 | 53 | typedef struct tss_entry 54 | { 55 | uint16_t prev_tss; // unused 56 | uint16_t reserved1; 57 | uint32_t esp0; // The stack pointer to load when we change to kernel mode. 58 | uint16_t ss0; // The stack segment to load when we change to kernel mode. 59 | uint16_t reserved2; 60 | uint32_t esp1; // everything below here is unused now... 61 | uint16_t ss1; 62 | uint16_t reserved3; 63 | uint32_t esp2; 64 | uint16_t ss2; 65 | uint16_t reserved4; 66 | uint32_t cr3; 67 | uint32_t eip; 68 | uint32_t eflags; 69 | uint32_t eax; 70 | uint32_t ecx; 71 | uint32_t edx; 72 | uint32_t ebx; 73 | uint32_t esp; 74 | uint32_t ebp; 75 | uint32_t esi; 76 | uint32_t edi; 77 | uint16_t es; 78 | uint16_t reserved5; 79 | uint16_t cs; 80 | uint16_t reserved6; 81 | uint16_t ss; 82 | uint16_t reserved7; 83 | uint16_t ds; 84 | uint16_t reserved8; 85 | uint16_t fs; 86 | uint16_t reserved9; 87 | uint16_t gs; 88 | uint16_t reserved10; 89 | uint16_t ldtr; 90 | uint16_t reserved11; 91 | uint16_t trap; 92 | uint16_t iomap_base; 93 | } __attribute__((packed)) tss_entry_t; 94 | 95 | void fill_descriptor(descriptor_entry_t *ptr, uint32_t base, uint32_t limit, uint32_t attr); 96 | void fill_gate(gate_entry_t *ptr, uint16_t selector, uint32_t offset, uint8_t attr); 97 | void prepare_tss_gdt_entry(); 98 | void init_pm(); 99 | void reset_tss_busy(descriptor_entry_t *ptr); 100 | void flush_tss(); 101 | void set_tss_stack0(ureg_t stack); 102 | void prepare_idt(); 103 | 104 | #endif // _WDOS_KERNEL_PM_H_ 105 | -------------------------------------------------------------------------------- /runtime/types.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_RUNTIME_TYPES_H_ 2 | #define _WDOS_RUNTIME_TYPES_H_ 3 | 4 | #define NULL ((void *)0) 5 | 6 | #ifdef X86_64 7 | 8 | // LP64 9 | // See more at: http://wiki.osdev.org/X86-64 10 | 11 | typedef unsigned char u8; 12 | typedef unsigned short u16; 13 | typedef unsigned int u32; 14 | typedef unsigned long u64; 15 | 16 | typedef signed char s8; 17 | typedef signed short s16; 18 | typedef signed int s32; 19 | typedef signed long s64; 20 | 21 | typedef s8 int8_t; 22 | typedef u8 uint8_t; 23 | 24 | typedef s16 int16_t; 25 | typedef u16 uint16_t; 26 | 27 | typedef s32 int32_t; 28 | typedef u32 uint32_t; 29 | 30 | typedef s64 int64_t; 31 | typedef u64 uint64_t; 32 | 33 | typedef s64 intptr_t; 34 | typedef u64 uintptr_t; 35 | 36 | typedef s64 ptrdiff_t; 37 | 38 | typedef u64 size_t; 39 | 40 | // register type 41 | typedef u64 ureg_t; 42 | typedef s64 reg_t; 43 | 44 | #else 45 | 46 | // 32-bit system 47 | 48 | typedef unsigned char u8; 49 | typedef unsigned short u16; 50 | typedef unsigned int u32; 51 | typedef unsigned long long u64; 52 | 53 | typedef signed char s8; 54 | typedef signed short s16; 55 | typedef signed int s32; 56 | typedef signed long long s64; 57 | 58 | typedef s8 int8_t; 59 | typedef u8 uint8_t; 60 | 61 | typedef s16 int16_t; 62 | typedef u16 uint16_t; 63 | 64 | typedef s32 int32_t; 65 | typedef u32 uint32_t; 66 | 67 | typedef s64 int64_t; 68 | typedef u64 uint64_t; 69 | 70 | typedef s32 intptr_t; 71 | typedef u32 uintptr_t; 72 | 73 | typedef s32 ptrdiff_t; 74 | 75 | typedef u32 size_t; 76 | 77 | // register type 78 | typedef u32 ureg_t; 79 | typedef s32 reg_t; 80 | 81 | #endif 82 | 83 | typedef uint8_t bool; 84 | #define true 1 85 | #define false 0 86 | 87 | #endif // _WDOS_RUNTIME_TYPES_H_ 88 | -------------------------------------------------------------------------------- /stdlib/bits.c: -------------------------------------------------------------------------------- 1 | #include "bits.h" 2 | 3 | #include 4 | 5 | const uint8_t debruijn[32] = 6 | { 7 | 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, 8 | 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 9 | }; 10 | -------------------------------------------------------------------------------- /stdlib/bits.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_STDLIB_BITS_H_ 2 | #define _WDOS_STDLIB_BITS_H_ 3 | 4 | #include 5 | 6 | extern const uint8_t debruijn[32]; 7 | 8 | #define bits_log2(x) (debruijn[((uint32_t)(((x) & -(x)) * 0x077CB531U)) >> 27]) 9 | 10 | // for 64 bit 11 | #define bits_llog2(x) (((x) >> 32) ? \ 12 | (bits_log2((x) >> 32) + 32) : \ 13 | (bits_log2((x) & 0xFFFFFFFFU))) 14 | 15 | #define is_power_of_2(x) (!((x) & ((x) - 1))) 16 | 17 | #define bits_mul(a, b) ((a) << bits_log2(b)) 18 | #define bits_div(a, b) ((a) >> bits_log2(b)) 19 | #define bits_mod(a, b) ((a) & ((b) - 1)) 20 | 21 | static inline uint32_t next_power_of_2(uint32_t x) 22 | { 23 | if (is_power_of_2(x)) 24 | { 25 | return x; 26 | } 27 | 28 | x--; 29 | x |= x >> 1; 30 | x |= x >> 2; 31 | x |= x >> 4; 32 | x |= x >> 8; 33 | x |= x >> 16; 34 | x++; 35 | return x; 36 | } 37 | 38 | #endif // _WDOS_STDLIB_BITS_H_ 39 | -------------------------------------------------------------------------------- /stdlib/memory.c: -------------------------------------------------------------------------------- 1 | #include "memory.h" 2 | 3 | uint32_t memset(void *dest, uint8_t value, uint32_t num) 4 | { 5 | uint32_t value32 = ((uint32_t)value << 24) | ((uint32_t)value << 16) | 6 | ((uint32_t)value << 8) | ((uint32_t)value << 0); 7 | uint32_t *dest32 = dest; 8 | uint8_t *dest8 = dest + (num & ~3); 9 | for (uint32_t i = 0; i < (num >> 2); ++i) 10 | { 11 | dest32[i] = value32; 12 | } 13 | for (uint32_t i = 0; i < (num & 3); ++i) 14 | { 15 | dest8[i] = value; 16 | } 17 | return num; 18 | } 19 | 20 | uint32_t memcpy(void *dest, const void *src, uint32_t num) 21 | { 22 | uint32_t *dest32 = dest; 23 | const uint32_t *src32 = src; 24 | uint8_t *dest8 = dest + (num & ~3); 25 | const uint8_t *src8 = src + (num & ~3); 26 | for (uint32_t i = 0; i < (num >> 2); ++i) 27 | { 28 | dest32[i] = src32[i]; 29 | } 30 | for (uint32_t i = 0; i < (num & 3); ++i) 31 | { 32 | dest8[i] = src8[i]; 33 | } 34 | return num; 35 | } 36 | 37 | int memcmp(const void *a, const void *b, uint32_t num) 38 | { 39 | const uint32_t *a32 = a; 40 | const uint32_t *b32 = b; 41 | const uint8_t *a8 = a + (num & ~3); 42 | const uint8_t *b8 = b + (num & ~3); 43 | for (uint32_t i = 0; i < (num >> 2); ++i) 44 | { 45 | if (a32[i] != b32[i]) 46 | { 47 | return 1; 48 | } 49 | } 50 | for (uint32_t i = 0; i < (num & 3); ++i) 51 | { 52 | if (a8[i] != b8[i]) 53 | { 54 | return 1; 55 | } 56 | } 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /stdlib/memory.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_STDLIB_MEMORY_H_ 2 | #define _WDOS_STDLIB_MEMORY_H_ 3 | 4 | #include 5 | 6 | uint32_t memset(void *dest, uint8_t value, uint32_t num); 7 | uint32_t memcpy(void *dest, const void *src, uint32_t num); 8 | int memcmp(const void *a, const void *b, uint32_t num); 9 | 10 | #endif // _WDOS_STDLIB_MEMORY_H_ 11 | -------------------------------------------------------------------------------- /stdlib/string.c: -------------------------------------------------------------------------------- 1 | #include "string.h" 2 | #include "memory.h" 3 | 4 | uint8_t utoh(uint32_t x, char *buffer) 5 | { 6 | #define HEX_COUNT (sizeof(x) * 2) 7 | for (int8_t i = HEX_COUNT - 1; i >= 0; --i) 8 | { 9 | buffer[i] = (x & 0xF) + '0'; 10 | if (buffer[i] > '9') 11 | { 12 | buffer[i] = buffer[i] - '9' + 'A' - 1; 13 | } 14 | x >>= 4; 15 | } 16 | buffer[HEX_COUNT] = 0; 17 | return HEX_COUNT; 18 | #undef HEX_COUNT 19 | } 20 | 21 | uint8_t ultoh(uint64_t x, char *buffer) 22 | { 23 | #define HEX_COUNT (sizeof(x) * 2) 24 | for (int8_t i = HEX_COUNT - 1; i >= 0; --i) 25 | { 26 | buffer[i] = (x & 0xF) + '0'; 27 | if (buffer[i] > '9') 28 | { 29 | buffer[i] = buffer[i] - '9' + 'A' - 1; 30 | } 31 | x >>= 4; 32 | } 33 | buffer[HEX_COUNT] = 0; 34 | return HEX_COUNT; 35 | #undef HEX_COUNT 36 | } 37 | 38 | uint8_t utob(uint32_t x, char *buffer) 39 | { 40 | #define BIT_COUNT (sizeof(x) * 8) 41 | for (uint8_t i = 0; i < BIT_COUNT; ++i) 42 | { 43 | buffer[i] = (x & 0x80000000) ? '1' : '0'; 44 | x <<= 1; 45 | } 46 | buffer[BIT_COUNT] = 0; 47 | return BIT_COUNT; 48 | #undef BIT_COUNT 49 | } 50 | 51 | uint8_t ultob(uint64_t x, char *buffer) 52 | { 53 | #define BIT_COUNT (sizeof(x) * 8) 54 | for (uint8_t i = 0; i < BIT_COUNT; ++i) 55 | { 56 | buffer[i] = (x & 0x8000000000000000ULL) ? '1' : '0'; 57 | x <<= 1; 58 | } 59 | buffer[BIT_COUNT] = 0; 60 | return BIT_COUNT; 61 | #undef BIT_COUNT 62 | } 63 | 64 | uint8_t itos(int32_t x, char *buffer) 65 | { 66 | if (!x) 67 | { 68 | buffer[0] = '0'; 69 | buffer[1] = '\0'; 70 | return 1; 71 | } 72 | 73 | if (x == -2147483648) 74 | { 75 | return strcpy(buffer, "-2147483648"); 76 | } 77 | 78 | if (x > 0) 79 | { 80 | return utos((uint32_t)x, buffer); 81 | } 82 | else // x < 0 83 | { 84 | buffer[0] = '-'; 85 | return utos((uint32_t)(-x), &buffer[1]) + 1; 86 | } 87 | } 88 | 89 | uint8_t utos(uint32_t x, char *buffer) 90 | { 91 | if (!x) 92 | { 93 | buffer[0] = '0'; 94 | buffer[1] = '\0'; 95 | return 1; 96 | } 97 | 98 | uint8_t i = 0; 99 | while (x) 100 | { 101 | buffer[i] = x % 10 + '0'; 102 | x /= 10; 103 | ++i; 104 | } 105 | 106 | // reverse 107 | for (uint8_t j = 0; j < (i >> 1); ++j) 108 | { 109 | char tmp = buffer[i - j - 1]; 110 | buffer[i - j - 1] = buffer[j]; 111 | buffer[j] = tmp; 112 | } 113 | 114 | buffer[i] = '\0'; 115 | return i; 116 | } 117 | 118 | uint8_t btoh(uint8_t x, char *buffer) 119 | { 120 | #define HEX_COUNT (sizeof(x) * 2) 121 | for (int8_t i = HEX_COUNT - 1; i >= 0; --i) 122 | { 123 | buffer[i] = (x & 0xF) + '0'; 124 | if (buffer[i] > '9') 125 | { 126 | buffer[i] = buffer[i] - '9' + 'A' - 1; 127 | } 128 | x >>= 4; 129 | } 130 | buffer[HEX_COUNT] = 0; 131 | return HEX_COUNT; 132 | #undef HEX_COUNT 133 | } 134 | 135 | uint32_t strlen(const char *src) 136 | { 137 | uint32_t length = 0; 138 | while (*src) 139 | { 140 | ++length; 141 | ++src; 142 | } 143 | return length; 144 | } 145 | 146 | uint32_t strcpy(char *dest, const char *src) 147 | { 148 | uint32_t length = 0; 149 | while (*src) 150 | { 151 | *dest = *src; 152 | ++length; 153 | ++src; 154 | ++dest; 155 | } 156 | *dest = '\0'; 157 | return length; 158 | } 159 | 160 | const char *strsplit(const char *str, char delim, char *out_buffer) 161 | { 162 | while (*str && *str != delim) 163 | { 164 | *out_buffer = *str; 165 | ++str; 166 | ++out_buffer; 167 | } 168 | *out_buffer = 0; 169 | if (!*str) 170 | { 171 | return NULL; // no more 172 | } 173 | else if (*str == delim) 174 | { 175 | return str + 1; 176 | } 177 | return NULL; 178 | } 179 | -------------------------------------------------------------------------------- /stdlib/string.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_STDLIB_STRING_H_ 2 | #define _WDOS_STDLIB_STRING_H_ 3 | 4 | #include 5 | 6 | uint8_t utoh(uint32_t x, char *buffer); 7 | uint8_t ultoh(uint64_t x, char *buffer); 8 | uint8_t utob(uint32_t x, char *buffer); 9 | uint8_t ultob(uint64_t x, char *buffer); 10 | uint8_t itos(int32_t x, char *buffer); 11 | uint8_t utos(uint32_t x, char *buffer); 12 | uint8_t btoh(uint8_t x, char *buffer); 13 | 14 | uint32_t strlen(const char *src); 15 | uint32_t strcpy(char *dest, const char *src); 16 | const char *strsplit(const char *str, char delim, char *out_buffer); 17 | 18 | #endif // _WDOS_STDLIB_STRING_H_ 19 | -------------------------------------------------------------------------------- /syscall.c: -------------------------------------------------------------------------------- 1 | #include "syscall.h" 2 | 3 | static inline uint32_t syscall0(uint32_t id) 4 | { 5 | uint32_t ret; 6 | asm volatile ("int " SYSCALL_INTERRUPT 7 | : "=a"(ret) 8 | : "a"(id)); 9 | return ret; 10 | } 11 | 12 | static inline uint32_t syscall1(uint32_t id, uint32_t arg1) 13 | { 14 | uint32_t ret; 15 | asm volatile ("int " SYSCALL_INTERRUPT 16 | : "=a"(ret) 17 | : "a"(id), "b"(arg1)); 18 | return ret; 19 | } 20 | 21 | static inline uint32_t syscall2(uint32_t id, uint32_t arg1, uint32_t arg2) 22 | { 23 | uint32_t ret; 24 | asm volatile ("int " SYSCALL_INTERRUPT 25 | : "=a"(ret) 26 | : "a"(id), "b"(arg1), "c"(arg2)); 27 | return ret; 28 | } 29 | 30 | static inline uint32_t syscall3(uint32_t id, uint32_t arg1, uint32_t arg2, uint32_t arg3) 31 | { 32 | uint32_t ret; 33 | asm volatile ("int " SYSCALL_INTERRUPT 34 | : "=a"(ret) 35 | : "a"(id), "b"(arg1), "c"(arg2), "d"(arg3)); 36 | return ret; 37 | } 38 | 39 | static inline uint32_t syscall4(uint32_t id, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4) 40 | { 41 | uint32_t ret; 42 | asm volatile ("int " SYSCALL_INTERRUPT 43 | : "=a"(ret) 44 | : "a"(id), "b"(arg1), "c"(arg2), "d"(arg3), "D"(arg4)); 45 | return ret; 46 | } 47 | 48 | static inline uint32_t syscall5(uint32_t id, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t arg4, 49 | uint32_t arg5) 50 | { 51 | uint32_t ret; 52 | asm volatile ("int " SYSCALL_INTERRUPT 53 | : "=a"(ret) 54 | : "a"(id), "b"(arg1), "c"(arg2), "d"(arg3), "D"(arg4), "S"(arg5)); 55 | return ret; 56 | } 57 | 58 | void sys_exit(int exitcode) 59 | { 60 | syscall1(SYS_exit, exitcode); 61 | } 62 | 63 | int sys_test() 64 | { 65 | return (int)syscall0(SYS_test); 66 | } 67 | 68 | int sys_add(int a, int b) 69 | { 70 | return (int)syscall2(SYS_add, (uint32_t)a, (uint32_t)b); 71 | } 72 | 73 | void sys_yield() 74 | { 75 | syscall0(SYS_yield); 76 | } 77 | 78 | void sys_delay(int x) 79 | { 80 | syscall1(SYS_delay, x); 81 | } 82 | 83 | -------------------------------------------------------------------------------- /syscall.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_SYSCALL_H_ 2 | #define _WDOS_SYSCALL_H_ 3 | 4 | #include 5 | 6 | #define SYSCALL_INTERRUPT "$0x80" 7 | 8 | #define SYS_exit 0 9 | #define SYS_test 1 10 | #define SYS_add 2 11 | #define SYS_yield 3 12 | #define SYS_delay 4 13 | #define SYSCALL_COUNT 256 14 | 15 | void sys_exit(int exitcode); 16 | int sys_test(); 17 | int sys_add(int a, int b); 18 | void sys_yield(); 19 | void sys_delay(int x); 20 | 21 | #endif // _WDOS_SYSCALL_H_ 22 | -------------------------------------------------------------------------------- /syscall_impl.c: -------------------------------------------------------------------------------- 1 | #include "syscall_impl.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #define RETURN(x) do { frame->eax = (uint32_t)(x); return; } while (0) 8 | 9 | typedef void (*syscall_handler_t)(interrupt_frame_t*, ...); 10 | 11 | typedef struct syscall 12 | { 13 | syscall_handler_t handler; 14 | uint8_t params_count; 15 | } syscall_t; 16 | 17 | static syscall_t syscall_handlers[SYSCALL_COUNT] = { NULL }; 18 | 19 | static void do_exit(interrupt_frame_t *frame, int exitcode) 20 | { 21 | 22 | } 23 | 24 | static void do_test(interrupt_frame_t *frame) 25 | { 26 | RETURN(0x900dbeef); 27 | } 28 | 29 | static void do_add(interrupt_frame_t *frame, int a, int b) 30 | { 31 | RETURN(a + b); 32 | } 33 | 34 | static void do_yield(interrupt_frame_t *frame) 35 | { 36 | thread_current()->ticks = 1; 37 | thread_irq_handler(IRQ_CLOCK, frame); 38 | } 39 | 40 | static void do_delay(interrupt_frame_t *frame, int x) 41 | { 42 | enable_interrupt(); // allow context switch 43 | 44 | while (!x); 45 | 46 | int i = 10000; 47 | while (--i) 48 | { 49 | int j = 10 * x; 50 | while (--j); 51 | } 52 | } 53 | 54 | static void register_syscall_handler(uint32_t id, syscall_handler_t handler, uint8_t params_count) 55 | { 56 | syscall_t *s = &syscall_handlers[id]; 57 | s->handler = handler; 58 | s->params_count = params_count; 59 | } 60 | 61 | void init_syscall_impl() 62 | { 63 | #define REGISTER(func, params_count) \ 64 | register_syscall_handler(SYS_##func, (syscall_handler_t)&do_##func, params_count) 65 | 66 | REGISTER(exit, 1); 67 | REGISTER(test, 0); 68 | REGISTER(add, 2); 69 | REGISTER(yield, 0); 70 | REGISTER(delay, 1); 71 | 72 | #undef REGISTER 73 | } 74 | 75 | void syscall_dispatch(uint32_t id, interrupt_frame_t *frame) 76 | { 77 | syscall_t *s = &syscall_handlers[id]; 78 | if (s->params_count == 0) 79 | { 80 | s->handler(frame); 81 | } 82 | else if (s->params_count == 1) 83 | { 84 | s->handler(frame, frame->ebx); 85 | } 86 | else if (s->params_count == 2) 87 | { 88 | s->handler(frame, frame->ebx, frame->ecx); 89 | } 90 | else if (s->params_count == 3) 91 | { 92 | s->handler(frame, frame->ebx, frame->ecx, frame->edx); 93 | } 94 | else if (s->params_count == 4) 95 | { 96 | s->handler(frame, frame->ebx, frame->ecx, frame->edx, frame->edi); 97 | } 98 | else if (s->params_count == 5) 99 | { 100 | s->handler(frame, frame->ebx, frame->ecx, frame->edx, frame->edi, frame->esi); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /syscall_impl.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_KERNEL_SYSCALL_IMPL_H_ 2 | #define _WDOS_KERNEL_SYSCALL_IMPL_H_ 3 | 4 | #include 5 | #include 6 | 7 | #define SYS_exit 0 8 | #define SYS_test 1 9 | #define SYS_add 2 10 | #define SYS_yield 3 11 | #define SYS_delay 4 12 | #define SYSCALL_COUNT 256 13 | 14 | void init_syscall_impl(); 15 | void syscall_dispatch(uint32_t id, interrupt_frame_t *frame); 16 | 17 | #endif // _WDOS_KERNEL_SYSCALL_IMPL_H_ 18 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | LD = ld 3 | 4 | CFLAGS = -g -m32 -fno-stack-protector -fno-asynchronous-unwind-tables \ 5 | -Wall -Wextra -I../ 6 | LDFLAGS = -melf_i386 -dynamic-linker /lib/ld-linux.so.2 -lc -lm 7 | 8 | .PHONY: all 9 | all: test_buddy.elf test_page_list.elf 10 | 11 | 12 | %.o: %.c 13 | $(CC) $(CFLAGS) -c $^ -o $@ 14 | 15 | test_buddy.elf: test_buddy.c ../mm/buddy.o ../mm/page_list.o ../stdlib/bits.o 16 | $(CC) $(CFLAGS) $^ -o $@ 17 | 18 | test_page_list.elf: test_page_list.c ../mm/page_list.o 19 | $(CC) $(CFLAGS) $^ -o $@ 20 | 21 | .PHONY: test 22 | test: test_page_list.elf test_buddy.elf 23 | ./test_page_list.elf 24 | ./test_buddy.elf 25 | 26 | .PHONY: clean 27 | clean: 28 | -rm *.d 29 | -rm *.o 30 | -rm *.elf 31 | -rm *.iso 32 | -rm ../driver/*.o 33 | -rm ../mm/*.o 34 | -rm ../stdlib/*.o 35 | -------------------------------------------------------------------------------- /test/test_buddy.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | void mkmem(void *begin, void *end) 11 | { 12 | void *ret = mmap(begin, end - begin, PROT_EXEC | PROT_READ | PROT_WRITE, 13 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); 14 | if (ret != begin) 15 | { 16 | perror("mmap"); 17 | exit(1); 18 | } 19 | memset(begin, 0, end - begin); 20 | } 21 | 22 | void print_bucket(bucket_t *b) 23 | { 24 | page_list_t *list = &b->list; 25 | for (page_node_t *iter = list->head->next; iter != list->tail; iter = iter->next) 26 | { 27 | printf(" [%p]page begin=%p, count=%u, used=%d\n", iter, 28 | iter->page, iter->count, iter->used); 29 | } 30 | } 31 | 32 | void print_buddy(buddy_t *b) 33 | { 34 | printf("======\n"); 35 | for (size_t i = 0; i < b->bucket_count; ++i) 36 | { 37 | printf("[BUCKET #%u %u pages]\n", i, 1 << i); 38 | print_bucket(&b->buckets[i]); 39 | } 40 | printf("======\n"); 41 | } 42 | 43 | int main() 44 | { 45 | // act as physical memory 46 | printf("mmapping..."); 47 | fflush(stdout); 48 | void *free1_begin = (void *)0x100000; 49 | void *free1_end = (void *)0x8000000; 50 | mkmem(free1_begin, free1_end); 51 | 52 | void *free2_begin = (void *)0x9000000; 53 | void *free2_end = (void *)0xF0000000; 54 | mkmem(free2_begin, free2_end); 55 | printf("done\n"); 56 | 57 | const size_t bucket_count = 20; 58 | const size_t page_size = 0x1000; 59 | const size_t node_count = (uintptr_t)free2_end / page_size; 60 | buddy_t buddy; 61 | bucket_t *buckets = (bucket_t *)free1_begin; 62 | free1_begin += bucket_count * sizeof(bucket_t); 63 | page_node_t *nodes = (page_node_t *)free1_begin; 64 | free1_begin += node_count * sizeof(page_node_t); 65 | 66 | buddy_init(&buddy, buckets, bucket_count, nodes, node_count, page_size); 67 | buddy_init_pages(&buddy, free1_begin, free1_end - free1_begin); 68 | print_buddy(&buddy); 69 | buddy_init_pages(&buddy, free2_begin, free2_end - free2_begin); 70 | print_buddy(&buddy); 71 | 72 | void *firstp = NULL; 73 | for (int i = 0; i < 100000000; ++i) 74 | { 75 | void *p = buddy_alloc_pages(&buddy, ((i & 0b1111111) << 5) + 1); 76 | /*if (i == 0) 77 | { 78 | firstp = p; 79 | }*/ 80 | page_node_t *node = buddy_page_node(&buddy, p); 81 | //print_buddy(&buddy); 82 | if (p) 83 | { 84 | //printf("alloc: [%p]page begin=%p, count=%u, used=%d\n", node, 85 | // node->page, node->count, node->used); 86 | buddy_free_pages(&buddy, p); 87 | } 88 | else 89 | { 90 | printf("alloc failed!\n"); 91 | return 1; 92 | } 93 | } 94 | //print_buddy(&buddy); 95 | //buddy_free_pages(&buddy, firstp); 96 | print_buddy(&buddy); 97 | return 0; 98 | } 99 | -------------------------------------------------------------------------------- /test/test_page_list.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | void print_all_node(page_list_t *list, size_t n) 8 | { 9 | printf("========\n"); 10 | printf("size=%u\n", list->size); 11 | page_node_t *nodes = list->nodes; 12 | for (size_t i = 0; i < n; ++i) 13 | { 14 | printf("[%p] prev=%p, next=%p, page=%u\n", &nodes[i], nodes[i].prev, nodes[i].next, 15 | (uint32_t)nodes[i].page); 16 | } 17 | printf("========\n"); 18 | } 19 | 20 | void print_each(page_list_t *list) 21 | { 22 | printf(">"); 23 | for (page_node_t *iter = list->head->next; iter != list->tail; iter = iter->next) 24 | { 25 | printf("%u ", (uint32_t)iter->page); 26 | } 27 | printf("\n<"); 28 | for (page_node_t *iter = list->tail->prev; iter != list->head; iter = iter->prev) 29 | { 30 | printf("%u ", (uint32_t)iter->page); 31 | } 32 | printf("\n"); 33 | } 34 | 35 | int main() 36 | { 37 | page_node_t *data = (page_node_t *)malloc(32 * sizeof(page_node_t)); 38 | page_list_t *list = (page_list_t *)malloc(sizeof(page_list_t)); 39 | page_list_init(list, data); 40 | print_all_node(list, 32); 41 | 42 | for (int i = 1; i < 6; ++i) 43 | { 44 | page_node_t *node = page_list_alloc_node(list); 45 | node->page = (void *)i; 46 | page_list_insert_as_prev(list, node, list->tail); 47 | } 48 | 49 | page_node_t *node = page_list_alloc_node(list); 50 | node->page = (void *)6; 51 | page_list_insert_as_prev(list, node, list->head->next->next->next->next); 52 | 53 | print_all_node(list, 32); 54 | 55 | node = node->prev; 56 | page_list_take_node(list, node); 57 | page_list_insert_as_prev(list, node, list->head->next); 58 | print_all_node(list, 32); 59 | print_each(list); 60 | 61 | page_node_t *node1 = list->head->next->next, *node2 = node1->next; 62 | page_list_swap_nodes(list, node1, node2); 63 | print_all_node(list, 32); 64 | print_each(list); 65 | 66 | node1 = list->head->next->next; 67 | node2 = node1->prev; 68 | page_list_swap_nodes(list, node1, node2); 69 | print_all_node(list, 32); 70 | print_each(list); 71 | 72 | printf("removed: %u\n", (uint32_t)page_list_remove_last_phy_node(list)); 73 | printf("removed: %u\n", (uint32_t)page_list_remove_last_phy_node(list)); 74 | print_all_node(list, 32); 75 | print_each(list); 76 | 77 | printf("removed: %u\n", 78 | (uint32_t)page_list_remove_node(list, list->head->next->next->next)); 79 | print_all_node(list, 32); 80 | print_each(list); 81 | printf("removed: %u\n", 82 | (uint32_t)page_list_remove_node(list, list->head->next)); 83 | printf("removed: %u\n", 84 | (uint32_t)page_list_remove_node(list, list->head->next)); 85 | printf("removed: %u\n", 86 | (uint32_t)page_list_remove_node(list, list->head->next)); 87 | print_all_node(list, 32); 88 | print_each(list); 89 | 90 | for (int i = 1; i < 32; i += 3) 91 | { 92 | page_node_t *node = page_list_alloc_node(list); 93 | node->page = (void *)i; 94 | page_list_insert_as_prev(list, node, list->tail); 95 | } 96 | print_all_node(list, 32); 97 | print_each(list); 98 | 99 | page_node_t target; 100 | target.page = (void *)5; 101 | printf("found: %p\n", page_list_find_gt(list, &target)); 102 | 103 | node = list->head->next->next->next->next; 104 | printf("updating: %p\n", node); 105 | page_list_update_position(list, node); 106 | print_all_node(list, 32); 107 | print_each(list); 108 | node->page = (void *)5; 109 | page_list_update_position(list, node); 110 | print_all_node(list, 32); 111 | print_each(list); 112 | node->page = (void *)777; 113 | page_list_update_position(list, node); 114 | print_all_node(list, 32); 115 | print_each(list); 116 | return 0; 117 | } 118 | -------------------------------------------------------------------------------- /thread.c: -------------------------------------------------------------------------------- 1 | #include "thread.h" 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | static thread_t threads[16]; 11 | static uint32_t thread_count = 0; 12 | static uint32_t current_thread = -1; 13 | static spinlock_t thread_lock; 14 | static volatile uint32_t ticks = 0; 15 | 16 | uint32_t get_pid() 17 | { 18 | return current_thread; 19 | } 20 | 21 | uint32_t get_ttyid() 22 | { 23 | return thread_current()->tty - default_tty; 24 | } 25 | 26 | void init_thread() 27 | { 28 | spinlock_init(&thread_lock); 29 | register_irq_handler(IRQ_CLOCK, &thread_irq_handler); 30 | } 31 | 32 | thread_t *thread_current() 33 | { 34 | if (current_thread != -1) 35 | { 36 | return &threads[current_thread]; 37 | } 38 | else 39 | { 40 | return NULL; 41 | } 42 | } 43 | 44 | inline interrupt_frame_t *thread_registers(thread_t *th) 45 | { 46 | if ((th->registers.cs & SELECTOR_RPL_MASK) != SELECTOR_RPL0) 47 | { 48 | return &(th->registers); 49 | } 50 | else 51 | { 52 | return (interrupt_frame_t *)(th->registers.isr_esp - sizeof(th->registers.isr_esp)); 53 | } 54 | } 55 | 56 | static inline void store_registers(thread_t *th, const interrupt_frame_t *src) 57 | { 58 | interrupt_frame_t *frame = &th->registers; 59 | if ((src->cs & SELECTOR_RPL_MASK) != SELECTOR_RPL0) 60 | { 61 | frame->gs = src->gs; 62 | frame->fs = src->fs; 63 | frame->es = src->es; 64 | frame->ds = src->ds; 65 | frame->edi = src->edi; 66 | frame->esi = src->esi; 67 | frame->ebp = src->ebp; 68 | frame->ebx = src->ebx; 69 | frame->edx = src->edx; 70 | frame->ecx = src->ecx; 71 | frame->eax = src->eax; 72 | frame->eip = src->eip; 73 | frame->cs = src->cs; 74 | frame->esp = src->esp; 75 | frame->ss = src->ss; 76 | // preserve system flags 77 | frame->eflags = (frame->eflags & ~EFLAGS_MASK) | (src->eflags & EFLAGS_MASK); 78 | } 79 | else 80 | { 81 | // For kernel threads, 82 | // registers are stored (pushed) in thread's own (kernel) stack, 83 | // so just record the ESP and remember it's a kernel thread using CS here. 84 | frame->isr_esp = src->isr_esp; 85 | frame->cs = src->cs; 86 | } 87 | } 88 | 89 | static inline void load_registers(interrupt_frame_t *dest, thread_t *th) 90 | { 91 | interrupt_frame_t *frame = thread_registers(th); 92 | 93 | // preserve system flags 94 | frame->eflags = (dest->eflags & ~EFLAGS_MASK) | (frame->eflags & EFLAGS_MASK); 95 | 96 | // If this is not a kernel thread, 97 | // restoring its kernel stack is also needed. 98 | if ((frame->cs & SELECTOR_RPL_MASK) != SELECTOR_RPL0) 99 | { 100 | set_tss_stack0(th->kernel_stack); 101 | } 102 | 103 | // Just let ESP point to the registers stored. 104 | dest->isr_esp = (uintptr_t)&frame->SECOND_REGISTER; 105 | 106 | // TODO: paging 107 | } 108 | 109 | bool thread_schedule() 110 | { 111 | thread_t *th = thread_current(); 112 | if (th) 113 | { 114 | --th->ticks; 115 | if (0 < th->ticks && th->ticks < th->priority) 116 | { 117 | return false; 118 | } 119 | th->ticks = th->priority; 120 | } 121 | 122 | // TODO: schedule 123 | ++current_thread; 124 | if (current_thread >= thread_count) 125 | { 126 | current_thread = 0; 127 | } 128 | return true; 129 | } 130 | 131 | void thread_irq_handler(uint8_t irq, interrupt_frame_t *frame) 132 | { 133 | if (!thread_count) 134 | { 135 | kprint_ok_fail("[KDEBUG] schedule failed: no thread", false); 136 | return; 137 | } 138 | 139 | if (!spinlock_try_lock(&thread_lock)) 140 | { 141 | return; 142 | } 143 | 144 | thread_t *th_interrupted = thread_current(); 145 | if (thread_schedule()) // if need to switch 146 | { 147 | // current_thread changed 148 | 149 | // save current registers 150 | if (th_interrupted) 151 | { 152 | store_registers(th_interrupted, frame); 153 | } 154 | 155 | thread_t *th_new = thread_current(); 156 | 157 | // change registers to switch context 158 | load_registers(frame, th_new); 159 | // TODO: paging 160 | } 161 | 162 | out: 163 | spinlock_release(&thread_lock); 164 | } 165 | 166 | uint32_t thread_create(const char *name, entry_point_t entry_point, void *stack, 167 | void *kernel_stack) 168 | { 169 | if (thread_count >= 16) 170 | { 171 | kprint_ok_fail("[KDEBUG] create thread failed: thread limit exceeded", false); 172 | return -1; 173 | } 174 | 175 | spinlock_wait_and_lock(&thread_lock); 176 | 177 | thread_t *th = &threads[thread_count]; 178 | ++thread_count; 179 | 180 | memset(th, 0, sizeof(thread_t)); 181 | 182 | strcpy(th->name, name); 183 | th->tty = tty_current_screen(); 184 | th->ticks = th->priority = THREAD_PRIORITY_DEFAULT; 185 | 186 | th->registers.cs = SELECTOR_USER_CODE; 187 | th->registers.eip = (uintptr_t)entry_point; 188 | th->registers.ss = SELECTOR_USER_DATA; 189 | th->registers.esp = (uintptr_t)stack; 190 | th->registers.ds = th->registers.es = th->registers.fs = th->registers.gs = 191 | SELECTOR_USER_DATA; 192 | 193 | th->kernel_stack = (uintptr_t)kernel_stack; 194 | 195 | spinlock_release(&thread_lock); 196 | return thread_count - 1; 197 | } 198 | 199 | uint32_t thread_create_kernel(const char *name, entry_point_t entry_point, void *stack) 200 | { 201 | if (thread_count >= 16) 202 | { 203 | kprint_ok_fail("[KDEBUG] create thread failed: thread limit exceeded", false); 204 | return -1; 205 | } 206 | 207 | spinlock_wait_and_lock(&thread_lock); 208 | 209 | thread_t *th = &threads[thread_count]; 210 | ++thread_count; 211 | 212 | memset(th, 0, sizeof(thread_t)); 213 | 214 | strcpy(th->name, name); 215 | th->tty = tty_current_screen(); 216 | th->ticks = th->priority = THREAD_PRIORITY_DEFAULT; 217 | 218 | th->registers.cs = SELECTOR_KERNEL_CODE; 219 | th->kernel_stack = NULL; // already kernel, so kernel_stack = NULL for TSS 220 | 221 | // "push" interrupt_frame 222 | interrupt_frame_t *frame = (interrupt_frame_t *)(stack - sizeof(interrupt_frame_t)); 223 | frame->cs = SELECTOR_KERNEL_CODE; 224 | frame->eip = (uintptr_t)entry_point; 225 | frame->ds = frame->es = frame->fs = frame->gs = SELECTOR_KERNEL_DATA; 226 | th->registers.isr_esp = (uintptr_t)&frame->SECOND_REGISTER; 227 | 228 | spinlock_release(&thread_lock); 229 | return thread_count - 1; 230 | } 231 | 232 | void thread_set_priority(uint8_t priority) 233 | { 234 | if (priority < THREAD_PRIORITY_MIN || priority > THREAD_PRIORITY_MAX) 235 | { 236 | return; 237 | } 238 | thread_current()->priority = priority; 239 | } 240 | -------------------------------------------------------------------------------- /thread.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_KERNEL_THREAD_H_ 2 | #define _WDOS_KERNEL_THREAD_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define THREAD_PRIORITY_MIN 1 9 | #define THREAD_PRIORITY_DEFAULT 7 10 | #define THREAD_PRIORITY_MAX 16 11 | 12 | // control and status bits (eg. CF, ZF, ...), no system bits (eg. IF, ...) 13 | #define EFLAGS_MASK 0b00000000000000000000110011010101 14 | 15 | typedef struct thread 16 | { 17 | char name[16]; 18 | tty_t *tty; 19 | interrupt_frame_t registers; 20 | ureg_t pdbr; // cr3 21 | ureg_t kernel_stack; 22 | uint8_t priority; 23 | uint8_t ticks; 24 | } thread_t; 25 | 26 | typedef void (*entry_point_t)(); 27 | 28 | uint32_t get_pid(); 29 | uint32_t get_ttyid(); 30 | void init_thread(); 31 | thread_t *thread_current(); 32 | interrupt_frame_t *thread_registers(thread_t *th); 33 | bool thread_schedule(); 34 | void thread_irq_handler(uint8_t irq, interrupt_frame_t *frame); 35 | uint32_t thread_create(const char *name, entry_point_t entry_point, void *stack, 36 | void *kernel_stack); 37 | uint32_t thread_create_kernel(const char *name, entry_point_t entry_point, void *stack); 38 | void thread_set_priority(uint8_t priority); 39 | 40 | #endif // _WDOS_KERNEL_THREAD_H_ 41 | -------------------------------------------------------------------------------- /tty.c: -------------------------------------------------------------------------------- 1 | #include "tty.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | static tty_t ttys[TTY_COUNT]; 8 | tty_t *const default_tty = &ttys[0]; 9 | static volatile tty_t *current_screen; 10 | static tty_t *current_tty = NULL; 11 | 12 | static size_t tty_width, tty_height; 13 | static tty_driver_t tty_driver; 14 | 15 | void init_tty(tty_driver_t *driver) 16 | { 17 | memcpy(&tty_driver, driver, sizeof(tty_driver_t)); 18 | tty_width = tty_driver.width; 19 | tty_height = tty_driver.height; 20 | 21 | for (int i = 0; i < TTY_COUNT; ++i) 22 | { 23 | tty_init(&ttys[i]); 24 | if (tty_driver.init) 25 | { 26 | tty_driver.init(&ttys[i], i); 27 | } 28 | } 29 | tty_switch(default_tty); 30 | } 31 | 32 | tty_t *tty_current_screen() 33 | { 34 | return current_screen; 35 | } 36 | 37 | tty_t *tty_current_process() 38 | { 39 | // TODO: process or thread? 40 | if (current_tty) 41 | { 42 | return current_tty; 43 | } 44 | thread_t *current_thread = thread_current(); 45 | if (current_thread) 46 | { 47 | return current_thread->tty; 48 | } 49 | else 50 | { 51 | return default_tty; 52 | } 53 | } 54 | 55 | void tty_init(tty_t *tty) 56 | { 57 | spinlock_init(&tty->lock); 58 | tty->x = tty->y = 0; 59 | tty->color = TTY_COLOR_DEFAULT; 60 | tty->mem = NULL; 61 | } 62 | 63 | void tty_enter(tty_t *tty) 64 | { 65 | spinlock_wait_and_lock(&tty->lock); 66 | } 67 | 68 | void tty_leave(tty_t *tty) 69 | { 70 | spinlock_release(&tty->lock); 71 | } 72 | 73 | tty_t *tty_select(size_t id) 74 | { 75 | return &ttys[id]; 76 | } 77 | 78 | void tty_switch(tty_t *tty) 79 | { 80 | if (current_screen == tty) 81 | { 82 | return; 83 | } 84 | 85 | current_screen = tty; 86 | if (tty_driver.switch_handler) 87 | { 88 | tty_driver.switch_handler(tty); 89 | } 90 | tty_update_cursor_location(); 91 | } 92 | 93 | void tty_set_current(tty_t *tty) 94 | { 95 | current_tty = tty; 96 | } 97 | 98 | void tty_update_cursor_location() 99 | { 100 | if (tty_driver.update_cursor_location) 101 | { 102 | tty_driver.update_cursor_location(current_screen); 103 | } 104 | } 105 | 106 | void tty_clear(tty_t *tty) 107 | { 108 | tty_fill_color(tty, 0); 109 | } 110 | 111 | void tty_fill_color(tty_t *tty, tty_color_t color) 112 | { 113 | uint32_t *gm_int = (uint32_t *)tty->mem; 114 | for (uint32_t i = 0; i < tty_width * tty_height / 2; ++i) 115 | { 116 | gm_int[i] = 0x00200020 | ((uint32_t)color << 24) | ((uint32_t)color << 8); 117 | } 118 | tty->x = tty->y = 0; 119 | if (tty == current_screen) 120 | { 121 | if (tty_driver.rerender) 122 | { 123 | tty_driver.rerender(tty); 124 | } 125 | tty_update_cursor_location(); 126 | } 127 | } 128 | 129 | void tty_newline(tty_t *tty) 130 | { 131 | tty->x = 0; 132 | ++tty->y; 133 | if (tty->y >= tty_height) 134 | { 135 | tty_scroll(tty); 136 | tty->y = tty_height - 1; 137 | } 138 | } 139 | 140 | void tty_scroll(tty_t *tty) 141 | { 142 | uint32_t *gm_int = (uint32_t *)tty->mem; 143 | for (int i = 0; i < tty_width * (tty_height - 1) / 2; ++i) 144 | { 145 | gm_int[i] = gm_int[i + tty_width / 2]; 146 | } 147 | for (int i = tty_width * (tty_height - 1) / 2; i < tty_width * tty_height / 2; ++i) 148 | { 149 | gm_int[i] = 0; 150 | } 151 | if (tty == current_screen) 152 | { 153 | if (tty_driver.rerender) 154 | { 155 | tty_driver.rerender(tty); 156 | } 157 | tty_update_cursor_location(); 158 | } 159 | } 160 | 161 | inline void tty_set_char(tty_t *tty, size_t x, size_t y, char ch, tty_color_t color) 162 | { 163 | tty->mem[x + y * tty_width] = (color << 8) | ch; 164 | if (tty == current_screen) 165 | { 166 | if (tty_driver.set_char) 167 | { 168 | tty_driver.set_char(tty, x, y, ch, color); 169 | } 170 | } 171 | } 172 | 173 | void tty_set_string(tty_t *tty, size_t x_offset, size_t y_offset, 174 | size_t width, const char *str, tty_color_t color) 175 | { 176 | for (int i = 0; str[i] != '\0'; ++i) 177 | { 178 | tty_set_char(tty, x_offset + i % width, y_offset + i / width, str[i], color); 179 | } 180 | } 181 | 182 | uint32_t tty_print(tty_t *tty, const char *str) 183 | { 184 | uint32_t i = 0; 185 | for (; str[i] != '\0'; ++i) 186 | { 187 | if (str[i] == TTY_CMD_SET_COLOR) 188 | { 189 | ++i; 190 | if (str[i] == '\0') 191 | { 192 | break; 193 | } 194 | tty->color = str[i]; 195 | } 196 | else if (str[i] == '\n') 197 | { 198 | // implies \r 199 | tty_newline(tty); 200 | } 201 | else if (str[i] == '\r') 202 | { 203 | tty->x = 0; 204 | } 205 | else if (str[i] == '\b') 206 | { 207 | if (tty->x) 208 | { 209 | --tty->x; 210 | } 211 | } 212 | else 213 | { 214 | tty_set_char(tty, tty->x, tty->y, str[i], tty->color); 215 | ++tty->x; 216 | if (tty->x >= tty_width) 217 | { 218 | tty_newline(tty); 219 | } 220 | } 221 | } 222 | if (tty == current_screen) 223 | { 224 | tty_update_cursor_location(); 225 | } 226 | return i; 227 | } 228 | 229 | void ktty_enter() 230 | { 231 | tty_enter(tty_current_process()); 232 | } 233 | 234 | void ktty_leave() 235 | { 236 | tty_leave(tty_current_process()); 237 | } 238 | 239 | void kclear() 240 | { 241 | tty_clear(tty_current_process()); 242 | } 243 | 244 | void kfill_color(tty_color_t color) 245 | { 246 | tty_fill_color(tty_current_process(), color); 247 | } 248 | 249 | uint8_t kget_color() 250 | { 251 | return tty_current_process()->color; 252 | } 253 | 254 | void kset_color(tty_color_t color) 255 | { 256 | tty_current_process()->color = color; 257 | } 258 | 259 | void kput_char(char ch) 260 | { 261 | char str[2] = { 0 }; 262 | str[0] = ch; 263 | kprint(str); 264 | } 265 | 266 | uint32_t kprint(const char *str) 267 | { 268 | return tty_print(tty_current_process(), str); 269 | } 270 | 271 | uint8_t kprint_hex(uint32_t x) 272 | { 273 | #define HEX_COUNT (sizeof(x) * 2) 274 | kprint("0x"); 275 | char buffer[HEX_COUNT + 1] = { '\0' }; 276 | utoh(x, buffer); 277 | #undef HEX_COUNT 278 | return kprint(buffer) + 2; 279 | } 280 | 281 | uint8_t kprint_bin(uint32_t x) 282 | { 283 | #define BIT_COUNT (sizeof(x) * 8) 284 | kprint("0b"); 285 | char buffer[BIT_COUNT + 1] = { '\0' }; 286 | utob(x, buffer); 287 | #undef BIT_COUNT 288 | return kprint(buffer) + 2; 289 | } 290 | 291 | uint8_t kprint_int(int32_t x) 292 | { 293 | char buffer[12] = { '\0' }; // -2 147 483 647, 11 chars 294 | itos(x, buffer); 295 | return kprint(buffer); 296 | } 297 | 298 | uint8_t kprint_uint(uint32_t x) 299 | { 300 | char buffer[11] = { '\0' }; // 4 294 967 295, 10 chars 301 | utos(x, buffer); 302 | return kprint(buffer); 303 | } 304 | 305 | uint8_t kprint_hex_long(uint64_t x) 306 | { 307 | #define HEX_COUNT (sizeof(x) * 2) 308 | kprint("0x"); 309 | char buffer[HEX_COUNT + 1] = { '\0' }; 310 | ultoh(x, buffer); 311 | #undef HEX_COUNT 312 | return kprint(buffer) + 2; 313 | } 314 | 315 | uint8_t kprint_byte(uint8_t x) 316 | { 317 | #define HEX_COUNT (sizeof(x) * 2) 318 | kprint("0x"); 319 | char buffer[HEX_COUNT + 1] = { '\0' }; 320 | btoh(x, buffer); 321 | #undef HEX_COUNT 322 | return kprint(buffer) + 2; 323 | } 324 | 325 | uint32_t kprint_ok_fail(const char *str, bool ok) 326 | { 327 | uint32_t len = kprint(str); 328 | uint8_t ok_length = 4; // [OK] 329 | if (!ok) 330 | { 331 | ok_length = 6; // [FAIL] 332 | } 333 | for (uint8_t i = 0; i < tty_width - len - ok_length; ++i) 334 | { 335 | kprint(" "); 336 | } 337 | uint8_t old_color = kget_color(); 338 | if (ok) 339 | { 340 | kprint("[" TTY_SET_OK_COLOR "OK" TTY_SET_DEFAULT_COLOR "]"); 341 | } 342 | else 343 | { 344 | kprint("[" TTY_SET_FAIL_COLOR "FAIL" TTY_SET_DEFAULT_COLOR "]"); 345 | } 346 | kset_color(old_color); 347 | return tty_width; 348 | } 349 | -------------------------------------------------------------------------------- /tty.h: -------------------------------------------------------------------------------- 1 | #ifndef _WDOS_KERNEL_TTY_H_ 2 | #define _WDOS_KERNEL_TTY_H_ 3 | 4 | #include 5 | #include 6 | 7 | #define TTY_COLOR_BLACK 0x0 8 | #define TTY_COLOR_BLUE 0x1 9 | #define TTY_COLOR_GREEN 0x2 10 | #define TTY_COLOR_CYAN 0x3 11 | #define TTY_COLOR_RED 0x4 12 | #define TTY_COLOR_MAGENTA 0x5 13 | #define TTY_COLOR_BROWN 0x6 14 | #define TTY_COLOR_LIGHTGREY 0x7 15 | #define TTY_COLOR_DARKGREY 0x8 16 | #define TTY_COLOR_LIGHTBLUE 0x9 17 | #define TTY_COLOR_LIGHTGREEN 0xA 18 | #define TTY_COLOR_LIGHTCYAN 0xB 19 | #define TTY_COLOR_LIGHTRED 0xC 20 | #define TTY_COLOR_LIGHTMAGENTA 0xD 21 | #define TTY_COLOR_LIGHTBROWN 0xE 22 | #define TTY_COLOR_WHITE 0xF 23 | 24 | #define TTY_MKCOLOR(f, b) (((b) << 4) | (f)) 25 | #define TTY_COLOR_DEFAULT TTY_MKCOLOR(TTY_COLOR_LIGHTGREY, TTY_COLOR_BLACK) 26 | 27 | #define TTY_COUNT 8 28 | 29 | #define TTY_CMD_SET_COLOR 0x01 30 | #define TTY_SET_COLOR "\001" 31 | #define TTY_DEFAULT_COLOR "\007" 32 | #define TTY_OK_COLOR "\002" 33 | #define TTY_FAIL_COLOR "\004" 34 | 35 | #define TTY_SET_DEFAULT_COLOR "\001\007" 36 | #define TTY_SET_OK_COLOR "\001\002" 37 | #define TTY_SET_FAIL_COLOR "\001\004" 38 | 39 | typedef uint8_t tty_color_t; 40 | typedef uint16_t tty_colored_char_t; 41 | 42 | typedef struct tty 43 | { 44 | spinlock_t lock; 45 | size_t x, y; 46 | tty_color_t color; 47 | tty_colored_char_t *mem; 48 | } tty_t; 49 | 50 | typedef struct tty_driver 51 | { 52 | size_t width, height; 53 | void (*init)(tty_t *, size_t); 54 | void (*rerender)(tty_t *); 55 | void (*switch_handler)(tty_t *); 56 | void (*update_cursor_location)(tty_t *); 57 | void (*set_char)(tty_t *, size_t, size_t, char, tty_color_t); 58 | } tty_driver_t; 59 | 60 | extern tty_t *const default_tty; 61 | 62 | void init_tty(); 63 | tty_t *tty_current_screen(); 64 | tty_t *tty_current_process(); 65 | void tty_init(tty_t *tty); 66 | void tty_enter(tty_t *tty); 67 | void tty_leave(tty_t *tty); 68 | tty_t *tty_select(size_t id); 69 | void tty_switch(tty_t *tty); 70 | void tty_set_current(tty_t *tty); 71 | void tty_update_cursor_location(); 72 | void tty_clear(tty_t *tty); 73 | void tty_fill_color(tty_t *tty, tty_color_t color); 74 | void tty_newline(tty_t *tty); 75 | void tty_scroll(tty_t *tty); 76 | void tty_set_char(tty_t *tty, size_t x, size_t y, char ch, tty_color_t color); 77 | void tty_set_string(tty_t *tty, size_t x_offset, size_t y_offset, 78 | size_t width, const char *str, tty_color_t color); 79 | uint32_t tty_print(tty_t *tty, const char *str); 80 | 81 | void ktty_enter(); 82 | void ktty_leave(); 83 | void kclear(); 84 | void kfill_color(tty_color_t color); 85 | tty_color_t kget_color(); 86 | void kset_color(tty_color_t color); 87 | void kput_char(char ch); 88 | uint32_t kprint(const char *str); 89 | uint8_t kprint_int(int32_t x); 90 | uint8_t kprint_uint(uint32_t x); 91 | uint8_t kprint_hex(uint32_t x); 92 | uint8_t kprint_bin(uint32_t x); 93 | uint8_t kprint_hex_long(uint64_t x); 94 | uint8_t kprint_byte(uint8_t x); 95 | uint32_t kprint_ok_fail(const char *str, bool ok); 96 | void kset_char(size_t x, size_t y, char ch, tty_color_t color); 97 | void kset_string(size_t x_offset, size_t y_offset, size_t width, 98 | const char *str, tty_color_t color); 99 | 100 | #endif // _WDOS_KERNEL_TTY_H_ 101 | --------------------------------------------------------------------------------