From e7a8d39ad71623d4e36454c5822cfe573570df23 Mon Sep 17 00:00:00 2001 From: 0x35c Date: Wed, 11 Sep 2024 16:46:39 +0200 Subject: [PATCH] reboot is done --- src/gdt/gdt.c | 71 +++++++++++++++++++++++++++++++++++++--------- src/shell/exec.c | 3 +- src/shell/reboot.c | 32 +++++++++++++++++++++ 3 files changed, 91 insertions(+), 15 deletions(-) diff --git a/src/gdt/gdt.c b/src/gdt/gdt.c index 9268238..72d256c 100644 --- a/src/gdt/gdt.c +++ b/src/gdt/gdt.c @@ -2,17 +2,18 @@ #include "gdt.h" #include "kprintf.h" -#include "string.h" extern void set_gdt(uint32_t gdt_ptr); uint8_t gdt_entries[GDT_SIZE * 8]; -struct gdt_descriptor *gdtr = (struct gdt_descriptor *) GDT_ADDRESS; +struct gdt_descriptor *gdtr = (struct gdt_descriptor *)GDT_ADDRESS; -static void set_gdt_entry_value(uint8_t *target, uint32_t base, uint32_t limit, uint8_t access, uint8_t granularity) +static void set_gdt_entry_value(uint8_t *target, uint32_t base, uint32_t limit, + uint8_t access, uint8_t granularity) { if (limit > 0xFFFFF) { - kprintf(KERN_ERR, "GDT cannot encode limits larger than 0xFFFFF"); + kprintf(KERN_ERR, + "GDT cannot encode limits larger than 0xFFFFF"); } // Encode the limit @@ -33,20 +34,62 @@ static void set_gdt_entry_value(uint8_t *target, uint32_t base, uint32_t limit, target[6] |= (granularity << 4); } -void initGdt() +void initGdt(void) { gdtr->size = 8 * GDT_SIZE - 1; - gdtr->base = (uint32_t) &gdt_entries; + gdtr->base = (uint32_t)&gdt_entries; - set_gdt_entry_value(gdt_entries + 0x00, 0, 0, 0, 0); // Null segment + set_gdt_entry_value(gdt_entries + 0x00, 0, 0, 0, 0); // Null segment - set_gdt_entry_value(gdt_entries + 0x08, 0, 0xFFFFF, GDT_ACCESS_P_VALID | GDT_ACCESS_DPL_KERNEL_MODE | GDT_ACCESS_S_CODE_OR_DATA | GDT_ACCESS_E_EXECUTABLE | GDT_ACCESS_DC_NOT_CONFORM | GDT_ACCESS_RW_READABLE_FOR_CODE_WRITABLE_FOR_DATA | GDT_ACCESS_A_ACCESSED, GDT_FLAG_32BIT_MODE | GDT_FLAG_PAGE_MODE); // Kernel code - set_gdt_entry_value(gdt_entries + 0x10, 0, 0xFFFFF, GDT_ACCESS_P_VALID | GDT_ACCESS_DPL_KERNEL_MODE | GDT_ACCESS_S_CODE_OR_DATA | GDT_ACCESS_E_NOT_EXECUTABLE | GDT_ACCESS_DC_NOT_CONFORM | GDT_ACCESS_RW_READABLE_FOR_CODE_WRITABLE_FOR_DATA | GDT_ACCESS_A_ACCESSED, GDT_FLAG_32BIT_MODE | GDT_FLAG_PAGE_MODE); // Kernel data - set_gdt_entry_value(gdt_entries + 0x18, 0, 0x0, GDT_ACCESS_P_VALID | GDT_ACCESS_DPL_KERNEL_MODE | GDT_ACCESS_S_CODE_OR_DATA | GDT_ACCESS_E_NOT_EXECUTABLE | GDT_ACCESS_DC_CONFORM |GDT_ACCESS_RW_READABLE_FOR_CODE_WRITABLE_FOR_DATA | GDT_ACCESS_A_ACCESSED, GDT_FLAG_32BIT_MODE | GDT_FLAG_PAGE_MODE); // Kernel stack + set_gdt_entry_value( + gdt_entries + 0x08, 0, 0xFFFFF, + GDT_ACCESS_P_VALID | GDT_ACCESS_DPL_KERNEL_MODE | + GDT_ACCESS_S_CODE_OR_DATA | GDT_ACCESS_E_EXECUTABLE | + GDT_ACCESS_DC_NOT_CONFORM | + GDT_ACCESS_RW_READABLE_FOR_CODE_WRITABLE_FOR_DATA | + GDT_ACCESS_A_ACCESSED, + GDT_FLAG_32BIT_MODE | GDT_FLAG_PAGE_MODE); // Kernel code + set_gdt_entry_value( + gdt_entries + 0x10, 0, 0xFFFFF, + GDT_ACCESS_P_VALID | GDT_ACCESS_DPL_KERNEL_MODE | + GDT_ACCESS_S_CODE_OR_DATA | GDT_ACCESS_E_NOT_EXECUTABLE | + GDT_ACCESS_DC_NOT_CONFORM | + GDT_ACCESS_RW_READABLE_FOR_CODE_WRITABLE_FOR_DATA | + GDT_ACCESS_A_ACCESSED, + GDT_FLAG_32BIT_MODE | GDT_FLAG_PAGE_MODE); // Kernel data + set_gdt_entry_value( + gdt_entries + 0x18, 0, 0x0, + GDT_ACCESS_P_VALID | GDT_ACCESS_DPL_KERNEL_MODE | + GDT_ACCESS_S_CODE_OR_DATA | GDT_ACCESS_E_NOT_EXECUTABLE | + GDT_ACCESS_DC_CONFORM | + GDT_ACCESS_RW_READABLE_FOR_CODE_WRITABLE_FOR_DATA | + GDT_ACCESS_A_ACCESSED, + GDT_FLAG_32BIT_MODE | GDT_FLAG_PAGE_MODE); // Kernel stack - set_gdt_entry_value(gdt_entries + 0x20, 0, 0xFFFFF, GDT_ACCESS_P_VALID | GDT_ACCESS_DPL_USER_MODE | GDT_ACCESS_S_CODE_OR_DATA | GDT_ACCESS_E_EXECUTABLE | GDT_ACCESS_DC_CONFORM | GDT_ACCESS_RW_READABLE_FOR_CODE_WRITABLE_FOR_DATA | GDT_ACCESS_A_ACCESSED, GDT_FLAG_32BIT_MODE | GDT_FLAG_PAGE_MODE); // User code - set_gdt_entry_value(gdt_entries + 0x28, 0, 0xFFFFF, GDT_ACCESS_P_VALID | GDT_ACCESS_DPL_USER_MODE | GDT_ACCESS_S_CODE_OR_DATA | GDT_ACCESS_E_NOT_EXECUTABLE | GDT_ACCESS_DC_NOT_CONFORM | GDT_ACCESS_RW_READABLE_FOR_CODE_WRITABLE_FOR_DATA | GDT_ACCESS_A_ACCESSED, GDT_FLAG_32BIT_MODE | GDT_FLAG_PAGE_MODE); // User data - set_gdt_entry_value(gdt_entries + 0x30, 0, 0xFFFFF, GDT_ACCESS_P_VALID | GDT_ACCESS_DPL_USER_MODE | GDT_ACCESS_S_CODE_OR_DATA | GDT_ACCESS_E_NOT_EXECUTABLE | GDT_ACCESS_DC_CONFORM | GDT_ACCESS_RW_READABLE_FOR_CODE_WRITABLE_FOR_DATA | GDT_ACCESS_A_ACCESSED, GDT_FLAG_32BIT_MODE | GDT_FLAG_PAGE_MODE); // User stack + set_gdt_entry_value( + gdt_entries + 0x20, 0, 0xFFFFF, + GDT_ACCESS_P_VALID | GDT_ACCESS_DPL_USER_MODE | + GDT_ACCESS_S_CODE_OR_DATA | GDT_ACCESS_E_EXECUTABLE | + GDT_ACCESS_DC_CONFORM | + GDT_ACCESS_RW_READABLE_FOR_CODE_WRITABLE_FOR_DATA | + GDT_ACCESS_A_ACCESSED, + GDT_FLAG_32BIT_MODE | GDT_FLAG_PAGE_MODE); // User code + set_gdt_entry_value( + gdt_entries + 0x28, 0, 0xFFFFF, + GDT_ACCESS_P_VALID | GDT_ACCESS_DPL_USER_MODE | + GDT_ACCESS_S_CODE_OR_DATA | GDT_ACCESS_E_NOT_EXECUTABLE | + GDT_ACCESS_DC_NOT_CONFORM | + GDT_ACCESS_RW_READABLE_FOR_CODE_WRITABLE_FOR_DATA | + GDT_ACCESS_A_ACCESSED, + GDT_FLAG_32BIT_MODE | GDT_FLAG_PAGE_MODE); // User data + set_gdt_entry_value( + gdt_entries + 0x30, 0, 0xFFFFF, + GDT_ACCESS_P_VALID | GDT_ACCESS_DPL_USER_MODE | + GDT_ACCESS_S_CODE_OR_DATA | GDT_ACCESS_E_NOT_EXECUTABLE | + GDT_ACCESS_DC_CONFORM | + GDT_ACCESS_RW_READABLE_FOR_CODE_WRITABLE_FOR_DATA | + GDT_ACCESS_A_ACCESSED, + GDT_FLAG_32BIT_MODE | GDT_FLAG_PAGE_MODE); // User stack - set_gdt(((uint32_t) gdtr)); + set_gdt(((uint32_t)gdtr)); } diff --git a/src/shell/exec.c b/src/shell/exec.c index e969761..5f891f7 100644 --- a/src/shell/exec.c +++ b/src/shell/exec.c @@ -85,7 +85,8 @@ void shell_init(void) "poweroff, echo, color, merdella\n"); break; case REBOOT: - kprintf(0, "rebooting\n"); + kprintf(0, "rebooting...\n"); + reboot(); break; case POWEROFF: kprintf(0, "powering off\n"); diff --git a/src/shell/reboot.c b/src/shell/reboot.c index e69de29..d97b836 100644 --- a/src/shell/reboot.c +++ b/src/shell/reboot.c @@ -0,0 +1,32 @@ +#include "sys/io.h" +#include + +#define KBD_INTERFACE 0x64 + +/* keyboard interface bits */ +#define KBD_BIT_KDATA 0 /* keyboard data */ +#define KBD_BIT_UDATA 1 /* user data */ + +#define KBD_IO 0x60 /* keyboard IO port */ +#define KBD_RESET 0xFE /* reset CPU command */ + +#define bit(n) (1 << (n)) /* Set bit n to 1 */ + +/* Check if bit n in flags is set */ +#define check_flag(flags, n) ((flags) & bit(n)) + +void reboot(void) +{ + uint8_t tmp; + + asm volatile("cli"); /* disable all interrupts */ + do { + tmp = inb(KBD_INTERFACE); /* empty user data */ + if (check_flag(tmp, KBD_BIT_KDATA)) + inb(KBD_IO); /* empty keyboard data */ + } while (check_flag(tmp, KBD_BIT_UDATA)); + outb(KBD_INTERFACE, KBD_RESET); /* pulse CPU reset line */ +loop: + asm volatile("hlt"); /* if that didn't work, halt the CPU */ + goto loop; /* if a NMI is received, halt again */ +}