diff --git a/targets/x86_64/include/boot.hpp b/targets/x86_64/include/boot.hpp index e02b6c9..032d265 100644 --- a/targets/x86_64/include/boot.hpp +++ b/targets/x86_64/include/boot.hpp @@ -63,4 +63,19 @@ struct EfiMemoryMap } }; +struct EfiDisplayInfo +{ + void* frameBufferBase; + uint64_t frameBufferSize; + uint32_t frameBufferWidth; + uint32_t frameBufferHeight; + uint32_t frameBufferPitch; +}; + +struct EfiBootInfo +{ + EfiMemoryMap memoryMap; + EfiDisplayInfo displayInfo; +}; + #endif // BOOT_HPP_INCLUDED diff --git a/targets/x86_64/src/kernel/boot.s b/targets/x86_64/src/kernel/boot.s index deb3204..140bec8 100644 --- a/targets/x86_64/src/kernel/boot.s +++ b/targets/x86_64/src/kernel/boot.s @@ -12,7 +12,7 @@ stack_top: .type _start, @function _start: // store the memory map - mov %rbx, (gMemoryMap) + mov %rbx, (gBootInfo) // setup stack mov $stack_top, %rsp diff --git a/targets/x86_64/src/kernel/startup.cpp b/targets/x86_64/src/kernel/startup.cpp index d39a002..3c8791b 100644 --- a/targets/x86_64/src/kernel/startup.cpp +++ b/targets/x86_64/src/kernel/startup.cpp @@ -61,7 +61,7 @@ void initGlobals() extern "C" { -EfiMemoryMap* gMemoryMap; +EfiBootInfo* gBootInfo; void _init(); void _fini(); @@ -76,10 +76,30 @@ void kernel_main() std::printf("Kernel End: %p\n", &gKernelEnd); + struct Pixel + { + uint8_t blue = 0; + uint8_t green = 0; + uint8_t red = 0; + uint8_t reserved = 0; + }; + auto setPixel = [](unsigned x, unsigned y, Pixel color) + { + Pixel* framebuffer = static_cast(gBootInfo->displayInfo.frameBufferBase); + framebuffer[y * gBootInfo->displayInfo.frameBufferPitch / 4 + x] = color; + }; + for (int x = 0; x < 100; ++x) + { + for (int y = 0; y < 100; ++y) + { + setPixel(x, y, {.red = 255}); + } + } + /* Initialize the heap */ // assert(gMultibootHeader->flags & MULTIBOOT_INFO_MEM_MAP); // initHeapFromMultibootHeader(gMultibootHeader->mmap_addr, gMultibootHeader->mmap_length); - initHeapFromEfiMemoryMap(*gMemoryMap); + initHeapFromEfiMemoryMap(gBootInfo->memoryMap); main(); diff --git a/targets/x86_64/src/loader/main.cpp b/targets/x86_64/src/loader/main.cpp index 881ed47..c0677f4 100644 --- a/targets/x86_64/src/loader/main.cpp +++ b/targets/x86_64/src/loader/main.cpp @@ -9,6 +9,7 @@ extern "C" #include "miniprintf.hpp" // debug stuff +// #define DUMP_DISPLAY_MODES // #define DUMP_MEMORY_MAP // #define DUMP_ELF @@ -16,6 +17,7 @@ namespace { EFI_SYSTEM_TABLE* gSystemTable; EFI_BOOT_SERVICES* gBootServices; +EFI_GRAPHICS_OUTPUT_PROTOCOL* gGraphicsOutputProtocol; EFI_STATUS openImageVolume(EFI_HANDLE image, EFI_FILE_HANDLE& outHandle) { @@ -132,6 +134,59 @@ EFI_STATUS getEfiMemoryMap(EfiMemoryMap& outMemoryMap) return EFI_SUCCESS; } +EFI_STATUS getEfiGraphicsOutputProtocol(EFI_GRAPHICS_OUTPUT_PROTOCOL*& outGOP) +{ + static const EFI_GUID GOP_GUID = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID; + + EFI_GRAPHICS_OUTPUT_PROTOCOL* gop; + EFI_STATUS status = gBootServices->LocateProtocol(const_cast(&GOP_GUID), nullptr, reinterpret_cast(&gop)); + if (EFI_ERROR(status)) { + return status; + } + outGOP = gop; + return EFI_SUCCESS; +} + +EFI_STATUS queryEfiDisplayModes(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION*& outModes) +{ + UINTN sizeOfInfo = gGraphicsOutputProtocol->Mode->SizeOfInfo; + outModes = new EFI_GRAPHICS_OUTPUT_MODE_INFORMATION[gGraphicsOutputProtocol->Mode->MaxMode]; + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION* buffer = static_cast(malloc(sizeOfInfo)); + + for (UINT32 modeIdx = 0; modeIdx < gGraphicsOutputProtocol->Mode->MaxMode; ++modeIdx) + { + EFI_STATUS status = gGraphicsOutputProtocol->QueryMode(gGraphicsOutputProtocol, modeIdx, &sizeOfInfo, &buffer); + if (EFI_ERROR(status)) + { + delete[] outModes; + free(buffer); + return status; + } + outModes[modeIdx] = *buffer; + } + free(buffer); + return EFI_SUCCESS; +} + +UINT32 findBestDisplayMode(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION* displayModes) +{ + UINT32 bestMode = 0; + uint32_t bestModePixels = 0; + for (UINT32 modeIdx = 0; modeIdx < gGraphicsOutputProtocol->Mode->MaxMode; ++modeIdx) + { + if (displayModes[modeIdx].PixelFormat != PixelBlueGreenRedReserved8BitPerColor) { + continue; // we don't care about anything but RGB + } + const uint32_t pixels = displayModes[modeIdx].VerticalResolution * displayModes[modeIdx].HorizontalResolution; + if (pixels > bestModePixels) + { + bestMode = modeIdx; + bestModePixels = pixels; + } + } + return bestMode; +} + bool isEfiMemoryTypeUsable(EFI_MEMORY_TYPE type) { switch (type) @@ -167,17 +222,56 @@ if (EFI_ERROR(status)) \ extern "C" EFI_STATUS efi_main(EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE* systemTable) { - /* Store the system table for future use in other functions */ + // store the system table for future use in other functions gSystemTable = systemTable; gBootServices = systemTable->BootServices; initMiniMalloc(); initMiniPrintf(&putchar); + // this will be passed to the OS + EfiBootInfo* bootInfo = new EfiBootInfo; + gSystemTable->ConOut->ClearScreen(gSystemTable->ConOut); + // load GOP and detect modes + EFI_STATUS status = getEfiGraphicsOutputProtocol(gGraphicsOutputProtocol); + DIE_ON_ERROR(L"Error getting EFI GOP."); + + EFI_GRAPHICS_OUTPUT_MODE_INFORMATION* displayModes = nullptr; + status = queryEfiDisplayModes(displayModes); + DIE_ON_ERROR(L"Error querying EFI display modes."); + + const UINT32 bestModeIdx = findBestDisplayMode(displayModes); + status = gGraphicsOutputProtocol->SetMode(gGraphicsOutputProtocol, bestModeIdx); + DIE_ON_ERROR(L"Error setting display mode."); + + bootInfo->displayInfo = { + .frameBufferBase = reinterpret_cast(gGraphicsOutputProtocol->Mode->FrameBufferBase), + .frameBufferSize = gGraphicsOutputProtocol->Mode->FrameBufferSize, + .frameBufferWidth = gGraphicsOutputProtocol->Mode->Info->HorizontalResolution, + .frameBufferHeight = gGraphicsOutputProtocol->Mode->Info->VerticalResolution, + .frameBufferPitch = 4 * gGraphicsOutputProtocol->Mode->Info->PixelsPerScanLine + }; + +#if defined(DUMP_DISPLAY_MODES) + printf("Display modes:\n"); + for (UINT32 modeIdx = 0; modeIdx < gGraphicsOutputProtocol->Mode->MaxMode; ++modeIdx) + { + const EFI_GRAPHICS_OUTPUT_MODE_INFORMATION& mode = displayModes[modeIdx]; + printf( + "Mode %d: width=%d, height=%d, format=%d%s\n", + modeIdx, + mode.HorizontalResolution, + mode.VerticalResolution, + mode.PixelFormat, + modeIdx == gGraphicsOutputProtocol->Mode->Mode ? " (current)" : "" + ); + } +#endif // defined(DUMP_DISPLAY_MODES) + EFI_FILE_HANDLE volume; - EFI_STATUS status = openImageVolume(imageHandle, volume); + status = openImageVolume(imageHandle, volume); DIE_ON_ERROR(L"Error opening image volume."); const CHAR16* fileName = L"kernel.bin"; @@ -204,7 +298,7 @@ extern "C" EFI_STATUS efi_main(EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE* systemT for (uint16_t phtEntry = 0; phtEntry < header.phtEntryCount; ++phtEntry) { status = fileHandle->SetPosition(fileHandle, header.phtOffset + phtEntry * header.phtEntrySize); - DIE_ON_ERROR("Error seeking in EFI64 file."); + DIE_ON_ERROR(L"Error seeking in EFI64 file."); Efi64ProgramHeader programHeader = {}; bufferSize = sizeof(Efi64ProgramHeader); status = fileHandle->Read(fileHandle, &bufferSize, &programHeader); @@ -230,8 +324,7 @@ extern "C" EFI_STATUS efi_main(EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE* systemT DIE_ON_ERROR("Error reading ELF64 section."); } - EfiMemoryMap* memoryMap = new EfiMemoryMap; - status = getEfiMemoryMap(*memoryMap); + status = getEfiMemoryMap(bootInfo->memoryMap); DIE_ON_ERROR("Error getting EFI memory map."); #if defined(DUMP_MEMORY_MAP) @@ -245,7 +338,7 @@ extern "C" EFI_STATUS efi_main(EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE* systemT continue; } printf( - "Entry %d: type: %d, physicalStart: 0x%lX, numberOfPages: %ld\n", + "Entry %d: type=%d, physicalStart=0x%lX, numberOfPages=%ld\n", entry, static_cast(descriptor.Type), static_cast(descriptor.PhysicalStart), @@ -259,7 +352,7 @@ extern "C" EFI_STATUS efi_main(EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE* systemT #undef DUMP_MEMORY_MAP #endif // defined(DUMP_MEMORY_MAP) - status = gBootServices->ExitBootServices(imageHandle, memoryMap->mapKey); + status = gBootServices->ExitBootServices(imageHandle, bootInfo->memoryMap.mapKey); DIE_ON_ERROR("Error exiting EFI boot services."); // up up and away! @@ -267,7 +360,7 @@ extern "C" EFI_STATUS efi_main(EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE* systemT ( "jmp %0" : - : "a"(header.entry), "b"(memoryMap) + : "a"(header.entry), "b"(bootInfo) ); // we should never get here