#include "boot.hpp" #include #include #include "os/draw.hpp" #include "os/serial.hpp" #include "os/tty.hpp" #include "./x86_64.hpp" extern "C" int gKernelEnd; namespace { void initHeapFromEfiMemoryMap(const EfiMemoryMap& memoryMap) noexcept { const uint64_t minAddr = reinterpret_cast(&gKernelEnd); for (const EFI_MEMORY_DESCRIPTOR& descriptor : memoryMap) { if (!isEfiMemoryTypeUsable(descriptor.Type)) { continue; } uint64_t addr = descriptor.PhysicalStart; uint64_t len = descriptor.NumberOfPages * 4096; // TODO: is this the correct page size? // anything before the kernel we ignore if (addr < minAddr) { // if the entire entry is before the kernel, continue if (addr + len <= minAddr) { continue; } // otherwise shrink it and use the rest len -= (minAddr - addr); addr = minAddr; } __ba_registerAllocatableMemory(reinterpret_cast(addr), len); } #if 0 const uint64_t minAddr = reinterpret_cast(&gKernelEnd); for (uint32_t addr = firstEntryAddr; addr < firstEntryAddr + bufferLength;) { multiboot_memory_map_t entry = *reinterpret_cast(addr); if(entry.type == MULTIBOOT_MEMORY_AVAILABLE) { std::printf("Start Addr: %X | Length: %b\n", static_cast(entry.addr), static_cast(entry.len)); // anything before the kernel we ignore if (entry.addr < minAddr) { // if the entire entry is before the kernel, continue if (entry.addr + entry.len <= minAddr) { addr += sizeof(entry.size) + entry.size; continue; } // otherwise shrink it and use the rest entry.len -= (minAddr - entry.addr); entry.addr = minAddr; } __ba_registerAllocatableMemory(reinterpret_cast(entry.addr), entry.len); } addr += sizeof(entry.size) + entry.size; } #endif } using initfunc_t = void *(); extern "C" initfunc_t* start_ctors; extern "C" initfunc_t* end_ctors; void initGlobals() { for (initfunc_t** initFunc = &start_ctors; initFunc != &end_ctors; ++initFunc) { // TODO: this confuses me if (*initFunc == reinterpret_cast(0xffffffffffffffff)) { break; } (*initFunc)(); } } constinit std::array GDT alignas(16) = { SEGMENT_NULL, SEGMENT_KERNEL_CODE, SEGMENT_KERNEL_DATA, SEGMENT_USER_CODE, SEGMENT_USER_DATA }; constinit std::array IDT alignas(16); extern "C" void __setGDT(uint16_t limit, void* base); extern "C" void __setIDT(uint16_t limit, void* base); void setupInterrupt(std::uint8_t index, void* handler, std::uint8_t flags) noexcept { const std::uint64_t offset = std::bit_cast(handler); IDT[index] = InterruptDescriptor{ .offsetLow = static_cast(offset & 0xFFFF), .selector = 1, // kernel code .interruptStackTable = 0, .gateType = InterruptGateType::INTERRUPT_GATE, .privilegeLevel = 0, .present = true, .offsetHigh = (offset >> 16) }; } } extern "C" { EfiBootInfo* gBootInfo; void main(); void kernel_main() { __setGDT(sizeof(GDT), &GDT); __setIDT(sizeof(IDT), &IDT); // done initializing OS stuff, enable interrupts __asm__ __volatile__("sti"); initGlobals(); // init the heap (required for the double buffer) // initHeapFromEfiMemoryMap(gBootInfo->memoryMap); // initialize the framebuffer draw::initializeDefaultFramebuffer({ /* base = */ static_cast(gBootInfo->displayInfo.frameBufferBase), /* width = */ gBootInfo->displayInfo.frameBufferWidth, /* height = */ gBootInfo->displayInfo.frameBufferHeight, /* pitch = */ gBootInfo->displayInfo.frameBufferPitch / 4 }); // initialize terminal interface tty::initialize(); if (!initSerialPort(PORT_COM1)) { tty::write("Error initializing serial port.\n"); return; } serialWriteString(PORT_COM1, "\r\n\r\n"); // write newlines to separate from UEFI output std::puts("This is BadAppleOS and everything is fine!\n"); main(); } } // extern "C"