Added framebuffer initialization using GOP.
This commit is contained in:
parent
bf8949113b
commit
9962ef21f2
@ -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
|
#endif // BOOT_HPP_INCLUDED
|
||||||
|
@ -12,7 +12,7 @@ stack_top:
|
|||||||
.type _start, @function
|
.type _start, @function
|
||||||
_start:
|
_start:
|
||||||
// store the memory map
|
// store the memory map
|
||||||
mov %rbx, (gMemoryMap)
|
mov %rbx, (gBootInfo)
|
||||||
|
|
||||||
// setup stack
|
// setup stack
|
||||||
mov $stack_top, %rsp
|
mov $stack_top, %rsp
|
||||||
|
@ -61,7 +61,7 @@ void initGlobals()
|
|||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
EfiMemoryMap* gMemoryMap;
|
EfiBootInfo* gBootInfo;
|
||||||
|
|
||||||
void _init();
|
void _init();
|
||||||
void _fini();
|
void _fini();
|
||||||
@ -76,10 +76,30 @@ void kernel_main()
|
|||||||
|
|
||||||
std::printf("Kernel End: %p\n", &gKernelEnd);
|
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 */
|
/* Initialize the heap */
|
||||||
// assert(gMultibootHeader->flags & MULTIBOOT_INFO_MEM_MAP);
|
// assert(gMultibootHeader->flags & MULTIBOOT_INFO_MEM_MAP);
|
||||||
// initHeapFromMultibootHeader(gMultibootHeader->mmap_addr, gMultibootHeader->mmap_length);
|
// initHeapFromMultibootHeader(gMultibootHeader->mmap_addr, gMultibootHeader->mmap_length);
|
||||||
initHeapFromEfiMemoryMap(*gMemoryMap);
|
initHeapFromEfiMemoryMap(gBootInfo->memoryMap);
|
||||||
|
|
||||||
main();
|
main();
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@ extern "C"
|
|||||||
#include "miniprintf.hpp"
|
#include "miniprintf.hpp"
|
||||||
|
|
||||||
// debug stuff
|
// debug stuff
|
||||||
|
// #define DUMP_DISPLAY_MODES
|
||||||
// #define DUMP_MEMORY_MAP
|
// #define DUMP_MEMORY_MAP
|
||||||
// #define DUMP_ELF
|
// #define DUMP_ELF
|
||||||
|
|
||||||
@ -16,6 +17,7 @@ namespace
|
|||||||
{
|
{
|
||||||
EFI_SYSTEM_TABLE* gSystemTable;
|
EFI_SYSTEM_TABLE* gSystemTable;
|
||||||
EFI_BOOT_SERVICES* gBootServices;
|
EFI_BOOT_SERVICES* gBootServices;
|
||||||
|
EFI_GRAPHICS_OUTPUT_PROTOCOL* gGraphicsOutputProtocol;
|
||||||
|
|
||||||
EFI_STATUS openImageVolume(EFI_HANDLE image, EFI_FILE_HANDLE& outHandle)
|
EFI_STATUS openImageVolume(EFI_HANDLE image, EFI_FILE_HANDLE& outHandle)
|
||||||
{
|
{
|
||||||
@ -132,6 +134,59 @@ EFI_STATUS getEfiMemoryMap(EfiMemoryMap& outMemoryMap)
|
|||||||
return EFI_SUCCESS;
|
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)
|
bool isEfiMemoryTypeUsable(EFI_MEMORY_TYPE type)
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
@ -167,17 +222,56 @@ if (EFI_ERROR(status)) \
|
|||||||
|
|
||||||
extern "C" EFI_STATUS efi_main(EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE* systemTable)
|
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;
|
gSystemTable = systemTable;
|
||||||
gBootServices = systemTable->BootServices;
|
gBootServices = systemTable->BootServices;
|
||||||
|
|
||||||
initMiniMalloc();
|
initMiniMalloc();
|
||||||
initMiniPrintf(&putchar);
|
initMiniPrintf(&putchar);
|
||||||
|
|
||||||
|
// this will be passed to the OS
|
||||||
|
EfiBootInfo* bootInfo = new EfiBootInfo;
|
||||||
|
|
||||||
gSystemTable->ConOut->ClearScreen(gSystemTable->ConOut);
|
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_FILE_HANDLE volume;
|
||||||
EFI_STATUS status = openImageVolume(imageHandle, volume);
|
status = openImageVolume(imageHandle, volume);
|
||||||
DIE_ON_ERROR(L"Error opening image volume.");
|
DIE_ON_ERROR(L"Error opening image volume.");
|
||||||
|
|
||||||
const CHAR16* fileName = L"kernel.bin";
|
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)
|
for (uint16_t phtEntry = 0; phtEntry < header.phtEntryCount; ++phtEntry)
|
||||||
{
|
{
|
||||||
status = fileHandle->SetPosition(fileHandle, header.phtOffset + phtEntry * header.phtEntrySize);
|
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 = {};
|
Efi64ProgramHeader programHeader = {};
|
||||||
bufferSize = sizeof(Efi64ProgramHeader);
|
bufferSize = sizeof(Efi64ProgramHeader);
|
||||||
status = fileHandle->Read(fileHandle, &bufferSize, &programHeader);
|
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.");
|
DIE_ON_ERROR("Error reading ELF64 section.");
|
||||||
}
|
}
|
||||||
|
|
||||||
EfiMemoryMap* memoryMap = new EfiMemoryMap;
|
status = getEfiMemoryMap(bootInfo->memoryMap);
|
||||||
status = getEfiMemoryMap(*memoryMap);
|
|
||||||
DIE_ON_ERROR("Error getting EFI memory map.");
|
DIE_ON_ERROR("Error getting EFI memory map.");
|
||||||
|
|
||||||
#if defined(DUMP_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;
|
continue;
|
||||||
}
|
}
|
||||||
printf(
|
printf(
|
||||||
"Entry %d: type: %d, physicalStart: 0x%lX, numberOfPages: %ld\n",
|
"Entry %d: type=%d, physicalStart=0x%lX, numberOfPages=%ld\n",
|
||||||
entry,
|
entry,
|
||||||
static_cast<int>(descriptor.Type),
|
static_cast<int>(descriptor.Type),
|
||||||
static_cast<unsigned long>(descriptor.PhysicalStart),
|
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
|
#undef DUMP_MEMORY_MAP
|
||||||
#endif // defined(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.");
|
DIE_ON_ERROR("Error exiting EFI boot services.");
|
||||||
|
|
||||||
// up up and away!
|
// up up and away!
|
||||||
@ -267,7 +360,7 @@ extern "C" EFI_STATUS efi_main(EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE* systemT
|
|||||||
(
|
(
|
||||||
"jmp %0"
|
"jmp %0"
|
||||||
:
|
:
|
||||||
: "a"(header.entry), "b"(memoryMap)
|
: "a"(header.entry), "b"(bootInfo)
|
||||||
);
|
);
|
||||||
|
|
||||||
// we should never get here
|
// we should never get here
|
||||||
|
Loading…
x
Reference in New Issue
Block a user