/* This file is part of Fennix Kernel. Fennix Kernel is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Fennix Kernel is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Fennix Kernel. If not, see . */ #include #include #include #include #include "../../../../../tools/limine/limine.h" #include "../../../../kernel.h" void InitLimine(); static volatile struct limine_entry_point_request EntryPointRequest = { .id = LIMINE_ENTRY_POINT_REQUEST, .revision = 0, .response = NULL, .entry = InitLimine}; static volatile struct limine_bootloader_info_request BootloaderInfoRequest = { .id = LIMINE_BOOTLOADER_INFO_REQUEST, .revision = 0}; static volatile struct limine_framebuffer_request FramebufferRequest = { .id = LIMINE_FRAMEBUFFER_REQUEST, .revision = 0}; static volatile struct limine_memmap_request MemmapRequest = { .id = LIMINE_MEMMAP_REQUEST, .revision = 0}; static volatile struct limine_kernel_address_request KernelAddressRequest = { .id = LIMINE_KERNEL_ADDRESS_REQUEST, .revision = 0}; static volatile struct limine_rsdp_request RsdpRequest = { .id = LIMINE_RSDP_REQUEST, .revision = 0}; static volatile struct limine_kernel_file_request KernelFileRequest = { .id = LIMINE_KERNEL_FILE_REQUEST, .revision = 0}; static volatile struct limine_module_request ModuleRequest = { .id = LIMINE_MODULE_REQUEST, .revision = 0}; static volatile struct limine_smbios_request SmbiosRequest = { .id = LIMINE_SMBIOS_REQUEST, .revision = 0}; void *TempStackPtr = NULL; __naked __used __no_stack_protector void InitLimine() { asmv("mov %%rsp, %0" : "=r"(TempStackPtr)); asmv("mov %0, %%rsp" : : "r"((uintptr_t)TempStackPtr - 0xFFFF800000000000)); asmv("mov $0, %rax\n" "mov $0, %rbx\n" "mov $0, %rcx\n" "mov $0, %rdx\n" "mov $0, %rsi\n" "mov $0, %rdi\n" "mov $0, %rbp\n" "mov $0, %r8\n" "mov $0, %r9\n" "mov $0, %r10\n" "mov $0, %r11\n" "mov $0, %r12\n" "mov $0, %r13\n" "mov $0, %r14\n" "mov $0, %r15"); asmv("jmp InitLimineAfterStack"); } nsa NIF void InitLimineAfterStack() { struct BootInfo binfo = {}; struct limine_bootloader_info_response *BootloaderInfoResponse = BootloaderInfoRequest.response; info("Bootloader: %s %s", BootloaderInfoResponse->name, BootloaderInfoResponse->version); struct limine_framebuffer_response *FrameBufferResponse = FramebufferRequest.response; struct limine_memmap_response *MemmapResponse = MemmapRequest.response; struct limine_kernel_address_response *KernelAddressResponse = KernelAddressRequest.response; struct limine_rsdp_response *RsdpResponse = RsdpRequest.response; struct limine_kernel_file_response *KernelFileResponse = KernelFileRequest.response; struct limine_module_response *ModuleResponse = ModuleRequest.response; struct limine_smbios_response *SmbiosResponse = SmbiosRequest.response; if (FrameBufferResponse == NULL || FrameBufferResponse->framebuffer_count < 1) { error("No framebuffer available [%#lx;%ld]", FrameBufferResponse, (FrameBufferResponse == NULL) ? 0 : FrameBufferResponse->framebuffer_count); inf_loop asmv("hlt"); } if (MemmapResponse == NULL || MemmapResponse->entry_count < 1) { error("No memory map available [%#lx;%ld]", MemmapResponse, (MemmapResponse == NULL) ? 0 : MemmapResponse->entry_count); inf_loop asmv("hlt"); } if (KernelAddressResponse == NULL) { error("No kernel address available [%#lx]", KernelAddressResponse); inf_loop asmv("hlt"); } if (RsdpResponse == NULL || RsdpResponse->address == 0) { error("No RSDP address available [%#lx;%#lx]", RsdpResponse, (RsdpResponse == NULL) ? 0 : RsdpResponse->address); inf_loop asmv("hlt"); } if (KernelFileResponse == NULL || KernelFileResponse->kernel_file == NULL) { error("No kernel file available [%#lx;%#lx]", KernelFileResponse, (KernelFileResponse == NULL) ? 0 : KernelFileResponse->kernel_file); inf_loop asmv("hlt"); } /* Actual parsing starts here */ for (uint64_t i = 0; i < FrameBufferResponse->framebuffer_count; i++) { struct limine_framebuffer *framebuffer = FrameBufferResponse->framebuffers[i]; switch (framebuffer->memory_model) { case LIMINE_FRAMEBUFFER_RGB: binfo.Framebuffer[i].Type = RGB; break; default: { error("Unsupported framebuffer memory model %d", framebuffer->memory_model); inf_loop asmv("hlt"); } } binfo.Framebuffer[i].BaseAddress = (void *)((uintptr_t)framebuffer->address - 0xFFFF800000000000); binfo.Framebuffer[i].Width = (uint32_t)framebuffer->width; binfo.Framebuffer[i].Height = (uint32_t)framebuffer->height; binfo.Framebuffer[i].Pitch = (uint32_t)framebuffer->pitch; binfo.Framebuffer[i].BitsPerPixel = framebuffer->bpp; binfo.Framebuffer[i].RedMaskSize = framebuffer->red_mask_size; binfo.Framebuffer[i].RedMaskShift = framebuffer->red_mask_shift; binfo.Framebuffer[i].GreenMaskSize = framebuffer->green_mask_size; binfo.Framebuffer[i].GreenMaskShift = framebuffer->green_mask_shift; binfo.Framebuffer[i].BlueMaskSize = framebuffer->blue_mask_size; binfo.Framebuffer[i].BlueMaskShift = framebuffer->blue_mask_shift; binfo.Framebuffer[i].ExtendedDisplayIdentificationData = framebuffer->edid; binfo.Framebuffer[i].EDIDSize = framebuffer->edid_size; debug("Framebuffer %d: %dx%d %d bpp", i, binfo.Framebuffer[i].Width, binfo.Framebuffer[i].Height, binfo.Framebuffer[i].BitsPerPixel); debug("More info:\nAddress: %#lx\nPitch: %ld\nType: %d\nRedMaskSize: %d\nRedMaskShift: %d\nGreenMaskSize: %d\nGreenMaskShift: %d\nBlueMaskSize: %d\nBlueMaskShift: %d\nEDID: %#lx\nEDIDSize: %d", binfo.Framebuffer[i].BaseAddress, binfo.Framebuffer[i].Pitch, binfo.Framebuffer[i].Type, binfo.Framebuffer[i].RedMaskSize, binfo.Framebuffer[i].RedMaskShift, binfo.Framebuffer[i].GreenMaskSize, binfo.Framebuffer[i].GreenMaskShift, binfo.Framebuffer[i].BlueMaskSize, binfo.Framebuffer[i].BlueMaskShift, binfo.Framebuffer[i].ExtendedDisplayIdentificationData, binfo.Framebuffer[i].EDIDSize); } binfo.Memory.Entries = MemmapResponse->entry_count; for (uint64_t i = 0; i < MemmapResponse->entry_count; i++) { if (MemmapResponse->entry_count > MAX_MEMORY_ENTRIES) { warn("Too many memory entries, skipping the rest..."); break; } struct limine_memmap_entry *entry = MemmapResponse->entries[i]; if (!entry) { warn("Null memory entry %ld (%#lx), skipping...", i, entry); continue; } binfo.Memory.Size += entry->length; switch (entry->type) { case LIMINE_MEMMAP_USABLE: binfo.Memory.Entry[i].BaseAddress = (void *)entry->base; binfo.Memory.Entry[i].Length = entry->length; binfo.Memory.Entry[i].Type = Usable; break; case LIMINE_MEMMAP_RESERVED: binfo.Memory.Entry[i].BaseAddress = (void *)entry->base; binfo.Memory.Entry[i].Length = entry->length; binfo.Memory.Entry[i].Type = Reserved; break; case LIMINE_MEMMAP_ACPI_RECLAIMABLE: binfo.Memory.Entry[i].BaseAddress = (void *)entry->base; binfo.Memory.Entry[i].Length = entry->length; binfo.Memory.Entry[i].Type = ACPIReclaimable; break; case LIMINE_MEMMAP_ACPI_NVS: binfo.Memory.Entry[i].BaseAddress = (void *)entry->base; binfo.Memory.Entry[i].Length = entry->length; binfo.Memory.Entry[i].Type = ACPINVS; break; case LIMINE_MEMMAP_BAD_MEMORY: binfo.Memory.Entry[i].BaseAddress = (void *)entry->base; binfo.Memory.Entry[i].Length = entry->length; binfo.Memory.Entry[i].Type = BadMemory; break; case LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE: binfo.Memory.Entry[i].BaseAddress = (void *)entry->base; binfo.Memory.Entry[i].Length = entry->length; binfo.Memory.Entry[i].Type = BootloaderReclaimable; break; case LIMINE_MEMMAP_KERNEL_AND_MODULES: binfo.Memory.Entry[i].BaseAddress = (void *)entry->base; binfo.Memory.Entry[i].Length = entry->length; binfo.Memory.Entry[i].Type = KernelAndModules; break; case LIMINE_MEMMAP_FRAMEBUFFER: binfo.Memory.Entry[i].BaseAddress = (void *)entry->base; binfo.Memory.Entry[i].Length = entry->length; binfo.Memory.Entry[i].Type = Framebuffer; break; default: binfo.Memory.Entry[i].BaseAddress = (void *)entry->base; binfo.Memory.Entry[i].Length = entry->length; binfo.Memory.Entry[i].Type = Unknown; break; } } if (ModuleResponse != NULL && ModuleResponse->module_count > 0) { for (uint64_t i = 0; i < ModuleResponse->module_count; i++) { if (i > MAX_MODULES) { warn("Too many modules, skipping the rest..."); break; } binfo.Modules[i].Address = (void *)((uint64_t)ModuleResponse->modules[i]->address - 0xFFFF800000000000); binfo.Modules[i].Size = ModuleResponse->modules[i]->size; strncpy(binfo.Modules[i].Path, ModuleResponse->modules[i]->path, strlen(ModuleResponse->modules[i]->path) + 1); strncpy(binfo.Modules[i].CommandLine, ModuleResponse->modules[i]->cmdline, strlen(ModuleResponse->modules[i]->cmdline) + 1); debug("Module %d:\nAddress: %#lx\nPath: \"%s\"\nCommand Line: \"%s\"\nSize: %ld", i, binfo.Modules[i].Address, binfo.Modules[i].Path, binfo.Modules[i].CommandLine, binfo.Modules[i].Size); } } binfo.RSDP = (struct RSDPInfo *)((uintptr_t)RsdpResponse->address - 0xFFFF800000000000); debug("RSDP: %#lx [Signature: \"%.8s\"] [OEM: \"%.6s\"]", binfo.RSDP, binfo.RSDP->Signature, binfo.RSDP->OEMID); if (SmbiosResponse->entry_64 != NULL) binfo.SMBIOSPtr = (void *)((uintptr_t)SmbiosResponse->entry_64 - 0xFFFF800000000000); else if (SmbiosResponse->entry_32 != NULL) binfo.SMBIOSPtr = (void *)((uintptr_t)SmbiosResponse->entry_32 - 0xFFFF800000000000); else binfo.SMBIOSPtr = NULL; debug("SMBIOS: %#lx %#lx (binfo: %#lx)", SmbiosResponse->entry_32, SmbiosResponse->entry_64, binfo.SMBIOSPtr); binfo.Kernel.PhysicalBase = (void *)KernelAddressResponse->physical_base; binfo.Kernel.VirtualBase = (void *)KernelAddressResponse->virtual_base; binfo.Kernel.FileBase = (void *)((uintptr_t)KernelFileResponse->kernel_file->address - 0xFFFF800000000000); binfo.Kernel.Size = KernelFileResponse->kernel_file->size; strncpy(binfo.Kernel.CommandLine, KernelFileResponse->kernel_file->cmdline, strlen(KernelFileResponse->kernel_file->cmdline) + 1); debug("Kernel physical address: %#lx", binfo.Kernel.PhysicalBase); debug("Kernel virtual address: %#lx", binfo.Kernel.VirtualBase); strncpy(binfo.Bootloader.Name, BootloaderInfoResponse->name, strlen(BootloaderInfoResponse->name) + 1); strncpy(binfo.Bootloader.Version, BootloaderInfoResponse->version, strlen(BootloaderInfoResponse->version) + 1); Entry(&binfo); }