view boot/bootx64.c @ 15:ac5d699b9787

add config and open.
author taiki
date Tue, 29 Jan 2013 14:45:00 +0900
parents 479240de2d64 09ced7d8f64a
children 2013da6b3211
line wrap: on
line source

/* 
 * This program is EFI boot loader.
 * load Mach-O kernel, and locate on memory, and jump kernel.
 *
 * Author: Taiki TAIRA.
 */

#include "bootx64.h"

INTN
efi_error(CHAR16* error_massage, EFI_STATUS status)
{
    Print(L"%s", error_massage);
    if (status < 0) return ERROR;
    return SUCCESS; 
}

EFI_STATUS
load_mach_o()
{
    Print(L"kernel load ... \n");
    return EFI_SUCCESS;
}

EFI_STATUS
open(CHAR16 *name, UINTN *fd, fs_t *fs)
{
    EFI_STATUS status;
    EFI_FILE_HANDLE fh;

    if (name == NULL || fd == NULL) return EFI_INVALID_PARAMETER;

    status = uefi_call_wrapper(fs->volume->Open, 5, fs->volume, &fh, name, EFI_FILE_MODE_READ, (UINT64)0);
    if (status == EFI_SUCCESS) { 
        *fd = (UINTN)fh;
    }
    return status;
}

EFI_STATUS
config_fs_one(EFI_HANDLE dev, VOID *fs)
{
    EFI_STATUS status;
    EFI_FILE_IO_INTERFACE *volume;
    EFI_FILE_HANDLE volume_fh;
    EFI_GUID LocalFsProtocol = LOCALFS_PROTOCOL;

    status = uefi_call_wrapper(BS->HandleProtocol, 3, dev, &FileSystemProtocol, (VOID **)&volume);
    if (EFI_ERROR(status)) return EFI_INVALID_PARAMETER;

    /* alloc */

    status = uefi_call_wrapper(volume->OpenVolume, 2, volume, &volume_fh);
    if (EFI_ERROR(status)) {
        Print(L"Can not open volume.\n");
        return status;
    }
    Print(L"Open volume.\n");
    
    fs_t *fs_tmp = (fs_t *)fs;

    SetMem(fs, sizeof(fs_t), 0);

    fs_tmp->dev = dev;
    fs_tmp->volume = volume_fh;

    status = LibInstallProtocolInterfaces(&dev, &LocalFsProtocol, fs, NULL);
    if (EFI_ERROR(status)) return status; 
    /* free */

    return EFI_SUCCESS;
}

EFI_STATUS
config_fs(EFI_HANDLE boot_handle, fs_t *fs, dev_tab_t *boot_dev)
{
    UINTN size = 0;
    UINTN i;
    EFI_GUID *proto = NULL;

    Print(L"configure filesystems for all volume. \n");

    uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &FileSystemProtocol, NULL, &size, NULL);
    if (size == 0) return EFI_UNSUPPORTED;

    /* alloc */

    dev_tab_t *dev_tab = NULL; // all devices
    EFI_STATUS status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &FileSystemProtocol, NULL, &size, (VOID **)dev_tab);
    if (status != EFI_SUCCESS) {
        efi_error(L"can't get handler.\n", status);
        /* free */
        return status;
    }

    UINTN ndev = size / sizeof(EFI_HANDLE);

    for (i = 0; i < ndev; i++) {
        VOID *fs = NULL;
        config_fs_one(dev_tab[i].dev, &fs);
        dev_tab[i].fs = fs;
    }

    status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, proto, NULL, &size, NULL);
    if (EFI_ERROR(status)) {
        Print(L"No useable filesystem found.\n");
        return status;
    }

    SetMem(proto, sizeof(EFI_HANDLE), 0);

    uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, &proto, NULL, &size, NULL);

    EFI_HANDLE *tab = NULL;

    SetMem(tab, size, 0);

    status = uefi_call_wrapper(BS->LocateHandle, 5, ByProtocol, proto, NULL, &size, tab);
    if (status != EFI_SUCCESS) {
        Print(L"faild to get handles\n");
    }

    size /= sizeof(EFI_HANDLE);

    UINTN idx = 0;

    for (i=0; i<size; i++) { 
        dev_tab[idx].dev = tab[i];
        if (tab[i] == boot_handle) boot_dev = dev_tab + idx;
        idx++;
    }

    return EFI_SUCCESS;
}

/* start cbc kernel boot loader. */

EFI_STATUS
efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *system_table)
{
    InitializeLib(image, system_table);

    EFI_LOADED_IMAGE *info;
    CHAR16 *kname = L"kernel";
    Print(L"Boot start. %s\n", kname);

    uefi_call_wrapper(BS->SetWatchdogTimer, 4, 0, 0x0, 0, NULL);
    Print(L"Set watchdog timer.\n");

    EFI_STATUS status = uefi_call_wrapper(BS->HandleProtocol, 3, image, &LoadedImageProtocol, (VOID **) &info);
    if (efi_error(L"Load error.\n", status)) {
        return EFI_LOAD_ERROR;
    }

    fs_t fs;
    dev_tab_t boot_dev;
    status = config_fs(info->DeviceHandle, &fs, &boot_dev);

    UINTN fd;
    open(kname, &fd, &fs);

    status = EFI_SUCCESS;
    return status;
}