Another problem is the mixed-bitness involved. I cannot link 32-bit (or 16-bit) code into a 64-bit UEFI image, so I need to load it (at a fixed location) from disc.
Here is my current attempt for 64-bit mode:
Code: Select all
param_struc STRUC
lfb_base DD ?,? ; address to LFB for printing
uefi_data DD ?,? ; address to UEFI data (yet to be specified)
param_struc ENDS
Code32 segment byte public use32 'code32'
org 0110000h ; put the code at a fixed position.
;
; UEFI entrypoint
;
db 0Ebh ; jmp init64
db 38h + SIZE param_struc
param param_struc <>
rom_gdt:
gdt0:
dw 0
dd 0
dw 0
gdt8: ; selector for setting up IDT
dw 10h*8-1
dd 92000000h
dw 0
gdt10: ; selector for setting up GDT
dw 28h-1
dd 92000000h + OFFSET rom_gdt
dw 0
gdt18: ; flat code selector
dw 0FFFFh
dd 9A000000h
dw 0CFh
gdt20: ; flat data selector
dw 0FFFFh
dd 92000000h
dw 0CFh
gdt_ptr: ; used for loading GDT
dw 28h-1
dq OFFSET rom_gdt
prot_ptr: ; used for indirect call to 32-bit mode
dd OFFSET prot_init
dw 18h
init64:
db 0FAh ; cli
db 0Fh ; lgdt gdt_ptr
db 01h
db 15h
dd 0FFFFFFE8h
;
db 0FFh ; call far prot_init
db 1Dh
dd 0FFFFFFECh
prot_init:
mov eax,20h
mov ds,ax
mov es,ax
mov fs,ax
mov gs,ax
mov ss,ax
mov esp,120000h
;
; disable paging
;
mov eax,cr0
and eax,7FFFFFFFh
mov cr0,eax
;
; disable long mode
;
mov ecx,IA32_EFER
rdmsr
and eax,0FFFFFEFFh
wrmsr
;
; draw some pattern if successful
;
mov edi,cs:param.lfb_base
mov ecx,10000h
mov eax,80706050h
rep stosd
stopl:
jmp stopl
Code: Select all
#define RDOS_LOADER 0x110000
char str[256];
CHAR16 wstr[256];
EFI_INPUT_KEY Key;
EFI_PHYSICAL_ADDRESS RdosLoaderBase = RDOS_LOADER;
unsigned int RdosLoaderPages = 16;
unsigned int LoaderEntry = (unsigned int)RDOS_LOADER;
void (*StartLoaderProc)();
struct LoaderParam
{
EFI_PHYSICAL_ADDRESS Lfb;
EFI_PHYSICAL_ADDRESS Param;
};
static void ConvertToWide(CHAR16 *dest, const char *src)
{
int i = 0;
while (src[i])
{
dest[i] = (CHAR16)src[i];
i++;
}
dest[i] = 0;
}
static int LoadBootLoader(EFI_FILE_IO_INTERFACE *Fs)
{
int ok = 0;
printf("Loading boot-loader <");
strcpy(str, "efi\\rdos\\boot64.bin");
ConvertToWide(wstr, str);
ST->ConOut->OutputString(ST->ConOut, wstr);
printf(">\n\r");
if (Fs->OpenVolume(Fs, &Root) == EFI_SUCCESS)
{
if (Root->Open(Root, &FileHandle, wstr, EFI_FILE_MODE_READ, EFI_FILE_READ_ONLY | EFI_FILE_HIDDEN | EFI_FILE_SYSTEM) == EFI_SUCCESS)
{
if (BS->AllocatePages(AllocateAddress, EfiRuntimeServicesData, RdosLoaderPages, &RdosLoaderBase) == EFI_SUCCESS)
{
if (FileHandle->Read(FileHandle, 0x10000, RdosLoaderBase) == EFI_SUCCESS)
ok = 1;
else
{
BS->FreePages(RdosLoaderBase, RdosLoaderPages);
printf("Failed to read RDOS loader\n\r");
}
}
else
printf("Failed to allocate fixed memory for RDOS loader\n\r");
FileHandle->Close(FileHandle);
}
else
printf("Cannot open loader file\n\r");
Root->Close(Root);
}
else
printf("Cannot open volume\n\r");
return ok;
}
static void StartLoader()
{
StartLoaderProc = (void *)LoaderEntry;
LoaderData = (struct LoaderParam *)LoaderParamPos;
LoaderData->Lfb = LfbBase;
(*StartLoaderProc)();
}
if (LoadBootLoader(Fs))
{
if (BS->GetMemoryMap(&MemMapSize, MemMap, &MapKey, &MemDescrSize, &MemDescrVersion) == EFI_SUCCESS)
{
if (BS->ExitBootServices(ImageHandle, MapKey) == EFI_SUCCESS)
StartLoader();
else
printf("Exit boot services failed\n\r");
}
else
printf("Get memory map failed\n\r");
BS->FreePages(RdosLoaderBase, RdosLoaderPages);
}
BS->FreePages(RdosImageBase, RdosImagePages);
}
Thoughts?