diff --git a/.clangd b/.clangd deleted file mode 100644 index 6c5daf0..0000000 --- a/.clangd +++ /dev/null @@ -1,2 +0,0 @@ -CompileFlags: - Add: [ -m32, -ffreestanding, -fno-stack-protector, -nostdlib, -nostdinc, -Wall, -Wextra, -std=c23 ] diff --git a/src/linker.ld b/linker/x86_64.ld similarity index 100% rename from src/linker.ld rename to linker/x86_64.ld diff --git a/makefile b/makefile index 5441db0..d0836d9 100644 --- a/makefile +++ b/makefile @@ -8,7 +8,7 @@ LDFLAGS = -g ASFLAGS = -g -F dwarf # Do not modify -CFLAGS += -m32 -ffreestanding -fno-stack-protector -nostdlib -nostdinc -Wall -Wextra -std=c23 +CFLAGS += -m32 -ffreestanding -fno-stack-protector -nostdlib -nostdinc -Wall -Wextra -std=c23 -Isrc/shared LDFLAGS += ASFLAGS += -f elf32 @@ -26,14 +26,14 @@ run: .build/nub-os.iso clean: @rm -r .build 2>/dev/null || true -.build/nub-os.iso: .build/nub-os src/grub.cfg +.build/nub-os.iso: .build/nub-os src/boot/grub.cfg mkdir -p .build/grub/boot/grub - cp src/grub.cfg .build/grub/boot/grub + cp src/boot/grub.cfg .build/grub/boot/grub cp .build/nub-os .build/grub/boot/ grub-mkrescue -o .build/nub-os.iso .build/grub/ .build/nub-os: $(OBJS) - $(LD) $(LDFLAGS) -T src/linker.ld -o $@ $^ + $(LD) $(LDFLAGS) -T linker/x86_64.ld -o $@ $^ .build/%.o: src/%.c @mkdir -p $(dir $@) diff --git a/src/boot.asm b/src/boot/boot.asm similarity index 84% rename from src/boot.asm rename to src/boot/boot.asm index a8fe1ec..fb08473 100644 --- a/src/boot.asm +++ b/src/boot/boot.asm @@ -1,5 +1,5 @@ global _start -extern kmain +extern c_start %define MAGIC 0xe85250d6 %define ARCH 0x0 @@ -27,10 +27,12 @@ stack: .top: section .text -bits 32 _start: mov esp, stack.top - call kmain + push ebx + push eax + call c_start + add esp, 8 .halt: cli hlt diff --git a/src/console.c b/src/boot/console.c similarity index 51% rename from src/console.c rename to src/boot/console.c index ea5d789..0c01893 100644 --- a/src/console.c +++ b/src/boot/console.c @@ -1,4 +1,5 @@ #include "console.h" +#include #define ROWS 25 #define COLUMNS 80 @@ -95,4 +96,73 @@ void console_clear() { cursor_row = 0; cursor_col = 0; +} + +// Supported formats: +// - `d`: i32 (decimal) +// - `u`: u32 (decimal) +// - `x`: u32 (hex) +// - `c`: char (ascii) +// - `s`: char* (ascii string) +// +// ```c +// printf( +// "The answer is %d is located at offset %x in file %s", +// 42, +// 0x2000 +// "hitchhiker.txt" +// ); +// ``` +void kprintf(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + + bool should_format = false; + + for (size_t i = 0; fmt[i] != '\0'; i++) { + if (should_format) { + should_format = false; + + if (fmt[i] == '%') { + console_putchar('%', VGA_DEFAULT_COLOR); + } else if (fmt[i] == 's') { + const char *str = va_arg(args, const char *); + for (size_t j = 0; str[j] != '\0'; j++) { + console_putchar(str[j], VGA_DEFAULT_COLOR); + } + } else if (fmt[i] == 'c') { + char character = (char)va_arg(args, u32); + console_putchar(character, VGA_DEFAULT_COLOR); + } else if (fmt[i] == 'd') { + u32 val = va_arg(args, u32); + char buf[21]; + itoa(val, buf); + for (size_t j = 0; buf[j] != '\0'; j++) { + console_putchar(buf[j], VGA_DEFAULT_COLOR); + } + } else if (fmt[i] == 'u') { + u32 val = va_arg(args, u32); + char buf[21]; + uitoa(val, buf); + for (size_t j = 0; buf[j] != '\0'; j++) { + console_putchar(buf[j], VGA_DEFAULT_COLOR); + } + } else if (fmt[i] == 'x') { + u32 val = va_arg(args, u32); + char buf[17]; + uitoa_hex(val, buf); + for (size_t j = 0; buf[j] != '\0'; j++) { + console_putchar(buf[j], VGA_DEFAULT_COLOR); + } + } else { + console_putchar(fmt[i], VGA_DEFAULT_COLOR); + } + } else if (fmt[i] == '%') { + should_format = true; + } else { + console_putchar(fmt[i], VGA_DEFAULT_COLOR); + } + } + + va_end(args); } \ No newline at end of file diff --git a/src/console.h b/src/boot/console.h similarity index 87% rename from src/console.h rename to src/boot/console.h index f1ba7ce..5aaf878 100644 --- a/src/console.h +++ b/src/boot/console.h @@ -1,6 +1,6 @@ #pragma once -#include "def.h" +#include #define VGA_BLACK 0 #define VGA_BLUE 1 @@ -24,4 +24,6 @@ #define VGA_DEFAULT_COLOR VGA_COLOR(VGA_LIGHT_GRAY, VGA_BLACK) void console_putchar(char character, u8 color); -void console_clear(); \ No newline at end of file +void console_clear(); + +void kprintf(const char *fmt, ...); \ No newline at end of file diff --git a/src/boot/entry.c b/src/boot/entry.c new file mode 100644 index 0000000..0bf128a --- /dev/null +++ b/src/boot/entry.c @@ -0,0 +1,154 @@ +#include +#include "console.h" +#include "multiboot2.h" + +static inline void hlt() { + asm("hlt"); +} + +static inline void cli() { + asm("cli"); +} + +void kpanic(const char *message) { + kprintf("panic: %s\n", message); + while (true) { + cli(); + hlt(); + } +} + +u32 align(u32 num, u32 alignment) { + return (num + alignment - 1) & ~(alignment - 1); +} + +void c_start(u32 magic, uptr multiboot_info) { + console_clear(); + + if (magic != MULTIBOOT_BOOTLOADER_MAGIC) { + kpanic("Magic is wrong"); + } + + uptr next = multiboot_info + 8; + + while (true) { + multiboot_tag *tag = (multiboot_tag*)next; + + if (tag->type == MULTIBOOT_TAG_TYPE_END) { + break; + } + + switch (tag->type) { + case MULTIBOOT_TAG_TYPE_CMDLINE: { + multiboot_tag_string *tag_cmdline = (multiboot_tag_string*)tag; + kprintf("cmdline: %s\n", tag_cmdline->string); + break; + } + case MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME: { + multiboot_tag_string *tag_bootloader = (multiboot_tag_string*)tag; + kprintf("bootloader: %s\n", tag_bootloader->string); + break; + } + case MULTIBOOT_TAG_TYPE_MODULE: { + multiboot_tag_module *tag_module = (multiboot_tag_module*)tag; + kprintf("MULTIBOOT_TAG_TYPE_MODULE\n"); + break; + } + case MULTIBOOT_TAG_TYPE_BASIC_MEMINFO: { + multiboot_tag_basic_meminfo *tag_basic_meminfo = (multiboot_tag_basic_meminfo*)tag; + kprintf("MULTIBOOT_TAG_TYPE_BASIC_MEMINFO\n"); + break; + } + case MULTIBOOT_TAG_TYPE_BOOTDEV: { + multiboot_tag_bootdev *tag_bootdev = (multiboot_tag_bootdev*)tag; + kprintf("MULTIBOOT_TAG_TYPE_BOOTDEV\n"); + break; + } + case MULTIBOOT_TAG_TYPE_MMAP: { + multiboot_tag_mmap *tag_mmap = (multiboot_tag_mmap*)tag; + kprintf("MULTIBOOT_TAG_TYPE_MMAP\n"); + break; + } + case MULTIBOOT_TAG_TYPE_VBE: { + multiboot_tag_vbe *tag_vbe = (multiboot_tag_vbe*)tag; + kprintf("MULTIBOOT_TAG_TYPE_VBE\n"); + break; + } + case MULTIBOOT_TAG_TYPE_FRAMEBUFFER: { + multiboot_tag_framebuffer *tag_framebuffer = (multiboot_tag_framebuffer*)tag; + kprintf("MULTIBOOT_TAG_TYPE_FRAMEBUFFER\n"); + break; + } + case MULTIBOOT_TAG_TYPE_ELF_SECTIONS: { + multiboot_tag_elf_sections *tag_elf_sections = (multiboot_tag_elf_sections*)tag; + kprintf("MULTIBOOT_TAG_TYPE_ELF_SECTIONS\n"); + break; + } + case MULTIBOOT_TAG_TYPE_APM: { + multiboot_tag_apm *tag_apm = (multiboot_tag_apm*)tag; + kprintf("MULTIBOOT_TAG_TYPE_APM\n"); + break; + } + case MULTIBOOT_TAG_TYPE_EFI32: { + multiboot_tag_efi32 *tag_efi32 = (multiboot_tag_efi32*)tag; + kprintf("MULTIBOOT_TAG_TYPE_EFI32\n"); + break; + } + case MULTIBOOT_TAG_TYPE_EFI64: { + multiboot_tag_efi64 *tag_efi64 = (multiboot_tag_efi64*)tag; + kprintf("MULTIBOOT_TAG_TYPE_EFI64\n"); + break; + } + case MULTIBOOT_TAG_TYPE_SMBIOS: { + multiboot_tag_smbios *tag_smbios = (multiboot_tag_smbios*)tag; + kprintf("MULTIBOOT_TAG_TYPE_SMBIOS\n"); + break; + } + case MULTIBOOT_TAG_TYPE_ACPI_OLD: { + multiboot_tag_old_acpi *tag_old_acpi = (multiboot_tag_old_acpi*)tag; + kprintf("MULTIBOOT_TAG_TYPE_ACPI_OLD\n"); + break; + } + case MULTIBOOT_TAG_TYPE_ACPI_NEW: { + multiboot_tag_new_acpi *tag_new_acpi = (multiboot_tag_new_acpi*)tag; + kprintf("MULTIBOOT_TAG_TYPE_ACPI_NEW\n"); + break; + } + case MULTIBOOT_TAG_TYPE_NETWORK: { + multiboot_tag_network *tag_network = (multiboot_tag_network*)tag; + kprintf("MULTIBOOT_TAG_TYPE_NETWORK\n"); + break; + } + case MULTIBOOT_TAG_TYPE_EFI_MMAP: { + multiboot_tag_efi_mmap *tag_efi_mmap = (multiboot_tag_efi_mmap*)tag; + kprintf("MULTIBOOT_TAG_TYPE_EFI_MMAP\n"); + break; + } + case MULTIBOOT_TAG_TYPE_EFI_BS: { + // note(nub31): Just a flag, no data + break; + } + case MULTIBOOT_TAG_TYPE_EFI32_IH: { + multiboot_tag_efi32_ih *tag_efi32_ih = (multiboot_tag_efi32_ih*)tag; + kprintf("MULTIBOOT_TAG_TYPE_EFI32_IH\n"); + break; + } + case MULTIBOOT_TAG_TYPE_EFI64_IH: { + multiboot_tag_efi64_ih *tag_efi64_ih = (multiboot_tag_efi64_ih*)tag; + kprintf("MULTIBOOT_TAG_TYPE_EFI64_IH\n"); + break; + } + case MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR: { + multiboot_tag_load_base_addr *tag_load_base_addr = (multiboot_tag_load_base_addr*)tag; + kprintf("MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR\n"); + break; + } + default: { + kpanic("Unhandled multiboot tag"); + break; + } + } + + next = align(next + tag->size, MULTIBOOT_TAG_ALIGN); + } +} diff --git a/src/grub.cfg b/src/boot/grub.cfg similarity index 100% rename from src/grub.cfg rename to src/boot/grub.cfg diff --git a/src/boot/multiboot2.h b/src/boot/multiboot2.h new file mode 100644 index 0000000..a95a1d8 --- /dev/null +++ b/src/boot/multiboot2.h @@ -0,0 +1,221 @@ +#pragma once + +#define MULTIBOOT_BOOTLOADER_MAGIC 0x36d76289 + +#define MULTIBOOT_TAG_ALIGN 8 + +#define MULTIBOOT_TAG_TYPE_END 0 +#define MULTIBOOT_TAG_TYPE_CMDLINE 1 +#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2 +#define MULTIBOOT_TAG_TYPE_MODULE 3 +#define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4 +#define MULTIBOOT_TAG_TYPE_BOOTDEV 5 +#define MULTIBOOT_TAG_TYPE_MMAP 6 +#define MULTIBOOT_TAG_TYPE_VBE 7 +#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8 +#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9 +#define MULTIBOOT_TAG_TYPE_APM 10 +#define MULTIBOOT_TAG_TYPE_EFI32 11 +#define MULTIBOOT_TAG_TYPE_EFI64 12 +#define MULTIBOOT_TAG_TYPE_SMBIOS 13 +#define MULTIBOOT_TAG_TYPE_ACPI_OLD 14 +#define MULTIBOOT_TAG_TYPE_ACPI_NEW 15 +#define MULTIBOOT_TAG_TYPE_NETWORK 16 +#define MULTIBOOT_TAG_TYPE_EFI_MMAP 17 +#define MULTIBOOT_TAG_TYPE_EFI_BS 18 +#define MULTIBOOT_TAG_TYPE_EFI32_IH 19 +#define MULTIBOOT_TAG_TYPE_EFI64_IH 20 +#define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR 21 + +typedef struct { + u8 red; + u8 green; + u8 blue; +} multiboot_color; + +#define MULTIBOOT_MEMORY_AVAILABLE 1 +#define MULTIBOOT_MEMORY_RESERVED 2 +#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 +#define MULTIBOOT_MEMORY_NVS 4 +#define MULTIBOOT_MEMORY_BADRAM 5 + +typedef struct { + u32 type; + u32 size; +} multiboot_tag; + +typedef struct { + u32 type; + u32 size; + char string[0]; +} multiboot_tag_string; + +typedef struct { + u32 type; + u32 size; + u32 mod_start; + u32 mod_end; + char cmdline[0]; +} multiboot_tag_module; + +typedef struct { + u32 type; + u32 size; + u32 mem_lower; + u32 mem_upper; +} multiboot_tag_basic_meminfo; + +typedef struct { + u32 type; + u32 size; + u32 biosdev; + u32 slice; + u32 part; +} multiboot_tag_bootdev; + +typedef struct { + u64 addr; + u64 len; + u32 type; + u32 zero; +} multiboot_mmap_entry; + +typedef struct { + u32 type; + u32 size; + u32 entry_size; + u32 entry_version; + multiboot_mmap_entry entries[0]; +} multiboot_tag_mmap; + +typedef struct { + u32 type; + u32 size; + + u16 vbe_mode; + u16 vbe_interface_seg; + u16 vbe_interface_off; + u16 vbe_interface_len; + + u8 vbe_control_info[512]; + u8 vbe_mode_info[256]; +} multiboot_tag_vbe; + +#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0 +#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1 +#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2 + +typedef struct { + u32 type; + u32 size; + u64 framebuffer_addr; + u32 framebuffer_pitch; + u32 framebuffer_width; + u32 framebuffer_height; + u8 framebuffer_bpp; + u8 framebuffer_type; + u16 reserved; + + union { + struct { + u16 framebuffer_palette_num_colors; + multiboot_color framebuffer_palette[0]; + }; + struct { + u8 framebuffer_red_field_position; + u8 framebuffer_red_mask_size; + u8 framebuffer_green_field_position; + u8 framebuffer_green_mask_size; + u8 framebuffer_blue_field_position; + u8 framebuffer_blue_mask_size; + }; + }; +} multiboot_tag_framebuffer; + +typedef struct { + u32 type; + u32 size; + u32 num; + u32 entsize; + u32 shndx; + char sections[0]; +} multiboot_tag_elf_sections; + +typedef struct { + u32 type; + u32 size; + u16 version; + u16 cseg; + u32 offset; + u16 cseg_16; + u16 dseg; + u16 flags; + u16 cseg_len; + u16 cseg_16_len; + u16 dseg_len; +} multiboot_tag_apm; + +typedef struct { + u32 type; + u32 size; + u32 pointer; +} multiboot_tag_efi32; + +typedef struct { + u32 type; + u32 size; + u64 pointer; +} multiboot_tag_efi64; + +typedef struct { + u32 type; + u32 size; + u8 major; + u8 minor; + u8 reserved[6]; + u8 tables[0]; +} multiboot_tag_smbios; + +typedef struct { + u32 type; + u32 size; + u8 rsdp[0]; +} multiboot_tag_old_acpi; + +typedef struct { + u32 type; + u32 size; + u8 rsdp[0]; +} multiboot_tag_new_acpi; + +typedef struct { + u32 type; + u32 size; + u8 dhcpack[0]; +} multiboot_tag_network; + +typedef struct { + u32 type; + u32 size; + u32 descr_size; + u32 descr_vers; + u8 efi_mmap[0]; +} multiboot_tag_efi_mmap; + +typedef struct { + u32 type; + u32 size; + u32 pointer; +} multiboot_tag_efi32_ih; + +typedef struct { + u32 type; + u32 size; + u64 pointer; +} multiboot_tag_efi64_ih; + +typedef struct { + u32 type; + u32 size; + u32 load_base_addr; +} multiboot_tag_load_base_addr; diff --git a/src/main.c b/src/main.c deleted file mode 100644 index 1531798..0000000 --- a/src/main.c +++ /dev/null @@ -1,8 +0,0 @@ -#include "console.h" -#include "print.h" - -// Multiboot 2 puts us in 32-bit protected mode with interrupts disabled -void kmain(void) { - console_clear(); - kprintf("booting nub-os\n"); -} diff --git a/src/print.c b/src/print.c deleted file mode 100644 index c4b8b86..0000000 --- a/src/print.c +++ /dev/null @@ -1,73 +0,0 @@ -#include "print.h" -#include "console.h" -#include "def.h" -#include "string.h" - -// Supported formats: -// - `d`: i32 (decimal) -// - `u`: u32 (decimal) -// - `x`: u32 (hex) -// - `c`: char (ascii) -// - `s`: char* (ascii string) -// -// ```c -// printf( -// "The answer is %d is located at offset %x in file %s", -// 42, -// 0x2000 -// "hitchhiker.txt" -// ); -// ``` -void kprintf(const char *fmt, ...) { - va_list args; - va_start(args, fmt); - - bool should_format = false; - - for (size_t i = 0; fmt[i] != '\0'; i++) { - if (should_format) { - should_format = false; - - if (fmt[i] == '%') { - console_putchar('%', VGA_DEFAULT_COLOR); - } else if (fmt[i] == 's') { - const char *str = va_arg(args, const char *); - for (size_t j = 0; str[j] != '\0'; j++) { - console_putchar(str[j], VGA_DEFAULT_COLOR); - } - } else if (fmt[i] == 'c') { - char character = (char)va_arg(args, u32); - console_putchar(character, VGA_DEFAULT_COLOR); - } else if (fmt[i] == 'd') { - u32 val = va_arg(args, u32); - char buf[21]; - itoa(val, buf); - for (size_t j = 0; buf[j] != '\0'; j++) { - console_putchar(buf[j], VGA_DEFAULT_COLOR); - } - } else if (fmt[i] == 'u') { - u32 val = va_arg(args, u32); - char buf[21]; - uitoa(val, buf); - for (size_t j = 0; buf[j] != '\0'; j++) { - console_putchar(buf[j], VGA_DEFAULT_COLOR); - } - } else if (fmt[i] == 'x') { - u32 val = va_arg(args, u32); - char buf[17]; - uitoa_hex(val, buf); - for (size_t j = 0; buf[j] != '\0'; j++) { - console_putchar(buf[j], VGA_DEFAULT_COLOR); - } - } else { - console_putchar(fmt[i], VGA_DEFAULT_COLOR); - } - } else if (fmt[i] == '%') { - should_format = true; - } else { - console_putchar(fmt[i], VGA_DEFAULT_COLOR); - } - } - - va_end(args); -} \ No newline at end of file diff --git a/src/print.h b/src/print.h deleted file mode 100644 index 93e2152..0000000 --- a/src/print.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -void kprintf(const char *fmt, ...); \ No newline at end of file diff --git a/src/def.h b/src/shared/def.h similarity index 79% rename from src/def.h rename to src/shared/def.h index 2be3332..62455ab 100644 --- a/src/def.h +++ b/src/shared/def.h @@ -2,6 +2,8 @@ typedef __builtin_va_list va_list; +#define asm __asm__ + #define va_start(ap, last) __builtin_va_start(ap, last) #define va_arg(ap, type) __builtin_va_arg(ap, type) #define va_end(ap) __builtin_va_end(ap) @@ -14,6 +16,8 @@ typedef __builtin_va_list va_list; typedef unsigned long size_t; typedef unsigned long uintptr_t; +typedef unsigned long uptr; + #define offsetof(type, member) __builtin_offsetof(type, member) typedef unsigned char u8; @@ -22,6 +26,8 @@ typedef unsigned short u16; typedef signed short i16; typedef unsigned int u32; typedef signed int i32; +typedef unsigned long long u64; +typedef signed long long i64; #define I8_MIN (-128) #define I8_MAX 127 @@ -41,6 +47,12 @@ typedef signed int i32; #define U32_MIN 0x0 #define U32_MAX 0xffffffffU +#define I64_MIN (-9223372036854775807LL - 1) +#define I64_MAX 9223372036854775807LL + +#define U64_MIN 0x0 +#define U64_MAX 0xffffffffffffffffULL + #define I8_C(x) x #define U8_C(x) x##U @@ -50,6 +62,9 @@ typedef signed int i32; #define I32_C(x) x #define U32_C(x) x##U +#define I64_C(x) x##LL +#define U64_C(x) x##ULL + #define KiB(count) (U64_C(count) * U64_C(1024)) #define MiB(count) (U64_C(count) * U64_C(1024) * U64_C(1024)) #define GiB(count) (U64_C(count) * U64_C(1024) * U64_C(1024) * U64_C(1024)) diff --git a/src/string.c b/src/shared/string.c similarity index 100% rename from src/string.c rename to src/shared/string.c diff --git a/src/string.h b/src/shared/string.h similarity index 75% rename from src/string.h rename to src/shared/string.h index c440d31..943fa8d 100644 --- a/src/string.h +++ b/src/shared/string.h @@ -1,6 +1,6 @@ #pragma once -#include "def.h" +#include int strcmp(const char *a, const char *b); void reverse(char *str, size_t length);