Ejemplo n.º 1
0
int
load_kernel_and_config(struct loader_info *li)
{
	EFI_HANDLE handles[128];
	EFI_BLOCK_IO *blkio;
	UINTN i, nparts = sizeof(handles);
	EFI_STATUS status;
	EFI_DEVICE_PATH *devpath;
	unsigned char buf[512];
	EFI_LBA head;
	UINTN size;

	status = systab->BootServices->LocateHandle(ByProtocol, &BlockIoGUID, NULL, &nparts, handles);
	nparts /= sizeof(handles[0]);

	for (i = 0; i < nparts; i++) {

		status = systab->BootServices->HandleProtocol(handles[i], &DevicePathGUID, (void **)&devpath); 
		if (EFI_ERROR(status))
			continue;

		while (!IsDevicePathEnd(NextDevicePathNode(devpath)))
			devpath = NextDevicePathNode(devpath);

		status = systab->BootServices->HandleProtocol(handles[i], &BlockIoGUID, (void **)&blkio); 
		if (EFI_ERROR(status))
			continue;

		if (!blkio->Media->LogicalPartition)
			continue;

		status = blkio->ReadBlocks(blkio, blkio->Media->MediaId, 0, 512, buf);
		if (EFI_ERROR(status))
			continue;

		if (buf[0] != 0xeb && buf[0] != 0xe9)
			continue;

		if (buf[510] != 0x55 || buf[511] != 0xaa)
			continue;

		/* ここまできたら blkio は FAT ファイルシステム */

		if (search_kernel(blkio, &head, &size))
			continue;

		if (load_kernel(blkio, &head, &size, li))
			return -1;

		printstr("KERNEL BASE: ");
		printhex64(li->kernel_base);
		putchar('\n');
		printstr("KERNEL SIZE: ");
		printhex64(li->kernel_size);
		putchar('\n');

		if (search_config(blkio, &head, &size)
		  || (size == 0)
		  || load_config(blkio, &head, &size, li)) {
			li->config_base = 0;
			li->config_size = 0;
		}

		printstr("CONFIG BASE: ");
		printhex64(li->config_base);
		putchar('\n');
		printstr("CONFIG SIZE: ");
		printhex64(li->config_size);
		putchar('\n');

		/* 正常完了 */
		return 0;
	}

	/* 失敗 */
	return -1;
}
Ejemplo n.º 2
0
EFI_STATUS EfiMain(EFI_HANDLE hImage, EFI_SYSTEM_TABLE *pST)
{
    EFI_LOADED_IMAGE *pImage;
    EFI_STATUS nStatus;
    EFI_HANDLE hDriver, *hBlkDevs;
    UINTN nBlkDevs;
    EFI_DEVICE_PATH *pBootPart, *pBootDisk = NULL;

    g_hImage = hImage;
    InitializeLib(hImage, pST);
    Print(L"%H\n*** UEFI:NTFS multiboot ***");

    if (EFI_ERROR((nStatus = BS->OpenProtocol(hImage, &LoadedImageProtocol, &pImage, hImage, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL)))) {
        Print(L"%E\nUnable to convert handle to interface: %r\n", nStatus);
        goto end;
    }

    pBootPart = DevicePathFromHandle(pImage->DeviceHandle);
    pBootDisk = GetParentDevice(pBootPart);

    CHAR16 *pszDev = DevicePathToStr(pBootDisk);
    Print(L"%N\nDisk: %s\n", pszDev);
    FreePool(pszDev);

    Print(L"%H\n[ INFO ] Disconnecting problematic File System drivers\n");
    DisconnectBlockingDrivers();

    Print(L"%H\n[ WAIT ] Loading NTFS driver");
    EFI_DEVICE_PATH *pDrvPath = FileDevicePath(pImage->DeviceHandle, DriverPath);
    if (pDrvPath == NULL) {
        Print(L"%E\r[ FAIL ] Unable to construct path to NTFS driver\n");
        goto end;
    }
    nStatus = BS->LoadImage(FALSE, hImage, pDrvPath, NULL, 0, &hDriver);
    FreePool(pDrvPath);
    if (EFI_ERROR(nStatus)) {
        Print(L"%E\r[ FAIL ] Unable to load NTFS driver: %r\n", nStatus);
        goto end;
    }
    if (EFI_ERROR((nStatus = BS->StartImage(hDriver, NULL, NULL)))) {
        Print(L"%E\r[ FAIL ] Unable to start NTFS driver: %r\n", nStatus);
        goto end;
    }

    Print(L"%H\r[  OK  ] NTFS driver loaded and started\n");

    LINKED_LOADER_PATH_LIST_NODE *list = NULL;
    EFI_DEVICE_PATH *ldr;

    if (EFI_ERROR((nStatus = BS->LocateHandleBuffer(ByProtocol, &BlockIoProtocol, NULL, &nBlkDevs, &hBlkDevs)))) {
        Print(L"%E\r[ FAIL ] Unable to enumerate block devices: %r\n", nStatus);
        goto end;
    }
    for (UINTN i = 0; i < nBlkDevs; i++) {
        EFI_DEVICE_PATH *pDevice = DevicePathFromHandle(hBlkDevs[i]);
        pszDev = DevicePathToStr(pDevice);
        Print(L"%N\r[ INFO ] Probing %d devices... [%d] %s", nBlkDevs, i + 1, pszDev);
        FreePool(pszDev);

        if (CompareDevicePaths(pDevice, pBootPart) == 0) continue;
        if (CompareDevicePaths(pDevice, pBootDisk) == 0) continue;

        EFI_DEVICE_PATH *pDisk = GetParentDevice(pDevice);
        _Bool probe = CompareDevicePaths(pDisk, pBootDisk) == 0;
        FreePool(pDisk);
#if !defined(_DEBUG)
        if (!probe) continue;
#endif

        EFI_BLOCK_IO *blkIo;
        if (EFI_ERROR((nStatus = BS->OpenProtocol(hBlkDevs[i], &BlockIoProtocol, &blkIo, hImage, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL)))) {
            Print(L"%E\n[ WARN ] Unable to open block device, skipping: %r\n", nStatus);
            continue;
        }

        //No media or not a partition.
        if ((blkIo->Media == NULL) || (!blkIo->Media->LogicalPartition))
            continue;

        CHAR8 *buffer = AllocatePool(blkIo->Media->BlockSize);
        if (buffer == NULL) {
            Print(L"%E\n[ WARN ] Unable to allocate buffer of size %d\n", blkIo->Media->BlockSize);
            continue;
        }

        nStatus = blkIo->ReadBlocks(blkIo, blkIo->Media->MediaId, 0, blkIo->Media->BlockSize, buffer);
        _Bool isNTFS = CompareMem(&buffer[3], NTFSMagic, sizeof(NTFSMagic)) == 0;
        FreePool(buffer);
        if (EFI_ERROR(nStatus)) {
            Print(L"%E\n[ WARN ] Unable to read block device, skipping: %r\n", nStatus);
            continue;
        }
        if (!isNTFS) continue;

        Print(L"%H\n[ WAIT ] Attaching NTFS driver to device");
        EFI_FILE_IO_INTERFACE *fs;
        nStatus = BS->OpenProtocol(hBlkDevs[i], &FileSystemProtocol, NULL, hImage, NULL, EFI_OPEN_PROTOCOL_TEST_PROTOCOL);
        if (nStatus == EFI_UNSUPPORTED) {
            nStatus = BS->ConnectController(hBlkDevs[i], NULL, NULL, TRUE);
        }
        for (UINTN j = 0; j < NUM_RETRIES; j++) {
            if ((!EFI_ERROR((nStatus = BS->OpenProtocol(hBlkDevs[i], &FileSystemProtocol, &fs, hImage, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL))))) {
                break;
            }
            Print(L".");
            BS->Stall(DELAY * 1000000);
        }
        if(EFI_ERROR(nStatus)) {
            Print(L"%E\r[ WARN ] Unable to attach NTFS driver, skipping: %r\n", nStatus);
            continue;
        }
        Print(L"%H\r[  OK  ] NTFS driver attached to current device\n");

        Print(L"%H\r[ WAIT ] Locating EFI boot loader");
        EFI_FILE *fsRoot;
        if (EFI_ERROR((nStatus = fs->OpenVolume(fs, &fsRoot)))) {
            Print(L"%E\r[ WARN ] Unable to open root directory, skipping: %r\n", nStatus);
            continue;
        }
        CHAR16 *loader = StrDuplicate(LoaderPath);
        if (EFI_ERROR((nStatus = SetPathCase(fsRoot, loader)))) {
            FreePool(loader);
            Print(L"%E\r[ WARN ] Unable to locate EFI boot loader on this device: %r\n", nStatus);
            continue;
        }
        Print(L"%H\r[  OK  ] EFI boot loader located at %s\n", loader);

        ldr = FileDevicePath(hBlkDevs[i], loader);
        ListAppend(&list, ldr);
        FreePool(loader);
    }

    UINTN nListEntries = 0, nBootEntry = 0, nPage = 0, nTotalPage = 0;
    EFI_INPUT_KEY key;
    _Bool interactive = FALSE;
    ListTraverse(&list, CountEntries, 0, 0, &nListEntries);

    switch (nListEntries) {
    case 0:
        Print(L"%E\n[ FAIL ] No bootable partition\n", nStatus);
        nStatus = EFI_NOT_FOUND;
        goto end;
    case 1:
        goto boot;
    default:
        nTotalPage = (nListEntries - 1) / PAGE_SIZE + 1;
        while (1) {
            ST->ConOut->ClearScreen(ST->ConOut);
            Print(L"%H*** UEFI:NTFS Multiboot ***\n");
            pszDev = DevicePathToStr(pBootDisk);
            Print(L"%NDisk: %s\n\n%H", pszDev);
            FreePool(pszDev);

            ListTraverse(&list, DisplayEntries, nPage * PAGE_SIZE, PAGE_SIZE, NULL);

            Print(L"%N\nPage %hd / %hd, %hd entries\n", nPage + 1, nTotalPage, nListEntries);
            Print(L"%H\n[F1 - F8] [1 - 8] %N Boot corresponding entry");
            Print(L"%H\n[PgUp]  [<]  [-]  %N Previous page");
            Print(L"%H\n[PgDn]  [>]  [+]  %N Next page");

            if (!interactive) {
                INTN nCountDown = AUTOBOOT_TIME;
                Print(L"%N\n\n");
                while (nCountDown >= 0) {
                    Print(L"\rWill automatically boot the first entry in %d seconds...", nCountDown);
                    if (WaitForSingleEvent(ST->ConIn->WaitForKey, 1000 * 1000 * 10) != EFI_TIMEOUT) {
                        interactive = TRUE;
                        break;
                    }
                    nCountDown--;
                }
                if (!interactive) {
                    goto boot;
                }
            }
            else {
                WaitForSingleEvent(ST->ConIn->WaitForKey, 0);
            }
            ST->ConIn->ReadKeyStroke(ST->ConIn, &key);
            switch (key.UnicodeChar) {
            case L'1':case L'2':case L'3':case L'4':case L'5':case L'6':case L'7':case L'8':
                nBootEntry = nPage * PAGE_SIZE + (key.UnicodeChar - L'1');
                goto boot;
            case L'+':case L'=':case L'>':case L'.':
                if ((nPage + 1) != nTotalPage) {
                    nPage++;
                }
                break;
            case L'-':case L'_': case L'<': case L',':
                if (nPage != 0) {
                    nPage--;
                }
                break;
            default:
                switch (key.ScanCode) {
                case 0x09:
                    if (nPage != 0) {
                        nPage--;
                    }
                    break;
                case 0x0a:
                    if ((nPage + 1) != nTotalPage) {
                        nPage++;
                    }
                    break;
                case 0x0b:case 0x0c:case 0x0d:case 0x0e:case 0x0f:case 0x10:case 0x11:case 0x12:
                    nBootEntry = nPage * PAGE_SIZE + (key.ScanCode - 0x0b);
                    goto boot;
                }
            }
        }
    }

boot:
    ldr = NULL;
    Print(L"%H");
    ST->ConOut->ClearScreen(ST->ConOut);
    ListTraverse(&list, ReadEntry, nBootEntry, 1, &ldr);
    ListTraverse(&list, DisplayEntries, nBootEntry, 1, NULL);
    if (ldr == NULL) {
        Print(L"%E\n[ FAIL ] No such boot entry\n", nStatus);
        nStatus = EFI_NOT_FOUND;
        goto end;
    }

    ldr = DuplicateDevicePath(ldr);
    ListTraverse(&list, DestroyEntries, 0, 0, NULL);
    ListDestroy(&list);

    EFI_HANDLE hChain;
    nStatus = BS->LoadImage(FALSE, hImage, ldr, NULL, 0, &hChain);
    FreePool(ldr);
    if (EFI_ERROR(nStatus)) {
        Print(L"%E\n[ FAIL ] Unable to load boot loader: %r\n", nStatus);
        goto end;
    }
    Print(L"%N");
    if (EFI_ERROR((nStatus = BS->StartImage(hChain, NULL, NULL)))) {
        Print(L"%E\n[ FAIL ] Unable to start boot loader: %r\n", nStatus);
        goto end;
    }

end:
    if (pBootDisk) FreePool(pBootDisk);
    if (EFI_ERROR(nStatus)) {
        Print(L"Press any key to exit\n");
        WaitForSingleEvent(ST->ConIn->WaitForKey, 0);
        ST->ConIn->ReadKeyStroke(ST->ConIn, &key);
    }
    return nStatus;
}