diff --git a/.cache/clangd/index/kmain.c.9B04FE5F8A3537CE.idx b/.cache/clangd/index/kmain.c.9B04FE5F8A3537CE.idx index 5da2d05..b460e54 100644 Binary files a/.cache/clangd/index/kmain.c.9B04FE5F8A3537CE.idx and b/.cache/clangd/index/kmain.c.9B04FE5F8A3537CE.idx differ diff --git a/gdt.c b/gdt.c new file mode 100644 index 0000000..f5a8af2 --- /dev/null +++ b/gdt.c @@ -0,0 +1,28 @@ +#include + +void write_tss(struct tss_entry *tss, struct gdt_entry *gdt, int num, uint16_t ss0, uint32_t esp0) { + uint32_t base = (uint32_t)tss; + uint32_t limit = base + sizeof(struct tss_entry); + + gdt[num].base_low = base & 0xFFFF; + gdt[num].base_middle = (base >> 16) & 0xFF; + gdt[num].base_high = (base >> 24) & 0xFF; + gdt[num].limit_low = limit & 0xFFFF; + gdt[num].granularity = (limit >> 16) & 0x0F; + gdt[num].granularity |= 0x40; + gdt[num].access = 0x89; + + memset(&tss, 0, sizeof(struct tss_entry)); + tss->ss0 = ss0; + tss->esp0 = esp0; + tss->cs = 0x0b; + tss->ss = tss->ds = tss->es = tss->fs = tss->gs = 0x13; +} + +void tss_flush(uint16_t tss_selector) { + asm volatile ( + "ltr %0" + : // no output + : "r" (tss_selector) + ); +} diff --git a/image.img b/image.img new file mode 100644 index 0000000..c4b85c4 Binary files /dev/null and b/image.img differ diff --git a/include/fat12.h b/include/fat12.h deleted file mode 100644 index ff71f10..0000000 --- a/include/fat12.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef RK_FAT12_H_ -#define RK_FAT12_H_ - -#include - -struct fat12_boot_sector { - uint8_t jump_boot[3]; // Jump instruction to boot code - uint8_t oem_name[8]; // OEM name and version - uint16_t bytes_per_sector; // Bytes per sector - uint8_t sectors_per_cluster; // Sectors per cluster - uint16_t reserved_sectors; // Reserved sectors - uint8_t num_fats; // Number of FATs - uint16_t root_entry_count; // Number of root directory entries - uint16_t total_sectors_16; // Total sectors (16-bit) - uint8_t media; // Media descriptor - uint16_t fat_size_16; // Sectors per FAT (16-bit) - uint16_t sectors_per_track; // Sectors per track (for BIOS) - uint16_t num_heads; // Number of heads (for BIOS) - uint32_t hidden_sectors; // Hidden sectors - uint32_t total_sectors_32; // Total sectors (32-bit) - - // Extended Boot Record (EBR) fields - uint8_t drive_number; // Drive number - uint8_t reserved1; // Reserved - uint8_t boot_signature; // Extended boot signature - uint32_t volume_id; // Volume ID (serial number) - uint8_t volume_label[11]; // Volume label - uint8_t file_system_type[8]; // File system type (e.g., "FAT12 ") - - uint8_t boot_code[448]; // Boot code - uint16_t boot_sector_signature; // Boot sector signature (0xAA55) -} __attribute__((packed)); - -#endif diff --git a/include/gdt.h b/include/gdt.h index e6241e9..d0d3477 100644 --- a/include/gdt.h +++ b/include/gdt.h @@ -2,10 +2,17 @@ #define RK_GDT_H_ #include +#include #define GDT_NULL 0 #define GDT_KERNEL_CODE 1 #define GDT_KERNEL_DATA 2 +#define GDT_USER_CODE 3 +#define GDT_USER_DATA 4 + +#define RING0 0 +#define RING3 3 + #define GDT_SEGMENT_SELECTOR(i, p) ((i << 3) | p) struct gdt_entry { @@ -47,4 +54,7 @@ struct tss_entry { uint16_t iomap_base; } __attribute__((packed)); +void write_tss(struct tss_entry *tss, struct gdt_entry *gdt, int num, uint16_t ss0, uint32_t esp0); +void tss_flush(uint16_t tss_selector); + #endif diff --git a/include/mem.h b/include/mem.h index c628ae7..1e7e296 100644 --- a/include/mem.h +++ b/include/mem.h @@ -15,6 +15,12 @@ void mmap_free_block(struct kernel_context *ctx, int block); void *mmap_find_first_free_block(struct kernel_context *ctx); void *mmap_block_to_physical(struct kernel_context *ctx, int block); -void *memset(void *s, int c, uint32_t len); +void memset(void *s, int c, uint32_t len); +void memcpy(void *dest, void *src, int n); + +typedef struct { + void *data; + void *next; +} linked_mem_t; #endif diff --git a/kmain.c b/kmain.c index 952d712..c436ea5 100644 --- a/kmain.c +++ b/kmain.c @@ -11,35 +11,51 @@ #include #include #include -#include - -struct kernel_context ctx = {0}; - -struct idt_entry g_idt[256] = {0}; -struct idtr g_idtr = {0}; - -extern uint32_t isr_stub_table[32]; -extern void ps2_isr(); #define MAGIC_BREAKPOINT __asm__ volatile("xchgw %bx, %bx"); +#define FD_STDOUT 0 +#define FD_STDIN 1 -#define USER_DS 0x23 // User data segment selector -#define USER_CS 0x1B // User code segment selector - +struct kernel_context ctx = {0}; +struct idt_entry g_idt[256] = {0}; +struct idtr g_idtr = {0}; +extern uint32_t isr_stub_table[32]; +extern void ps2_isr(); extern struct gdt_entry gdt[6]; +extern void syscall_isr(); +extern void syscall(); +extern void test(); + +linked_mem_t stdout = {0}; +linked_mem_t stdin = {0}; + struct tss_entry tss; -void tss_flush(uint16_t tss_selector) { - asm volatile ( - "ltr %0" - : // no output - : "r" (tss_selector) - ); +struct stack_frame { + uint32_t edi, esi, ebp, esp, ebx, edx, ecx, eax; +}; + +void syscall_read(struct stack_frame regs) { + uint32_t fd = regs.edi; + char *buf = (char *)regs.esi; + uint32_t count = regs.edx; + + if (fd == FD_STDOUT) { + int pages = count / BLOCK_SIZE; + if (pages == 0) { + memcpy(buf, stdout.data, count); + } + } } -void test() { - printf("\n\nHello from user mode!\n"); - for (;;) {} +void syscall_write(struct stack_frame regs) { + uint32_t fd = regs.edi; + char *buf = (char *)regs.esi; + //uint32_t count = regs.edx; + + if (fd == FD_STDOUT) { + printf("%s", buf); + } } void switch_to_user_mode(void *user_stack, void *user_entry) { @@ -67,25 +83,6 @@ void switch_to_user_mode(void *user_stack, void *user_entry) { ); } -void write_tss(int num, uint16_t ss0, uint32_t esp0) { - uint32_t base = (uint32_t)&tss; - uint32_t limit = base + sizeof(tss); - - gdt[num].base_low = base & 0xFFFF; - gdt[num].base_middle = (base >> 16) & 0xFF; - gdt[num].base_high = (base >> 24) & 0xFF; - gdt[num].limit_low = limit & 0xFFFF; - gdt[num].granularity = (limit >> 16) & 0x0F; - gdt[num].granularity |= 0x40; - gdt[num].access = 0x89; - - memset(&tss, 0, sizeof(tss)); - tss.ss0 = ss0; - tss.esp0 = esp0; - tss.cs = 0x0b; - tss.ss = tss.ds = tss.es = tss.fs = tss.gs = 0x13; -} - void kmain(struct multiboot_info *info) { clear_screen(); set_color(VGA_COLOR_CYAN); @@ -95,22 +92,13 @@ void kmain(struct multiboot_info *info) { ctx.multi_mmap = (struct multiboot_mmap_entry *)info->memMapAddress; ctx.multi_mmap_size = info->memMapLength / sizeof(struct multiboot_mmap_entry); - for (uint32_t i = 0; i < ctx.multi_mmap_size; i++) { - struct multiboot_mmap_entry entry = ctx.multi_mmap[i]; - if (entry.type != MULTIBOOT_MEMORY_AVAILABLE) continue; - - uint32_t len = (uint32_t)(entry.len_low | entry.len_high); - uint32_t addr = (uint32_t)(entry.addr_low | entry.addr_high); - printf("Region #%d: 0x%08X-0x%08X\n", i, addr, addr+len); - } - if (!mmap_init(&ctx)) { set_color(VGA_COLOR_RED); printf("Failed to create memory map\n"); goto halt; } - printf("Detected %d bytes of memory\n", ctx.available_bytes); + printf("[KERNEL] Detected %d bytes of memory\n", ctx.available_bytes); // Create and load an IDT for (int i = 0; i < 32; i++) { @@ -156,7 +144,7 @@ void kmain(struct multiboot_info *info) { goto halt; } - printf("Using ACPI v1.0\n"); + printf("[KERNEL] Using ACPI v1.0\n"); struct fadt *fadt = acpi_locate_sdt(ctx.rsdt, "FACP"); if (!fadt) { @@ -164,9 +152,9 @@ void kmain(struct multiboot_info *info) { printf("Failed to find FADT\n"); goto halt; } - printf("Found FADT at 0x%x\n", fadt); + printf("[KERNEL] Found FADT at 0x%x\n", fadt); if (fadt->Flags & 1) - printf("Legacy devices are supported\n"); + printf("[KERNEL] Legacy devices are supported\n"); else { /* set_color(VGA_COLOR_RED); @@ -176,10 +164,18 @@ void kmain(struct multiboot_info *info) { } pic_remap(PIC_1_START, PIC_2_START); // ACPI version 1.0 is so old that we assume that our PC supports the 8042 ps/2 controller - initialize_8042ps2(); - encode_idt_entry(g_idt, 0x21, (uint32_t)&ps2_isr, GDT_SEGMENT_SELECTOR(GDT_KERNEL_CODE, 0x00), INT_GATE_32 | INT_RING0 | INT_PRESENT); - asm volatile ("sti" ::); + // Allocate 4KiB for stdout + stdout.data = mmap_find_first_free_block(&ctx); + stdout.next = NULL; + // Allocate 4KiB for stdin + stdin.data = mmap_find_first_free_block(&ctx); + stdin.next = NULL; + + initialize_8042ps2(); + encode_idt_entry(g_idt, 0x21, (uint32_t)&ps2_isr, GDT_SEGMENT_SELECTOR(GDT_KERNEL_CODE, RING0), INT_GATE_32 | INT_RING0 | INT_PRESENT); + asm volatile ("sti" ::); +/* struct mcfg *mcfg = acpi_locate_sdt(ctx.rsdt, "MCFG"); if (!mcfg) { set_color(VGA_COLOR_RED); @@ -196,19 +192,62 @@ void kmain(struct multiboot_info *info) { ide_identify(ATA_PRIMARY, ATA_MASTER, ide_buf); } } +*/ - set_color(VGA_COLOR_WHITE); - - void *buf = mmap_find_first_free_block(&ctx); - ata_read_sector(ATA_PRIMARY, ATA_MASTER, 0, (uint8_t *)buf); -// struct fat12_boot_sector *boot_sect = (struct fat12_boot_sector *)buf; -// int fat_size = boot_sect->total_sectors_16 * boot_sect->bytes_per_sector; - - write_tss(5, 0x10, 0x0); + write_tss(&tss, gdt, 5, 0x10, 0x0); tss_flush(0x2B); + encode_idt_entry(g_idt, 0x80, (uint32_t)&syscall_isr, GDT_SEGMENT_SELECTOR(GDT_USER_CODE, RING3), INT_GATE_32 | INT_RING3 | INT_PRESENT); + + uint16_t cs_selector = 0x10; // Example code segment selector + uint32_t eip = (uint32_t)&syscall; // Example entry point address + uint32_t esp; + + // Get the current value of ESP + __asm__ volatile ("mov %%esp, %0" : "=r"(esp)); + + // Write to MSR_SYSENTER_CS (0x174) + __asm__ volatile ( + "movl $0x174, %%ecx \n\t" // MSR address + "movl %0, %%eax \n\t" // Lower 32 bits (cs_selector) + "xor %%edx, %%edx \n\t" // Upper 32 bits (zero for 32-bit value) + "wrmsr" + : + : "r"((uint32_t)cs_selector) + : "eax", "ecx", "edx" + ); + + // Write to MSR_SYSENTER_ESP (0x175) + __asm__ volatile ( + "movl $0x175, %%ecx \n\t" // MSR address + "movl %0, %%eax \n\t" // Lower 32 bits (esp) + "xor %%edx, %%edx \n\t" // Upper 32 bits (zero for 32-bit value) + "wrmsr" + : + : "r"(esp) + : "eax", "ecx", "edx" + ); + + // Write to MSR_SYSENTER_EIP (0x176) + __asm__ volatile ( + "movl $0x176, %%ecx \n\t" // MSR address + "movl %0, %%eax \n\t" // Lower 32 bits (eip) + "xor %%edx, %%edx \n\t" // Upper 32 bits (zero for 32-bit value) + "wrmsr" + : + : "r"(eip) + : "eax", "ecx", "edx" + ); + + void *page = mmap_find_first_free_block(&ctx); + ata_read_sector(ATA_PRIMARY, ATA_MASTER, 0, page); + printf("[KERNEL] Init program loaded to 0x%08X\n", page); + printf("[KERNEL] Transferring control... goodbye\n"); + set_color(VGA_COLOR_WHITE); + // 4 KiB for stack void *stack_bottom = mmap_find_first_free_block(&ctx); - void *stack_top = stack_bottom + 4096; - switch_to_user_mode(stack_top, buf); + void *stack_top = stack_bottom + 0x1000; + MAGIC_BREAKPOINT + switch_to_user_mode(stack_top, page); halt: for (;;) {} } diff --git a/mem.c b/mem.c index bd445a2..20e6924 100644 --- a/mem.c +++ b/mem.c @@ -19,14 +19,18 @@ void *mmap_block_to_physical(struct kernel_context *ctx, int block) { return 0; } -void *memset(void *s, int c, uint32_t len) { +void memset(void *s, int c, uint32_t len) { unsigned char *dst = s; while (len > 0) { *dst = (unsigned char) c; dst++; len--; } - return s; +} + +void memcpy(void *dest, void *src, int n) { + for (int i=0; immap_size = ctx->available_bytes / BLOCK_SIZE / 8; - printf("Memory map size: %d bytes\n", ctx->mmap_size); // Loop again to find the first region with enough space to hold the memory map int index = -1; @@ -113,6 +116,7 @@ void *mmap_find_first_free_block(struct kernel_context *ctx) { uint32_t dword = ctx->mmap[index]; if (!(dword & mask)) { + mmap_set_block(ctx, i); return mmap_block_to_physical(ctx, i); } } diff --git a/multiboot.asm b/multiboot.asm index c5d9240..26cbf49 100644 --- a/multiboot.asm +++ b/multiboot.asm @@ -116,15 +116,45 @@ isr_stub_table: global ps2_isr ps2_isr: - cli extern ps2_handler pushad cld - and esp, 0xFFFFFFF0 call ps2_handler popad iret +global test +test: + push ebp + mov ebp, esp + + mov eax, 1 + mov edi, 0 + mov esi, buf + int 0x80 + jmp $ +buf: db "Hello from stdout!", 0 + +global syscall_isr +syscall_isr: + xchg bx, bx + pushad + mov ecx, esp + sysenter +after_syscall: + popad + iret + +global syscall +syscall: + imul eax, eax, 4 + add eax, syscall_table + pushad + call [eax] + popad + mov edx, after_syscall + sysexit + ; GDT for a flat memory layout ; We get access to all memory and can utilize paging global gdt @@ -167,6 +197,13 @@ gdtp: dw gdt_end - gdt - 1 dd gdt +global syscall_table +syscall_table: + extern syscall_read + dd syscall_read + + extern syscall_write + dd syscall_write ; Reserve 16KiB of kernel stack space section .bss diff --git a/ps2.c b/ps2.c index 2f0b990..0f67b43 100644 --- a/ps2.c +++ b/ps2.c @@ -5,6 +5,7 @@ #include #include #include +#include #define cpu_relax asm volatile ("pause" ::); @@ -54,6 +55,8 @@ void initialize_8042ps2() { outportb(PS2_8042_DATA, config); } +extern linked_mem_t stdin; + void ps2_handler() { uint8_t scancode = inportb(0x60); diff --git a/test.a b/test.a new file mode 100644 index 0000000..a0c3005 --- /dev/null +++ b/test.a @@ -0,0 +1,15 @@ +[org 0x6000] +[bits 32] +_start: + push ebp + mov ebp, esp + ; Syscall #1 = write + mov eax, 1 + ; File descriptor = stdout + mov edi, 0 + ; ESI = buffer + mov esi, buf + int 0x80 + jmp $ + +buf: db "Andew skibidi pomni", 0