diff options
author | Randall Spangler <rspangler@chromium.org> | 2011-07-01 16:12:47 -0700 |
---|---|---|
committer | Randall Spangler <rspangler@chromium.org> | 2011-07-08 13:31:36 -0700 |
commit | 1b1998dff0002f20b3f27a21e6e79d8951e64684 (patch) | |
tree | fec838ef7d0867dc021087308c57b8b9cd1197b1 | |
parent | e49e8af65fce38da7a308305566f8a14f102254a (diff) | |
download | vboot-1b1998dff0002f20b3f27a21e6e79d8951e64684.tar.gz |
Vboot wrapper initial implementation
Patch 1: Initial change
Patch 2: Fix comment in vboot_struct.h
Patch 3: Revert files unintentionally reverted
Patch 4: (rebase)
Patch 5: (rebase)
Patch 6: Revert files unintentionally reverted (again)
Patch 7: Fix mocked tlcl for ARM build
BUG=chromium-os:17010
TEST=make && make runtests; works on H2C; emerge-tegra2_seaboard chromeos-bootimage compiles
Change-Id: I6e5ce72d41b9297c07a3f330a881eba68cfabee2
Reviewed-on: http://gerrit.chromium.org/gerrit/3593
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Tested-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r-- | firmware/Makefile | 7 | ||||
-rw-r--r-- | firmware/include/boot_device.h | 26 | ||||
-rw-r--r-- | firmware/include/load_firmware_fw.h | 2 | ||||
-rw-r--r-- | firmware/include/tlcl.h | 1 | ||||
-rw-r--r-- | firmware/include/tlcl_stub.h | 35 | ||||
-rw-r--r-- | firmware/include/vboot_api.h | 4 | ||||
-rw-r--r-- | firmware/include/vboot_struct.h | 12 | ||||
-rw-r--r-- | firmware/lib/include/vboot_kernel.h | 6 | ||||
-rw-r--r-- | firmware/lib/rollback_index.c | 3 | ||||
-rw-r--r-- | firmware/lib/tpm_lite/mocked_tlcl.c | 5 | ||||
-rw-r--r-- | firmware/lib/tpm_lite/tlcl.c | 12 | ||||
-rw-r--r-- | firmware/lib/vboot_api_firmware.c | 115 | ||||
-rw-r--r-- | firmware/lib/vboot_api_init.c | 133 | ||||
-rw-r--r-- | firmware/lib/vboot_api_kernel.c | 570 | ||||
-rw-r--r-- | firmware/lib/vboot_firmware.c | 34 | ||||
-rw-r--r-- | firmware/lib/vboot_kernel.c | 49 | ||||
-rw-r--r-- | firmware/linktest/main.c | 10 | ||||
-rw-r--r-- | firmware/stub/boot_device_stub.c | 20 | ||||
-rw-r--r-- | firmware/stub/load_firmware_stub.c | 127 | ||||
-rw-r--r-- | firmware/stub/tpm_lite_stub.c | 31 | ||||
-rw-r--r-- | host/Makefile | 2 | ||||
-rw-r--r-- | utility/load_kernel_test.c | 15 |
22 files changed, 908 insertions, 311 deletions
diff --git a/firmware/Makefile b/firmware/Makefile index 72e813e3..f72000a1 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -1,4 +1,4 @@ -# Copyright (c) 2010 The Chromium OS Authors. All rights reserved. +# 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. @@ -60,6 +60,9 @@ LIB_SRCS = \ ./lib/stateful_util.c \ ./lib/utility.c \ ./lib/utility_string.c \ + ./lib/vboot_api_init.c \ + ./lib/vboot_api_firmware.c \ + ./lib/vboot_api_kernel.c \ ./lib/vboot_common.c \ ./lib/vboot_firmware.c \ ./lib/vboot_kernel.c \ @@ -80,8 +83,6 @@ endif LIB_OBJS = $(LIB_SRCS:%.c=${BUILD_ROOT}/%.o) STUB_SRCS = \ - ./stub/boot_device_stub.c \ - ./stub/load_firmware_stub.c \ ./stub/tpm_lite_stub.c \ ./stub/utility_stub.c \ ./stub/vboot_api_stub.c \ diff --git a/firmware/include/boot_device.h b/firmware/include/boot_device.h deleted file mode 100644 index 10303ca4..00000000 --- a/firmware/include/boot_device.h +++ /dev/null @@ -1,26 +0,0 @@ -/* Copyright (c) 2010 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. - */ - -/* Helper functions/wrappers for raw sector access to current boot device. */ - -#ifndef VBOOT_REFERENCE_BOOT_DEVICE_H_ -#define VBOOT_REFERENCE_BOOT_DEVICE_H_ - -#include "sysincludes.h" - -int BootDeviceReadLBA(uint64_t lba_start, uint64_t lba_count, void *buffer); -/* Reads lba_count LBA sectors, starting at sector lba_start, from the current - * boot device, into the buffer. - * - * Returns 0 if successful or 1 if error. */ - -int BootDeviceWriteLBA(uint64_t lba_start, uint64_t lba_count, - const void *buffer); -/* Writes lba_count LBA sectors, starting at sector lba_start, to the current - * boot device, from the buffer. - * - * Returns 0 if successful or 1 if error. */ - -#endif /* VBOOT_REFERENCE_BOOT_DEVICE_H_ */ diff --git a/firmware/include/load_firmware_fw.h b/firmware/include/load_firmware_fw.h index 11fb0ce7..98beabd3 100644 --- a/firmware/include/load_firmware_fw.h +++ b/firmware/include/load_firmware_fw.h @@ -100,7 +100,7 @@ int LoadFirmware(LoadFirmwareParams* params); * by [size] bytes stored in [*data]. This function must only be * called inside GetFirmwareBody(). */ void UpdateFirmwareBodyHash(LoadFirmwareParams* params, - uint8_t* data, uint64_t size); + uint8_t* data, uint32_t size); /* Handle S3 resume. * diff --git a/firmware/include/tlcl.h b/firmware/include/tlcl.h index 10d08024..cb7ea9ab 100644 --- a/firmware/include/tlcl.h +++ b/firmware/include/tlcl.h @@ -13,7 +13,6 @@ #include "sysincludes.h" #include "tss_constants.h" -#include "tlcl_stub.h" /*****************************************************************************/ /* Functions implemented in tlcl.c */ diff --git a/firmware/include/tlcl_stub.h b/firmware/include/tlcl_stub.h deleted file mode 100644 index ea7d96a3..00000000 --- a/firmware/include/tlcl_stub.h +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright (c) 2010-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. - */ - -/* TPM Lightweight Command Library. - * - * A low-level library for interfacing to TPM hardware or an emulator. - */ - -#ifndef VBOOT_REFERENCE_TLCL_STUB_H_ -#define VBOOT_REFERENCE_TLCL_STUB_H_ - -#include "sysincludes.h" -#include "tss_constants.h" - -/*****************************************************************************/ -/* Functions to be implemented by the stub library */ - -/* Initialize the stub library. Returns 0 if success, nonzero if error. */ -uint32_t TlclStubInit(void); - -/* Close and open the device. This is needed for running more complex commands - * at user level, such as TPM_TakeOwnership, since the TPM device can be opened - * only by one process at a time. Returns 0 if success, nonzero if error. - */ -uint32_t TlclCloseDevice(void); -uint32_t TlclOpenDevice(void); - -/* Send data to the TPM and receive a response. Returns 0 if success, - * nonzero if error. */ -uint32_t TlclStubSendReceive(const uint8_t* request, int request_length, - uint8_t* response, int max_length); - -#endif /* VBOOT_REFERENCE_TLCL_STUB_H_ */ diff --git a/firmware/include/vboot_api.h b/firmware/include/vboot_api.h index 0de2dadf..c9eeb33d 100644 --- a/firmware/include/vboot_api.h +++ b/firmware/include/vboot_api.h @@ -93,6 +93,8 @@ typedef struct VbCommonParams { #define VB_INIT_FLAG_REC_BUTTON_PRESSED 0x00000002 /* Hardware write protect was enabled at boot time. */ #define VB_INIT_FLAG_WP_ENABLED 0x00000004 +/* This is a S3 resume, not a normal boot. */ +#define VB_INIT_FLAG_S3_RESUME 0x00000008 /* Output flags for VbInitParams.out_flags. Used to indicate @@ -113,6 +115,8 @@ typedef struct VbCommonParams { * VB_DISK_FLAG_REMOVABLE flag. If this flag is not present, VbExDisk*() * functions will only be called for fixed disks. */ #define VB_INIT_OUT_ENABLE_USB_STORAGE 0x00000008 +/* If this is a S3 resume, do a debug reset boot instead */ +#define VB_INIT_OUT_S3_DEBUG_BOOT 0x00000010 /* Data only used by VbInit() */ diff --git a/firmware/include/vboot_struct.h b/firmware/include/vboot_struct.h index 2dab7421..e9336dfe 100644 --- a/firmware/include/vboot_struct.h +++ b/firmware/include/vboot_struct.h @@ -155,6 +155,8 @@ typedef struct VbKernelPreambleHeader { #define VBSD_BOOT_REC_SWITCH_ON 0x00000020 /* Firmware write protect was enabled at boot time */ #define VBSD_BOOT_FIRMWARE_WP_ENABLED 0x00000040 +/* Boot is a S3->S0 resume, not a S5->S0 normal boot */ +#define VBSD_BOOT_S3_RESUME 0x00000100 /* Result codes for VbSharedDataHeader.check_fw_a_result (and b_result) */ @@ -277,11 +279,11 @@ typedef struct VbSharedDataHeader { * start of this struct */ uint64_t kernel_subkey_data_size; /* Size of kernel subkey data */ - /* Timer values from VbGetTimer(). Unused values are set to 0. If a - * function is called mutiple times, these are the times from the - * most recent call. */ - uint64_t timer_load_firmware_start_enter; /* LoadFirmwareStart() - enter */ - uint64_t timer_load_firmware_start_exit; /* LoadFirmwareStart() - exit */ + /* Timer values from VbExGetTimer(). Unused values are set to 0. + * If a function is called mutiple times, these are the times from + * the most recent call. See crosbug.com/17018. */ + uint64_t timer_load_firmware_start_enter; /* VbInit() - enter */ + uint64_t timer_load_firmware_start_exit; /* VbInit() - exit */ uint64_t timer_load_firmware_enter; /* LoadFirmware() - enter */ uint64_t timer_load_firmware_exit; /* LoadFirmware() - exit */ uint64_t timer_load_kernel_enter; /* LoadKernel() - enter */ diff --git a/firmware/lib/include/vboot_kernel.h b/firmware/lib/include/vboot_kernel.h index ab7e9fc8..a9d8a407 100644 --- a/firmware/lib/include/vboot_kernel.h +++ b/firmware/lib/include/vboot_kernel.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. +/* 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. * @@ -17,10 +17,10 @@ * secondary header and entries are filled on output. * * Returns 0 if successful, 1 if error. */ -int AllocAndReadGptData(GptData* gptdata); +int AllocAndReadGptData(VbExDiskHandle_t disk_handle, GptData* gptdata); /* Writes any changes for the GPT data back to the drive, then frees the * buffers. */ -int WriteAndFreeGptData(GptData* gptdata); +int WriteAndFreeGptData(VbExDiskHandle_t disk_handle, GptData* gptdata); #endif /* VBOOT_REFERENCE_VBOOT_KERNEL_H_ */ diff --git a/firmware/lib/rollback_index.c b/firmware/lib/rollback_index.c index e9ddccb8..a06f4858 100644 --- a/firmware/lib/rollback_index.c +++ b/firmware/lib/rollback_index.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2011 The Chromium OS Authors. All rights reserved. +/* 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. * @@ -7,7 +7,6 @@ */ #include "rollback_index.h" - #include "tlcl.h" #include "tpm_bootmode.h" #include "tss_constants.h" diff --git a/firmware/lib/tpm_lite/mocked_tlcl.c b/firmware/lib/tpm_lite/mocked_tlcl.c index 6253105d..790274f5 100644 --- a/firmware/lib/tpm_lite/mocked_tlcl.c +++ b/firmware/lib/tpm_lite/mocked_tlcl.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2010-2011 The Chromium OS Authors. All rights reserved. +/* 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. */ @@ -6,9 +6,10 @@ #include "tlcl.h" #include "tlcl_internal.h" #include "utility.h" +#include "vboot_api.h" uint32_t TlclLibInit(void) { - return TlclStubInit(); + return VbExTpmInit(); } uint32_t TlclStartup(void) { diff --git a/firmware/lib/tpm_lite/tlcl.c b/firmware/lib/tpm_lite/tlcl.c index 5c623b6f..fc820b55 100644 --- a/firmware/lib/tpm_lite/tlcl.c +++ b/firmware/lib/tpm_lite/tlcl.c @@ -50,6 +50,8 @@ static INLINE int TpmReturnCode(const uint8_t* buffer) { */ static uint32_t TlclSendReceiveNoRetry(const uint8_t* request, uint8_t* response, int max_length) { + + uint32_t response_length = max_length; uint32_t result; #ifdef EXTRA_LOGGING @@ -59,8 +61,8 @@ static uint32_t TlclSendReceiveNoRetry(const uint8_t* request, request[6], request[7], request[8], request[9])); #endif - result = TlclStubSendReceive(request, TpmCommandSize(request), - response, max_length); + result = VbExTpmSendReceive(request, TpmCommandSize(request), + response, &response_length); if (0 != result) { /* Communication with TPM failed, so response is garbage */ VBDEBUG(("TPM: command 0x%x send/receive failed: 0x%x\n", @@ -70,6 +72,10 @@ static uint32_t TlclSendReceiveNoRetry(const uint8_t* request, /* Otherwise, use the result code from the response */ result = TpmReturnCode(response); + /* TODO: add paranoia about returned response_length vs. max_length + * (and possibly expected length from the response header). See + * crosbug.com/17017 */ + #ifdef EXTRA_LOGGING VBDEBUG(("TPM: response: %x%x %x%x%x%x %x%x%x%x\n", response[0], response[1], @@ -127,7 +133,7 @@ static uint32_t Send(const uint8_t* command) { /* Exported functions. */ uint32_t TlclLibInit(void) { - return TlclStubInit(); + return VbExTpmInit(); } uint32_t TlclStartup(void) { diff --git a/firmware/lib/vboot_api_firmware.c b/firmware/lib/vboot_api_firmware.c new file mode 100644 index 00000000..b4c14811 --- /dev/null +++ b/firmware/lib/vboot_api_firmware.c @@ -0,0 +1,115 @@ +/* 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. + * + * High-level firmware wrapper API - entry points for init, firmware selection + */ + +#include "gbb_header.h" +#include "load_firmware_fw.h" +#include "utility.h" +#include "vboot_api.h" +#include "vboot_common.h" +#include "vboot_nvstorage.h" + + +VbError_t VbSelectFirmware(VbCommonParams* cparams, + VbSelectFirmwareParams* fparams) { + VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob; + LoadFirmwareParams p; + VbNvContext vnc; + int rv; + + /* If recovery is requested, go straight to recovery without checking the + * RW firmware. */ + if (VBNV_RECOVERY_NOT_REQUESTED != shared->recovery_reason) { + VBDEBUG(("VbSelectFirmware() detected recovery request, reason=%d.\n", + (int)shared->recovery_reason)); + fparams->selected_firmware = VB_SELECT_FIRMWARE_RECOVERY; + return VBERROR_SUCCESS; + } + + /* Copy parameters from wrapper API structs to old struct */ + p.gbb_data = cparams->gbb_data; + p.gbb_size = cparams->gbb_size; + p.shared_data_blob = cparams->shared_data_blob; + p.shared_data_size = cparams->shared_data_size; + p.nv_context = &vnc; + + /* TODO: LoadFirmware() should use VbSharedDataHeader.flags directly. */ + p.boot_flags = 0; + if (shared->flags & VBSD_BOOT_DEV_SWITCH_ON) + p.boot_flags |= BOOT_FLAG_DEVELOPER; + + p.verification_block_0 = fparams->verification_block_A; + p.verification_block_1 = fparams->verification_block_B; + p.verification_size_0 = fparams->verification_size_A; + p.verification_size_1 = fparams->verification_size_B; + + /* Load NV storage */ + VbExNvStorageRead(vnc.raw); + vnc.raw_changed = 0; + + /* Use vboot_context and caller_internal to link our params with + * LoadFirmware()'s params. */ + // TODO: clean up LoadFirmware() to use common params? + p.caller_internal = (void*)cparams; + cparams->vboot_context = (void*)&p; + + /* Chain to LoadFirmware() */ + rv = LoadFirmware(&p); + + /* Save NV storage, if necessary */ + if (vnc.raw_changed) + VbExNvStorageWrite(vnc.raw); + + /* Copy amount of used shared data back to the wrapper API struct */ + cparams->shared_data_size = (uint32_t)p.shared_data_size; + + /* Translate return codes */ + if (LOAD_FIRMWARE_SUCCESS == rv) { + /* Found good firmware in either A or B */ + if (0 == p.firmware_index) + fparams->selected_firmware = VB_SELECT_FIRMWARE_A; + else + fparams->selected_firmware = VB_SELECT_FIRMWARE_B; + return VBERROR_SUCCESS; + + } else if (LOAD_FIRMWARE_REBOOT == rv) { + /* Reboot in the same mode we just left; copy the recovery reason */ + VbNvSetup(&vnc); + VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, shared->recovery_reason); + VbNvTeardown(&vnc); + if (vnc.raw_changed) + VbExNvStorageWrite(vnc.raw); + return 1; + + } else { + /* Other error */ + return 1; + } +} + + +/* TODO: Move this inside vboot_firmware.c; for now this just translates to + * the original function call. */ +void VbUpdateFirmwareBodyHash(VbCommonParams* cparams, uint8_t* data, + uint32_t size) { + LoadFirmwareParams* lfparams = (LoadFirmwareParams*)cparams->vboot_context; + + UpdateFirmwareBodyHash(lfparams, data, size); +} + + +/* Translation layer from LoadFirmware()'s GetFirmwareBody() to the new + * wrapper API call. + * + * TODO: call directly from LoadFirmware() */ +int GetFirmwareBody(LoadFirmwareParams* lfparams, uint64_t index) { + VbCommonParams* cparams = (VbCommonParams*)lfparams->caller_internal; + VbError_t rv; + + rv = VbExHashFirmwareBody(cparams, (index ? VB_SELECT_FIRMWARE_B : + VB_SELECT_FIRMWARE_A)); + return (VBERROR_SUCCESS == rv ? 0 : 1); +} diff --git a/firmware/lib/vboot_api_init.c b/firmware/lib/vboot_api_init.c new file mode 100644 index 00000000..8bccfe53 --- /dev/null +++ b/firmware/lib/vboot_api_init.c @@ -0,0 +1,133 @@ +/* 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. + * + * High-level firmware wrapper API - entry points for init, firmware selection + */ + +#include "gbb_header.h" +#include "load_firmware_fw.h" +#include "rollback_index.h" +#include "utility.h" +#include "vboot_api.h" +#include "vboot_common.h" +#include "vboot_nvstorage.h" + + +VbError_t VbInit(VbCommonParams* cparams, VbInitParams* iparams) { + VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob; + VbNvContext vnc; + uint32_t recovery = VBNV_RECOVERY_NOT_REQUESTED; + int is_s3_resume = 0; + uint32_t s3_debug_boot = 0; + + VBDEBUG(("VbInit() input flags 0x%x\n", iparams->flags)); + + /* Initialize output flags */ + iparams->out_flags = 0; + + /* Set up NV storage */ + VbExNvStorageRead(vnc.raw); + VbNvSetup(&vnc); + + /* Initialize shared data structure */ + if (0 != VbSharedDataInit(shared, cparams->shared_data_size)) { + VBDEBUG(("Shared data init error\n")); + return 1; + } + + shared->timer_load_firmware_start_enter = VbExGetTimer(); + + /* Copy boot switch flags */ + shared->flags = 0; + if (iparams->flags & VB_INIT_FLAG_DEV_SWITCH_ON) + shared->flags |= VBSD_BOOT_DEV_SWITCH_ON; + if (iparams->flags & VB_INIT_FLAG_REC_BUTTON_PRESSED) + shared->flags |= VBSD_BOOT_REC_SWITCH_ON; + if (iparams->flags & VB_INIT_FLAG_WP_ENABLED) + shared->flags |= VBSD_BOOT_FIRMWARE_WP_ENABLED; + if (iparams->flags & VB_INIT_FLAG_S3_RESUME) + shared->flags |= VBSD_BOOT_S3_RESUME; + + is_s3_resume = (iparams->flags & VB_INIT_FLAG_S3_RESUME ? 1 : 0); + + /* Check if the OS is requesting a debug S3 reset */ + VbNvGet(&vnc, VBNV_DEBUG_RESET_MODE, &s3_debug_boot); + if (s3_debug_boot) { + if (is_s3_resume) { + VBDEBUG(("VbInit() requesting S3 debug boot\n")); + iparams->out_flags |= VB_INIT_OUT_S3_DEBUG_BOOT; + is_s3_resume = 0; /* Proceed as if this is a normal boot */ + } + + /* Clear the request even if this is a normal boot, since we don't + * want the NEXT S3 resume to be a debug reset unless the OS + * asserts the request again. */ + VbNvSet(&vnc, VBNV_DEBUG_RESET_MODE, 0); + } + + /* If this isn't a S3 resume, read the current recovery request, then clear + * it so we don't get stuck in recovery mode. */ + if (!is_s3_resume) { + VbNvGet(&vnc, VBNV_RECOVERY_REQUEST, &recovery); + if (VBNV_RECOVERY_NOT_REQUESTED != recovery) + VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_NOT_REQUESTED); + } + + /* If recovery button is pressed, override recovery reason. Note that we + * do this in the S3 resume path also. */ + if (iparams->flags & VB_INIT_FLAG_REC_BUTTON_PRESSED) + recovery = VBNV_RECOVERY_RO_MANUAL; + + /* Set output flags */ + if (VBNV_RECOVERY_NOT_REQUESTED != recovery) { + /* Requesting recovery mode */ + iparams->out_flags |= (VB_INIT_OUT_ENABLE_RECOVERY | + VB_INIT_OUT_CLEAR_RAM | + VB_INIT_OUT_ENABLE_DISPLAY | + VB_INIT_OUT_ENABLE_USB_STORAGE); + } + else if (iparams->flags & VB_INIT_FLAG_DEV_SWITCH_ON) { + /* Developer switch is on, so need to support dev mode */ + iparams->out_flags |= (VB_INIT_OUT_CLEAR_RAM | + VB_INIT_OUT_ENABLE_DISPLAY | + VB_INIT_OUT_ENABLE_USB_STORAGE); + } + + /* Copy current recovery reason to shared data */ + shared->recovery_reason = (uint8_t)recovery; + + /* Clear the recovery request, so we won't get stuck in recovery mode */ + VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, VBNV_RECOVERY_NOT_REQUESTED); + + // TODO: Handle S3 resume path ourselves, if VB_INIT_FLAG_S3_RESUME + // (I believe we can do this now...) + + /* Tear down NV storage */ + VbNvTeardown(&vnc); + if (vnc.raw_changed) + VbExNvStorageWrite(vnc.raw); + + VBDEBUG(("VbInit() output flags 0x%x\n", iparams->out_flags)); + + shared->timer_load_firmware_start_exit = VbExGetTimer(); + + return VBERROR_SUCCESS; +} + + +VbError_t VbS3Resume(void) { + + /* TODO: handle test errors (requires passing in VbNvContext) */ + + /* Resume the TPM */ + uint32_t status = RollbackS3Resume(); + + /* If we can't resume, just do a full reboot. No need to go to recovery + * mode here, since if the TPM is really broken we'll catch it on the + * next boot. */ + if (status == TPM_SUCCESS) + return VBERROR_SUCCESS; + else + return 1; +} diff --git a/firmware/lib/vboot_api_kernel.c b/firmware/lib/vboot_api_kernel.c new file mode 100644 index 00000000..1afac378 --- /dev/null +++ b/firmware/lib/vboot_api_kernel.c @@ -0,0 +1,570 @@ +/* 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. + * + * High-level firmware wrapper API - entry points for kernel selection + */ + +#include "gbb_header.h" +#include "load_kernel_fw.h" +#include "utility.h" +#include "vboot_api.h" +#include "vboot_common.h" +#include "vboot_nvstorage.h" + + +/* Global variables */ +static uint32_t disp_current_screen = VB_SCREEN_BLANK; +static uint32_t disp_width = 0, disp_height = 0; +static VbNvContext vnc; + + +#ifdef CHROMEOS_ENVIRONMENT +/* Global variable accessors for unit tests */ +VbNvContext* VbApiKernelGetVnc(void) { + return &vnc; +} +#endif + + +/* Set recovery request */ +static void VbSetRecoveryRequest(uint32_t recovery_request) { + VBDEBUG(("VbSetRecoveryRequest(%d)\n", (int)recovery_request)); + + VbNvSetup(&vnc); + VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, recovery_request); + VbNvTeardown(&vnc); + if (vnc.raw_changed) + VbExNvStorageWrite(vnc.raw); +} + + +/* Get the number of localizations in the GBB bitmap data. */ +static VbError_t VbGetLocalizationCount(VbCommonParams* cparams, + uint32_t* count) { + GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)cparams->gbb_data; + BmpBlockHeader* hdr; + + /* Default to 0 on error */ + *count = 0; + + /* Make sure the bitmap data is inside the GBB and is non-zero in size */ + if (0 == gbb->bmpfv_size || + gbb->bmpfv_offset > cparams->gbb_size || + gbb->bmpfv_offset + gbb->bmpfv_size > cparams->gbb_size) { + return 1; + } + + /* Sanity-check the bitmap block header */ + hdr = (BmpBlockHeader *)(((uint8_t*)gbb) + gbb->bmpfv_offset); + if ((0 != Memcmp(hdr->signature, BMPBLOCK_SIGNATURE, + BMPBLOCK_SIGNATURE_SIZE)) || + (hdr->major_version > BMPBLOCK_MAJOR_VERSION) || + ((hdr->major_version == BMPBLOCK_MAJOR_VERSION) && + (hdr->minor_version > BMPBLOCK_MINOR_VERSION))) { + return 1; + } + + *count = hdr->number_of_localizations; + return VBERROR_SUCCESS; +} + + +/* Display a screen from the GBB. */ +static VbError_t VbDisplayScreenFromGBB(VbCommonParams* cparams, + uint32_t screen) { + GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)cparams->gbb_data; + uint8_t* bmpfv = NULL; + BmpBlockHeader* hdr; + ScreenLayout* layout; + ImageInfo* image_info; + uint32_t screen_index; + uint32_t localization = 0; + VbError_t retval = 1; /* Assume error until proven successful */ + uint32_t offset; + uint32_t i; + + /* Make sure the bitmap data is inside the GBB and is non-zero in size */ + if (0 == gbb->bmpfv_size || + gbb->bmpfv_offset > cparams->gbb_size || + gbb->bmpfv_offset + gbb->bmpfv_size > cparams->gbb_size) { + VBDEBUG(("VbDisplayScreenFromGBB(): invalid bmpfv offset/size\n")); + return 1; + } + + /* Copy bitmap data from GBB into RAM for speed */ + bmpfv = (uint8_t*)VbExMalloc(gbb->bmpfv_size); + Memcpy(bmpfv, ((uint8_t*)gbb) + gbb->bmpfv_offset, gbb->bmpfv_size); + + /* Sanity-check the bitmap block header */ + hdr = (BmpBlockHeader *)bmpfv; + if ((0 != Memcmp(hdr->signature, BMPBLOCK_SIGNATURE, + BMPBLOCK_SIGNATURE_SIZE)) || + (hdr->major_version > BMPBLOCK_MAJOR_VERSION) || + ((hdr->major_version == BMPBLOCK_MAJOR_VERSION) && + (hdr->minor_version > BMPBLOCK_MINOR_VERSION))) { + VBDEBUG(("VbDisplayScreenFromGBB(): invalid/too new bitmap header\n")); + goto VbDisplayScreenFromGBB_exit; + } + + /* Translate screen ID into index. Note that not all screens are in the + * GBB. */ + /* TODO: ensure screen IDs match indices? Having this translation + * here is awful. */ + switch (screen) { + case VB_SCREEN_DEVELOPER_WARNING: + screen_index = 0; + break; + case VB_SCREEN_RECOVERY_REMOVE: + screen_index = 1; + break; + case VB_SCREEN_RECOVERY_NO_GOOD: + screen_index = 2; + break; + case VB_SCREEN_RECOVERY_INSERT: + screen_index = 3; + break; + case VB_SCREEN_BLANK: + case VB_SCREEN_DEVELOPER_EGG: + default: + /* Screens which aren't in the GBB */ + VBDEBUG(("VbDisplayScreenFromGBB(): screen %d not in the GBB\n", + (int)screen)); + goto VbDisplayScreenFromGBB_exit; + } + if (screen_index >= hdr->number_of_screenlayouts) { + VBDEBUG(("VbDisplayScreenFromGBB(): screen %d index %d not in the GBB\n", + (int)screen, (int)screen_index)); + goto VbDisplayScreenFromGBB_exit; + } + + /* Clip localization to the number of localizations present in the GBB */ + VbNvSetup(&vnc); + VbNvGet(&vnc, VBNV_LOCALIZATION_INDEX, &localization); + if (localization >= hdr->number_of_localizations) { + localization = 0; + VbNvSet(&vnc, VBNV_LOCALIZATION_INDEX, localization); + } + VbNvTeardown(&vnc); + if (vnc.raw_changed) + VbExNvStorageWrite(vnc.raw); + + /* Calculate offset of screen layout = start of screen stuff + + * correct locale + correct screen. */ + offset = sizeof(BmpBlockHeader) + + localization * hdr->number_of_screenlayouts * sizeof(ScreenLayout) + + screen_index * sizeof(ScreenLayout); + VBDEBUG(("VbDisplayScreenFromGBB(): scr_%d_%d at offset 0x%x\n", + localization, screen_index, offset)); + layout = (ScreenLayout*)(bmpfv + offset); + + /* Display all bitmaps for the image */ + for (i = 0; i < MAX_IMAGE_IN_LAYOUT; i++) { + if (layout->images[i].image_info_offset) { + offset = layout->images[i].image_info_offset; + image_info = (ImageInfo*)(bmpfv + offset); + VBDEBUG(("VbDisplayScreenFromGBB: image %d: %dx%d+%d+%d %d/%d" + "tag %d at 0x%x\n", + i, image_info->width, image_info->height, + layout->images[i].x, layout->images[i].y, + image_info->compressed_size, image_info->original_size, + image_info->tag, offset)); + + retval = VbExDisplayImage(layout->images[i].x, layout->images[i].y, + image_info, bmpfv + offset + sizeof(ImageInfo)); + if (VBERROR_SUCCESS != retval) + goto VbDisplayScreenFromGBB_exit; + } + } + + /* Successful if all bitmaps displayed */ + retval = VBERROR_SUCCESS; + +VbDisplayScreenFromGBB_exit: + + /* Free the bitmap data copy */ + VbExFree(bmpfv); + return retval; +} + + +/* Display a screen, initializing the display if necessary. If force!=0, + * redisplays the screen even if it's the same as the current screen. */ +static VbError_t VbDisplayScreen(VbCommonParams* cparams, uint32_t screen, + int force) { + + VBDEBUG(("VbDisplayScreen(%d, %d)\n", (int)screen, force)); + + /* Initialize display if necessary */ + if (!disp_width) { + if (VBERROR_SUCCESS != VbExDisplayInit(&disp_width, &disp_height)) + return 1; + } + + /* If the requested screen is the same as the current one, we're done. */ + if (disp_current_screen == screen && 0 == force) + return VBERROR_SUCCESS; + + /* If the screen is blank, turn off the backlight; else turn it on. */ + VbExDisplayBacklight(VB_SCREEN_BLANK == screen ? 0 : 1); + + /* Request the screen */ + disp_current_screen = screen; + + /* Look in the GBB first */ + if (VBERROR_SUCCESS == VbDisplayScreenFromGBB(cparams, screen)) + return VBERROR_SUCCESS; + + /* If the screen wasn't in the GBB bitmaps, fall back to a default screen. */ + return VbExDisplayScreen(screen); +} + + +static VbError_t VbCheckDisplayKey(VbCommonParams* cparams, uint32_t key) { + + if ('\t' == key) { + /* Tab = display debug info */ + + /* Redisplay the current screen, to overwrite any previous debug output */ + VbDisplayScreen(cparams, disp_current_screen, 1); + + /* TODO: add real data: + * - HWID + * - Current recovery request + * - Boot flags + * - Information on current disks + * - Anything else interesting from cparams and/or nvram + * + * TODO: Add a VbExSnprintf() function for this? */ + return VbExDisplayDebugInfo("Testing 1 2 3\nTesting 4 5 6\n"); + + } else if (VB_KEY_LEFT == key || VB_KEY_RIGHT == key) { + /* Arrow keys = change localization */ + uint32_t loc = 0; + uint32_t count = 0; + + /* Get localization count */ + VbGetLocalizationCount(cparams, &count); + + /* Change localization */ + VbNvSetup(&vnc); + VbNvGet(&vnc, VBNV_LOCALIZATION_INDEX, &loc); + if (VB_KEY_RIGHT == key) + loc = (loc < count - 1 ? loc + 1 : 0); + else + loc = (loc > 0 ? loc - 1 : count - 1); + VBDEBUG(("VbCheckDisplayKey() - change localization to %d\n", (int)loc)); + VbNvSet(&vnc, VBNV_LOCALIZATION_INDEX, loc); + VbNvTeardown(&vnc); + if (vnc.raw_changed) + VbExNvStorageWrite(vnc.raw); + + /* Force redraw of current screen */ + return VbDisplayScreen(cparams, disp_current_screen, 1); + } + + return VBERROR_SUCCESS; +} + + +/* Return codes fof VbTryLoadKernel, in addition to VBERROR_SUCCESS */ +enum VbTryLoadKernelError_t { + /* No disks found */ + VBERROR_TRY_LOAD_NO_DISKS = 1, + /* Need to reboot to same mode/recovery reason as this boot */ + VBERROR_TRY_LOAD_REBOOT = 2, + /* Some other error; go to recovery mode if this was the only hope to boot */ + VBERROR_TRY_LOAD_RECOVERY = 3, +}; + + +/* Attempt loading a kernel from the specified type(s) of disks. If + * successful, sets p->disk_handle to the disk for the kernel. See + * VBERROR_TRY_LOAD_* for additional return codes. */ +uint32_t VbTryLoadKernel(VbCommonParams* cparams, LoadKernelParams* p, + uint32_t get_info_flags) { + VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob; + int retval = VBERROR_TRY_LOAD_NO_DISKS; + VbDiskInfo* disk_info = NULL; + uint32_t disk_count = 0; + uint32_t i; + + VBDEBUG(("VbTryLoadKernel() start, get_info_flags=0x%x\n", + (int)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_TRY_LOAD_NO_DISKS; + } + + /* Loop over disks */ + for (i = 0; i < disk_count; i++) { + VBDEBUG(("VbTryLoadKernel() trying disk %d\n", (int)i)); + p->disk_handle = disk_info[i].handle; + p->bytes_per_lba = disk_info[i].bytes_per_lba; + p->ending_lba = disk_info[i].lba_count - 1; + retval = LoadKernel(p); + VBDEBUG(("VbTryLoadKernel() LoadKernel() returned %d\n", retval)); + + /* Stop now if we found a kernel or we need to reboot */ + /* TODO: If recovery requested, should track the farthest we get, instead + * of just returning the value from the last disk attempted. */ + if (LOAD_KERNEL_SUCCESS == retval || LOAD_KERNEL_REBOOT == retval) + break; + } + + /* If we didn't succeed, don't return a disk handle */ + if (LOAD_KERNEL_SUCCESS != retval) + p->disk_handle = NULL; + + VbExDiskFreeInfo(disk_info, p->disk_handle); + + /* Translate return codes */ + switch (retval) { + case LOAD_KERNEL_SUCCESS: + return VBERROR_SUCCESS; + case LOAD_KERNEL_REBOOT: + /* Reboot to same mode, so reuse the current recovery reason */ + VbSetRecoveryRequest(shared->recovery_reason); + return VBERROR_TRY_LOAD_REBOOT; + case LOAD_KERNEL_NOT_FOUND: + VbSetRecoveryRequest(VBNV_RECOVERY_RW_NO_OS); + return VBERROR_TRY_LOAD_RECOVERY; + case LOAD_KERNEL_INVALID: + VbSetRecoveryRequest(VBNV_RECOVERY_RW_INVALID_OS); + return VBERROR_TRY_LOAD_RECOVERY; + case LOAD_KERNEL_RECOVERY: + return VBERROR_TRY_LOAD_RECOVERY; + default: + VbSetRecoveryRequest(VBNV_RECOVERY_RW_UNSPECIFIED); + return VBERROR_TRY_LOAD_RECOVERY; + } +} + + +/* Handle a normal boot from fixed drive only. */ +VbError_t VbBootNormal(VbCommonParams* cparams, LoadKernelParams* p) { + return VbTryLoadKernel(cparams, p, VB_DISK_FLAG_FIXED); +} + + +#ifdef BUILD_FVDEVELOPER +/* Developer mode delays. All must be multiples of DEV_DELAY_INCREMENT */ +#define DEV_DELAY_INCREMENT 250 /* Delay each loop, in msec */ +#define DEV_DELAY_BEEP1 20000 /* Beep for first time at this time */ +#define DEV_DELAY_BEEP2 21000 /* Beep for second time at this time */ +#define DEV_DELAY_TIMEOUT 30000 /* Give up at this time */ + +/* Handle a developer-mode boot */ +VbError_t VbBootDeveloper(VbCommonParams* cparams, LoadKernelParams* p) { + uint32_t delay_time = 0; + + /* Show the dev mode warning screen */ + VbDisplayScreen(cparams, VB_SCREEN_DEVELOPER_WARNING, 0); + + /* Loop for dev mode warning delay */ + for (delay_time = 0; delay_time < DEV_DELAY_TIMEOUT; + delay_time += DEV_DELAY_INCREMENT) { + uint32_t key; + + if (VbExIsShutdownRequested()) + return 1; + + if (DEV_DELAY_BEEP1 == delay_time || DEV_DELAY_BEEP2 == delay_time) + VbExBeep(DEV_DELAY_INCREMENT, 400); + else + VbExSleepMs(DEV_DELAY_INCREMENT); + + /* Handle keypress */ + key = VbExKeyboardRead(); + switch (key) { + case '\r': + case ' ': + case 0x1B: + /* Enter, space, or ESC = reboot to recovery */ + VBDEBUG(("VbBootDeveloper() - user pressed ENTER/SPACE/ESC")); + VbSetRecoveryRequest(VBNV_RECOVERY_RW_DEV_SCREEN); + return 1; + case 0x04: + /* Ctrl+D = dismiss warning; advance to timeout */ + VBDEBUG(("VbBootDeveloper() - user pressed Ctrl+D; skip delay\n")); + delay_time = DEV_DELAY_TIMEOUT; + break; + case 0x15: + /* Ctrl+U = try USB boot, or beep if failure */ + VBDEBUG(("VbBootDeveloper() - user pressed Ctrl+U; try USB\n")); + if (VBERROR_SUCCESS == VbTryLoadKernel(cparams, p, + VB_DISK_FLAG_REMOVABLE)) { + VBDEBUG(("VbBootDeveloper() - booting USB\n")); + return VBERROR_SUCCESS; + } else { + VBDEBUG(("VbBootDeveloper() - no kernel found on USB\n")); + VbExBeep(DEV_DELAY_INCREMENT, 400); + } + break; + default: + VbCheckDisplayKey(cparams, key); + break; + /* TODO: xyzzy easter egg check */ + } + } + + /* Timeout or Ctrl+D; attempt loading from fixed disk */ + VBDEBUG(("VbBootDeveloper() - trying fixed disk\n")); + return VbTryLoadKernel(cparams, p, VB_DISK_FLAG_FIXED); +} + +#endif /* BUILD_FVDEVELOPER */ + + +/* Delay between disk checks in recovery mode */ +#define REC_DELAY_INCREMENT 250 + +/* Handle a recovery-mode boot */ +VbError_t VbBootRecovery(VbCommonParams* cparams, LoadKernelParams* p) { + VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob; + uint32_t retval; + int i; + + VBDEBUG(("VbBootRecovery() start\n")); + + /* If dev mode switch is off, require removal of all external media. */ + if (!(shared->flags & VBSD_BOOT_DEV_SWITCH_ON)) { + VbDiskInfo* disk_info = NULL; + uint32_t disk_count = 0; + + VBDEBUG(("VbBootRecovery() forcing device removal\n")); + + while (1) { + 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); + break; + } + + VBDEBUG(("VbBootRecovery() waiting for %d disks to be removed\n", + (int)disk_count)); + + VbDisplayScreen(cparams, VB_SCREEN_RECOVERY_REMOVE, 0); + + /* Scan keyboard more frequently than media, since x86 platforms + * don't like to scan USB too rapidly. */ + for (i = 0; i < 4; i++) { + VbCheckDisplayKey(cparams, VbExKeyboardRead()); + if (VbExIsShutdownRequested()) + return 1; + VbExSleepMs(REC_DELAY_INCREMENT); + } + } + } + + /* Loop and wait for a recovery image */ + while (1) { + VBDEBUG(("VbBootRecovery() attempting to load kernel\n")); + retval = VbTryLoadKernel(cparams, p, VB_DISK_FLAG_REMOVABLE); + + if (VBERROR_SUCCESS == retval) + break; /* Found a recovery kernel */ + else if (VBERROR_TRY_LOAD_REBOOT == retval) + return 1; /* Must reboot (back into recovery mode) */ + + VbDisplayScreen(cparams, VBERROR_TRY_LOAD_NO_DISKS == retval ? + VB_SCREEN_RECOVERY_INSERT : VB_SCREEN_RECOVERY_NO_GOOD, 0); + + /* Scan keyboard more frequently than media, since x86 platforms don't like + * to scan USB too rapidly. */ + for (i = 0; i < 4; i++) { + VbCheckDisplayKey(cparams, VbExKeyboardRead()); + if (VbExIsShutdownRequested()) + return 1; + VbExSleepMs(REC_DELAY_INCREMENT); + } + } + + return VBERROR_SUCCESS; +} + + +VbError_t VbSelectAndLoadKernel(VbCommonParams* cparams, + VbSelectAndLoadKernelParams* kparams) { + VbSharedDataHeader* shared = (VbSharedDataHeader*)cparams->shared_data_blob; + VbError_t retval; + LoadKernelParams p; + + VBDEBUG(("VbSelectAndLoadKernel() start\n")); + + VbExNvStorageRead(vnc.raw); + vnc.raw_changed = 0; + + /* Clear output params in case we fail */ + kparams->disk_handle = NULL; + kparams->partition_number = 0; + kparams->bootloader_address = 0; + kparams->bootloader_size = 0; + Memset(kparams->partition_guid, 0, sizeof(kparams->partition_guid)); + + /* Fill in params for calls to LoadKernel() */ + p.shared_data_blob = cparams->shared_data_blob; + p.shared_data_size = cparams->shared_data_size; + p.gbb_data = cparams->gbb_data; + p.gbb_size = cparams->gbb_size; + p.kernel_buffer = kparams->kernel_buffer; + p.kernel_buffer_size = kparams->kernel_buffer_size; + p.nv_context = &vnc; + p.boot_flags = 0; + if (shared->flags & VBSD_BOOT_DEV_SWITCH_ON) + p.boot_flags |= BOOT_FLAG_DEVELOPER; + + /* Select boot path */ + if (shared->recovery_reason) { + /* Recovery boot */ + p.boot_flags |= BOOT_FLAG_RECOVERY; + retval = VbBootRecovery(cparams, &p); + VbDisplayScreen(cparams, VB_SCREEN_BLANK, 0); + } else { + /* TODO: vboot compiler define for developer mode; this is the H2C one */ +#ifdef BUILD_FVDEVELOPER + /* Developer boot */ + p.boot_flags |= BOOT_FLAG_DEV_FIRMWARE; + retval = VbBootDeveloper(cparams, &p); + VbDisplayScreen(cparams, VB_SCREEN_BLANK, 0); +#else + /* Normal boot */ + retval = VbBootNormal(cparams, &p); +#endif + } + + if (VBERROR_SUCCESS == retval) { + /* Save disk parameters */ + kparams->disk_handle = p.disk_handle; + kparams->partition_number = (uint32_t)p.partition_number; + kparams->bootloader_address = p.bootloader_address; + kparams->bootloader_size = (uint32_t)p.bootloader_size; + Memcpy(kparams->partition_guid, p.partition_guid, + sizeof(kparams->partition_guid)); + + /* Since we did find something to boot, clear recovery request, if any, + * resulting from disk checks during developer or recovery mode. */ + VbSetRecoveryRequest(VBNV_RECOVERY_NOT_REQUESTED); + } + + if (vnc.raw_changed) + VbExNvStorageWrite(vnc.raw); + + VBDEBUG(("VbSelectAndLoadKernel() returning %d\n", (int)retval)); + + /* Pass through return value from boot path */ + return retval; +} diff --git a/firmware/lib/vboot_firmware.c b/firmware/lib/vboot_firmware.c index 40ddf4cb..1022ad9d 100644 --- a/firmware/lib/vboot_firmware.c +++ b/firmware/lib/vboot_firmware.c @@ -26,7 +26,7 @@ typedef struct VbLoadFirmwareInternal { void UpdateFirmwareBodyHash(LoadFirmwareParams* params, - uint8_t* data, uint64_t size) { + uint8_t* data, uint32_t size) { VbLoadFirmwareInternal* lfi = (VbLoadFirmwareInternal*)params->load_firmware_internal; @@ -35,14 +35,6 @@ void UpdateFirmwareBodyHash(LoadFirmwareParams* params, } -int LoadFirmwareSetup(void) { - /* TODO: handle test errors (requires passing in VbNvContext) */ - /* TODO: record timer values (requires passing in VbSharedData) */ - /* TODO: start initializing the TPM */ - return LOAD_FIRMWARE_SUCCESS; -} - - int LoadFirmware(LoadFirmwareParams* params) { VbSharedDataHeader* shared = (VbSharedDataHeader*)params->shared_data_blob; GoogleBinaryBlockHeader* gbb = (GoogleBinaryBlockHeader*)params->gbb_data; @@ -72,12 +64,7 @@ int LoadFirmware(LoadFirmwareParams* params) { /* Setup NV storage */ VbNvSetup(vnc); - /* Initialize shared data structure. */ - if (0 != VbSharedDataInit(shared, params->shared_data_size)) { - VBDEBUG(("Shared data init error\n")); - recovery = VBNV_RECOVERY_RO_SHARED_DATA; - goto LoadFirmwareExit; - } + /* Start timer */ shared->timer_load_firmware_enter = VbExGetTimer(); /* Handle test errors */ @@ -399,20 +386,3 @@ LoadFirmwareExit: return retval; } - - -int S3Resume(void) { - - /* TODO: handle test errors (requires passing in VbNvContext) */ - - /* Resume the TPM */ - uint32_t status = RollbackS3Resume(); - - /* If we can't resume, just do a full reboot. No need to go to recovery - * mode here, since if the TPM is really broken we'll catch it on the - * next boot. */ - if (status == TPM_SUCCESS) - return LOAD_FIRMWARE_SUCCESS; - else - return LOAD_FIRMWARE_REBOOT; -} diff --git a/firmware/lib/vboot_kernel.c b/firmware/lib/vboot_kernel.c index ab96edf4..26c91210 100644 --- a/firmware/lib/vboot_kernel.c +++ b/firmware/lib/vboot_kernel.c @@ -6,7 +6,7 @@ * (Firmware portion) */ -#include "boot_device.h" + #include "cgptlib.h" #include "cgptlib_internal.h" #include "gbb_header.h" @@ -17,7 +17,6 @@ #include "vboot_common.h" #include "vboot_kernel.h" - #define KBUF_SIZE 65536 /* Bytes to read at start of kernel partition */ #define LOWEST_TPM_VERSION 0xffffffff @@ -33,7 +32,7 @@ typedef enum BootMode { * secondary header and entries are filled on output. * * Returns 0 if successful, 1 if error. */ -int AllocAndReadGptData(GptData* gptdata) { +int AllocAndReadGptData(VbExDiskHandle_t disk_handle, GptData* gptdata) { uint64_t entries_sectors = TOTAL_ENTRIES_SIZE / gptdata->sector_bytes; @@ -51,15 +50,17 @@ int AllocAndReadGptData(GptData* gptdata) { return 1; /* Read data from the drive, skipping the protective MBR */ - if (0 != BootDeviceReadLBA(1, 1, gptdata->primary_header)) + if (0 != VbExDiskRead(disk_handle, 1, 1, gptdata->primary_header)) return 1; - if (0 != BootDeviceReadLBA(2, entries_sectors, gptdata->primary_entries)) + if (0 != VbExDiskRead(disk_handle, 2, entries_sectors, + gptdata->primary_entries)) return 1; - if (0 != BootDeviceReadLBA(gptdata->drive_sectors - entries_sectors - 1, - entries_sectors, gptdata->secondary_entries)) + if (0 != VbExDiskRead(disk_handle, + gptdata->drive_sectors - entries_sectors - 1, + entries_sectors, gptdata->secondary_entries)) return 1; - if (0 != BootDeviceReadLBA(gptdata->drive_sectors - 1, - 1, gptdata->secondary_header)) + if (0 != VbExDiskRead(disk_handle, gptdata->drive_sectors - 1, 1, + gptdata->secondary_header)) return 1; return 0; @@ -70,14 +71,14 @@ int AllocAndReadGptData(GptData* gptdata) { * the buffers. * * Returns 0 if successful, 1 if error. */ -int WriteAndFreeGptData(GptData* gptdata) { +int WriteAndFreeGptData(VbExDiskHandle_t disk_handle, GptData* gptdata) { uint64_t entries_sectors = TOTAL_ENTRIES_SIZE / gptdata->sector_bytes; if (gptdata->primary_header) { if (gptdata->modified & GPT_MODIFIED_HEADER1) { VBDEBUG(("Updating GPT header 1\n")); - if (0 != BootDeviceWriteLBA(1, 1, gptdata->primary_header)) + if (0 != VbExDiskWrite(disk_handle, 1, 1, gptdata->primary_header)) return 1; } VbExFree(gptdata->primary_header); @@ -86,8 +87,8 @@ int WriteAndFreeGptData(GptData* gptdata) { if (gptdata->primary_entries) { if (gptdata->modified & GPT_MODIFIED_ENTRIES1) { VBDEBUG(("Updating GPT entries 1\n")); - if (0 != BootDeviceWriteLBA(2, entries_sectors, - gptdata->primary_entries)) + if (0 != VbExDiskWrite(disk_handle, 2, entries_sectors, + gptdata->primary_entries)) return 1; } VbExFree(gptdata->primary_entries); @@ -96,8 +97,9 @@ int WriteAndFreeGptData(GptData* gptdata) { if (gptdata->secondary_entries) { if (gptdata->modified & GPT_MODIFIED_ENTRIES2) { VBDEBUG(("Updating GPT header 2\n")); - if (0 != BootDeviceWriteLBA(gptdata->drive_sectors - entries_sectors - 1, - entries_sectors, gptdata->secondary_entries)) + if (0 != VbExDiskWrite(disk_handle, + gptdata->drive_sectors - entries_sectors - 1, + entries_sectors, gptdata->secondary_entries)) return 1; } VbExFree(gptdata->secondary_entries); @@ -106,8 +108,8 @@ int WriteAndFreeGptData(GptData* gptdata) { if (gptdata->secondary_header) { if (gptdata->modified & GPT_MODIFIED_HEADER2) { VBDEBUG(("Updating GPT entries 2\n")); - if (0 != BootDeviceWriteLBA(gptdata->drive_sectors - 1, 1, - gptdata->secondary_header)) + if (0 != VbExDiskWrite(disk_handle, gptdata->drive_sectors - 1, 1, + gptdata->secondary_header)) return 1; } VbExFree(gptdata->secondary_header); @@ -285,7 +287,7 @@ int LoadKernel(LoadKernelParams* params) { /* Read GPT data */ gpt.sector_bytes = (uint32_t)blba; gpt.drive_sectors = params->ending_lba + 1; - if (0 != AllocAndReadGptData(&gpt)) { + if (0 != AllocAndReadGptData(params->disk_handle, &gpt)) { VBDEBUG(("Unable to read GPT data\n")); if (shcall) shcall->check_result = VBSD_LKC_CHECK_GPT_READ_ERROR; @@ -346,7 +348,8 @@ int LoadKernel(LoadKernelParams* params) { goto bad_kernel; } - if (0 != BootDeviceReadLBA(part_start, kbuf_sectors, kbuf)) { + if (0 != VbExDiskRead(params->disk_handle, part_start, kbuf_sectors, + kbuf)) { VBDEBUG(("Unable to read start of partition.\n")); if (shpart) shpart->check_result = VBSD_LKP_CHECK_READ_START; @@ -504,9 +507,9 @@ int LoadKernel(LoadKernelParams* params) { /* Read the kernel data */ VBPERFSTART("VB_RKD"); - if (0 != BootDeviceReadLBA(part_start + body_offset_sectors, - body_sectors, - params->kernel_buffer)) { + if (0 != VbExDiskRead(params->disk_handle, + part_start + body_offset_sectors, + body_sectors, params->kernel_buffer)) { VBDEBUG(("Unable to read kernel data.\n")); VBPERFEND("VB_RKD"); if (shpart) @@ -589,7 +592,7 @@ int LoadKernel(LoadKernelParams* params) { VbExFree(kbuf); /* Write and free GPT data */ - WriteAndFreeGptData(&gpt); + WriteAndFreeGptData(params->disk_handle, &gpt); /* Handle finding a good partition */ if (good_partition >= 0) { diff --git a/firmware/linktest/main.c b/firmware/linktest/main.c index a3ed21a5..49500b71 100644 --- a/firmware/linktest/main.c +++ b/firmware/linktest/main.c @@ -43,9 +43,6 @@ int main(void) SetTPMBootModeState(0, 0, 0); /* tlcl.h */ - TlclLibInit(); - TlclCloseDevice(); - TlclOpenDevice(); TlclStartup(); TlclResume(); TlclSelfTestFull(); @@ -67,6 +64,13 @@ int main(void) TlclExtend(0, 0, 0); TlclGetPermissions(0, 0); + /* vboot_api.h - entry points INTO vboot_reference */ + VbS3Resume(); + VbInit(0, 0); + VbSelectFirmware(0, 0); + VbUpdateFirmwareBodyHash(0, 0, 0); + VbSelectAndLoadKernel(0, 0); + /* vboot_common.h */ OffsetOf(0, 0); GetPublicKeyData(0); diff --git a/firmware/stub/boot_device_stub.c b/firmware/stub/boot_device_stub.c deleted file mode 100644 index 1316e01c..00000000 --- a/firmware/stub/boot_device_stub.c +++ /dev/null @@ -1,20 +0,0 @@ -/* Copyright (c) 2010 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. - * - * Stub implementations of boot device functions. - */ - -#include "boot_device.h" - -/* disable MSVC warnings on unused arguments */ -__pragma(warning (disable: 4100)) - -int BootDeviceReadLBA(uint64_t lba_start, uint64_t lba_count, void *buffer) { - return 1; -} - -int BootDeviceWriteLBA(uint64_t lba_start, uint64_t lba_count, - const void *buffer) { - return 1; -} diff --git a/firmware/stub/load_firmware_stub.c b/firmware/stub/load_firmware_stub.c deleted file mode 100644 index bdae981c..00000000 --- a/firmware/stub/load_firmware_stub.c +++ /dev/null @@ -1,127 +0,0 @@ -/* 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. - * - * TEMPORARY stub for calling LoadFirmware() which looks like the old - * VerifyFirmwareDriver_f() call. - * (Firmware portion) - */ - -#include "load_firmware_fw.h" -#include "utility.h" -#include "vboot_api.h" - -#define BOOT_FIRMWARE_A_CONTINUE 1 -#define BOOT_FIRMWARE_B_CONTINUE 2 -#define BOOT_FIRMWARE_RECOVERY_CONTINUE 3 - -typedef struct CallerInternal { - uint8_t *firmwareA; - uint64_t firmwareA_size; - uint8_t *firmwareB; - uint64_t firmwareB_size; -} CallerInternal; - -int GetFirmwareBody(LoadFirmwareParams* params, uint64_t index) { - - CallerInternal* ci = (CallerInternal*)params->caller_internal; - uint8_t *fw; - uint64_t size; - - /* In a real implementation, GetFirmwareBody() should be what reads - * and decompresses the firmware volume. In this temporary hack, we - * just pass the pointer which we got from - * VerifyFirmwareDriver_Stub(). */ - switch(index) { - case 0: - size = ci->firmwareA_size; - fw = ci->firmwareA; - break; - - case 1: - size = ci->firmwareB_size; - fw = ci->firmwareB; - break; - - default: - /* Anything else is invalid */ - return 1; - } - - /* Need to call UpdateFirmwareBodyHash() with the firmware volume - * data. In this temporary hack, the FV is already decompressed, so - * we pass in the entire volume at once. In a real implementation, - * you should call this as the FV is being decompressed. */ - UpdateFirmwareBodyHash(params, fw, size); - - /* Success */ - return 0; -} - - -/* Where you're currently calling VerifyFirmwareDriver_f(), call this - * function instead. Because you still need to read in both firmware - * volumes, this call will still be slow. Once we reach feature - * complete, you should modify your code to call LoadImage() - * directly. */ -int VerifyFirmwareDriver_stub(uint8_t* gbb_data, - uint64_t gbb_size, - uint8_t* verification_headerA, - uint8_t* firmwareA, - uint8_t* verification_headerB, - uint8_t* firmwareB) { - - int rv; - - CallerInternal ci; - LoadFirmwareParams p; - VbNvContext vnc; - - /* TODO: YOU SHOULD CALL LoadFirmwareSetup() AS SOON AS THE TPM - * INTERFACE IS AVAILABLE */ - LoadFirmwareSetup(); - - /* Copy the firmware volume pointers to our global variables. */ - ci.firmwareA = firmwareA; - ci.firmwareB = firmwareB; - - /* TODO: YOU NEED TO PASS IN THE FIRMWARE VOLUME SIZES SOMEHOW */ - ci.firmwareA_size = 0; - ci.firmwareB_size = 0; - - /* TODO: YOU NEED TO LOAD vnc.raw[] FROM NON-VOLATILE STORAGE */ - - /* Set up the params for LoadFirmware() */ - p.caller_internal = &ci; - p.gbb_data = gbb_data; - p.gbb_size = gbb_size; - p.verification_block_0 = verification_headerA; - p.verification_block_1 = verification_headerB; - p.nv_context = &vnc; - - /* Allocate a shared data buffer */ - p.shared_data_blob = VbExMalloc(VB_SHARED_DATA_REC_SIZE); - p.shared_data_size = VB_SHARED_DATA_REC_SIZE; - - /* TODO: YOU NEED TO SET THE BOOT FLAGS SOMEHOW */ - p.boot_flags = 0; - - /* Call LoadFirmware() */ - rv = LoadFirmware(&p); - - if (vnc.raw_changed) { - /* TODO: YOU NEED TO SAVE vnc.raw TO NON-VOLATILE STORAGE */ - } - - if (LOAD_FIRMWARE_SUCCESS == rv) { - /* TODO: YOU NEED TO KEEP TRACK OF p.shared_data_blob AND - * p.shared_data_size SO YOU CAN PASS THEM TO LoadKernel(). */ - - return (0 == p.firmware_index ? BOOT_FIRMWARE_A_CONTINUE : - BOOT_FIRMWARE_B_CONTINUE); - - } else { - /* Error */ - return BOOT_FIRMWARE_RECOVERY_CONTINUE; - } -} diff --git a/firmware/stub/tpm_lite_stub.c b/firmware/stub/tpm_lite_stub.c index 0317f933..1b498368 100644 --- a/firmware/stub/tpm_lite_stub.c +++ b/firmware/stub/tpm_lite_stub.c @@ -100,25 +100,25 @@ POSSIBLY_UNUSED static INLINE int TpmResponseSize(const uint8_t* buffer) { } -uint32_t TlclStubInit(void) { - return TlclOpenDevice(); +VbError_t VbExTpmInit(void) { + return VbExTpmOpen(); } -uint32_t TlclCloseDevice(void) { +VbError_t VbExTpmClose(void) { if (tpm_fd != -1) { close(tpm_fd); tpm_fd = -1; } - return 0; + return VBERROR_SUCCESS; } -uint32_t TlclOpenDevice(void) { +VbError_t VbExTpmOpen(void) { char* device_path; if (tpm_fd >= 0) - return 0; /* Already open */ + return VBERROR_SUCCESS; /* Already open */ device_path = getenv("TPM_DEVICE_PATH"); if (device_path == NULL) { @@ -127,16 +127,16 @@ uint32_t TlclOpenDevice(void) { tpm_fd = open(device_path, O_RDWR); if (tpm_fd < 0) { - VbExError("TPM: Cannot open TPM device %s: %s\n", device_path, - strerror(errno)); + VbExError("TPM: Cannot open TPM device %s: %s\n", + device_path, strerror(errno)); } - return 0; + return VBERROR_SUCCESS; } -uint32_t TlclStubSendReceive(const uint8_t* request, int request_length, - uint8_t* response, int max_length) { +VbError_t VbExTpmSendReceive(const uint8_t* request, uint32_t request_length, + uint8_t* response, uint32_t* response_length) { /* * In a real firmware implementation, this function should contain * the equivalent API call for the firmware TPM driver which takes a @@ -154,20 +154,19 @@ uint32_t TlclStubSendReceive(const uint8_t* request, int request_length, * response); * // Error checking depending on the value of the status above */ - uint32_t response_length = max_length; #ifndef NDEBUG int tag, response_tag; #endif struct timeval before, after; gettimeofday(&before, NULL); - TpmExecute(request, request_length, response, &response_length); + TpmExecute(request, request_length, response, response_length); gettimeofday(&after, NULL); #ifdef VBOOT_DEBUG { int x = request_length; - int y = response_length; + int y = *response_length; VBDEBUG(("request (%d bytes): ", x)); PrintBytes(request, 10); PrintBytes(request + 10, x - 10); @@ -191,8 +190,8 @@ uint32_t TlclStubSendReceive(const uint8_t* request, int request_length, response_tag == TPM_TAG_RSP_AUTH1_COMMAND) || (tag == TPM_TAG_RQU_AUTH2_COMMAND && response_tag == TPM_TAG_RSP_AUTH2_COMMAND)); - assert(response_length == TpmResponseSize(response)); + assert(*response_length == TpmResponseSize(response)); #endif - return 0; /* Success */ + return VBERROR_SUCCESS; } diff --git a/host/Makefile b/host/Makefile index c32076a1..3e3eb4cd 100644 --- a/host/Makefile +++ b/host/Makefile @@ -27,8 +27,6 @@ LIB_SRCS = \ ./lib/signature_digest.c STUB_SRCS = \ - ../firmware/stub/boot_device_stub.c \ - ../firmware/stub/load_firmware_stub.c \ ../firmware/stub/tpm_lite_stub.c \ ../firmware/stub/utility_stub.c \ ../firmware/stub/vboot_api_stub.c diff --git a/utility/load_kernel_test.c b/utility/load_kernel_test.c index 6b0f9a88..6918e8c0 100644 --- a/utility/load_kernel_test.c +++ b/utility/load_kernel_test.c @@ -14,7 +14,6 @@ #include <sys/types.h> #include <unistd.h> -#include "boot_device.h" #include "gbb_header.h" #include "host_common.h" #include "load_firmware_fw.h" @@ -33,7 +32,8 @@ static FILE *image_file = NULL; /* Boot device stub implementations to read from the image file */ -int BootDeviceReadLBA(uint64_t lba_start, uint64_t lba_count, void *buffer) { +VbError_t VbExDiskRead(VbExDiskHandle_t handle, uint64_t lba_start, + uint64_t lba_count, void *buffer) { printf("Read(%" PRIu64 ", %" PRIu64 ")\n", lba_start, lba_count); if (lba_start > lkp.ending_lba || @@ -48,11 +48,12 @@ int BootDeviceReadLBA(uint64_t lba_start, uint64_t lba_count, void *buffer) { fprintf(stderr, "Read error."); return 1; } - return 0; + return VBERROR_SUCCESS; } -int BootDeviceWriteLBA(uint64_t lba_start, uint64_t lba_count, - const void *buffer) { + +VbError_t VbExDiskWrite(VbExDiskHandle_t handle, uint64_t lba_start, + uint64_t lba_count, const void *buffer) { printf("Write(%" PRIu64 ", %" PRIu64 ")\n", lba_start, lba_count); if (lba_start > lkp.ending_lba || @@ -63,14 +64,14 @@ int BootDeviceWriteLBA(uint64_t lba_start, uint64_t lba_count, } /* TODO: enable writes, once we're sure it won't trash our example file */ - return 0; + return VBERROR_SUCCESS; fseek(image_file, lba_start * lkp.bytes_per_lba, SEEK_SET); if (1 != fwrite(buffer, lba_count * lkp.bytes_per_lba, 1, image_file)) { fprintf(stderr, "Read error."); return 1; } - return 0; + return VBERROR_SUCCESS; } |