diff --git a/README.md b/README.md index a974b4b..834dec3 100644 --- a/README.md +++ b/README.md @@ -2,16 +2,29 @@ ## Dependencies +### Building the kernel + - `make` -- `grub` - `mtools` - `x86_64-elf-gcc` - `x86_64-elf-ld` +### Creating a disk image + +- `grub` + ## Building +### Kernel + ```sh -make +make kernel +``` + +### Disk image + +```sh +make iso ``` ## Running @@ -19,5 +32,5 @@ make After building, run the following: ```sh -qemu-system-x86_64 -cdrom .build/nub-os.iso +qemu-system-i386 -kernel .build/kernel ``` diff --git a/grub.cfg b/grub.cfg index a771cd1..462bb74 100644 --- a/grub.cfg +++ b/grub.cfg @@ -1,7 +1,6 @@ menuentry "nub-os" { - multiboot2 /boot/kernel - boot + multiboot /boot/kernel } -set default="nub-os" +set default=0 set timeout=0 diff --git a/src/boot.ld b/linker.ld similarity index 93% rename from src/boot.ld rename to linker.ld index 66b9d81..e56537d 100644 --- a/src/boot.ld +++ b/linker.ld @@ -6,7 +6,7 @@ SECTIONS .text BLOCK(4K) : ALIGN(4K) { - *(.multiboot2) + *(.multiboot) *(.text) } diff --git a/makefile b/makefile index c13d4f0..f2d10ed 100644 --- a/makefile +++ b/makefile @@ -1,16 +1,21 @@ -CC = x86_64-elf-gcc -LD = x86_64-elf-ld +CC = i386-elf-gcc +AS = i386-elf-as +LD = i386-elf-ld -CFLAGS = -m64 -ffreestanding -fno-builtin -Wall -Wextra -Wshadow -std=c23 +CFLAGS = -m32 -ffreestanding -fno-builtin -Wall -Wextra -Wshadow -std=c23 LDFLAGS = +ASFLAGS = -SRC_C := src/kernel.c src/vga.c src/idt.c src/string.c src/keyboard.c -SRC_ASM := src/boot.asm src/idt_stub.asm +SRC_C := src/kernel.c src/string.c src/vga.c +SRC_ASM := src/boot.s OBJ_C := $(SRC_C:src/%.c=.build/%.o) -OBJ_ASM := $(SRC_ASM:src/%.asm=.build/%.o) +OBJ_ASM := $(SRC_ASM:src/%.s=.build/%.o) OBJS := $(OBJ_C) $(OBJ_ASM) +kernel: .build/kernel + @echo "Kernel created at '.build/kernel'" + iso: .build/nub-os.iso @echo "ISO created at '.build/nub-os.iso'" @@ -20,17 +25,17 @@ clean: build-dir: mkdir .build 2>/dev/null || true -.build/nub-os.iso: .build/kernel +.build/nub-os.iso: .build/kernel grub.cfg mkdir -p .build/nub-os/boot/grub cp grub.cfg .build/nub-os/boot/grub cp .build/kernel .build/nub-os/boot/ grub-mkrescue -o .build/nub-os.iso .build/nub-os/ -.build/kernel: $(OBJS) - $(LD) $(LDFLAGS) -T src/boot.ld -o $@ $^ +.build/kernel: $(OBJS) | linker.ld + $(LD) $(LDFLAGS) -m elf_i386 -T linker.ld -o $@ $^ .build/%.o: src/%.c | build-dir $(CC) $(CFLAGS) -c -o $@ $< -.build/%.o: src/%.asm | build-dir - nasm -f elf64 -o $@ $< \ No newline at end of file +.build/%.o: src/%.s | build-dir + $(AS) $(ASFLAGS) -o $@ $< \ No newline at end of file diff --git a/src/boot.asm b/src/boot.asm deleted file mode 100644 index dc65ba7..0000000 --- a/src/boot.asm +++ /dev/null @@ -1,204 +0,0 @@ -%define MAGIC 0xe85250d6 -%define ARCH 0 -%define LEN header_end - header_start -%define CHECKSUM -(MAGIC + ARCH + LEN) - -section .multiboot2 -header_start: -align 4 - dd MAGIC - dd ARCH - dd LEN - dd CHECKSUM - dw 0 - dd 8 -header_end: - -section .bss -align 16 - resb 16384 -stack_top: - -align 4096 -pml4_table: - resb 4096 -pdp_table: - resb 4096 -pd_table: - resb 4096 - -section .text -bits 32 -global _start -_start: - cli - mov esp, stack_top - - ; Check if CPU supports 64-bit mode - call check_multiboot - call check_cpuid - call check_long_mode - - ; Set up paging for 64-bit mode - call set_up_page_tables - call enable_paging - - ; Load GDT and jump to 64-bit mode - lgdt [gdt64.pointer] - jmp gdt64.code:long_mode_start - -check_multiboot: - cmp eax, 0x36d76289 - jne .no_multiboot - ret - -.no_multiboot: - mov al, 'M' - jmp error - -check_cpuid: - ; Copy flags to eax through the stack - pushfd - pop eax - - ; Copy flags to ecx for a later comparison - mov ecx, eax - - ; Flit the cpuid bit - xor eax, 1 << 21 - - ; Copy eax (with the flipped cpuid bit) back to flags - push eax - popfd - - ; Copy flags back to eax. The cpiuid bit will be flipped if cpuid is supported - pushfd - pop eax - - ; Restore flags from the original flags stored in ecx - push ecx - popfd - - ; Compare eax and ecx. If thry are equal, cpuid is not supported - cmp eax, ecx - je .no_cpuid - ret - -.no_cpuid: - mov al, 'I' - jmp error - -check_long_mode: - ; Test if extended processor info is available - mov eax, 0x80000000 - cpuid - cmp eax, 0x80000001 - jb .no_long_mode - - ; Test if long mode is available - mov eax, 0x80000001 - cpuid - test edx, 1 << 29 - jz .no_long_mode - ret - -.no_long_mode: - mov al, 'L' - jmp error - -; todo(nub): This is copy pasted. I will research hat it does later -set_up_page_tables: - ; Map first PML4 entry to PDP table - mov eax, pdp_table - or eax, 0b11 ; present + writable - mov [pml4_table], eax - - ; Map first PDP entry to PD table - mov eax, pd_table - or eax, 0b11 ; present + writable - mov [pdp_table], eax - - ; Map each PD entry to a huge 2MiB page - mov ecx, 0 ; counter variable -.map_pd_table: - ; Map ecx-th PD entry to a huge page that starts at address (2MiB * ecx) - mov eax, 0x200000 ; 2MiB - mul ecx ; Start address of ecx-th page - or eax, 0b10000011 ; present + writable + huge - mov [pd_table + ecx * 8], eax ; Map ecx-th entry - - inc ecx ; Increase counter - cmp ecx, 512 ; If counter == 512, the whole PD table is mapped - jne .map_pd_table ; Else map the next entry - - ret - -; todo(nub): This is copy pasted. I will research hat it does later -enable_paging: - ; Load PML4 to cr3 register (cpu uses this to access the PML4 table) - mov eax, pml4_table - mov cr3, eax - - ; Enable PAE-flag in cr4 (Physical Address Extension) - mov eax, cr4 - or eax, 1 << 5 - mov cr4, eax - - ; Set the long mode bit in the EFER MSR (model specific register) - mov ecx, 0xC0000080 - rdmsr - or eax, 1 << 8 - wrmsr - - ; Enable paging in the cr0 register - mov eax, cr0 - or eax, 1 << 31 - mov cr0, eax - - ret - -error: - mov byte [0xb8000], '[' - mov byte [0xb8002], ' ' - mov byte [0xb8004], 'E' - mov byte [0xb8005], 4 - mov byte [0xb8006], 'R' - mov byte [0xb8007], 4 - mov byte [0xb8008], 'R' - mov byte [0xb8009], 4 - mov byte [0xb800a], ' ' - mov byte [0xb800c], ']' - mov byte [0xb800e], ':' - mov byte [0xb8010], ' ' - mov byte [0xb8012], al - cli -.hang: - hlt - jmp .hang - -section .rodata -gdt64: - dq 0 -.code: equ $ - gdt64 - dq (1<<43) | (1<<44) | (1<<47) | (1<<53) -.pointer: - dw $ - gdt64 - 1 - dq gdt64 - -section .text -bits 64 -long_mode_start: - mov ax, 0 - mov ss, ax - mov ds, ax - mov es, ax - mov fs, ax - mov gs, ax - - extern kernel_main - call kernel_main - - cli -.hang: - hlt - jmp .hang \ No newline at end of file diff --git a/src/boot.s b/src/boot.s new file mode 100644 index 0000000..c41e7d5 --- /dev/null +++ b/src/boot.s @@ -0,0 +1,37 @@ +.intel_syntax noprefix + +.set ALIGN, 1<<0 +.set MEMINFO, 1<<1 +.set FLAGS, ALIGN | MEMINFO +.set MAGIC, 0x1BADB002 +.set CHECKSUM, -(MAGIC + FLAGS) + +.section .multiboot +.align 4 +.long MAGIC +.long FLAGS +.long CHECKSUM + +.section .bss +.align 16 +stack_bottom: +.skip 16384 +stack_top: + +.set BOOTLOADER_MAGIC, 0x2BADB002 + +.section .text +.global _start +_start: + mov stack_top, esp + + cmp eax, BOOTLOADER_MAGIC + jne hang + + push ebx + call kernel_main + add esp, 4 +hang: + cli + hlt + jmp hang \ No newline at end of file diff --git a/src/kernel.c b/src/kernel.c index a97791c..2d4054d 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -1,35 +1,17 @@ #include "kernel.h" -#include "idt.h" -#include "keyboard.h" +#include "multiboot.h" #include "vga.h" #include +#include -void keyboard_handler(const keyboard_event_t* event) -{ - if (event->pressed && event->ascii) - { - vga_print_char(event->ascii); - } -} - -void kernel_main(void) +void kernel_main(multiboot_info_t* multiboot_info) { vga_clear(); vga_print_success(); vga_print(" VGA intialzied\n"); - init_idt(); - vga_print_success(); - vga_print(" IDT intialzied\n"); - - init_keyboard(); - vga_print_success(); - vga_print(" Keyboard driver intialzied\n"); - vga_print("\nWelcome to nub OS\n"); - register_keypress_handler(keyboard_handler); - while (true) { } diff --git a/src/multiboot.h b/src/multiboot.h new file mode 100644 index 0000000..1036405 --- /dev/null +++ b/src/multiboot.h @@ -0,0 +1,58 @@ +#pragma once +#include + +typedef struct multiboot_info +{ + uint32_t flags; // required + + // Available if flags[0] is set + uint32_t mem_lower; + uint32_t mem_upper; + + // Available if flags[1] is set + uint32_t boot_device; + + // Available if flags[2] is set + uint32_t cmdline; + + // Available if flags[3] is set + uint32_t mods_count; + uint32_t mods_addr; + + // Available if flags[4] or flags[5] is set + uint8_t syms[16]; // 28 - 40 bytes, exact layout may differ depending on a.out or ELF + + // Available if flags[6] is set + uint32_t mmap_length; + uint32_t mmap_addr; + + // Available if flags[7] is set + uint32_t drives_length; + uint32_t drives_addr; + + // Available if flags[8] is set + uint32_t config_table; + + // Available if flags[9] is set + uint32_t boot_loader_name; + + // Available if flags[10] is set + uint32_t apm_table; + + // Available if flags[11] is set + uint32_t vbe_control_info; + uint32_t vbe_mode_info; + uint16_t vbe_mode; + uint16_t vbe_interface_seg; + uint16_t vbe_interface_off; + uint16_t vbe_interface_len; + + // Available if flags[12] is set + uint64_t framebuffer_addr; // 64-bit for large memory addresses + uint32_t framebuffer_pitch; + uint32_t framebuffer_width; + uint32_t framebuffer_height; + uint8_t framebuffer_bpp; + uint8_t framebuffer_type; + uint8_t color_info[6]; // 110-115 bytes +} __attribute__((packed)) multiboot_info_t; \ No newline at end of file diff --git a/src/string.c b/src/string.c index 16b3349..2880649 100644 --- a/src/string.c +++ b/src/string.c @@ -26,7 +26,7 @@ void reverse(char* str, size_t length) } } -int uitoa(uint64_t value, char* buffer) +int uitoa(uint32_t value, char* buffer) { int i = 0; if (value == 0) @@ -47,7 +47,7 @@ int uitoa(uint64_t value, char* buffer) return i; } -int itoa(int64_t value, char* buffer) +int itoa(int32_t value, char* buffer) { int i = 0; @@ -59,16 +59,16 @@ int itoa(int64_t value, char* buffer) } bool negative = false; - uint64_t v; + uint32_t v; if (value < 0) { negative = true; - v = (uint64_t)(-value); + v = (uint32_t)(-value); } else { - v = (uint64_t)value; + v = (uint32_t)value; } while (v > 0) diff --git a/src/string.h b/src/string.h index 91ec791..5b535e2 100644 --- a/src/string.h +++ b/src/string.h @@ -5,5 +5,5 @@ int strcmp(const char* a, const char* b); void reverse(char* str, size_t length); -int uitoa(uint64_t value, char* buffer); -int itoa(int64_t value, char* buffer); \ No newline at end of file +int uitoa(uint32_t value, char* buffer); +int itoa(int32_t value, char* buffer); \ No newline at end of file diff --git a/src/vga.c b/src/vga.c index 16725c8..301324c 100644 --- a/src/vga.c +++ b/src/vga.c @@ -138,14 +138,14 @@ void vga_print_error(void) vga_print(" ]"); } -void vga_print_uint(uint64_t value) +void vga_print_uint(uint32_t value) { char buffer[11]; uitoa(value, buffer); vga_print(buffer); } -void vga_print_int(int64_t value) +void vga_print_int(int32_t value) { char buffer[12]; itoa(value, buffer); diff --git a/src/vga.h b/src/vga.h index a369490..0c8a084 100644 --- a/src/vga.h +++ b/src/vga.h @@ -30,8 +30,8 @@ void vga_print_colored(const char* string, vga_color_t color); void vga_print_success(void); void vga_print_error(void); -void vga_print_uint(uint64_t value); -void vga_print_int(int64_t value); +void vga_print_uint(uint32_t value); +void vga_print_int(int32_t value); static inline vga_color_t vga_color(vga_color_t fg_color, vga_color_t bg_color) {