Added framebuffer initialization using GOP.

This commit is contained in:
Patrick 2024-01-15 16:21:06 +01:00
parent bf8949113b
commit 9962ef21f2
4 changed files with 139 additions and 11 deletions

View File

@ -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

View File

@ -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

View File

@ -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<Pixel*>(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();

View File

@ -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<EFI_GUID*>(&GOP_GUID), nullptr, reinterpret_cast<void**>(&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<EFI_GRAPHICS_OUTPUT_MODE_INFORMATION*>(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<void*>(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<int>(descriptor.Type),
static_cast<unsigned long>(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