#include #include #include #include #include "video/render.h" #include "video/tga.h" #include "stdio.h" #include "arch/x86_64/gdt.h" #include "arch/x86_64/idt.h" #include "arch/x86_64/isr.h" #include "arch/x86_64/irq.h" #include "mm/memory.h" #include "mm/pmm.h" #include "mm/vmm.h" #include "arch/x86_64/ata.h" #include "fs/ext2.h" #include "string.h" #include "arch/x86_64/io.h" #include "arch/x86_64/usermode.h" #include "syscall/syscall.h" #include "fs/vfs.h" #include "time/time.h" #include "arch/x86_64/pit.h" #include #include #include #include "arch/x86_64/pci.h" #include "sound/hda.h" #include "sound/pcm.h" #include "input/input.h" #include "arch/x86_64/apic.h" #include "arch/x86_64/ioapic.h" #include "input/ps2.h" uintptr_t g_hhdm_offset; #define CPU_STACK_SIZE (64 * 1024) // Set the base revision to 6, this is recommended as this is the latest // base revision described by the Limine boot protocol specification. // See specification for further info. __attribute__((used, section(".limine_requests"))) static volatile uint64_t limine_base_revision[] = LIMINE_BASE_REVISION(6); // The Limine requests can be placed anywhere, but it is important that // the compiler does not optimise them away, so, usually, they should // be made volatile or equivalent, _and_ they should be accessed at least // once or marked as used with the "used" attribute as done here. __attribute__((used, section(".limine_requests"))) static volatile struct limine_framebuffer_request framebuffer_request = { .id = LIMINE_FRAMEBUFFER_REQUEST_ID, .revision = 6 }; __attribute__((used, section(".limine_requests"))) static volatile struct limine_memmap_request memmap_request = { .id = LIMINE_MEMMAP_REQUEST_ID, .revision = 6 }; __attribute__((used, section(".limine_requests"))) static volatile struct limine_rsdp_request rsdp_request = { .id = LIMINE_RSDP_REQUEST_ID, .revision = 6 }; __attribute__((used, section(".limine_requests"))) volatile struct limine_stack_size_request stack_size_request = { .id = LIMINE_STACK_SIZE_REQUEST_ID, .revision = 0, .stack_size = CPU_STACK_SIZE, }; // Finally, define the start and end markers for the Limine requests. // These can also be moved anywhere, to any .c file, as seen fit. __attribute__((used, section(".limine_requests_start"))) static volatile uint64_t limine_requests_start_marker[] = LIMINE_REQUESTS_START_MARKER; __attribute__((used, section(".limine_requests_end"))) static volatile uint64_t limine_requests_end_marker[] = LIMINE_REQUESTS_END_MARKER; // Halt and catch fire function. static void hcf(void) { for (;;) { asm volatile ("pause"); } } extern struct kernel_pagemap; uint64_t g_rsdp_phys; void shutdown(void) { uacpi_status ret2 = uacpi_prepare_for_sleep_state(UACPI_SLEEP_STATE_S5); if (uacpi_unlikely_error(ret2)) { printf("failed to prepare for sleep: %s", uacpi_status_to_string(ret2)); } ret2 = uacpi_enter_sleep_state(UACPI_SLEEP_STATE_S5); if (uacpi_unlikely_error(ret2)) { printf("failed to enter sleep: %s", uacpi_status_to_string(ret2)); } } static uacpi_interrupt_ret handle_power_button(uacpi_handle ctx) { /* * Shut down right here using the helper we have defined above. * * Note that it's generally terrible practice to run any AML from * an interrupt handler, as it's allowed to allocate, map, sleep, * stall, acquire mutexes, etc. So, if possible in your kernel, * instead schedule the shutdown callback to be run in a normal * preemptible context later. */ shutdown(); return UACPI_INTERRUPT_HANDLED; } void kmain(void) { if (LIMINE_BASE_REVISION_SUPPORTED(limine_base_revision) == false) { hcf(); } uint64_t rsp; asm volatile("mov %%rsp, %0" : "=r"(rsp)); // Ensure we got a framebuffer. if (framebuffer_request.response == NULL || framebuffer_request.response->framebuffer_count < 1) { hcf(); } // Fetch the first framebuffer. struct limine_framebuffer *framebuffer = framebuffer_request.response->framebuffers[0]; struct limine_memmap_response *memmap_response = memmap_request.response; struct limine_rsdp_response *rsdp_response = rsdp_request.response; g_rsdp_phys = (uint64_t)rsdp_response->address - MEM_PHYS_OFFSET; if (!memmap_response) { hcf(); } fb = framebuffer->address; fb_width = framebuffer->width; fb_height = framebuffer->height; fb_pitch = framebuffer->pitch / 4; printf("Hello, Kernel!\n"); printf("Number: %d\n", 1234); printf("Hex: %x\n", 0xBEEF); for (size_t i = 0; i < memmap_response->entry_count; i++) { struct limine_memmap_entry *entry = memmap_response->entries[i]; printf("Base: 0x%x%x, Length: 0x%x%x, Type: %d\n", (uint32_t)(entry->base >> 32), (uint32_t)entry->base, (uint32_t)(entry->length >> 32), (uint32_t)entry->length, entry->type); } x86_64_DisableInterrupts(); uint32_t msr_lo, msr_hi; asm volatile("rdmsr" : "=a"(msr_lo), "=d"(msr_hi) : "c"(0x1B)); msr_lo &= ~(1 << 11); asm volatile("wrmsr" : : "a"(msr_lo), "d"(msr_hi), "c"(0x1B)); printf("rsdp: 0x%x\n", g_rsdp_phys); printf("init pmm\n"); pmm_init(memmap_response->entries, memmap_response->entry_count); printf("init slab\n"); slab_init(); printf("init vmm\n"); vmm_init(memmap_response->entries, memmap_response->entry_count); printf("init gdt"); x86_64_GDT_Initialize(); x86_64_IDT_Initialize(); x86_64_ISR_Initialize(); x86_64_IRQ_Initialize(); x86_64_PIT_Initialize(1000); asm volatile("sti"); calibrate_tsc(); //while (1) asm volatile("hlt"); ata_init(); ata_identify(); if (!ext2_read_superblock()) { printf("EXT2 failed\n"); hcf(); } if (!ext2_read_group_desc_table()) { printf("GDT failed\n"); hcf(); } ext2_read_root_dir(); uint32_t inum = ext2_resolve_path("charlie.tga"); if (!inum) { printf("file not found\n"); hcf(); } ext2_inode_t inode; if (!ext2_read_inode(inum, &inode)) { printf("inode read failed\n"); hcf(); } uint32_t tga_size = inode.i_size; if (!tga_size) { printf("tga file is empty\n"); hcf(); } uint8_t *file_buf = kmalloc(tga_size); if (!file_buf) { printf("OOM allocating tga buffer (%u bytes)\n", tga_size); hcf(); } if (!ext2_read_file(&inode, file_buf)) { printf("read failed\n"); kfree(file_buf); hcf(); } uint32_t *img = tga_parse(file_buf, tga_size); kfree(file_buf); // free the raw file buffer as soon as parse is done if (!img) { printf("tga parse failed\n"); hcf(); } int x = 0; int y = 0; int new_w = img[0] * 5; int new_h = img[1] * 5; clear_screen(0xFF1E1E1E); draw_image_bilinear(img, x, y, new_w, new_h); kfree(img); //clear_screen(0xFF1E1E1E); printf("\nKirkOS %s\n", KIRKOS_VERSION); x86_64_EnableInterrupts(); /* * Start with this as the first step of the initialization. This loads all * tables, brings the event subsystem online, and enters ACPI mode. We pass * in 0 as the flags as we don't want to override any default behavior for now. */ uacpi_status ret = uacpi_initialize(0); if (uacpi_unlikely_error(ret)) { printf("uacpi_initialize error: %s", uacpi_status_to_string(ret)); } /* * Load the AML namespace. This feeds DSDT and all SSDTs to the interpreter * for execution. */ ret = uacpi_namespace_load(); if (uacpi_unlikely_error(ret)) { printf("uacpi_namespace_load error: %s", uacpi_status_to_string(ret)); } /* * Initialize the namespace. This calls all necessary _STA/_INI AML methods, * as well as _REG for registered operation region handlers. */ ret = uacpi_namespace_initialize(); if (uacpi_unlikely_error(ret)) { printf("uacpi_namespace_initialize error: %s", uacpi_status_to_string(ret)); } /* * Tell uACPI that we have marked all GPEs we wanted for wake (even though we haven't * actually marked any, as we have no power management support right now). This is * needed to let uACPI enable all unmarked GPEs that have a corresponding AML handler. * These handlers are used by the firmware to dynamically execute AML code at runtime * to e.g. react to thermal events or device hotplug. */ ret = uacpi_finalize_gpe_initialization(); if (uacpi_unlikely_error(ret)) { printf("uACPI GPE initialization error: %s", uacpi_status_to_string(ret)); } /*pci_init(); pci_device_t hda; if (pci_find_hda(&hda)) { printf("[PCI] Found HDA controller at %02x:%02x.%x %04x:%04x\n", hda.addr.bus, hda.addr.device, hda.addr.function, hda.vendor_id, hda.device_id); if (hda_init(&hda)) { pcm_play_file("kirky.wav"); } } else { printf("[PCI] No HDA controller found!\n"); }*/ lapic_init(); ioapic_init(); irq_redirect_to_apic(0, 0x20, lapic_id(), false); printf("tst"); input_init(); ps2_kbd_init(); gdt_load_tss((size_t)&kernel_tss); kernel_tss.rsp0 = rsp; syscall_init(); start_userspace(); // We're done, just hang... hcf(); }