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; }
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; }