Das Projekt Bootloader geht in die zweite Runde. Ziel der Reise ist das Hauptverzeichnis…
Zugriff auf Boot-Medium und Hauptverzeichnis:
#include <stdint.h>
// ===================================================================
// 1. BASISTYPEN & DEFINITIONEN
// ===================================================================
typedef unsigned long long UINTN;
typedef long long INTN;
typedef void *EFI_HANDLE;
typedef INTN EFI_STATUS;
#define EFI_SUCCESS 0
typedef struct {
uint32_t Data1;
uint16_t Data2;
uint16_t Data3;
uint8_t Data4[8];
} EFI_GUID;
// Die "Ausweise" für die UEFI-Dienste, die wir suchen
static EFI_GUID LoadedImageProtocolGuid = {0x5B1B31A1, 0x9562, 0x11D2, {0x8E, 0x3F, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B}};
static EFI_GUID SimpleFileSystemProtocolGuid = {0x0964E5B2, 0x82F1, 0x11D2, {0x8E, 0x39, 0x00, 0xA0, 0xC9, 0x69, 0x72, 0x3B}};
// ====================================================================
// 2. UEFI PROTOKOLLE & FUNKTIONSZEIGER
// ====================================================================
// --- VORAB-DEKLARATIONEN (Damit der Compiler die Typen kennt) ---
struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL;
struct _EFI_SIMPLE_FILE_SYSTEM_PROTOCOL;
struct _EFI_FILE_PROTOCOL;
// --- Textausgabe (Kapitel 1) ---
typedef EFI_STATUS (__attribute__((ms_abi)) *EFI_TEXT_STR)(struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This, const uint16_t *String);
typedef EFI_STATUS (__attribute__((ms_abi)) *EFI_TEXT_CLR)(struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This);
typedef struct _EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL {
void *Reset;
EFI_TEXT_STR OutputString;
void *TestString;
void *QueryMode;
void *SetMode;
void *SetAttribute;
EFI_TEXT_CLR ClearScreen;
} EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL;
// --- Dateisystem (Kapitel 2) ---
typedef EFI_STATUS (__attribute__((ms_abi)) *EFI_VOLUME_OPEN)(struct _EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *This, struct _EFI_FILE_PROTOCOL **Root);
typedef struct _EFI_SIMPLE_FILE_SYSTEM_PROTOCOL {
uint64_t Revision;
EFI_VOLUME_OPEN OpenVolume;
} EFI_SIMPLE_FILE_SYSTEM_PROTOCOL;
typedef struct {
uint32_t Revision;
EFI_HANDLE ParentHandle;
void *SystemTable;
EFI_HANDLE DeviceHandle; // Zeigt auf das Laufwerk, von dem wir gebootet haben
} EFI_LOADED_IMAGE_PROTOCOL;
// ====================================================================
// 3. UEFI SYSTEM-TABELLEN (Die Infrastruktur)
// ====================================================================
// Boot Services (Wichtig: HandleProtocol muss an der exakten Stelle sitzen!)
typedef EFI_STATUS (__attribute__((ms_abi)) *EFI_HANDLE_PROTOCOL)(EFI_HANDLE Handle, EFI_GUID *Protocol, void **Interface);
typedef struct {
char Header[24];
void *RaiseTPL; void *RestoreTPL; void *AllocatePages; void *FreePages;
void *GetMemoryMap; void *AllocatePool; void *FreePool; void *CreateEvent;
void *SetTimer; void *WaitForEvent; void *SignalEvent; void *CloseEvent;
void *CheckEvent; void *InstallProtocolInterface; void *ReinstallProtocolInterface;
void *UninstallProtocolInterface;
EFI_HANDLE_PROTOCOL HandleProtocol; // Unsere Suchfunktion
} EFI_BOOT_SERVICES;
// Haupttabelle (Erweitert um StandardError und BootServices am Ende)
typedef struct {
char Header[24];
void *FirmwareVendor;
uint32_t FirmwareRevision;
EFI_HANDLE ConsoleInHandle;
void *ConIn;
EFI_HANDLE ConsoleOutHandle;
EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
void *StandardError; // Platzhalter, um die richtige Reihenfolge zu wahren
EFI_BOOT_SERVICES *BootServices; // <--- WICHTIG: Hier angedockt!
} EFI_SYSTEM_TABLE;
// ============================================================================
// 4. EINSTIEGSPUNKT (Die Logik)
// ============================================================================
__attribute__((ms_abi))
EFI_STATUS efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE *SystemTable) {
// 1. Start-Meldung ausgeben
SystemTable->ConOut->ClearScreen(SystemTable->ConOut);
SystemTable->ConOut->OutputString(SystemTable->ConOut, (const uint16_t *)L"UEFI-Bootloader \r\n");
// Variablen für die Protokolle
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem;
void *RootDirectory = 0;
EFI_STATUS status;
// 2. Welches Laufwerk hat uns gestartet?
status = SystemTable->BootServices->HandleProtocol(ImageHandle, &LoadedImageProtocolGuid, (void **)&LoadedImage);
if (status == EFI_SUCCESS) {
SystemTable->ConOut->OutputString(SystemTable->ConOut, (const uint16_t *)L"[OK] Boot-Medium lokalisiert.\r\n");
// 3. Dateisystem dieses Laufwerks ansprechen
status = SystemTable->BootServices->HandleProtocol(LoadedImage->DeviceHandle, &SimpleFileSystemProtocolGuid, (void **)&FileSystem);
if (status == EFI_SUCCESS) {
SystemTable->ConOut->OutputString(SystemTable->ConOut, (const uint16_t *)L"[OK] FAT-Dateisystem geoeffnet.\r\n");
// 4. Das Hauptverzeichnis (Root) öffnen
status = FileSystem->OpenVolume(FileSystem, (struct _EFI_FILE_PROTOCOL **)&RootDirectory);
if (status == EFI_SUCCESS) {
SystemTable->ConOut->OutputString(SystemTable->ConOut, (const uint16_t *)L"[OK] Hauptverzeichnis (/) erfolgreich geoeffnet!\r\n");
}
}
}
// Fehlerprüfung, falls irgendwo auf dem Weg etwas schiefging
if (status != EFI_SUCCESS) {
SystemTable->ConOut->OutputString(SystemTable->ConOut, (const uint16_t *)L"[FEHLER] Dateisystem-Zugriff fehlgeschlagen!\r\n");
}
// Endlosschleife zum Lesen der Ausgaben
while(1) {
__asm__("hlt");
}
return EFI_SUCCESS;
}
Terminalbefehl für den Ming-Compiler:
- x86_64-w64-mingw32-gcc -shared -nostdlib -fno-builtin -fshort-wchar -mno-red-zone -Wl,-entry=efi_main -Wl,–subsystem,10 -o BOOTX64.EFI bootloader.c
Praxistest und Statusmeldung:
Der aktuelle Bootloader zeigt jetzt einige neue Textmeldungen. Das Boot-Medium wird bereits erfolgreich lokalisiert und auch das FAT-Dateisystem wird geöffnet. Nur das Hauptverzeichnis wird noch nicht geöffnet und damit geht es im nächsten Artikel weiter…