static int do_vbexport_test_diskinfo_flags(uint32_t flags) { int ret = 0; VbDiskInfo *info; uint32_t count, i; ret = VbExDiskGetInfo(&info, &count, flags); if (ret) return ret; if (count == 0) { VbExDebug("No disk found!\n"); } else { VbExDebug("handle byte/lba lba_count f name\n"); for (i = 0; i < count; i++) { VbExDebug("%08lx %-9llu %-10llu %-2lu %s", info[i].handle, info[i].bytes_per_lba, info[i].lba_count, info[i].flags, info[i].name); if ((flags & info[i].flags) != flags) { VbExDebug(" INCORRECT: flag mismatched\n"); ret = 1; } else VbExDebug("\n"); } } return VbExDiskFreeInfo(info, NULL) || ret; }
/* * Gets the first internal disk and caches the result in a static variable. * Returns 0 for success, non-zero for failure. */ static int get_internal_disk(VbDiskInfo **disk_ptr) { static VbDiskInfo internal_disk; if (internal_disk.handle == NULL) { VbDiskInfo *disk_info; uint32_t disk_count; if (VbExDiskGetInfo(&disk_info, &disk_count, VB_DISK_FLAG_FIXED) || disk_count == 0) { VBDEBUG("No internal disk found!\n"); return 1; } internal_disk = disk_info[0]; VbExDiskFreeInfo(disk_info, internal_disk.handle); } *disk_ptr = &internal_disk; return 0; }
static int do_vbexport_test_diskrw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { int ret = 0; VbDiskInfo *disk_info; VbExDiskHandle_t handle; uint32_t disk_count, test_lba_count, buf_byte_count, i; uint8_t *original_buf, *target_buf, *verify_buf; uint64_t t0, t1; switch (argc) { case 1: /* if no argument given, use the default lba count */ test_lba_count = DEFAULT_TEST_LBA_COUNT; break; case 2: /* use argument */ test_lba_count = simple_strtoul(argv[1], NULL, 10); if (!test_lba_count) { VbExDebug("The first argument is not a number!\n"); return cmd_usage(cmdtp); } break; default: return cmd_usage(cmdtp); } /* We perform read/write operations on the first internal disk. */ if (VbExDiskGetInfo(&disk_info, &disk_count, VB_DISK_FLAG_FIXED) || disk_count == 0) { VbExDebug("No internal disk found!\n"); return 1; } handle = disk_info[0].handle; buf_byte_count = disk_info[0].bytes_per_lba * test_lba_count; VbExDiskFreeInfo(disk_info, handle); /* Allocate the buffer and fill the target test pattern. */ original_buf = VbExMalloc(buf_byte_count); target_buf = VbExMalloc(buf_byte_count); verify_buf = VbExMalloc(buf_byte_count); /* Fill the target test pattern. */ for (i = 0; i < buf_byte_count; i++) target_buf[i] = i & 0xff; t0 = VbExGetTimer(); if (VbExDiskRead(handle, TEST_LBA_START, test_lba_count, original_buf)) { VbExDebug("Failed to read disk.\n"); goto out; } t1 = VbExGetTimer(); VbExDebug("test_diskrw: disk_read, lba_count: %u, time: %llu\n", test_lba_count, t1 - t0); t0 = VbExGetTimer(); ret = VbExDiskWrite(handle, TEST_LBA_START, test_lba_count, target_buf); t1 = VbExGetTimer(); VbExDebug("test_diskrw: disk_write, lba_count: %u, time: %llu\n", test_lba_count, t1 - t0); if (ret) { VbExDebug("Failed to write disk.\n"); ret = 1; } else { /* Read back and verify the data. */ VbExDiskRead(handle, TEST_LBA_START, test_lba_count, verify_buf); if (memcmp(target_buf, verify_buf, buf_byte_count) != 0) { VbExDebug("Verify failed. The target data wrote " "wrong.\n"); ret = 1; } } /* Write the original data back. */ if (VbExDiskWrite(handle, TEST_LBA_START, test_lba_count, original_buf)) { VbExDebug("Failed to write the original data back. The disk " "may now be corrupt.\n"); } out: VbExDiskFreeInfo(disk_info, NULL); VbExFree(original_buf); VbExFree(target_buf); VbExFree(verify_buf); if (ret == 0) VbExDebug("Read and write disk test SUCCESS.\n"); return ret; }
/** * Attempt loading a kernel from the specified type(s) of disks. * * If successful, sets p->disk_handle to the disk for the kernel and returns * VBERROR_SUCCESS. * * Returns VBERROR_NO_DISK_FOUND if no disks of the specified type were found. * * May return other VBERROR_ codes for other failures. */ uint32_t VbTryLoadKernel(VbCommonParams *cparams, LoadKernelParams *p, uint32_t get_info_flags) { VbError_t retval = VBERROR_UNKNOWN; VbDiskInfo* disk_info = NULL; uint32_t disk_count = 0; uint32_t i; VBDEBUG(("VbTryLoadKernel() start, get_info_flags=0x%x\n", (unsigned)get_info_flags)); p->disk_handle = NULL; /* Find disks */ if (VBERROR_SUCCESS != VbExDiskGetInfo(&disk_info, &disk_count, get_info_flags)) disk_count = 0; VBDEBUG(("VbTryLoadKernel() found %d disks\n", (int)disk_count)); if (0 == disk_count) { VbSetRecoveryRequest(VBNV_RECOVERY_RW_NO_DISK); return VBERROR_NO_DISK_FOUND; } /* Loop over disks */ for (i = 0; i < disk_count; i++) { VBDEBUG(("VbTryLoadKernel() trying disk %d\n", (int)i)); /* * Sanity-check what we can. FWIW, VbTryLoadKernel() is always * called with only a single bit set in get_info_flags. * * Ensure 512-byte sectors and non-trivially sized disk (for * cgptlib) and that we got a partition with only the flags we * asked for. */ if (512 != disk_info[i].bytes_per_lba || 16 > disk_info[i].lba_count || get_info_flags != (disk_info[i].flags & ~VB_DISK_FLAG_EXTERNAL_GPT)) { VBDEBUG((" skipping: bytes_per_lba=%" PRIu64 " lba_count=%" PRIu64 " flags=0x%x\n", disk_info[i].bytes_per_lba, disk_info[i].lba_count, disk_info[i].flags)); continue; } p->disk_handle = disk_info[i].handle; p->bytes_per_lba = disk_info[i].bytes_per_lba; p->gpt_lba_count = disk_info[i].lba_count; p->streaming_lba_count = disk_info[i].streaming_lba_count ?: p->gpt_lba_count; p->boot_flags |= disk_info[i].flags & VB_DISK_FLAG_EXTERNAL_GPT ? BOOT_FLAG_EXTERNAL_GPT : 0; retval = LoadKernel(p, cparams); VBDEBUG(("VbTryLoadKernel() LoadKernel() = %d\n", retval)); /* * Stop now if we found a kernel. * * TODO: If recovery requested, should track the farthest we * get, instead of just returning the value from the last disk * attempted. */ if (VBERROR_SUCCESS == retval) break; } /* If we didn't find any good kernels, don't return a disk handle. */ if (VBERROR_SUCCESS != retval) { VbSetRecoveryRequest(VBNV_RECOVERY_RW_NO_KERNEL); p->disk_handle = NULL; } VbExDiskFreeInfo(disk_info, p->disk_handle); /* * Pass through return code. Recovery reason (if any) has already been * set by LoadKernel(). */ return retval; }
VbError_t VbBootRecovery(VbCommonParams *cparams, LoadKernelParams *p) { VbSharedDataHeader *shared = (VbSharedDataHeader *)cparams->shared_data_blob; uint32_t retval; uint32_t key; int i; VBDEBUG(("VbBootRecovery() start\n")); /* * If the dev-mode switch is off and the user didn't press the recovery * button, require removal of all external media. */ if (!(shared->flags & VBSD_BOOT_DEV_SWITCH_ON) && !(shared->flags & VBSD_BOOT_REC_SWITCH_ON)) { VbDiskInfo *disk_info = NULL; uint32_t disk_count = 0; VBDEBUG(("VbBootRecovery() forcing device removal\n")); /* If no media is detected initially, delay and make one extra * attempt, in case devices appear later than expected. */ if (VBERROR_SUCCESS != VbExDiskGetInfo(&disk_info, &disk_count, VB_DISK_FLAG_REMOVABLE)) disk_count = 0; VbExDiskFreeInfo(disk_info, NULL); if (0 == disk_count) VbExSleepMs(REC_MEDIA_INIT_DELAY); while (1) { disk_info = NULL; disk_count = 0; if (VBERROR_SUCCESS != VbExDiskGetInfo(&disk_info, &disk_count, VB_DISK_FLAG_REMOVABLE)) disk_count = 0; VbExDiskFreeInfo(disk_info, NULL); if (0 == disk_count) { VbDisplayScreen(cparams, VB_SCREEN_BLANK, 0, &vnc); break; } VBDEBUG(("VbBootRecovery() " "waiting for %d disks to be removed\n", (int)disk_count)); VbDisplayScreen(cparams, VB_SCREEN_RECOVERY_REMOVE, 0, &vnc); /* * Scan keyboard more frequently than media, since x86 * platforms don't like to scan USB too rapidly. */ for (i = 0; i < REC_DISK_DELAY; i += REC_KEY_DELAY) { VbCheckDisplayKey(cparams, VbExKeyboardRead(), &vnc); if (VbWantShutdown(cparams->gbb->flags)) return VBERROR_SHUTDOWN_REQUESTED; VbExSleepMs(REC_KEY_DELAY); } } } /* Loop and wait for a recovery image */ while (1) { VBDEBUG(("VbBootRecovery() attempting to load kernel2\n")); retval = VbTryLoadKernel(cparams, p, VB_DISK_FLAG_REMOVABLE); /* * Clear recovery requests from failed kernel loading, since * we're already in recovery mode. Do this now, so that * powering off after inserting an invalid disk doesn't leave * us stuck in recovery mode. */ VbSetRecoveryRequest(VBNV_RECOVERY_NOT_REQUESTED); if (VBERROR_SUCCESS == retval) break; /* Found a recovery kernel */ VbDisplayScreen(cparams, VBERROR_NO_DISK_FOUND == retval ? VB_SCREEN_RECOVERY_INSERT : VB_SCREEN_RECOVERY_NO_GOOD, 0, &vnc); /* * Scan keyboard more frequently than media, since x86 * platforms don't like to scan USB too rapidly. */ for (i = 0; i < REC_DISK_DELAY; i += REC_KEY_DELAY) { key = VbExKeyboardRead(); /* * We might want to enter dev-mode from the Insert * screen if all of the following are true: * - user pressed Ctrl-D * - we can honor the virtual dev switch * - not already in dev mode * - user forced recovery mode * - EC isn't pwned */ if (key == 0x04 && shared->flags & VBSD_HONOR_VIRT_DEV_SWITCH && !(shared->flags & VBSD_BOOT_DEV_SWITCH_ON) && (shared->flags & VBSD_BOOT_REC_SWITCH_ON) && VbExTrustEC(0)) { if (!(shared->flags & VBSD_BOOT_REC_SWITCH_VIRTUAL) && VbExGetSwitches( VB_INIT_FLAG_REC_BUTTON_PRESSED)) { /* * Is the recovery button stuck? In * any case we don't like this. Beep * and ignore. */ VBDEBUG(("%s() - ^D but rec switch " "is pressed\n", __func__)); VbExBeep(120, 400); continue; } /* Ask the user to confirm entering dev-mode */ VbDisplayScreen(cparams, VB_SCREEN_RECOVERY_TO_DEV, 0, &vnc); /* SPACE means no... */ uint32_t vbc_flags = VB_CONFIRM_SPACE_MEANS_NO | VB_CONFIRM_MUST_TRUST_KEYBOARD; switch (VbUserConfirms(cparams, vbc_flags)) { case 1: VBDEBUG(("%s() Enabling dev-mode...\n", __func__)); if (TPM_SUCCESS != SetVirtualDevMode(1)) return VBERROR_TPM_SET_BOOT_MODE_STATE; VBDEBUG(("%s() Reboot so it will take " "effect\n", __func__)); if (VbExGetSwitches (VB_INIT_FLAG_ALLOW_USB_BOOT)) VbAllowUsbBoot(); return VBERROR_TPM_REBOOT_REQUIRED; case -1: VBDEBUG(("%s() - Shutdown requested\n", __func__)); return VBERROR_SHUTDOWN_REQUESTED; default: /* zero, actually */ VBDEBUG(("%s() - Not enabling " "dev-mode\n", __func__)); /* * Jump out of the outer loop to * refresh the display quickly. */ i = 4; break; } } else { VbCheckDisplayKey(cparams, key, &vnc); } if (VbWantShutdown(cparams->gbb->flags)) return VBERROR_SHUTDOWN_REQUESTED; VbExSleepMs(REC_KEY_DELAY); } } return VBERROR_SUCCESS; }