586 lines
21 KiB
C
586 lines
21 KiB
C
// UEFI Bootloader for 64-bit kernel
|
||
// GNU-EFI based bootloader - FINAL PRODUCTION VERSION (FULLY COMPATIBLE)
|
||
// Complies with UEFI Spec 2.8 + x86_64 System V ABI
|
||
// Compatible with old GNU-EFI (<3.0) + C99 compilers + legacy firmware
|
||
|
||
#include <efi.h>
|
||
#include <efilib.h>
|
||
#include <stdint.h>
|
||
#include <assert.h>
|
||
|
||
// ==========================
|
||
// Compatibility Macros (Critical for Legacy Environments)
|
||
// ==========================
|
||
// Fix EFI_MEMORY_WB missing in old GNU-EFI versions
|
||
#ifndef EFI_MEMORY_WB
|
||
#define EFI_MEMORY_WB 0x0000000000000040ULL // WriteBack memory attribute
|
||
#endif
|
||
|
||
// Fix _Static_assert missing in C99 (use typedef fallback)
|
||
#if __STDC_VERSION__ >= 201112L
|
||
#define STATIC_ASSERT(expr, msg) _Static_assert(expr, #msg)
|
||
#else
|
||
#define STATIC_ASSERT(expr, msg) typedef char static_assert_##msg[(expr) ? 1 : -1]
|
||
#endif
|
||
|
||
// Kernel boot info structure
|
||
typedef struct {
|
||
unsigned long memmap_addr;
|
||
unsigned long memmap_size;
|
||
unsigned long memmap_desc_size;
|
||
unsigned long kernel_phys_addr;
|
||
unsigned long framebuffer_addr;
|
||
unsigned long framebuffer_size;
|
||
unsigned long framebuffer_width;
|
||
unsigned long framebuffer_height;
|
||
unsigned long framebuffer_pitch;
|
||
unsigned long framebuffer_format;
|
||
unsigned long system_table;
|
||
} boot_info_t;
|
||
|
||
// Kernel entry point type
|
||
typedef void (*KernelEntry)(boot_info_t*) __attribute__((noreturn));
|
||
|
||
// ==========================
|
||
// Core Configuration (Type-Safe + Compile-Time Validated)
|
||
// ==========================
|
||
// Kernel load address (matches kernel link address, 4KB page aligned)
|
||
#define KERNEL_LOAD_ADDRESS 0x100000ULL // unsigned long long (x86_64 safe)
|
||
// Fallback address for dynamic allocation (if fixed address is reserved)
|
||
#define KERNEL_FALLBACK_ADDRESS 0x200000ULL // 2MB fallback (avoid 1MB reserved)
|
||
// x86_64 code/data alignment requirement (16-byte for ABI compliance)
|
||
#define KERNEL_ALIGNMENT 16U
|
||
|
||
// ==========================
|
||
// Stack Configuration (ABI Compliant + Type-Safe)
|
||
// ==========================
|
||
// x86_64 System V ABI: RSP must be 16-byte aligned BEFORE call instruction
|
||
// call pushes 8-byte return address → RSP = STACK_TOP - 8 (still 16-byte aligned)
|
||
#define BOOTLOADER_STACK_SIZE 0x20000ULL // 128KB stack (type-safe)
|
||
#define BOOTLOADER_STACK_TOP 0x80000ULL // 16-byte aligned (0x80000 % 16 = 0)
|
||
#define BOOTLOADER_STACK_BOTTOM (BOOTLOADER_STACK_TOP - BOOTLOADER_STACK_SIZE)
|
||
|
||
// ==========================
|
||
// Compile-Time Assertions (Critical Validations)
|
||
// ==========================
|
||
// Ensure stack top is 16-byte aligned (x86_64 ABI requirement)
|
||
STATIC_ASSERT((BOOTLOADER_STACK_TOP % 16U) == 0U, StackTopNotAligned);
|
||
// Ensure kernel address is 4KB page aligned (UEFI AllocatePages requirement)
|
||
STATIC_ASSERT((KERNEL_LOAD_ADDRESS % 0x1000ULL) == 0ULL, KernelAddrNotPageAligned);
|
||
// Ensure stack size is positive and non-zero
|
||
STATIC_ASSERT(BOOTLOADER_STACK_SIZE > 0ULL, StackSizeZero);
|
||
// Ensure stack region does not overlap with kernel load address
|
||
STATIC_ASSERT(BOOTLOADER_STACK_TOP < KERNEL_LOAD_ADDRESS, StackOverlapsKernel);
|
||
// Ensure fallback address is page aligned
|
||
STATIC_ASSERT((KERNEL_FALLBACK_ADDRESS % 0x1000ULL) == 0ULL, FallbackAddrNotPageAligned);
|
||
|
||
// ==========================
|
||
// Validate Stack Memory Region (Robust Descriptor Traversal)
|
||
// ==========================
|
||
EFI_STATUS ValidateStackMemory(EFI_SYSTEM_TABLE *SystemTable) {
|
||
EFI_STATUS Status;
|
||
UINTN MemoryMapSize = 0U;
|
||
UINTN MapKey;
|
||
UINTN DescriptorSize;
|
||
UINT32 DescriptorVersion;
|
||
EFI_MEMORY_DESCRIPTOR *MemoryMap = NULL;
|
||
EFI_MEMORY_DESCRIPTOR *Descriptor;
|
||
UINTN NumDescriptors;
|
||
BOOLEAN StackRegionValid = FALSE;
|
||
|
||
// Get memory map size (first call - get required size)
|
||
Status = SystemTable->BootServices->GetMemoryMap(
|
||
&MemoryMapSize,
|
||
MemoryMap,
|
||
&MapKey,
|
||
&DescriptorSize,
|
||
&DescriptorVersion
|
||
);
|
||
if (Status != EFI_BUFFER_TOO_SMALL) {
|
||
Print(L"Error: GetMemoryMap failed (size check) - %r\r\n", Status);
|
||
return Status;
|
||
}
|
||
|
||
// Allocate buffer with extra space (safety margin for firmware changes)
|
||
MemoryMapSize += 2U * DescriptorSize;
|
||
Status = SystemTable->BootServices->AllocatePool(
|
||
EfiLoaderData,
|
||
MemoryMapSize,
|
||
(VOID**)&MemoryMap
|
||
);
|
||
if (EFI_ERROR(Status)) {
|
||
Print(L"Error: Allocate MemoryMap failed - %r\r\n", Status);
|
||
return Status;
|
||
}
|
||
|
||
// Get actual memory map
|
||
Status = SystemTable->BootServices->GetMemoryMap(
|
||
&MemoryMapSize,
|
||
MemoryMap,
|
||
&MapKey,
|
||
&DescriptorSize,
|
||
&DescriptorVersion
|
||
);
|
||
if (EFI_ERROR(Status)) {
|
||
Print(L"Error: GetMemoryMap failed (actual) - %r\r\n", Status);
|
||
SystemTable->BootServices->FreePool(MemoryMap);
|
||
return Status;
|
||
}
|
||
|
||
// Check if stack region is usable conventional memory
|
||
// FIX: Traverse ALL descriptors until valid one is found (no premature break)
|
||
Descriptor = MemoryMap;
|
||
NumDescriptors = MemoryMapSize / DescriptorSize;
|
||
|
||
for (UINTN i = 0U; i < NumDescriptors; i++) {
|
||
const UINT64 DescStart = Descriptor->PhysicalStart;
|
||
const UINT64 DescEnd = DescStart + (Descriptor->NumberOfPages * 0x1000ULL);
|
||
|
||
// Check if descriptor fully covers stack region
|
||
if (DescStart <= BOOTLOADER_STACK_BOTTOM && DescEnd >= BOOTLOADER_STACK_TOP) {
|
||
// Must be writable conventional memory (EfiConventionalMemory + WriteBack)
|
||
if (Descriptor->Type == EfiConventionalMemory &&
|
||
(Descriptor->Attribute & EFI_MEMORY_WB)) {
|
||
StackRegionValid = TRUE;
|
||
break; // Only break when valid descriptor is found
|
||
}
|
||
// Continue traversal if descriptor covers stack but is invalid
|
||
}
|
||
|
||
// Move to next descriptor (correct pointer arithmetic for x86_64)
|
||
Descriptor = (EFI_MEMORY_DESCRIPTOR*)((UINT8*)Descriptor + DescriptorSize);
|
||
}
|
||
|
||
// Cleanup memory map (safe to free - only used for validation)
|
||
SystemTable->BootServices->FreePool(MemoryMap);
|
||
|
||
// Final validation check
|
||
if (!StackRegionValid) {
|
||
Print(L"Error: Stack region 0x%lx-0x%lx is not usable conventional memory\r\n",
|
||
BOOTLOADER_STACK_BOTTOM, BOOTLOADER_STACK_TOP);
|
||
return EFI_INVALID_PARAMETER;
|
||
}
|
||
|
||
Print(L"✅ Stack region validated: 0x%lx-0x%lx\r\n",
|
||
BOOTLOADER_STACK_BOTTOM, BOOTLOADER_STACK_TOP);
|
||
return EFI_SUCCESS;
|
||
}
|
||
|
||
// ==========================
|
||
// Read Kernel File from Disk (Resource-Safe + Fallback Allocation)
|
||
// ==========================
|
||
EFI_STATUS ReadKernelFile(
|
||
EFI_HANDLE ImageHandle,
|
||
EFI_SYSTEM_TABLE *SystemTable,
|
||
VOID **KernelBuffer,
|
||
UINTN *KernelSize
|
||
) {
|
||
EFI_STATUS Status;
|
||
EFI_LOADED_IMAGE *LoadedImage = NULL;
|
||
EFI_FILE_IO_INTERFACE *FileIo = NULL;
|
||
EFI_FILE_HANDLE RootDir = NULL;
|
||
EFI_FILE_HANDLE KernelFile = NULL;
|
||
EFI_FILE_INFO *FileInfo = NULL;
|
||
UINTN InfoSize = 0U;
|
||
const CHAR16 KernelPath[] = L"\\sys\\kernel\\x86_64\\kernel.bin";
|
||
|
||
// Initialize outputs to safe values (prevent wild pointers)
|
||
*KernelBuffer = NULL;
|
||
*KernelSize = 0U;
|
||
|
||
// Get Loaded Image Protocol (to find boot device)
|
||
Status = SystemTable->BootServices->HandleProtocol(
|
||
ImageHandle,
|
||
&gEfiLoadedImageProtocolGuid,
|
||
(VOID**)&LoadedImage
|
||
);
|
||
if (EFI_ERROR(Status)) {
|
||
Print(L"Error: Get LoadedImage Protocol - %r\r\n", Status);
|
||
return Status;
|
||
}
|
||
|
||
// Get Simple File System Protocol
|
||
Status = SystemTable->BootServices->HandleProtocol(
|
||
LoadedImage->DeviceHandle,
|
||
&gEfiSimpleFileSystemProtocolGuid,
|
||
(VOID**)&FileIo
|
||
);
|
||
if (EFI_ERROR(Status)) {
|
||
Print(L"Error: Get FileSystem Protocol - %r\r\n", Status);
|
||
return Status;
|
||
}
|
||
|
||
// Open root directory
|
||
Status = FileIo->OpenVolume(FileIo, &RootDir);
|
||
if (EFI_ERROR(Status)) {
|
||
Print(L"Error: Open Root Directory - %r\r\n", Status);
|
||
return Status;
|
||
}
|
||
|
||
// Open kernel file (read-only)
|
||
Status = RootDir->Open(
|
||
RootDir,
|
||
&KernelFile,
|
||
(CHAR16*)KernelPath,
|
||
EFI_FILE_MODE_READ,
|
||
0U
|
||
);
|
||
if (EFI_ERROR(Status)) {
|
||
Print(L"Error: Open Kernel File %s - %r\r\n", KernelPath, Status);
|
||
RootDir->Close(RootDir);
|
||
return Status;
|
||
}
|
||
|
||
// Get file size (first call - get required buffer size)
|
||
Status = KernelFile->GetInfo(
|
||
KernelFile,
|
||
&gEfiFileInfoGuid,
|
||
&InfoSize,
|
||
NULL
|
||
);
|
||
if (Status != EFI_BUFFER_TOO_SMALL) {
|
||
Print(L"Error: Get FileInfo Size - %r\r\n", Status);
|
||
KernelFile->Close(KernelFile);
|
||
RootDir->Close(RootDir);
|
||
return Status;
|
||
}
|
||
|
||
// Allocate buffer for file info
|
||
Status = SystemTable->BootServices->AllocatePool(
|
||
EfiLoaderData,
|
||
InfoSize,
|
||
(VOID**)&FileInfo
|
||
);
|
||
if (EFI_ERROR(Status)) {
|
||
Print(L"Error: Allocate FileInfo - %r\r\n", Status);
|
||
KernelFile->Close(KernelFile);
|
||
RootDir->Close(RootDir);
|
||
return Status;
|
||
}
|
||
|
||
// Get actual file info
|
||
Status = KernelFile->GetInfo(
|
||
KernelFile,
|
||
&gEfiFileInfoGuid,
|
||
&InfoSize,
|
||
FileInfo
|
||
);
|
||
if (EFI_ERROR(Status)) {
|
||
Print(L"Error: Get FileInfo - %r\r\n", Status);
|
||
SystemTable->BootServices->FreePool(FileInfo);
|
||
KernelFile->Close(KernelFile);
|
||
RootDir->Close(RootDir);
|
||
return Status;
|
||
}
|
||
|
||
// Validate file size (non-empty)
|
||
*KernelSize = FileInfo->FileSize;
|
||
if (*KernelSize == 0U) {
|
||
Print(L"Error: Kernel File is Empty\r\n");
|
||
SystemTable->BootServices->FreePool(FileInfo);
|
||
KernelFile->Close(KernelFile);
|
||
RootDir->Close(RootDir);
|
||
return EFI_INVALID_PARAMETER;
|
||
}
|
||
|
||
// Allocate physical pages (fixed address first, fallback to dynamic)
|
||
const UINTN PagesNeeded = (*KernelSize + 0xFFFU) / 0x1000U; // Round up to 4KB pages
|
||
EFI_PHYSICAL_ADDRESS KernelPhysAddr = KERNEL_LOAD_ADDRESS;
|
||
|
||
// Step 1: Try fixed address allocation (preferred)
|
||
Status = SystemTable->BootServices->AllocatePages(
|
||
AllocateAddress, // Fixed address allocation (matches kernel link address)
|
||
EfiLoaderCode, // Memory type: executable code
|
||
PagesNeeded,
|
||
&KernelPhysAddr
|
||
);
|
||
|
||
// Step 2: Fallback to dynamic allocation if fixed address fails
|
||
if (EFI_ERROR(Status)) {
|
||
Print(L"Warning: Fixed address allocation (0x%lx) failed - %r\r\n",
|
||
KERNEL_LOAD_ADDRESS, Status);
|
||
Print(L"Falling back to dynamic allocation at 0x%lx...\r\n", KERNEL_FALLBACK_ADDRESS);
|
||
|
||
KernelPhysAddr = KERNEL_FALLBACK_ADDRESS;
|
||
Status = SystemTable->BootServices->AllocatePages(
|
||
AllocateAnyPages, // Dynamic allocation (UEFI chooses address)
|
||
EfiLoaderCode,
|
||
PagesNeeded,
|
||
&KernelPhysAddr
|
||
);
|
||
|
||
if (EFI_ERROR(Status)) {
|
||
Print(L"Error: Dynamic allocation failed - %r\r\n", Status);
|
||
SystemTable->BootServices->FreePool(FileInfo);
|
||
KernelFile->Close(KernelFile);
|
||
RootDir->Close(RootDir);
|
||
return Status;
|
||
}
|
||
}
|
||
|
||
// Validate kernel address alignment (x86_64 requirement)
|
||
if ((UINTN)KernelPhysAddr % KERNEL_ALIGNMENT != 0U) {
|
||
Print(L"Error: Kernel Address Not Aligned (0x%lx, req: %d bytes)\r\n",
|
||
KernelPhysAddr, KERNEL_ALIGNMENT);
|
||
SystemTable->BootServices->FreePages(KernelPhysAddr, PagesNeeded);
|
||
SystemTable->BootServices->FreePool(FileInfo);
|
||
KernelFile->Close(KernelFile);
|
||
RootDir->Close(RootDir);
|
||
return EFI_INVALID_PARAMETER;
|
||
}
|
||
|
||
// Read kernel file into allocated memory
|
||
*KernelBuffer = (VOID*)KernelPhysAddr;
|
||
Status = KernelFile->Read(KernelFile, KernelSize, *KernelBuffer);
|
||
if (EFI_ERROR(Status)) {
|
||
Print(L"Error: Read Kernel File - %r\r\n", Status);
|
||
SystemTable->BootServices->FreePages(KernelPhysAddr, PagesNeeded);
|
||
SystemTable->BootServices->FreePool(FileInfo);
|
||
KernelFile->Close(KernelFile);
|
||
RootDir->Close(RootDir);
|
||
return Status;
|
||
}
|
||
|
||
// Success - print kernel info
|
||
Print(L"✅ Kernel Loaded Successfully\r\n");
|
||
Print(L" Address: 0x%lx (aligned to %d bytes)\r\n", KernelPhysAddr, KERNEL_ALIGNMENT);
|
||
Print(L" Size: %lu bytes (%lu pages)\r\n", *KernelSize, PagesNeeded);
|
||
|
||
// Cleanup resources (all allocated resources freed)
|
||
SystemTable->BootServices->FreePool(FileInfo);
|
||
KernelFile->Close(KernelFile);
|
||
RootDir->Close(RootDir);
|
||
|
||
return EFI_SUCCESS;
|
||
}
|
||
|
||
// ==========================
|
||
// 修复版:兼容老旧/定制UEFI固件的ExitBootServices + 内核跳转
|
||
// 核心:显示所有GOP模式 + 默认使用第0个(第一个)模式
|
||
// ==========================
|
||
EFI_STATUS ExitBootServicesAndJumpToKernel(
|
||
EFI_HANDLE ImageHandle,
|
||
EFI_SYSTEM_TABLE *SystemTable,
|
||
VOID *KernelBuffer
|
||
) {
|
||
EFI_STATUS Status = EFI_SUCCESS;
|
||
|
||
// ==========================
|
||
// 前置校验
|
||
// ==========================
|
||
UINT64 ActualKernelAddr = (UINT64)KernelBuffer;
|
||
Print(L"Kernel Address: 0x%lx\r\n", ActualKernelAddr);
|
||
|
||
UINT8 *KernelCode = (UINT8*)KernelBuffer;
|
||
Print(L"Kernel First Byte: 0x%02x\r\n", KernelCode[0]);
|
||
|
||
// ==========================
|
||
// 获取GOP
|
||
// ==========================
|
||
EFI_GRAPHICS_OUTPUT_PROTOCOL *Gop = NULL;
|
||
EFI_STATUS GopStatus = SystemTable->BootServices->LocateProtocol(
|
||
&gEfiGraphicsOutputProtocolGuid,
|
||
NULL,
|
||
(VOID**)&Gop
|
||
);
|
||
|
||
unsigned long framebuffer_addr = 0;
|
||
unsigned long framebuffer_size = 0;
|
||
unsigned long framebuffer_width = 0;
|
||
unsigned long framebuffer_height = 0;
|
||
unsigned long framebuffer_pitch = 0;
|
||
unsigned long framebuffer_format = 0;
|
||
|
||
Print(L"GopStatus: %r\r\n", GopStatus);
|
||
Print(L"Gop: 0x%lx\r\n", (unsigned long)Gop);
|
||
|
||
// ==========================
|
||
// 显示所有 GOP 模式 + 分辨率,并使用第 0 个模式
|
||
// ==========================
|
||
if (!EFI_ERROR(GopStatus) && Gop != NULL) {
|
||
Print(L"\n=== All Supported Graphics Modes ===\r\n");
|
||
UINTN MaxMode = Gop->Mode->MaxMode;
|
||
|
||
// 遍历并打印所有模式
|
||
for (UINTN i = 0; i < MaxMode; i++) {
|
||
EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
|
||
UINTN SizeOfInfo;
|
||
EFI_STATUS s = Gop->QueryMode(Gop, i, &SizeOfInfo, &Info);
|
||
if (EFI_ERROR(s)) continue;
|
||
|
||
UINT32 W = Info->HorizontalResolution;
|
||
UINT32 H = Info->VerticalResolution;
|
||
Print(L"Mode %2lu: %lux%lu\r\n", i, W, H);
|
||
}
|
||
Print(L"====================================\r\n");
|
||
|
||
// ==========================
|
||
// 关键:强制使用模式
|
||
// ==========================
|
||
UINTN UseMode = 15;
|
||
Status = Gop->SetMode(Gop, UseMode);
|
||
if (!EFI_ERROR(Status)) {
|
||
Print(L"✅ Using Mode %lu: %lux%lu\r\n",
|
||
UseMode,
|
||
Gop->Mode->Info->HorizontalResolution,
|
||
Gop->Mode->Info->VerticalResolution);
|
||
}
|
||
|
||
// 读取帧缓冲信息
|
||
if (Gop->Mode != NULL && Gop->Mode->FrameBufferBase != 0) {
|
||
framebuffer_addr = (unsigned long)Gop->Mode->FrameBufferBase;
|
||
framebuffer_size = Gop->Mode->FrameBufferSize;
|
||
framebuffer_width = Gop->Mode->Info->HorizontalResolution;
|
||
framebuffer_height = Gop->Mode->Info->VerticalResolution;
|
||
framebuffer_pitch = Gop->Mode->Info->PixelsPerScanLine * 4;
|
||
|
||
// 像素格式
|
||
switch (Gop->Mode->Info->PixelFormat) {
|
||
case PixelRedGreenBlueReserved8BitPerColor: framebuffer_format = 0; break;
|
||
case PixelBlueGreenRedReserved8BitPerColor: framebuffer_format = 1; break;
|
||
case PixelBitMask: framebuffer_format = 2; break;
|
||
case PixelBltOnly: framebuffer_format = 3; break;
|
||
default: framebuffer_format = 1; break;
|
||
}
|
||
|
||
UINT64 calc_size = framebuffer_width * framebuffer_height * 4;
|
||
if (framebuffer_size < calc_size) framebuffer_size = calc_size;
|
||
}
|
||
}
|
||
|
||
// ==========================
|
||
// 兜底:GOP不可用时使用 1920×1080
|
||
// ==========================
|
||
if (framebuffer_addr == 0) {
|
||
Print(L"Warning: Using fallback 1920x1080\r\n");
|
||
framebuffer_addr = 0x80000000;
|
||
framebuffer_width = 1920;
|
||
framebuffer_height = 1080;
|
||
framebuffer_pitch = 1920 * 4;
|
||
framebuffer_size = 1920 * 1080 * 4;
|
||
framebuffer_format = 1;
|
||
}
|
||
|
||
Print(L"Final FB: 0x%lx | %lux%lu | pitch %lu | format %lu\r\n",
|
||
framebuffer_addr, framebuffer_width, framebuffer_height, framebuffer_pitch, framebuffer_format);
|
||
|
||
// ==========================
|
||
// ExitBootServices 流程
|
||
// ==========================
|
||
Print(L"Exiting Boot Services...\r\n");
|
||
|
||
UINTN MemoryMapSize = 0;
|
||
UINTN MapKey;
|
||
UINTN DescriptorSize;
|
||
UINT32 DescriptorVersion;
|
||
EFI_MEMORY_DESCRIPTOR *MemoryMap = NULL;
|
||
|
||
do {
|
||
Status = SystemTable->BootServices->GetMemoryMap(
|
||
&MemoryMapSize, NULL, &MapKey, &DescriptorSize, &DescriptorVersion
|
||
);
|
||
if (Status != EFI_BUFFER_TOO_SMALL) break;
|
||
|
||
if (MemoryMap) SystemTable->BootServices->FreePool(MemoryMap);
|
||
MemoryMapSize += 2 * DescriptorSize;
|
||
|
||
Status = SystemTable->BootServices->AllocatePool(
|
||
EfiLoaderData, MemoryMapSize, (VOID**)&MemoryMap
|
||
);
|
||
if (EFI_ERROR(Status)) return Status;
|
||
|
||
Status = SystemTable->BootServices->GetMemoryMap(
|
||
&MemoryMapSize, MemoryMap, &MapKey, &DescriptorSize, &DescriptorVersion
|
||
);
|
||
} while (Status == EFI_BUFFER_TOO_SMALL);
|
||
|
||
if (EFI_ERROR(Status)) return Status;
|
||
|
||
// 将MemoryMap复制到静态缓冲区,避免ExitBootServices后数据被覆盖
|
||
static UINT8 SafeMemmap[16384]; // 16KB should be enough for memory map
|
||
if (MemoryMapSize <= sizeof(SafeMemmap)) {
|
||
__builtin_memcpy(SafeMemmap, MemoryMap, MemoryMapSize);
|
||
}
|
||
|
||
// 构造启动信息
|
||
boot_info_t BootInfo;
|
||
BootInfo.memmap_addr = (unsigned long)(MemoryMapSize <= sizeof(SafeMemmap) ? (void*)SafeMemmap : (void*)MemoryMap);
|
||
BootInfo.memmap_size = MemoryMapSize;
|
||
BootInfo.memmap_desc_size = DescriptorSize;
|
||
BootInfo.kernel_phys_addr = (unsigned long)KernelBuffer;
|
||
BootInfo.framebuffer_addr = framebuffer_addr;
|
||
BootInfo.framebuffer_size = framebuffer_size;
|
||
BootInfo.framebuffer_width = framebuffer_width;
|
||
BootInfo.framebuffer_height = framebuffer_height;
|
||
BootInfo.framebuffer_pitch = framebuffer_pitch;
|
||
BootInfo.framebuffer_format = framebuffer_format;
|
||
BootInfo.system_table = 0;
|
||
|
||
static boot_info_t static_boot_info;
|
||
static_boot_info = BootInfo;
|
||
void* stack_top = (void*)0x80000;
|
||
|
||
// 退出UEFI引导服务
|
||
Status = SystemTable->BootServices->ExitBootServices(ImageHandle, MapKey);
|
||
if (EFI_ERROR(Status)) return Status;
|
||
|
||
// 跳转到内核
|
||
__asm__ volatile (
|
||
".intel_syntax noprefix\n"
|
||
"cli\n"
|
||
"cld\n"
|
||
"mov rdi, %1\n"
|
||
"mov rsp, %2\n"
|
||
"jmp %0\n"
|
||
".att_syntax\n"
|
||
: : "r"(KernelBuffer), "r"(&static_boot_info), "r"(stack_top)
|
||
);
|
||
|
||
while (1) __asm__ volatile ("hlt");
|
||
return EFI_SUCCESS;
|
||
}
|
||
|
||
// ==========================
|
||
// Main UEFI Entry Point (Clean + Readable)
|
||
// ==========================
|
||
EFI_STATUS efi_main (EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
|
||
EFI_STATUS Status;
|
||
VOID *KernelBuffer = NULL;
|
||
UINTN KernelSize = 0U;
|
||
UINT64 CurrentRsp;
|
||
|
||
// Initialize GNU-EFI library (required for Print/Protocol access)
|
||
InitializeLib(ImageHandle, SystemTable);
|
||
|
||
// Print bootloader header (user feedback)
|
||
Print(L"\n=== UD UEFI Bootloader (x86_64) ===\r\n");
|
||
Print(L"=====================================\r\n");
|
||
|
||
// Print initial system info (debug/validation)
|
||
__asm__ volatile ("mov %%rsp, %0" : "=r" (CurrentRsp));
|
||
Print(L"Initial RSP: 0x%lx\r\n", CurrentRsp);
|
||
Print(L"Kernel Load Address (fixed): 0x%lx\r\n", KERNEL_LOAD_ADDRESS);
|
||
Print(L"Kernel Fallback Address: 0x%lx\r\n", KERNEL_FALLBACK_ADDRESS);
|
||
Print(L"Stack Region: 0x%lx-0x%lx\r\n",
|
||
BOOTLOADER_STACK_BOTTOM, BOOTLOADER_STACK_TOP);
|
||
|
||
// Step 1: Load kernel from disk
|
||
Print(L"\n[1/3] Loading Kernel...\r\n");
|
||
Status = ReadKernelFile(ImageHandle, SystemTable, &KernelBuffer, &KernelSize);
|
||
if (EFI_ERROR(Status)) {
|
||
Print(L"Error: Kernel Load Failed - %r\r\n", Status);
|
||
return Status;
|
||
}
|
||
|
||
// Step 2: Exit boot services and jump to kernel
|
||
Print(L"\n[2/3] Exiting Boot Services...(If you see 3/3, that's mean the kernel has finished, that is an error!)\r\n");
|
||
Status = ExitBootServicesAndJumpToKernel(ImageHandle, SystemTable, KernelBuffer);
|
||
Print(L"\n[3/3] OK...\r\n");
|
||
if (EFI_ERROR(Status)) {
|
||
Print(L"Error: Jump to Kernel Failed - %r\r\n", Status);
|
||
return Status;
|
||
}
|
||
|
||
// Unreachable (kernel is marked noreturn)
|
||
return EFI_SUCCESS;
|
||
} |