diff --git a/Makefile b/Makefile index b3fc9e0..e17f7a8 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ ISO := Hazel.iso CFLAGS := -ffreestanding -Wall -Wextra -Werror -I $(INCLUDEDIR) -I lib LDFLAGS := -ffreestanding -nostdlib -lgcc -T kernel/kernel.ld -QEMUFLAGS := -cdrom $(BUILDDIR)/$(ISO) -s -m 512M -serial stdio +QEMUFLAGS := -cdrom $(BUILDDIR)/$(ISO) -s -m 512M -serial stdio -device virtio-gpu $(BUILDDIR)/$(KIMG): $(KOBJ) $(LOBJ) $(CC) $^ -o $@ $(LDFLAGS) diff --git a/boot/initrd b/boot/initrd index d3b310e..0430873 100755 Binary files a/boot/initrd and b/boot/initrd differ diff --git a/include/kernel/acpi.h b/include/kernel/acpi.h index 3e9ff66..ca2a150 100644 --- a/include/kernel/acpi.h +++ b/include/kernel/acpi.h @@ -111,8 +111,11 @@ typedef struct { struct GenericAddressStructure X_GPE1Block; } fadt_t; +typedef _Bool bool; + rsdp_t *acpi_find_rsdp(); uint8_t acpi_checksum(void *s, int size); void *acpi_find_sdt(rsdt_t *rsdt, const char *sig); +bool acpi_init(); #endif diff --git a/include/kernel/kernel.h b/include/kernel/kernel.h index e25809d..4ee59c4 100644 --- a/include/kernel/kernel.h +++ b/include/kernel/kernel.h @@ -4,11 +4,17 @@ #include #include #include +#include #define cpu_relax asm volatile ("pause" ::) #define CHECK_FLAG(x, n) (x & (1< + +typedef enum { + DEV_COM1, + DEV_VGA_TXT, +} dev_t; + +typedef struct { + dev_t dev; + + uint8_t *output; + uint8_t *input; + + uint32_t output_len; + uint32_t input_len; +} tty_t; + +#endif diff --git a/include/kernel/vga.h b/include/kernel/vga.h new file mode 100644 index 0000000..3de6cc6 --- /dev/null +++ b/include/kernel/vga.h @@ -0,0 +1,67 @@ +#ifndef HAZEL_VGA_H_ +#define HAZEL_VGA_H_ + + +#include + +/* + * Location of the linear text buffer + * Used to directly modify text on screen + * 80 columns by 25 rows + */ +#define VGA_MEMORY_ADDR 0xb8000 + +#define VGA_MAX_COLS 80 +#define VGA_MAX_ROWS 25 + +#define CRTC_ADDR_PORT 0x3d4 +#define CRTC_DATA_PORT 0x3d5 + +#define CRTC_CURSOR_LO_REGISTER 0x0f +#define CRTC_CURSOR_HI_REGISTER 0x0e + +enum VGA_COLOR { + VGA_COLOR_BLACK = 0, + VGA_COLOR_BLUE = 1, + VGA_COLOR_GREEN = 2, + VGA_COLOR_CYAN = 3, + VGA_COLOR_RED = 4, + VGA_COLOR_MAGENTA = 5, + VGA_COLOR_BROWN = 6, + VGA_COLOR_LIGHT_GREY = 7, + VGA_COLOR_DARK_GREY = 8, + VGA_COLOR_LIGHT_BLUE = 9, + VGA_COLOR_LIGHT_GREEN = 10, + VGA_COLOR_LIGHT_CYAN = 11, + VGA_COLOR_LIGHT_RED = 12, + VGA_COLOR_LIGHT_MAGENTA = 13, + VGA_COLOR_LIGHT_BROWN = 14, + VGA_COLOR_WHITE = 15 +}; + +/** + * @brief Gets the text-mode cursor's position. + * + * @return The position, not offset, of the cursor. Multiply this by two for the offset. + */ +uint16_t get_cursor_pos(); + + +/** + * @brief Sets the cursor's position in VGA text-mode. + * + * @param pos The position, not offset, of the cursor. Multiply by two for the offset. + */ +void set_cursor_pos(uint16_t pos); + +/** + * @brief Clears the screen in VGA text-mode by overwriting every character with a zero, then resets the cursor position. + */ +void clear_screen(void); + +void vga_putc(char c); +void popchar(); + +void set_color(enum VGA_COLOR col); + +#endif diff --git a/kernel/acpi.c b/kernel/acpi.c index 284a8da..31fe453 100644 --- a/kernel/acpi.c +++ b/kernel/acpi.c @@ -1,6 +1,8 @@ #include #include +extern kernel_ctx_t ctx; + rsdp_t *acpi_find_rsdp() { char *ptr = (char *)(KERNEL_VMA + BIOS_START); const char sig[RSDP_SIG_LEN] = RSDP_SIG; @@ -38,3 +40,38 @@ void *acpi_find_sdt(rsdt_t *rsdt, const char *sig) { return 0; } + +bool acpi_init() { + rsdp_t *rsdp = acpi_find_rsdp(); + if (!rsdp) { + LOG("Invalid RSDP\n"); + return FALSE; + } + if (!acpi_checksum(rsdp, sizeof(rsdp_t))) { + LOG("Invalid RSDP checksum\n"); + return FALSE; + } + + if (rsdp->Revision == 0) LOG("Using ACPI version 1.0\n") + else if (rsdp->Revision == 2) { + LOG("ACPI versions higher than 1.0 are not currently supported!\n"); + return FALSE; + } + + rsdt_t *rsdt = (rsdt_t *)(rsdp->RsdtAddress); + if (!rsdt) { + LOG("Invalid RSDT\n"); + return FALSE; + } + if (!acpi_checksum(rsdt, rsdt->hdr.Length)) { + LOG("Invalid RSDT checksum\n"); + return FALSE; + } + ctx.rsdt = rsdt; + LOG("RSDT is valid\n"); + + void *mcfg = acpi_find_sdt(rsdt, "MCFG"); + if (!mcfg) LOG("PCIe not supported\n"); + + return TRUE; +} diff --git a/kernel/init.asm b/kernel/init.asm index 34a17cf..6f9936c 100644 --- a/kernel/init.asm +++ b/kernel/init.asm @@ -280,11 +280,13 @@ boot_page_tab: times 1024 dd 0 extern syscall_read extern syscall_write extern syscall_reboot +extern syscall_uptime global syscall_table syscall_table: dd syscall_read dd syscall_write dd syscall_reboot + dd syscall_uptime section .bss align 16 diff --git a/kernel/kernel.c b/kernel/kernel.c index 91ce9c5..611c842 100644 --- a/kernel/kernel.c +++ b/kernel/kernel.c @@ -10,6 +10,7 @@ #include #include #include +#include #include kernel_ctx_t ctx = {0}; @@ -34,9 +35,12 @@ extern uint32_t boot_page_tab[1024]; void syscall_write(stack_frame_t r) { uint32_t fd = r.edi; uint8_t *buf = (uint8_t *)r.esi; + int len = r.edx; if (fd == FD_STDOUT) { - LOG("%s", buf); - } + for (int i = 0; i < len; i++) { + vga_putc(buf[i]); + } + } } void syscall_read(stack_frame_t r) { @@ -62,8 +66,10 @@ void syscall_reboot(stack_frame_t r) { } void syscall_uptime(stack_frame_t r) { - uint64_t *buf = (uint64_t *)r.esi; - *buf = ctx.ticks; + uint32_t *low = (uint32_t *)r.esi; + uint32_t *high = (uint32_t *)r.edi; + *low = (uint32_t)ctx.ticks; + *high = (uint32_t)(ctx.ticks >> 32); } void exception_handler(int_stack_frame_t r) { @@ -76,15 +82,20 @@ void exception_handler(int_stack_frame_t r) { if (r.int_no == 0xe) { uint32_t cr2 = 0; asm volatile ("mov %%cr2, %0" : "=r" (cr2)); + LOG("CR2: 0x%08X\n", cr2) - if ((boot_page_dir[PAGE_DIR_INDEX(cr2)] & 0xFFFFF000) == 0) { + uint32_t cr3 = 0; + asm volatile ("mov %%cr3, %0" : "=r" (cr3)); + uint32_t *page_dir = (uint32_t *)(KERNEL_VMA + cr3); + + if ((page_dir[PAGE_DIR_INDEX(cr2)] & 0xFFFFF000) == 0) { LOG("Creating new page table\n"); uint32_t *page_tab = mmap_find_first_free_block(); if (!page_tab) for (;;) {} page_tab[PAGE_TAB_INDEX(cr2)] = (cr2 & 0xFFFFF000) | 7; - boot_page_dir[PAGE_DIR_INDEX(cr2)] = ((uint32_t)page_tab - KERNEL_VMA) | 7; + page_dir[PAGE_DIR_INDEX(cr2)] = ((uint32_t)page_tab - KERNEL_VMA) | 7; } else { - uint32_t *page_tab = (uint32_t *)(KERNEL_VMA + (boot_page_dir[PAGE_DIR_INDEX(cr2)] & 0xFFFFF000)); + uint32_t *page_tab = (uint32_t *)(KERNEL_VMA + (page_dir[PAGE_DIR_INDEX(cr2)] & 0xFFFFF000)); page_tab[PAGE_TAB_INDEX(cr2)] = (cr2 & 0xFFFFF000) | 7; } } @@ -100,7 +111,7 @@ void idt_init(void) { for (int i = 0; i < 32; i++) { idt_encode_entry(idt, i, isr_stub_table[i], GDT_SEGMENT_SELECTOR(GDT_KERNEL_CODE, RING0), TRAP_GATE_32 | INT_RING0 | INT_PRESENT); } - idt_encode_entry(idt, 32, (uint32_t)pit_isr, GDT_SEGMENT_SELECTOR(GDT_KERNEL_CODE, RING0), TRAP_GATE_32 | INT_RING0 | INT_PRESENT); + idt_encode_entry(idt, 0x20, (uint32_t)pit_isr, GDT_SEGMENT_SELECTOR(GDT_KERNEL_CODE, RING0), TRAP_GATE_32 | INT_RING0 | INT_PRESENT); idt_encode_entry(idt, 0x21, (uint32_t)ps2_isr, GDT_SEGMENT_SELECTOR(GDT_KERNEL_CODE, RING0), TRAP_GATE_32 | INT_RING0 | INT_PRESENT); idt_encode_entry(idt, 0x80, (uint32_t)syscall_isr, GDT_SEGMENT_SELECTOR(GDT_USER_CODE, RING3), TRAP_GATE_32 | INT_RING3 | INT_PRESENT); @@ -110,10 +121,11 @@ void idt_init(void) { asm volatile ("lidt %0" :: "m"(idtr)); } + void kernel(multiboot_info_t *info) { if (!CHECK_FLAG(info->flags, 3)) goto halt; // Modules if (!CHECK_FLAG(info->flags, 6)) goto halt; // Memory map - if (!CHECK_FLAG(info->flags, 12)) goto halt; // VBE data + if (!CHECK_FLAG(info->flags, 12)) goto halt; // VBE data if (serial_port_init(COM1)) ctx.log_method = LOG_COM1; LOG("Kernel log being sent to COM1\n"); @@ -125,23 +137,8 @@ void kernel(multiboot_info_t *info) { if (!mmap_init()) goto halt; LOG("%d bytes of RAM detected\nCreated a %d byte large physical memory map at 0x%08X\n", ctx.mmap_size*BLOCK_SIZE*8, ctx.mmap_size, (uint32_t)ctx.mmap); - rsdp_t *rsdp = acpi_find_rsdp(); - if (!rsdp) goto halt; - if (!acpi_checksum(rsdp, sizeof(rsdp_t))) goto halt; - - if (rsdp->Revision == 0) LOG("Using ACPI version 1.0\n") - else if (rsdp->Revision == 2) { - LOG("ACPI versions higher than 1.0 are not currently supported!\n"); - goto halt; - } - - rsdt_t *rsdt = (rsdt_t *)(rsdp->RsdtAddress); - if (!rsdt) goto halt; - if (!acpi_checksum(rsdt, rsdt->hdr.Length)) goto halt; - LOG("RSDT is valid\n"); - - void *mcfg = acpi_find_sdt(rsdt, "MCFG"); - if (!mcfg) LOG("PCIe not supported\n"); + clear_screen(); + acpi_init(); for (int i = 0; i < 256; i++) { for (int j = 0; j < 32; j++) { @@ -150,7 +147,7 @@ void kernel(multiboot_info_t *info) { uint8_t class = (uint8_t)(w >> 8); uint8_t subclass = (uint8_t)w; if (class == 0xFF) continue; - LOG("Class: %04X | Subclass: %04X\n", class, subclass); + LOG("PCI Class: %04X | Subclass: %04X\n", class, subclass); } } } @@ -160,7 +157,7 @@ void kernel(multiboot_info_t *info) { asm volatile ("sti" ::); ctx.ticks = 0; pit_init(); - + // Setup TSS uint32_t base = (uint32_t)&tss; uint32_t limit = base + sizeof(tss_t); @@ -180,31 +177,6 @@ void kernel(multiboot_info_t *info) { tss.ss = tss.ds = tss.es = tss.fs = tss.gs = GDT_SEGMENT_SELECTOR(GDT_USER_DATA, RING3); flush_tss(GDT_SEGMENT_SELECTOR(5, RING3)); - /* - task_t task1 = {0}; - task_t task2 = {0}; - task1.cr3 = (uint32_t)boot_page_dir - KERNEL_VMA; - task1.next = (uint32_t *)&task2; - ctx.current_task = &task1; - - uint32_t *stack = mmap_find_first_free_block(); - asm volatile ("mov %%esp, %0" : "=r" (task1.esp)); - stack[1023] = 0x207; - stack[1022] = 0x8; - stack[1021] = (uint32_t)test; - stack[1020] = 0xDEADBEEF; - stack[1019] = 0xDEADBEEF; - stack[1018] = 0xDEADBEEF; - stack[1017] = 0xDEADBEEF; - stack[1016] = 0xDEADBEEF; - stack[1015] = 0xDEADBEEF; - stack[1014] = 0xDEADBEEF; - stack[1013] = 0xDEADBEEF; - task2.esp = (uint32_t)stack + (0x1000 - 44); - task2.cr3 = (uint32_t)boot_page_dir - KERNEL_VMA; - task2.next = 0; - */ - multi_mod_t *init = (multi_mod_t *)(info->moduleaddress + KERNEL_VMA); elf_t *elf = (elf_t *)(init->mod_start+KERNEL_VMA); task_t task = {0}; diff --git a/kernel/log.c b/kernel/log.c index a3ee681..0891458 100644 --- a/kernel/log.c +++ b/kernel/log.c @@ -1,6 +1,7 @@ #include #include #include +#include extern kernel_ctx_t ctx; diff --git a/kernel/ps2.c b/kernel/ps2.c index 8bcb2ac..535ed3d 100644 --- a/kernel/ps2.c +++ b/kernel/ps2.c @@ -2,6 +2,7 @@ #include #include #include +#include extern kernel_ctx_t ctx; char shell_buffer[512] = {0}; @@ -52,7 +53,11 @@ void ps2_init() { void push_stdin(const char c) { ctx.current_task->stdin[ctx.current_task->stdin_len++] = c; - _putchar(c); + vga_putc(c); +} + +void pop_stdin() { + ctx.current_task->stdin[--ctx.current_task->stdin_len] = 0; } void ps2_handler() { @@ -100,11 +105,10 @@ void ps2_handler() { push_stdin('='); break; case KBD_BACKSPACE: - /* - if (shell_index > 0) { - //popchar(); - shell_buffer[--shell_index] = 0; - }*/ + if (ctx.current_task->stdin_len > 0) { + popchar(); + pop_stdin(); + } break; case KBD_TAB: break; diff --git a/kernel/task.c b/kernel/task.c index 7a5f83b..b364bd3 100644 --- a/kernel/task.c +++ b/kernel/task.c @@ -10,23 +10,8 @@ int task_init(task_t *task, elf_t *elf) { if (!elf) return 0; uint8_t *s = (uint8_t *)mmap_find_first_free_block(); - /* - memset(s, 0, 0x1000); - int idx = 0; - // Loop section header to find ALLOC sections then allocate them - for (int i = 0; i < elf->e_shnum; i++) { - section_t *sec = (section_t *)((uint32_t)elf + elf->e_shoff + i*elf->e_shentsize); - if (!(sec->sh_flags & 0x2)) continue; - if (!sec->sh_addr) continue; - idx += sec->sh_offset; - memcpy(s + idx, (void *)((uint32_t)elf + sec->sh_offset), sec->sh_offset); - LOG("%d\n", sec->sh_offset); - } - */ memcpy(s, elf, 0x1000); - //section_t *text = elf_find_section(elf, ".text"); - //if (!text) return 0; task->eip = elf->e_entry; // Allocate a page for a stack task->esp = (uint32_t)mmap_find_first_free_block() + 0x1000; @@ -47,16 +32,7 @@ int task_init(task_t *task, elf_t *elf) { else page_dir[i] = 6; } // Map the ELF image to its specified entry - // This will cause problems if the ELF image is larger than 4 MiB so I need to fix this - //page_dir[PAGE_DIR_INDEX(elf->e_entry)] = ((uint32_t)page_tab - KERNEL_VMA) | 7; page_dir[PAGE_DIR_INDEX(elf->e_entry)] = ((uint32_t)page_tab - KERNEL_VMA) | 7; - - /* - uint32_t elf_phys = (uint32_t)s - KERNEL_VMA; - for (int i = 0; i < 1024; i++) { - page_tab[i] = (elf_phys + 0x1000*i) | 7; - } - */ page_tab[PAGE_TAB_INDEX(elf->e_entry)] = ((uint32_t)s - KERNEL_VMA) | 7; return 1; diff --git a/kernel/tty.c b/kernel/tty.c new file mode 100644 index 0000000..a0f841b --- /dev/null +++ b/kernel/tty.c @@ -0,0 +1,14 @@ +#include +#include + +void tty_putc(tty_t *tty, char c) { + switch (tty->dev) { + case DEV_COM1: + serial_putc(COM1, c); + break; + case DEV_VGA_TXT: + break; + default: + break; + } +} diff --git a/kernel/vga.c b/kernel/vga.c new file mode 100644 index 0000000..23a34d9 --- /dev/null +++ b/kernel/vga.c @@ -0,0 +1,98 @@ +/** + * @file vga.c + * @brief Basic functions for interacting with the CRTC controller in VGA text-mode. + * @author rami + * @version 0.1 + * @date 2024-02-03 + */ + +#include +#include +#include +#include + +enum VGA_COLOR vga_color = VGA_COLOR_WHITE; + +uint16_t get_cursor_pos() { + uint16_t pos = 0; + + /* Tell CRTC controller we want the low cursor position */ + outb(CRTC_ADDR_PORT, CRTC_CURSOR_LO_REGISTER); + /* Read it through the data port */ + pos = inb(CRTC_DATA_PORT); + + /* Repeat with high position */ + outb(CRTC_ADDR_PORT, CRTC_CURSOR_HI_REGISTER); + uint16_t hi_pos = 0; + hi_pos = inb(CRTC_DATA_PORT); + pos |= hi_pos << 8; + + return pos; +} + +void set_cursor_pos(uint16_t pos) { + /* Tell CRTC controller we want the low cursor position */ + outb(CRTC_ADDR_PORT, CRTC_CURSOR_LO_REGISTER); + outb(CRTC_DATA_PORT, (uint8_t)(pos & 0xFF)); + /* Repeat with high position */ + outb(CRTC_ADDR_PORT, CRTC_CURSOR_HI_REGISTER); + outb(CRTC_DATA_PORT, (uint8_t)((pos >> 8) & 0xFF)); +} + +void clear_screen(void) { + char *video_memory = (char *)VGA_MEMORY_ADDR; + for (int i = 0; i < VGA_MAX_COLS * VGA_MAX_ROWS; i++) { + video_memory[i * 2] = 0; + } + + set_cursor_pos(0); +} + +void vga_putc(char character) { + uint16_t pos = get_cursor_pos(); + + if (pos == VGA_MAX_COLS * VGA_MAX_ROWS) { + if (character != '\n') { + // Move video memory up one row + memcpy((char*)VGA_MEMORY_ADDR, (char *)(VGA_MEMORY_ADDR + VGA_MAX_COLS*2), VGA_MAX_COLS * (VGA_MAX_ROWS - 1) * 2); + // Clear last row + for (int i = 0; i < VGA_MAX_COLS*2; i+=2) { + ((char *)(VGA_MEMORY_ADDR + VGA_MAX_COLS*(VGA_MAX_ROWS - 1)*2))[i] = 0; + ((char *)(VGA_MEMORY_ADDR + VGA_MAX_COLS*(VGA_MAX_ROWS - 1)*2))[i+1] = 0x0f; + } + pos = VGA_MAX_COLS * (VGA_MAX_ROWS - 1); + } else { + // Move video memory up two rows + memcpy((char*)VGA_MEMORY_ADDR, (char *)(VGA_MEMORY_ADDR + VGA_MAX_COLS*2*2), VGA_MAX_COLS * (VGA_MAX_ROWS - 2) * 2); + // Clear last 2 rows + for (int i = 0; i < VGA_MAX_COLS*2*2; i+=2) { + ((char *)(VGA_MEMORY_ADDR + VGA_MAX_COLS*(VGA_MAX_ROWS - 2)*2))[i] = 0; + ((char *)(VGA_MEMORY_ADDR + VGA_MAX_COLS*(VGA_MAX_ROWS - 2)*2))[i+1] = 0x0f; + } + pos = VGA_MAX_COLS * (VGA_MAX_ROWS - 2); + } + } + + char *video_memory = (char *)VGA_MEMORY_ADDR + pos * 2; + + if (character == '\n') { + uint16_t next_line = VGA_MAX_COLS * (pos / VGA_MAX_COLS + 1); + set_cursor_pos(next_line); + } else { + video_memory[0] = character; + video_memory[1] = vga_color; + set_cursor_pos(pos + 1); + } +} + +void popchar() { + uint16_t pos = get_cursor_pos(); + if (pos == 0) return; + char *video_memory = (char *)(VGA_MEMORY_ADDR + (pos - 1) * 2); + video_memory[0] = 0; + set_cursor_pos(pos - 1); +} + +void set_color(enum VGA_COLOR col) { + vga_color = col; +} diff --git a/user/shell.c b/user/shell.c index 08d6b16..9ca0db6 100644 --- a/user/shell.c +++ b/user/shell.c @@ -1,14 +1,36 @@ #include "../lib/strcmp.h" +int strlen(const char *str) { + const char *s; + for (s = str; *s; s++) + ; + + return s - str; +} + +void putc(const char c) { + asm volatile ( + "movl $1, %%eax\n\t" + "movl $1, %%edi\n\t" + "movl %0, %%esi\n\t" + "movl $1, %%edx\n\t" + "int $0x80" + : + : "r"(&c) + : "%eax", "%edi", "%esi", "%edx" + ); +} + void puts(const char *str) { asm volatile ( "movl $1, %%eax\n\t" "movl $1, %%edi\n\t" "movl %0, %%esi\n\t" + "movl %1, %%edx\n\t" "int $0x80" : - : "r"(str) - : "%eax", "%edi", "%esi" + : "r"(str), "r"(strlen(str)) + : "%eax", "%edi", "%esi", "%edx" ); } @@ -32,18 +54,50 @@ void reboot() { ); } +uint64_t uptime() { + uint32_t low = 0; + uint32_t high = 0; + asm volatile ( + "movl $3, %%eax\n\t" + "movl %0, %%esi\n\t" + "movl %1, %%edi\n\t" + "int $0x80" + : + : "r" (&low), "r" (&high) + : "eax", "esi" + ); + + return (uint64_t)low | ((uint64_t)high << 32); +} + extern char *buf; +void print_int(int num){ + if (num < 0) + { + putc('-'); + num = -num; + } + + if (num > 9) print_int(num/10); + + putc(('0'+ (num%10))); + } + void _start() { char buf1[256] = {0}; puts("Welcome to the Hazel user shell!\n"); while (1) { - puts("> "); + puts("$ "); read(0, buf1, 256); if (!strcmp(buf1, "SKIBIDI")) { puts("dop dop yes yes!\n"); } else if (!strcmp(buf1, "REBOOT")) { reboot(); + } else if (!strcmp(buf1, "UPTIME")) { + uint64_t ticks = uptime(); + print_int(ticks); + puts("\n"); } else { puts("unknown command!\n");