Sep 11, 2013 at 5:20am UTC
//main.c (cont)
static Elf_File *
OpenImageFile(SIMPLE_READ_FILE file)
{
Elf_File *ef = (Elf_File *)AllocatePool(sizeof(*ef));
if (!ef) {
// DebugPrint(D_INFO, "Memory allocation failed\n");
debugPrint_0(L"Memory allocation failed\n");
return NULL;
}
RtZeroMem(ef, sizeof(*ef));
ef->f_priv = AllocatePool(sizeof(ImageFile));
if (!ef->f_priv) {
// DebugPrint(D_INFO, "Memory allocation failed\n");
debugPrint_0(L"Memory allocation failed\n");
CloseImageFile(ef);
return NULL;
}
ef->Close = CloseImageFile;
ef->Seek = SeekImageFile;
ef->Read = ReadImageFile;
ImageFile *img = (ImageFile *)ef->f_priv;
RtZeroMem(img, sizeof(*img));
img->file = file;
img->hFile = GetSimpleReadFileHandle(img->file);
/* Get file size */
EFI_FILE_INFO *info = LibFileInfo(img->hFile);
if (!info) {
// DebugPrint(D_INFO, "Failed to get file info\n");
debugPrint_0(L"Failed to get file info\n");
CloseImageFile(ef);
return NULL;
}
img->size = info->FileSize;
FreePool(info);
return ef;
}
WCHAR_T *
LoaderStrConvert(const char *str)
{
size_t len, i;
for (len = 0; str[len]; len++);
CHAR16 *msgW = AllocatePool((len + 1) * sizeof(CHAR16));
for (i = 0; i < len; i++) {
msgW[i] = str[i];
}
msgW[len] = 0;
return msgW;
}
int
LoaderGetMemory(vaddr_t address, u64 pages)
{
EFI_STATUS rc;
rc = uefi_call_wrapper(BS->AllocatePages, 4,
AllocateAddress,
EfiRuntimeServicesCode,
pages,
&address);
return EFI_ERROR(rc) ? -1 : 0;
}
void *
LoaderAlloc(size_t size)
{
return AllocatePool(size);
}
void
LoaderFree(void *ptr)
{
return FreePool(ptr);
}
int
LoaderReadFile(Elf_File *file, u64 offset, u64 size, void *mem)
{
while (size) {
size_t num_read = ReadImageFileOff(file, offset, mem, size);
if (!num_read) {
return -1;
}
ASSERT(size >= num_read);
size -= num_read;
offset += num_read;
}
return 0;
}
typedef void (*KernelEntry)(BootParam *bootParam);
static EFI_STATUS
StartKernel(vaddr_t entry_addr)
{
/* Prepare boot parameters */
/* Kernel command line */
bootParam.cmdLine = kernelCmdLine;
for (bootParam.cmdLineSize = 0;
bootParam.cmdLine[bootParam.cmdLineSize];
bootParam.cmdLineSize++);
bootParam.cmdLineSize++;
/* Get memory map */
UINTN mapKey, mapDescSize, numEntries;
UINT32 mapDescVersion;
EFI_MEMORY_DESCRIPTOR *map = LibMemoryMap(&numEntries, &mapKey,
&mapDescSize, &mapDescVersion);
if (!map) {
Print(L"Failed to get memory map\n");
return EFI_LOAD_ERROR;
}
bootParam.memMap = map;
bootParam.memMapNumDesc = numEntries;
bootParam.memMapDescSize = mapDescSize;
bootParam.memMapDescVersion = mapDescVersion;
/* Take control over the system */
EFI_STATUS rc = uefi_call_wrapper(BS->ExitBootServices, 2,
imageHandle, mapKey);
if (EFI_ERROR(rc)) {
Print(L"Failed to exit boot services (%r)\n", rc);
return rc;
}
/* The system is ours */
ST->ConsoleInHandle = NULL;
ST->ConIn = NULL;
ST->ConsoleOutHandle = NULL;
ST->ConOut = NULL;
ST->StandardErrorHandle = NULL;
ST->StdErr = NULL;
ST->BootServices = NULL;
SetCrc(&ST->Hdr);
bootParam.efiSystemTable = (paddr_t)ST;
/* Pass control to the kernel */
KernelEntry ke = (KernelEntry)entry_addr;
ke(&bootParam);
/* NOT REACHED */
return EFI_SUCCESS;
}
static EFI_STATUS
LoadImage(SIMPLE_READ_FILE file)
{
elf_malloc = _elf_malloc;
elf_mfree = _elf_mfree;
elf_mrealloc = _elf_mrealloc;
Elf_File *ef = OpenImageFile(file);
if (!ef) {
Print(L"Failed to open image file\n");
return EFI_LOAD_ERROR;
}
if (elf_version(EV_CURRENT) == EV_NONE) {
CloseImageFile(ef);
Print(L"ELF library initialization failed: %a", elf_errmsg(-1));
return EFI_LOAD_ERROR;
}
Elf *elf = elf_begin(ef, ELF_C_READ, NULL);
if (!elf) {
CloseImageFile(ef);
Print(L"Failed to open ELF file: %a\n", elf_errmsg(-1));
return EFI_LOAD_ERROR;
}
vaddr_t entry_addr;
EFI_STATUS rc = LoadElfImage(ef, elf, &entry_addr) ? EFI_LOAD_ERROR : EFI_SUCCESS;
elf_end(elf);
if (!EFI_ERROR(rc)) {
rc = StartKernel(entry_addr);
}
return rc;
}
static EFI_STATUS
LoadKernel()
{
// DebugPrint(D_INFO, "Kernel image: '%s'\n", kernelImage);
debugPrint_1("Kernel image: '%s'\n", kernelImage);
EFI_DEVICE_PATH *path;
EFI_STATUS rc = EFI_SUCCESS;
SIMPLE_READ_FILE readHandle = NULL;
UINTN handleCount, handleIdx;
EFI_HANDLE *handleBuffer;
rc = uefi_call_wrapper(BS->LocateHandleBuffer, 5,
ByProtocol,
&FileSystemProtocol,
NULL,
&handleCount,
&handleBuffer);
if (EFI_ERROR(rc)) {
return rc;
}
for (handleIdx = 0; handleIdx < handleCount; handleIdx++) {
EFI_HANDLE deviceHandle;
path = FileDevicePath(handleBuffer[handleIdx], kernelImage);
if (!path) {
rc = EFI_NOT_FOUND;
break;
}
rc = OpenSimpleReadFile(TRUE, NULL, 0, &path, &deviceHandle, &readHandle);
if (!EFI_ERROR(rc)) {
break;
}
FreePool(path);
path = NULL;
}
if (!EFI_ERROR(rc)) {
rc = LoadImage(readHandle);
}
if (readHandle) {
CloseSimpleReadFile(readHandle);
}
if (path) {
FreePool(path);
}
FreePool(handleBuffer);
return rc;
}
EFI_STATUS
efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *systab)
{
EFI_STATUS status, rc;
InitializeLib(image, systab);
imageHandle = image;
status = uefi_call_wrapper(BS->OpenProtocol,
6,
image,
&LoadedImageProtocol,
(void **)&loadedImage,
image,
NULL,
EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL);
if (EFI_ERROR(status)) {
Print(L"OpenProtocol: %r\n", status);
return status;
}
# ifdef EFI_DEBUG
// DebugPrint(D_INFO, "Image base: 0x%lx\n", loadedImage->ImageBase);
debugPrint_1(L"Image base: 0x%lx\n", loadedImage->ImageBase);
# endif
rc = ProcessOptions(loadedImage->LoadOptions,
loadedImage->LoadOptionsSize / sizeof(CHAR16));
if (!EFI_ERROR(rc)) {
if (optDebugger) {
WaitDebugger();
}
rc = LoadKernel();
}
status = uefi_call_wrapper(BS->CloseProtocol,
4,
image,
&LoadedImageProtocol,
image,
NULL);
if (EFI_ERROR(status)) {
Print(L"CloseProtocol: %r\n", status);
}
if (EFI_ERROR(rc)) {
Print(L"Exit with error: %r\n", rc);
}
return rc;
}
[/