[WIP] Implementing "console" output and stuff.

This commit is contained in:
2024-01-16 10:21:14 +01:00
parent e938f76823
commit 6ec9e0d320
21 changed files with 509 additions and 216 deletions

View File

@@ -28,6 +28,8 @@ crtn_o = kernel_env.Object('src/crt/crtn.s')
kernel_env['LINKCOM'] = env['LINKCOM'].replace('$_LIBFLAGS', f'{crti_o[0].abspath} {crtbegin_o} $_LIBFLAGS -lgcc {crtend_o} {crtn_o[0].abspath}')
kernel_sources = env['KERNEL_SOURCES'] + Split('''
src/cstdlib/memory.s
src/kernel/boot.s
src/kernel/startup.cpp
''')
@@ -37,7 +39,7 @@ prog_kernel = kernel_env.Program(
target = kernel_target,
source = kernel_sources
)
kernel_env.Depends(prog_kernel, [crti_o, crtn_o])
kernel_env.Depends(prog_kernel, [crti_o, crtn_o] + kernel_sources)
kernel_env.Default(prog_kernel)
x86_64_iso_files = [
@@ -69,7 +71,6 @@ uefi_env.Append(CPPPATH = ['/usr/include/efi', 'include'])
loader_sources = Split('''
src/loader/main.cpp
src/loader/minimalloc.cpp
src/loader/miniprintf.cpp
''')
loader_target = uefi_env.File('#loader.x86_64.efi')

View File

@@ -75,7 +75,34 @@ struct EfiDisplayInfo
struct EfiBootInfo
{
EfiMemoryMap memoryMap;
EfiDisplayInfo displayInfo;
EfiDisplayInfo displayInfo = {};
};
inline bool isEfiMemoryTypeUsable(UINT32 type) noexcept
{
switch (type)
{
case EfiLoaderCode:
case EfiLoaderData:
case EfiBootServicesCode:
case EfiBootServicesData:
case EfiConventionalMemory:
return true;
case EfiReservedMemoryType:
case EfiRuntimeServicesCode:
case EfiRuntimeServicesData:
case EfiUnusableMemory:
case EfiACPIReclaimMemory:
case EfiACPIMemoryNVS:
case EfiMemoryMappedIO:
case EfiMemoryMappedIOPortSpace:
case EfiPalCode:
case EfiMaxMemoryType:
default:
return false;
}
}
#endif // BOOT_HPP_INCLUDED

View File

@@ -0,0 +1,27 @@
.section .text
.global memcpy
.type memcpy @function
// int memcpy(void* dest [%rdi], void* src [%rsi], size_t count [%rdx])
//
memcpy:
cmpq %rdx, 4
jl memcpy_bytes
movq (%rsi), %rax
movq %rax, (%rdi)
addq $4, %rsi
addq $4, %rdi
subq $4, %rdx
jmp memcpy
memcpy_bytes:
cmpq %rdx, 0
je memcpy_end
movb (%rsi), %ah
movb %ah, (%rdi)
addq $1, %rsi
addq $1, %rdi
subq $1, %rdx
jmp memcpy_bytes
memcpy_end:
ret

View File

@@ -1,5 +1,6 @@
#include <cstdio>
#include <cstring>
#include "boot.hpp"
#include "os/draw.hpp"
@@ -14,8 +15,7 @@ void initHeapFromEfiMemoryMap(const EfiMemoryMap& memoryMap) noexcept
const uint64_t minAddr = reinterpret_cast<uint64_t>(&gKernelEnd);
for (const EFI_MEMORY_DESCRIPTOR& descriptor : memoryMap)
{
// TODO: what about other types?
if (descriptor.Type != EfiConventionalMemory)
if (!isEfiMemoryTypeUsable(descriptor.Type))
{
continue;
}
@@ -97,7 +97,7 @@ void kernel_main()
initGlobals();
// init the heap (required for the double buffer)
initHeapFromEfiMemoryMap(gBootInfo->memoryMap);
// initHeapFromEfiMemoryMap(gBootInfo->memoryMap);
// initialize the framebuffer
draw::initializeDefaultFramebuffer({
@@ -108,18 +108,27 @@ void kernel_main()
});
// initialize terminal interface
// tty::initialize();
tty::initialize();
// std::printf("Kernel End: %p\n", &gKernelEnd);
uint8_t test[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
uint8_t dest[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
std::memcpy(&dest[1], &test[3], 2);
for (int i = 0; i < 400; ++i)
{
std::printf("Hello font %d!\n", i);
}
#if 0
for (int x = 0; x < 100; ++x)
{
for (int y = 0; y < 100; ++y)
{
draw::setPixel(x, y, {.red = 255});
draw::setPixelDirect(x, y, {.red = 255});
}
}
draw::flushPixels();
#endif
//draw::flushPixels();
/* Initialize the heap */
// assert(gMultibootHeader->flags & MULTIBOOT_INFO_MEM_MAP);

View File

@@ -5,13 +5,15 @@ extern "C"
}
#include "boot.hpp"
#include "minielf.hpp"
#include "minimalloc.hpp"
#include "miniprintf.hpp"
// debug stuff
// #define DUMP_DISPLAY_MODES
// #define DUMP_MEMORY_MAP
// #define DUMP_ELF
#define PRINTLINE3(file, line) print(L"At: " file L":" #line L"\r\n")
#define PRINTLINE2(file, line) PRINTLINE3(file, line)
#define PRINTLINE() PRINTLINE2(__FILE__, __LINE__)
namespace
{
@@ -19,6 +21,21 @@ EFI_SYSTEM_TABLE* gSystemTable;
EFI_BOOT_SERVICES* gBootServices;
EFI_GRAPHICS_OUTPUT_PROTOCOL* gGraphicsOutputProtocol;
void* malloc(size_t size) noexcept
{
void* ptr = nullptr;
gBootServices->AllocatePool(EfiLoaderData, size, &ptr);
return ptr;
}
void free(void* ptr) noexcept
{
// if (ptr != nullptr)
// {
// gBootServices->FreePool(ptr);
// }
}
EFI_STATUS openImageVolume(EFI_HANDLE image, EFI_FILE_HANDLE& outHandle)
{
EFI_LOADED_IMAGE* loadedImage = nullptr;
@@ -112,18 +129,29 @@ EFI_STATUS getEfiMemoryMap(EfiMemoryMap& outMemoryMap)
UINTN mapKey = 0;
UINTN descriptorSize = 0;
UINT32 descriptorVersion = 0;
EFI_STATUS status = gBootServices->GetMemoryMap(&mapSize, nullptr, &mapKey, &descriptorSize, &descriptorVersion);
if (status != EFI_BUFFER_TOO_SMALL) {
return status;
EFI_STATUS status = EFI_BUFFER_TOO_SMALL;
while (true)
{
status = gBootServices->GetMemoryMap(&mapSize, map, &mapKey, &descriptorSize, &descriptorVersion);
if (status != EFI_BUFFER_TOO_SMALL) {
break;
}
if (map != nullptr)
{
free(map);
}
map = static_cast<EFI_MEMORY_DESCRIPTOR*>(malloc(mapSize));
if (map == nullptr) {
return EFI_OUT_OF_RESOURCES;
}
}
map = static_cast<EFI_MEMORY_DESCRIPTOR*>(malloc(mapSize));
if (map == nullptr) {
return EFI_OUT_OF_RESOURCES;
}
status = gBootServices->GetMemoryMap(&mapSize, map, &mapKey, &descriptorSize, &descriptorVersion);
if (EFI_ERROR(status))
{
free(map);
if (map != nullptr)
{
gBootServices->FreePool(map);
}
return status;
}
outMemoryMap.mapSize = mapSize;
@@ -150,7 +178,7 @@ EFI_STATUS getEfiGraphicsOutputProtocol(EFI_GRAPHICS_OUTPUT_PROTOCOL*& outGOP)
EFI_STATUS queryEfiDisplayModes(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION*& outModes)
{
UINTN sizeOfInfo = gGraphicsOutputProtocol->Mode->SizeOfInfo;
outModes = new EFI_GRAPHICS_OUTPUT_MODE_INFORMATION[gGraphicsOutputProtocol->Mode->MaxMode];
outModes = static_cast<EFI_GRAPHICS_OUTPUT_MODE_INFORMATION*>(malloc(gGraphicsOutputProtocol->Mode->MaxMode * sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)));
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION* buffer = static_cast<EFI_GRAPHICS_OUTPUT_MODE_INFORMATION*>(malloc(sizeOfInfo));
for (UINT32 modeIdx = 0; modeIdx < gGraphicsOutputProtocol->Mode->MaxMode; ++modeIdx)
@@ -158,7 +186,7 @@ EFI_STATUS queryEfiDisplayModes(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION*& outModes)
EFI_STATUS status = gGraphicsOutputProtocol->QueryMode(gGraphicsOutputProtocol, modeIdx, &sizeOfInfo, &buffer);
if (EFI_ERROR(status))
{
delete[] outModes;
free(outModes);
free(buffer);
return status;
}
@@ -187,37 +215,86 @@ UINT32 findBestDisplayMode(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION* displayModes)
return bestMode;
}
bool isEfiMemoryTypeUsable(EFI_MEMORY_TYPE type)
const char* efiStatusToString(EFI_STATUS status)
{
switch (type)
switch (status)
{
case EfiLoaderCode:
case EfiLoaderData:
case EfiBootServicesCode:
case EfiBootServicesData:
case EfiConventionalMemory:
return true;
case EfiReservedMemoryType:
case EfiRuntimeServicesCode:
case EfiRuntimeServicesData:
case EfiUnusableMemory:
case EfiACPIReclaimMemory:
case EfiACPIMemoryNVS:
case EfiMemoryMappedIO:
case EfiMemoryMappedIOPortSpace:
case EfiPalCode:
case EfiMaxMemoryType:
case EFI_SUCCESS:
return "EFI_SUCCESS";
case EFI_LOAD_ERROR:
return "EFI_LOAD_ERROR";
case EFI_INVALID_PARAMETER:
return "EFI_INVALID_PARAMETER";
case EFI_UNSUPPORTED:
return "EFI_UNSUPPORTED";
case EFI_BAD_BUFFER_SIZE:
return "EFI_BAD_BUFFER_SIZE";
case EFI_BUFFER_TOO_SMALL:
return "EFI_BUFFER_TOO_SMALL";
case EFI_NOT_READY:
return "EFI_NOT_READY";
case EFI_DEVICE_ERROR:
return "EFI_DEVICE_ERROR";
case EFI_WRITE_PROTECTED:
return "EFI_WRITE_PROTECTED";
case EFI_OUT_OF_RESOURCES:
return "EFI_OUT_OF_RESOURCES";
case EFI_VOLUME_CORRUPTED:
return "EFI_VOLUME_CORRUPTED";
case EFI_VOLUME_FULL:
return "EFI_VOLUME_FULL";
case EFI_NO_MEDIA:
return "EFI_NO_MEDIA";
case EFI_MEDIA_CHANGED:
return "EFI_MEDIA_CHANGED";
case EFI_NOT_FOUND:
return "EFI_NOT_FOUND";
case EFI_ACCESS_DENIED:
return "EFI_ACCESS_DENIED";
case EFI_NO_RESPONSE:
return "EFI_NO_RESPONSE";
case EFI_NO_MAPPING:
return "EFI_NO_MAPPING";
case EFI_TIMEOUT:
return "EFI_TIMEOUT";
case EFI_NOT_STARTED:
return "EFI_NOT_STARTED";
case EFI_ALREADY_STARTED:
return "EFI_ALREADY_STARTED";
case EFI_ABORTED:
return "EFI_ABORTED";
case EFI_ICMP_ERROR:
return "EFI_ICMP_ERROR";
case EFI_TFTP_ERROR:
return "EFI_TFTP_ERROR";
case EFI_PROTOCOL_ERROR:
return "EFI_PROTOCOL_ERROR";
case EFI_INCOMPATIBLE_VERSION:
return "EFI_INCOMPATIBLE_VERSION";
case EFI_SECURITY_VIOLATION:
return "EFI_SECURITY_VIOLATION";
case EFI_CRC_ERROR:
return "EFI_CRC_ERROR";
case EFI_END_OF_MEDIA:
return "EFI_END_OF_MEDIA";
case EFI_END_OF_FILE:
return "EFI_END_OF_FILE";
case EFI_INVALID_LANGUAGE:
return "EFI_INVALID_LANGUAGE";
case EFI_COMPROMISED_DATA:
return "EFI_COMPROMISED_DATA";
default:
return false;
return "UNKNOWN";
}
}
}
#define DIE_ON_ERROR(message) \
if (EFI_ERROR(status)) \
{ \
printAndWait(message L"\r\n"); \
return status; \
#define DIE_ON_ERROR(message) \
if (EFI_ERROR(status)) \
{ \
printf("Status: %s\n", efiStatusToString(status)); \
printAndWait(message L"\r\n"); \
return status; \
}
extern "C" EFI_STATUS efi_main(EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE* systemTable)
@@ -226,11 +303,10 @@ extern "C" EFI_STATUS efi_main(EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE* systemT
gSystemTable = systemTable;
gBootServices = systemTable->BootServices;
initMiniMalloc();
initMiniPrintf(&putchar);
// this will be passed to the OS
EfiBootInfo* bootInfo = new EfiBootInfo;
EfiBootInfo* bootInfo = static_cast<EfiBootInfo*>(malloc(sizeof(EfiBootInfo)));
gSystemTable->ConOut->ClearScreen(gSystemTable->ConOut);
@@ -246,6 +322,10 @@ extern "C" EFI_STATUS efi_main(EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE* systemT
status = gGraphicsOutputProtocol->SetMode(gGraphicsOutputProtocol, bestModeIdx);
DIE_ON_ERROR(L"Error setting display mode.");
UINTN consoleColumns, consoleRows;
status = gSystemTable->ConOut->QueryMode(gSystemTable->ConOut, gSystemTable->ConOut->Mode->Mode, &consoleColumns, &consoleRows);
DIE_ON_ERROR(L"Error fetching console mode.");
bootInfo->displayInfo = {
.frameBufferBase = reinterpret_cast<void*>(gGraphicsOutputProtocol->Mode->FrameBufferBase),
.frameBufferSize = gGraphicsOutputProtocol->Mode->FrameBufferSize,
@@ -329,14 +409,24 @@ extern "C" EFI_STATUS efi_main(EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE* systemT
#if defined(DUMP_MEMORY_MAP)
int entry = -1;
for (const EFI_MEMORY_DESCRIPTOR& descriptor : *memoryMap)
{
++entry;
// if (!isEfiMemoryTypeUsable(static_cast<EFI_MEMORY_TYPE>(descriptor->Type))) {
if (descriptor.Type != EfiConventionalMemory) {
UINTN leftThisPage = consoleRows - 1;
printf("ltp: %d\n", static_cast<int>(leftThisPage));
for (const EFI_MEMORY_DESCRIPTOR& descriptor : bootInfo->memoryMap)
{
if (!isEfiMemoryTypeUsable(descriptor.Type)) {
// if (descriptor.Type != EfiBootServicesCode) {
continue;
}
++entry;
if (leftThisPage == 0)
{
printAndWait(L"-- Any key to continue --\r\n");
leftThisPage = consoleRows;
}
--leftThisPage;
printf(
"Entry %d: type=%d, physicalStart=0x%lX, numberOfPages=%ld\n",
entry,
@@ -347,7 +437,7 @@ extern "C" EFI_STATUS efi_main(EFI_HANDLE imageHandle, EFI_SYSTEM_TABLE* systemT
}
// printing may have invalidated the map, get it again
status = getEfiMemoryMap(*memoryMap);
status = getEfiMemoryMap(bootInfo->memoryMap);
DIE_ON_ERROR("Error getting EFI memory map.");
#undef DUMP_MEMORY_MAP
#endif // defined(DUMP_MEMORY_MAP)

View File

@@ -1,126 +0,0 @@
#include <stddef.h>
namespace
{
inline const size_t INIT_MALLOC_SPACE_ELEMENTS = 1024;
inline const size_t INIT_MALLOC_SPACE_BYTES = INIT_MALLOC_SPACE_ELEMENTS * sizeof(max_align_t);
max_align_t gInitMallocSpace[INIT_MALLOC_SPACE_ELEMENTS];
struct MallocBlock
{
size_t elements;
MallocBlock* nextBlock;
};
struct AllocInfo
{
size_t elements;
};
static_assert(sizeof(MallocBlock) <= sizeof(max_align_t));
static_assert(sizeof(AllocInfo) <= sizeof(max_align_t));
MallocBlock* gNextBlock;
}
void initMiniMalloc()
{
gNextBlock = reinterpret_cast<MallocBlock*>(gInitMallocSpace);
gNextBlock->elements = INIT_MALLOC_SPACE_ELEMENTS;
gNextBlock->nextBlock = nullptr;
}
extern "C"
{
void* malloc(size_t size) noexcept
{
if (size == 0)
{
return nullptr;
}
const size_t requiredElements = (size + sizeof(max_align_t) - 1) / sizeof(max_align_t) + 1;
MallocBlock* prevBlock = nullptr;
for (MallocBlock* block = gNextBlock; block != nullptr; block = block->nextBlock)
{
if (block->elements >= requiredElements)
{
MallocBlock* newBlock = nullptr;
if (block->elements > requiredElements)
{
newBlock = reinterpret_cast<MallocBlock*>(reinterpret_cast<max_align_t*>(block) + requiredElements);
newBlock->nextBlock = block->nextBlock;
newBlock->elements = block->elements - requiredElements;
}
else
{
newBlock = block->nextBlock;
}
if (prevBlock != nullptr)
{
prevBlock->nextBlock = newBlock;
}
else
{
gNextBlock = newBlock;
}
AllocInfo* allocInfo = reinterpret_cast<AllocInfo*>(block);
allocInfo->elements = requiredElements;
return reinterpret_cast<max_align_t*>(block) + 1;
}
prevBlock = block;
}
return nullptr;
}
void free(void* memory) noexcept
{
if (memory == nullptr)
{
return;
}
MallocBlock* block = reinterpret_cast<MallocBlock*>(static_cast<max_align_t*>(memory) - 1);
block->nextBlock = gNextBlock;
gNextBlock = block;
}
}
void* operator new(size_t count)
{
if (void* ptr = malloc(count); ptr != nullptr)
{
return ptr;
}
// TODO: some kind of abort
}
void operator delete(void* data) noexcept
{
free(data);
}
void* operator new[](size_t count)
{
if (void* ptr = malloc(count); ptr != nullptr)
{
return ptr;
}
// TODO: some kind of abort
}
void operator delete[](void* data) noexcept
{
free(data);
}
void operator delete(void* data, size_t /* size */) noexcept
{
free(data);
}
void operator delete[](void* data, size_t /* size */) noexcept
{
free(data);
}