/* * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. */ /* Implementation of boot stub of Chrome OS Verify Boot firmware */ #include #include #include #include #include #include #include #include #include #include /* Verify Boot interface */ #include #include #include #include #define PREFIX "cros_bootstub: " #define WARN_ON_FAILURE(action) do { \ int return_code = (action); \ if (return_code != 0) \ printf(PREFIX "%s failed, returning %d\n", \ #action, return_code); \ } while (0) /* * Read recovery firmware into . * * Return 0 on success, non-zero on error. */ int load_recovery_firmware(firmware_storage_t *file, uint8_t *recovery_firmware_buffer) { int retval; retval = firmware_storage_read(file, CONFIG_OFFSET_RECOVERY, CONFIG_LENGTH_RECOVERY, recovery_firmware_buffer); if (retval) { VBDEBUG(PREFIX "cannot load recovery firmware\n"); } return retval; } void jump_to_firmware(void (*firmware_entry_point)(void)) { VBDEBUG(PREFIX "jump to firmware %p\n", firmware_entry_point); cleanup_before_linux(); /* should never return! */ firmware_entry_point(); /* FIXME(clchiou) Bring up a sad face as boot has failed */ enable_interrupts(); VBDEBUG(PREFIX "error: firmware returns\n"); while (1); } int do_cros_bootstub(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { int status = LOAD_FIRMWARE_RECOVERY; firmware_storage_t file; VbNvContext nvcxt; uint64_t boot_flags = 0; uint32_t recovery_request = 0; uint32_t reason = VBNV_RECOVERY_NOT_REQUESTED; uint8_t *firmware_data; if (firmware_storage_init(&file)) { /* FIXME(clchiou) Bring up a sad face as boot has failed */ VBDEBUG(PREFIX "init_firmware_storage fail\n"); while (1); } if (is_firmware_write_protect_gpio_asserted()) WARN_ON_FAILURE(file.lock_device(file.context)); clear_kernel_shared_data(); /* Fill in the RO firmware ID */ KernelSharedDataType *sd = get_kernel_shared_data(); if (firmware_storage_read(&file, (off_t)CONFIG_OFFSET_RO_FRID, (size_t)CONFIG_LENGTH_RO_FRID, sd->frid)) { VBDEBUG(PREFIX "fail to read fwid\n"); reason = VBNV_RECOVERY_US_UNSPECIFIED; goto RECOVERY; } if (read_nvcontext(&nvcxt) || VbNvGet(&nvcxt, VBNV_RECOVERY_REQUEST, &recovery_request)) { VBDEBUG(PREFIX "fail to read nvcontext\n"); reason = VBNV_RECOVERY_US_UNSPECIFIED; goto RECOVERY; } /* clear VBNV_DEBUG_RESET_MODE after read */ if (VbNvSet(&nvcxt, VBNV_DEBUG_RESET_MODE, 0)) { VBDEBUG(PREFIX "fail to write nvcontext\n"); reason = VBNV_RECOVERY_US_UNSPECIFIED; goto RECOVERY; } if (recovery_request != VBNV_RECOVERY_NOT_REQUESTED) { VBDEBUG(PREFIX "boot recovery cookie set\n"); reason = recovery_request; goto RECOVERY; } if (is_recovery_mode_gpio_asserted()) { VBDEBUG(PREFIX "recovery button pressed\n"); reason = VBNV_RECOVERY_RO_MANUAL; goto RECOVERY; } if (is_developer_mode_gpio_asserted()) boot_flags |= BOOT_FLAG_DEVELOPER; status = load_firmware_wrapper(&file, boot_flags, &nvcxt, NULL, &firmware_data); if (nvcxt.raw_changed && write_nvcontext(&nvcxt)) { VBDEBUG(PREFIX "fail to write nvcontext\n"); reason = VBNV_RECOVERY_US_UNSPECIFIED; goto RECOVERY; } if (status == LOAD_FIRMWARE_SUCCESS) { jump_to_firmware((void (*)(void)) firmware_data); } else if (status == LOAD_FIRMWARE_REBOOT) { cold_reboot(); } /* assert(status == LOAD_FIRMWARE_RECOVERY) */ RECOVERY: VBDEBUG(PREFIX "write to recovery cookie\n"); /* * Although writing back VbNvContext cookies may fail, we boot * recovery firmware anyway. In this way, the recovery reason * would be incorrect, but this is much better than not booting * anything. */ if (reason != VBNV_RECOVERY_NOT_REQUESTED && VbNvSet(&nvcxt, VBNV_RECOVERY_REQUEST, reason)) { /* FIXME: bring up a sad face? */ VBDEBUG(PREFIX "error: cannot write recovery reason\n"); } if (VbNvTeardown(&nvcxt)) { /* FIXME: bring up a sad face? */ VBDEBUG(PREFIX "error: cannot tear down cookie\n"); } if (nvcxt.raw_changed && write_nvcontext(&nvcxt)) { /* FIXME: bring up a sad face? */ VBDEBUG(PREFIX "error: cannot write recovery cookie\n"); } VBDEBUG(PREFIX "jump to recovery firmware and never return\n"); firmware_data = malloc(CONFIG_LENGTH_RECOVERY); WARN_ON_FAILURE(load_recovery_firmware(&file, firmware_data)); jump_to_firmware((void (*)(void)) firmware_data); /* never reach here */ return 1; } U_BOOT_CMD(cros_bootstub, 1, 1, do_cros_bootstub, "verified boot stub firmware", NULL);