Splitting out UEFI bootloader code from kernel
Now the bootloader should be responsible for all initial setup, loading the kernel, and then handing off to the kernel with proper data in place.
This commit is contained in:
12
src/arch/x86_64/boot.s
Executable file
12
src/arch/x86_64/boot.s
Executable file
@@ -0,0 +1,12 @@
|
||||
; boot.s -- Kernel start location.
|
||||
|
||||
[BITS 64]
|
||||
ALIGN 4
|
||||
|
||||
SECTION .text
|
||||
[GLOBAL start]
|
||||
|
||||
start:
|
||||
; Load multiboot header location
|
||||
mov ebx, 0xdeadbeef
|
||||
jmp $
|
||||
@@ -1,5 +1,5 @@
|
||||
AS := nasm
|
||||
ASFLAGS := -felf
|
||||
ASFLAGS := -felf64
|
||||
LDFLAGS := -m elf_x86_64
|
||||
CFLAGS := -march=nocona -m64
|
||||
|
||||
|
||||
@@ -1,120 +0,0 @@
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "console.h"
|
||||
#include "utility.h"
|
||||
|
||||
UINTN ROWS = 0;
|
||||
UINTN COLS = 0;
|
||||
|
||||
EFI_STATUS
|
||||
con_initialize (const CHAR16 *version)
|
||||
{
|
||||
EFI_STATUS status;
|
||||
|
||||
Print(L"Setting console display mode...\n");
|
||||
|
||||
EFI_GRAPHICS_OUTPUT_PROTOCOL *gfx_out_proto;
|
||||
EFI_GUID gfx_out_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
|
||||
|
||||
status = ST->BootServices->LocateProtocol(
|
||||
&gfx_out_guid, NULL, (void**)&gfx_out_proto);
|
||||
CHECK_EFI_STATUS_OR_RETURN(status, "LocateProtocol gfx");
|
||||
|
||||
const uint32_t modes = gfx_out_proto->Mode->MaxMode;
|
||||
uint32_t res =
|
||||
gfx_out_proto->Mode->Info->HorizontalResolution *
|
||||
gfx_out_proto->Mode->Info->VerticalResolution;
|
||||
uint32_t best = gfx_out_proto->Mode->Mode;
|
||||
|
||||
for (uint32_t i = 0; i < modes; ++i) {
|
||||
UINTN size = 0;
|
||||
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *info = NULL;
|
||||
status = gfx_out_proto->QueryMode(gfx_out_proto, i, &size, &info);
|
||||
CHECK_EFI_STATUS_OR_RETURN(status, "QueryMode");
|
||||
|
||||
#ifdef MAX_HRES
|
||||
if (info->HorizontalResolution > MAX_HRES)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
const uint32_t new_res =
|
||||
info->HorizontalResolution *
|
||||
info->VerticalResolution;
|
||||
|
||||
if (new_res > res) {
|
||||
best = i;
|
||||
res = new_res;
|
||||
}
|
||||
}
|
||||
|
||||
status = gfx_out_proto->SetMode(gfx_out_proto, best);
|
||||
CHECK_EFI_STATUS_OR_RETURN(status, "SetMode %d/%d", best, modes);
|
||||
|
||||
status = ST->ConOut->QueryMode(
|
||||
ST->ConOut,
|
||||
ST->ConOut->Mode->Mode,
|
||||
&COLS, &ROWS);
|
||||
CHECK_EFI_STATUS_OR_RETURN(status, "QueryMode");
|
||||
|
||||
status = ST->ConOut->ClearScreen(ST->ConOut);
|
||||
CHECK_EFI_STATUS_OR_RETURN(status, "ClearScreen");
|
||||
|
||||
ST->ConOut->SetAttribute(ST->ConOut, EFI_LIGHTCYAN);
|
||||
ST->ConOut->OutputString(ST->ConOut, (CHAR16*)L"Popcorn OS ");
|
||||
|
||||
ST->ConOut->SetAttribute(ST->ConOut, EFI_LIGHTMAGENTA);
|
||||
ST->ConOut->OutputString(ST->ConOut, (CHAR16*)version);
|
||||
|
||||
ST->ConOut->SetAttribute(ST->ConOut, EFI_LIGHTGRAY);
|
||||
ST->ConOut->OutputString(ST->ConOut, (CHAR16*)L" booting...\r\n");
|
||||
|
||||
con_status_begin(L"Setting console display mode: ");
|
||||
Print(L"%ux%u (%ux%u chars)",
|
||||
gfx_out_proto->Mode->Info->HorizontalResolution,
|
||||
gfx_out_proto->Mode->Info->VerticalResolution,
|
||||
ROWS, COLS);
|
||||
con_status_ok();
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void
|
||||
con_status_begin (const CHAR16 *message)
|
||||
{
|
||||
ST->ConOut->SetAttribute(ST->ConOut, EFI_LIGHTGRAY);
|
||||
ST->ConOut->OutputString(ST->ConOut, (CHAR16*)message);
|
||||
}
|
||||
|
||||
void
|
||||
con_status_ok ()
|
||||
{
|
||||
UINTN row = ST->ConOut->Mode->CursorRow;
|
||||
ST->ConOut->SetCursorPosition(ST->ConOut, COLS-8, row);
|
||||
ST->ConOut->SetAttribute(ST->ConOut, EFI_LIGHTGRAY);
|
||||
ST->ConOut->OutputString(ST->ConOut, (CHAR16*)L"[");
|
||||
ST->ConOut->SetAttribute(ST->ConOut, EFI_GREEN);
|
||||
ST->ConOut->OutputString(ST->ConOut, (CHAR16*)L" ok ");
|
||||
ST->ConOut->SetAttribute(ST->ConOut, EFI_LIGHTGRAY);
|
||||
ST->ConOut->OutputString(ST->ConOut, (CHAR16*)L"]\r");
|
||||
ST->ConOut->SetCursorPosition(ST->ConOut, 0, row+1);
|
||||
}
|
||||
|
||||
void
|
||||
con_status_fail (const CHAR16 *error)
|
||||
{
|
||||
UINTN row = ST->ConOut->Mode->CursorRow;
|
||||
ST->ConOut->SetCursorPosition(ST->ConOut, COLS-8, row);
|
||||
ST->ConOut->SetAttribute(ST->ConOut, EFI_LIGHTGRAY);
|
||||
ST->ConOut->OutputString(ST->ConOut, (CHAR16*)L"[");
|
||||
ST->ConOut->SetAttribute(ST->ConOut, EFI_LIGHTRED);
|
||||
ST->ConOut->OutputString(ST->ConOut, (CHAR16*)L"failed");
|
||||
ST->ConOut->SetAttribute(ST->ConOut, EFI_LIGHTGRAY);
|
||||
ST->ConOut->OutputString(ST->ConOut, (CHAR16*)L"]\r");
|
||||
ST->ConOut->SetCursorPosition(ST->ConOut, 2, row+1);
|
||||
ST->ConOut->SetAttribute(ST->ConOut, EFI_RED);
|
||||
ST->ConOut->OutputString(ST->ConOut, (CHAR16*)error);
|
||||
ST->ConOut->SetCursorPosition(ST->ConOut, 0, row+2);
|
||||
ST->ConOut->SetAttribute(ST->ConOut, EFI_LIGHTGRAY);
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
#pragma once
|
||||
#include <efi.h>
|
||||
|
||||
EFI_STATUS con_initialize (const CHAR16 *version);
|
||||
void con_status_begin (const CHAR16 *message);
|
||||
void con_status_ok ();
|
||||
void con_status_fail (const CHAR16 *error);
|
||||
26
src/arch/x86_64/kernel.ld
Executable file
26
src/arch/x86_64/kernel.ld
Executable file
@@ -0,0 +1,26 @@
|
||||
ENTRY(start)
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x100000;
|
||||
|
||||
.text : {
|
||||
code = .;
|
||||
*(.text)
|
||||
. = ALIGN(4096);
|
||||
}
|
||||
|
||||
.data : {
|
||||
data = .;
|
||||
*(.data)
|
||||
*(.rodata)
|
||||
. = ALIGN(4096);
|
||||
}
|
||||
|
||||
.bss : {
|
||||
bss = .;
|
||||
*(.bss)
|
||||
. = ALIGN(4096);
|
||||
}
|
||||
|
||||
end = .;
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
|
||||
#include "console.h"
|
||||
#include "memory.h"
|
||||
#include "utility.h"
|
||||
|
||||
#ifndef GIT_VERSION
|
||||
#define GIT_VERSION L"no version"
|
||||
#endif
|
||||
|
||||
EFI_STATUS
|
||||
efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable)
|
||||
{
|
||||
EFI_STATUS status;
|
||||
|
||||
InitializeLib(ImageHandle, SystemTable);
|
||||
|
||||
// When checking the console initialization error,
|
||||
// use CHECK_EFI_STATUS_OR_RETURN because we can't
|
||||
// be sure if the console was fully set up
|
||||
status = con_initialize(GIT_VERSION);
|
||||
CHECK_EFI_STATUS_OR_RETURN(status, "con_initialize");
|
||||
|
||||
// From here on out, use CHECK_EFI_STATUS_OR_FAIL instead
|
||||
// because the console is now set up
|
||||
|
||||
/*
|
||||
Print(L" SystemTable: %x\n", SystemTable);
|
||||
if (SystemTable)
|
||||
Print(L" ConOut: %x\n", SystemTable->ConOut);
|
||||
if (SystemTable->ConOut)
|
||||
Print(L"OutputString: %x\n", SystemTable->ConOut->OutputString);
|
||||
*/
|
||||
|
||||
dump_memory_map();
|
||||
|
||||
UINTN memmap_size = 0;
|
||||
EFI_MEMORY_DESCRIPTOR *memmap;
|
||||
UINTN memmap_key;
|
||||
UINTN desc_size;
|
||||
UINT32 desc_version;
|
||||
|
||||
con_status_begin(L"Exiting boot services");
|
||||
memmap = LibMemoryMap(&memmap_size, &memmap_key,
|
||||
&desc_size, &desc_version);
|
||||
|
||||
status = ST->BootServices->ExitBootServices(ImageHandle, memmap_key);
|
||||
CHECK_EFI_STATUS_OR_FAIL(status);
|
||||
con_status_ok();
|
||||
|
||||
con_status_begin(L"Setting virtual address map");
|
||||
status = ST->RuntimeServices->SetVirtualAddressMap(
|
||||
memmap_size, desc_size, desc_version, memmap);
|
||||
CHECK_EFI_STATUS_OR_FAIL(status);
|
||||
con_status_ok();
|
||||
|
||||
while (1) __asm__("hlt");
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
|
||||
#include "memory.h"
|
||||
#include "utility.h"
|
||||
|
||||
const UINTN PAGE_SIZE = 4096;
|
||||
|
||||
const CHAR16 *memory_type_names[] = {
|
||||
L"EfiReservedMemoryType",
|
||||
L"EfiLoaderCode",
|
||||
L"EfiLoaderData",
|
||||
L"EfiBootServicesCode",
|
||||
L"EfiBootServicesData",
|
||||
L"EfiRuntimeServicesCode",
|
||||
L"EfiRuntimeServicesData",
|
||||
L"EfiConventionalMemory",
|
||||
L"EfiUnusableMemory",
|
||||
L"EfiACPIReclaimMemory",
|
||||
L"EfiACPIMemoryNVS",
|
||||
L"EfiMemoryMappedIO",
|
||||
L"EfiMemoryMappedIOPortSpace",
|
||||
L"EfiPalCode",
|
||||
L"EfiPersistentMemory",
|
||||
};
|
||||
|
||||
const CHAR16 *memory_type_name(UINT32 value) {
|
||||
if (value >= (sizeof(memory_type_names)/sizeof(CHAR16*)))
|
||||
return L"Bad Type Value";
|
||||
return memory_type_names[value];
|
||||
}
|
||||
|
||||
EFI_STATUS get_memory_map(EFI_MEMORY_DESCRIPTOR **buffer, UINTN *buffer_size,
|
||||
UINTN *key, UINTN *desc_size, UINT32 *desc_version) {
|
||||
EFI_STATUS status;
|
||||
|
||||
UINTN needs_size = 0;
|
||||
status = BS->GetMemoryMap(&needs_size, 0, key, desc_size, desc_version);
|
||||
if (status != EFI_BUFFER_TOO_SMALL) {
|
||||
CHECK_EFI_STATUS_OR_RETURN(status, "Failed to load memory map");
|
||||
}
|
||||
|
||||
// Give some extra buffer to account for changes.
|
||||
*buffer_size = needs_size + 256;
|
||||
Print(L"Trying to load memory map with size %d.\n", *buffer_size);
|
||||
status = BS->AllocatePool(EfiLoaderData, *buffer_size, (void**)buffer);
|
||||
CHECK_EFI_STATUS_OR_RETURN(status, "Failed to allocate space for memory map");
|
||||
|
||||
status = BS->GetMemoryMap(buffer_size, *buffer, key, desc_size, desc_version);
|
||||
CHECK_EFI_STATUS_OR_RETURN(status, "Failed to load memory map");
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS dump_memory_map() {
|
||||
EFI_MEMORY_DESCRIPTOR *buffer;
|
||||
UINTN buffer_size, desc_size, key;
|
||||
UINT32 desc_version;
|
||||
|
||||
EFI_STATUS status = get_memory_map(&buffer, &buffer_size, &key,
|
||||
&desc_size, &desc_version);
|
||||
CHECK_EFI_STATUS_OR_RETURN(status, "Failed to get memory map");
|
||||
|
||||
const UINTN count = buffer_size / desc_size;
|
||||
|
||||
Print(L"Memory map:\n");
|
||||
Print(L"\t Descriptor Count: %d (%d bytes)\n", count, buffer_size);
|
||||
Print(L"\t Version Key: %d\n", key);
|
||||
Print(L"\tDescriptor Version: %d (%d bytes)\n\n", desc_version, desc_size);
|
||||
|
||||
EFI_MEMORY_DESCRIPTOR *end = (EFI_MEMORY_DESCRIPTOR *)((uint8_t *)buffer + buffer_size);
|
||||
EFI_MEMORY_DESCRIPTOR *d = buffer;
|
||||
while (d < end) {
|
||||
UINTN size_bytes = d->NumberOfPages * PAGE_SIZE;
|
||||
|
||||
Print(L"Type: %s Attr: 0x%x\n", memory_type_name(d->Type), d->Attribute);
|
||||
Print(L"\t Physical %016llx - %016llx\n", d->PhysicalStart, d->PhysicalStart + size_bytes);
|
||||
Print(L"\t Virtual %016llx - %016llx\n\n", d->VirtualStart, d->VirtualStart + size_bytes);
|
||||
|
||||
d = (EFI_MEMORY_DESCRIPTOR *)((uint8_t *)d + desc_size);
|
||||
}
|
||||
|
||||
BS->FreePool(buffer);
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
#include <efi.h>
|
||||
|
||||
const CHAR16 *memory_type_name(UINT32 value);
|
||||
|
||||
EFI_STATUS get_memory_map(
|
||||
EFI_MEMORY_DESCRIPTOR **buffer,
|
||||
UINTN *buffer_size,
|
||||
UINTN *key,
|
||||
UINTN *desc_size,
|
||||
UINT32 *desc_version);
|
||||
|
||||
EFI_STATUS dump_memory_map();
|
||||
@@ -1,18 +0,0 @@
|
||||
#include <efi.h>
|
||||
|
||||
struct ErrorCode {
|
||||
EFI_STATUS code;
|
||||
const CHAR16 *desc;
|
||||
};
|
||||
|
||||
extern struct ErrorCode ErrorCodeTable[];
|
||||
|
||||
const CHAR16 *util_error_message(EFI_STATUS status) {
|
||||
int32_t i = -1;
|
||||
while (ErrorCodeTable[++i].desc != NULL) {
|
||||
if (ErrorCodeTable[i].code == status)
|
||||
return ErrorCodeTable[i].desc;
|
||||
}
|
||||
|
||||
return L"Unknown";
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
#include <efi.h>
|
||||
#include <efilib.h>
|
||||
#include "console.h"
|
||||
|
||||
const CHAR16 *util_error_message(EFI_STATUS status);
|
||||
|
||||
#define CHECK_EFI_STATUS_OR_RETURN(s, msg, ...) \
|
||||
if (EFI_ERROR((s))) { \
|
||||
Print(L"EFI_ERROR: " msg L": %s\n", ## __VA_ARGS__, util_error_message(s)); \
|
||||
return (s); \
|
||||
}
|
||||
|
||||
#define CHECK_EFI_STATUS_OR_FAIL(s) \
|
||||
if (EFI_ERROR((s))) { \
|
||||
con_status_fail(util_error_message(s)); \
|
||||
while (1) __asm__("hlt"); \
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user