major refactorings
Signed-off-by: kaguya3311 <kaguya3311@national.shitposting.agency>
This commit is contained in:
+102
-454
@@ -1,465 +1,113 @@
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <limine.h>
|
||||
#include "drivers/video/render.h"
|
||||
#include "drivers/video/tga.h"
|
||||
#include "libk/stdio.h"
|
||||
#include "arch/x86_64/boot/gdt.h"
|
||||
#include "arch/x86_64/boot/idt.h"
|
||||
#include "arch/x86_64/boot/isr.h"
|
||||
#include "arch/x86_64/sys/irq.h"
|
||||
#include "mm/memory.h"
|
||||
#include "mm/pmm.h"
|
||||
#include "mm/vmm.h"
|
||||
#include "arch/x86_64/bus/ata.h"
|
||||
#include "fs/ext2.h"
|
||||
#include "string.h"
|
||||
#include "arch/x86_64/cpu/io.h"
|
||||
#include "arch/x86_64/cpu/usermode.h"
|
||||
#include "syscall/syscall.h"
|
||||
#include "libk/debug.h"
|
||||
#include "fs/vfs.h"
|
||||
#include "arch/x86_64/sys/tsc.h"
|
||||
#include "arch/x86_64/sys/pit.h"
|
||||
#include <uacpi/uacpi.h>
|
||||
#include <uacpi/event.h>
|
||||
#include <uacpi/sleep.h>
|
||||
#include "arch/x86_64/bus/pci.h"
|
||||
#include "drivers/audio/hda.h"
|
||||
#include "drivers/audio/pcm.h"
|
||||
#include "drivers/input/input.h"
|
||||
#include "arch/x86_64/sys/apic.h"
|
||||
#include "arch/x86_64/sys/ioapic.h"
|
||||
#include "drivers/input/ps2.h"
|
||||
#include "sched/scheduler.h"
|
||||
#include "drivers/rand/random.h"
|
||||
#include "sched/sched_types.h"
|
||||
#include "sched/sched.h"
|
||||
#include "fs/tmpfs.h"
|
||||
#include "fs/devtmpfs.h"
|
||||
#include "libk/random.h"
|
||||
#include "fs/streams.h"
|
||||
#include "fs/partition.h"
|
||||
#include "drivers/fb/fb.h"
|
||||
#include "drivers/tty/console.h"
|
||||
#include "arch/x86_64/sys/timer.h"
|
||||
#include "libk/kargs.h"
|
||||
#include "fs/ramdisk.h"
|
||||
#include "sched/syscall.h"
|
||||
#include "mm/mmap.h"
|
||||
#include "drivers/tty/pty.h"
|
||||
#include "ipc/pipe.h"
|
||||
|
||||
|
||||
uintptr_t g_hhdm_offset;
|
||||
#define CPU_STACK_SIZE (64 * 1024)
|
||||
const char *module_list[] = {};
|
||||
|
||||
// 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.
|
||||
#define MODULE_LIST_SIZE (sizeof(module_list) / sizeof(module_list[0]))
|
||||
#define ONE_SECOND (uint64_t)(1000 * 1000 * 1000)
|
||||
|
||||
__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;
|
||||
|
||||
|
||||
uint8_t g_clean_fxstate[512] __attribute__((aligned(16)));
|
||||
|
||||
|
||||
// Halt and catch fire function.
|
||||
static void hcf(void) {
|
||||
for (;;) {
|
||||
asm volatile ("pause");
|
||||
}
|
||||
}
|
||||
|
||||
static inline void cpuid(uint32_t leaf, uint32_t subleaf,
|
||||
uint32_t *eax, uint32_t *ebx,
|
||||
uint32_t *ecx, uint32_t *edx) {
|
||||
asm volatile ("cpuid"
|
||||
: "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx)
|
||||
: "a"(leaf), "c"(subleaf));
|
||||
}
|
||||
|
||||
int cpu_has_leaf7() {
|
||||
uint32_t a, b, c, d;
|
||||
cpuid(0, 0, &a, &b, &c, &d);
|
||||
return a >= 7;
|
||||
}
|
||||
|
||||
int cpu_has_fsgsbase() {
|
||||
if (!cpu_has_leaf7())
|
||||
return 0;
|
||||
|
||||
uint32_t a, b, c, d;
|
||||
cpuid(7, 0, &a, &b, &c, &d);
|
||||
|
||||
return (b & (1u << 0)) != 0;
|
||||
}
|
||||
|
||||
static inline uint64_t read_cr4(void) {
|
||||
uint64_t val;
|
||||
__asm__ volatile ("mov %%cr4, %0" : "=r"(val));
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
static inline void write_cr4(uint64_t val) {
|
||||
asm volatile ("mov %0, %%cr4" :: "r"(val));
|
||||
}
|
||||
|
||||
static inline uint64_t read_cr0(void) {
|
||||
uint64_t val;
|
||||
__asm__ volatile ("mov %%cr0, %0" : "=r"(val));
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void write_cr0(uint64_t val) {
|
||||
__asm__ volatile ("mov %0, %%cr0" :: "r"(val));
|
||||
}
|
||||
|
||||
|
||||
#define CR4_FSGSBASE (1ULL << 16)
|
||||
|
||||
|
||||
|
||||
void enable_fsgsbase_if_supported() {
|
||||
if (!cpu_has_fsgsbase()) {
|
||||
// fallback: don't use wrfsbase
|
||||
printf("FSGSBASE not supported, skipping wrfsbase/wrgsbase\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t cr4 = read_cr4();
|
||||
cr4 |= CR4_FSGSBASE;
|
||||
write_cr4(cr4);
|
||||
}
|
||||
|
||||
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 init_simd(void) {
|
||||
uint64_t cr0 = read_cr0();
|
||||
uint64_t cr4 = read_cr4();
|
||||
|
||||
// --- CR0 setup ---
|
||||
cr0 &= ~(1 << 2); // Clear EM (Emulation) → allow FPU/SSE
|
||||
cr0 |= (1 << 1); // Set MP (Monitor Coprocessor)
|
||||
cr0 &= ~(1 << 3); // Clear TS (Task Switched) → no #NM
|
||||
|
||||
// --- CR4 setup ---
|
||||
cr4 |= (1 << 9); // OSFXSR → enable FXSAVE/FXRSTOR + SSE
|
||||
cr4 |= (1 << 10); // OSXMMEXCPT → enable SSE exceptions
|
||||
|
||||
write_cr0(cr0);
|
||||
write_cr4(cr4);
|
||||
|
||||
// Initialize FPU/SSE state
|
||||
__asm__ volatile ("fninit");
|
||||
|
||||
__asm__ volatile ("fxsave %0" : "=m"(g_clean_fxstate));
|
||||
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
random_init();
|
||||
|
||||
gdt_load_tss((size_t)&kernel_tss);
|
||||
kernel_tss.rsp0 = rsp;
|
||||
|
||||
|
||||
syscall_init();
|
||||
enable_fsgsbase_if_supported();
|
||||
init_simd();
|
||||
|
||||
sched_init();
|
||||
|
||||
|
||||
|
||||
start_userspace();
|
||||
|
||||
sched_yield();
|
||||
|
||||
|
||||
for (;;) {
|
||||
sched_yield();
|
||||
}
|
||||
|
||||
// We're done, just hang...
|
||||
//hcf();
|
||||
}
|
||||
|
||||
void kernel_main(void *args) {
|
||||
vfs_init();
|
||||
tmpfs_init();
|
||||
devtmpfs_init();
|
||||
vfs_mount(vfs_root, NULL, "/", "tmpfs");
|
||||
vfs_create(vfs_root, "/tmp", 0755 | S_IFDIR);
|
||||
vfs_mount(vfs_root, NULL, "/tmp", "tmpfs");
|
||||
vfs_create(vfs_root, "/dev", 0755 | S_IFDIR);
|
||||
vfs_mount(vfs_root, NULL, "/dev", "devtmpfs");
|
||||
streams_init();
|
||||
randdev_init();
|
||||
|
||||
kprintf("Hello I am %s\n", sched_get_running_thread()->mother_proc->name);
|
||||
|
||||
if (args != NULL) {
|
||||
uint64_t *module_info = (uint64_t *)args;
|
||||
kprintf("Ramdisk located at %p\n", module_info[0]);
|
||||
ramdisk_install(module_info[0], module_info[1]);
|
||||
}
|
||||
|
||||
partition_enumerate(NULL, NULL);
|
||||
|
||||
fbdev_init();
|
||||
|
||||
|
||||
|
||||
syscall_register_handler(0x0, syscall_read);
|
||||
syscall_register_handler(0x1, syscall_write);
|
||||
syscall_register_handler(0x2, syscall_open);
|
||||
syscall_register_handler(0x3, syscall_close);
|
||||
syscall_register_handler(0x8, syscall_seek);
|
||||
syscall_register_handler(0x9, syscall_mmap);
|
||||
syscall_register_handler(0xa, syscall_mprotect);
|
||||
syscall_register_handler(0xb, syscall_munmap);
|
||||
syscall_register_handler(0x10, syscall_ioctl);
|
||||
syscall_register_handler(0x48, syscall_fcntl);
|
||||
syscall_register_handler(0x4f, syscall_getcwd);
|
||||
syscall_register_handler(0x50, syscall_chdir);
|
||||
syscall_register_handler(0x59, syscall_readdir);
|
||||
syscall_register_handler(0x101, syscall_openat);
|
||||
syscall_register_handler(0x102, syscall_mkdirat);
|
||||
syscall_register_handler(0x103, syscall_mknodat);
|
||||
syscall_register_handler(0x106, syscall_fstatat);
|
||||
syscall_register_handler(0x107, syscall_unlinkat);
|
||||
syscall_register_handler(0x109, syscall_linkat);
|
||||
syscall_register_handler(0x10b, syscall_readlinkat);
|
||||
syscall_register_handler(0x10c, syscall_fchmodat);
|
||||
syscall_register_handler(0x124, syscall_dup3);
|
||||
syscall_register_handler(0x125, syscall_pipe);
|
||||
syscall_register_handler(0xff, syscall_openpty);
|
||||
syscall_register_handler(0x10f, syscall_ppoll);
|
||||
syscall_register_handler(0x54, syscall_rmdir);
|
||||
|
||||
kprintf("Halting for 5 seconds...");
|
||||
timer_sleep(5000);
|
||||
|
||||
console_init();
|
||||
|
||||
std_console_device = (vfs_get_node(vfs_root, "/dev/console", true))->resource;
|
||||
|
||||
char *argv[] = {"init", NULL};
|
||||
char* envp[] = {
|
||||
"HOME=/",
|
||||
"TERM=linux",
|
||||
NULL,
|
||||
};
|
||||
|
||||
char *init_path = "/bin/oksh";
|
||||
if (kernel_arguments.kernel_args & KERNEL_ARGS_INIT_PATH_GIVEN) {
|
||||
init_path = kernel_arguments.init_binary_path;
|
||||
}
|
||||
|
||||
kprintf("Running init binary %s\n", init_path);
|
||||
|
||||
if (!process_run_init(init_path, argv, envp, sched_get_running_thread()->mother_proc)) {
|
||||
panic("Failed to run the init binary o algo\n");
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
sched_yield(true);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user