vboot_api_init.c revision d79f111427ab11919d9f91aa4f54c893f9e9986a
1/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved. 2 * Use of this source code is governed by a BSD-style license that can be 3 * found in the LICENSE file. 4 * 5 * High-level firmware wrapper API - entry points for init, firmware selection 6 */ 7 8#include "sysincludes.h" 9 10#include "gbb_header.h" 11#include "load_firmware_fw.h" 12#include "rollback_index.h" 13#include "utility.h" 14#include "vboot_api.h" 15#include "vboot_common.h" 16#include "vboot_nvstorage.h" 17 18VbError_t VbInit(VbCommonParams *cparams, VbInitParams *iparams) 19{ 20 VbSharedDataHeader *shared = 21 (VbSharedDataHeader *)cparams->shared_data_blob; 22 GoogleBinaryBlockHeader *gbb = 23 (GoogleBinaryBlockHeader *)cparams->gbb_data; 24 VbNvContext vnc; 25 VbError_t retval = VBERROR_SUCCESS; 26 uint32_t recovery = VBNV_RECOVERY_NOT_REQUESTED; 27 int is_s3_resume = 0; 28 uint32_t s3_debug_boot = 0; 29 uint32_t require_official_os = 0; 30 uint32_t tpm_version = 0; 31 uint32_t tpm_status = 0; 32 int has_virt_dev_switch = 0; 33 int is_hw_dev = 0; 34 int is_virt_dev = 0; 35 uint32_t disable_dev_request = 0; 36 uint32_t clear_tpm_owner_request = 0; 37 int is_dev = 0; 38 39 VBDEBUG(("VbInit() input flags 0x%x gbb flags 0x%x\n", iparams->flags, 40 gbb->flags)); 41 42 /* Initialize output flags */ 43 iparams->out_flags = 0; 44 45 /* Set up NV storage */ 46 VbExNvStorageRead(vnc.raw); 47 VbNvSetup(&vnc); 48 49 /* Initialize shared data structure */ 50 if (0 != VbSharedDataInit(shared, cparams->shared_data_size)) { 51 VBDEBUG(("Shared data init error\n")); 52 return VBERROR_INIT_SHARED_DATA; 53 } 54 55 shared->timer_vb_init_enter = VbExGetTimer(); 56 57 /* Copy some boot switch flags */ 58 /* TODO: in next refactor, just save in/out flags in VbSharedData */ 59 shared->flags = 0; 60 if (iparams->flags & VB_INIT_FLAG_REC_BUTTON_PRESSED) 61 shared->flags |= VBSD_BOOT_REC_SWITCH_ON; 62 if (iparams->flags & VB_INIT_FLAG_WP_ENABLED) 63 shared->flags |= VBSD_BOOT_FIRMWARE_WP_ENABLED; 64 if (iparams->flags & VB_INIT_FLAG_SW_WP_ENABLED) 65 shared->flags |= VBSD_BOOT_FIRMWARE_SW_WP_ENABLED; 66 if (iparams->flags & VB_INIT_FLAG_S3_RESUME) 67 shared->flags |= VBSD_BOOT_S3_RESUME; 68 if (iparams->flags & VB_INIT_FLAG_RO_NORMAL_SUPPORT) 69 shared->flags |= VBSD_BOOT_RO_NORMAL_SUPPORT; 70 if (iparams->flags & VB_INIT_FLAG_EC_SOFTWARE_SYNC) 71 shared->flags |= VBSD_EC_SOFTWARE_SYNC; 72 if (iparams->flags & VB_INIT_FLAG_EC_SLOW_UPDATE) 73 shared->flags |= VBSD_EC_SLOW_UPDATE; 74 75 is_s3_resume = (iparams->flags & VB_INIT_FLAG_S3_RESUME ? 1 : 0); 76 77 /* Check if the OS is requesting a debug S3 reset */ 78 VbNvGet(&vnc, VBNV_DEBUG_RESET_MODE, &s3_debug_boot); 79 if (s3_debug_boot) { 80 if (is_s3_resume) { 81 VBDEBUG(("VbInit() requesting S3 debug boot\n")); 82 iparams->out_flags |= VB_INIT_OUT_S3_DEBUG_BOOT; 83 is_s3_resume = 0; /* Proceed as if normal boot */ 84 } 85 86 /* 87 * Clear the request even if this is a normal boot, since we 88 * don't want the NEXT S3 resume to be a debug reset unless the 89 * OS asserts the request again. 90 */ 91 VbNvSet(&vnc, VBNV_DEBUG_RESET_MODE, 0); 92 } 93 94 /* 95 * If this isn't a S3 resume, read the current recovery request, then 96 * clear it so we don't get stuck in recovery mode. 97 */ 98 if (!is_s3_resume) { 99 VbNvGet(&vnc, VBNV_RECOVERY_REQUEST, &recovery); 100 VBDEBUG(("VbInit sees recovery request = %d\n", recovery)); 101 if (VBNV_RECOVERY_NOT_REQUESTED != recovery) 102 VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, 103 VBNV_RECOVERY_NOT_REQUESTED); 104 } 105 106 /* 107 * If the previous boot failed in the firmware somewhere outside of 108 * verified boot, and recovery is not requested for our own reasons, 109 * request recovery mode. This gives the calling firmware a way to 110 * request recovery if it finds something terribly wrong. 111 */ 112 if (VBNV_RECOVERY_NOT_REQUESTED == recovery && 113 iparams->flags & VB_INIT_FLAG_PREVIOUS_BOOT_FAIL) { 114 recovery = VBNV_RECOVERY_RO_FIRMWARE; 115 } 116 117 /* 118 * If recovery button is pressed, override recovery reason. Note that 119 * we do this in the S3 resume path also. 120 */ 121 if (iparams->flags & VB_INIT_FLAG_REC_BUTTON_PRESSED) 122 recovery = VBNV_RECOVERY_RO_MANUAL; 123 124 /* 125 * Copy current recovery reason to shared data. If we fail later on, it 126 * won't matter, since we'll just reboot. 127 */ 128 shared->recovery_reason = (uint8_t)recovery; 129 VBDEBUG(("VbInit now sets shared->recovery_reason = %d\n", recovery)); 130 131 /* 132 * If this is a S3 resume, resume the TPM. 133 * 134 * FIXME: I think U-Boot won't ever ask us to do this. Can we remove 135 * it? 136 */ 137 if (is_s3_resume) { 138 if (TPM_SUCCESS != RollbackS3Resume()) { 139 /* 140 * If we can't resume, just do a full reboot. No need 141 * to go to recovery mode here, since if the TPM is 142 * really broken we'll catch it on the next boot. 143 */ 144 retval = VBERROR_TPM_S3_RESUME; 145 } 146 } else { 147 /* Should we pay attention to the TPM's virtual dev-switch? */ 148 if (iparams->flags & VB_INIT_FLAG_VIRTUAL_DEV_SWITCH) { 149 shared->flags |= VBSD_HONOR_VIRT_DEV_SWITCH; 150 has_virt_dev_switch = 1; 151 } 152 153 /* 154 * We always believe the HW dev-switch, since there's one 155 * attached to servo which may be active even on systems 156 * without a physical switch. The EC may also implement a fake 157 * dev-switch for testing. 158 */ 159 if (iparams->flags & VB_INIT_FLAG_DEV_SWITCH_ON) 160 is_hw_dev = 1; 161 162 /* We may be asked to clear the virtual dev-switch at boot. */ 163 VbNvGet(&vnc, VBNV_DISABLE_DEV_REQUEST, &disable_dev_request); 164 165 /* Allow GBB flag to override dev switch */ 166 if (gbb->flags & GBB_FLAG_FORCE_DEV_SWITCH_ON) 167 is_hw_dev = 1; 168 169 /* Have we been explicitly asked to clear the TPM owner? */ 170 VbNvGet(&vnc, VBNV_CLEAR_TPM_OWNER_REQUEST, 171 &clear_tpm_owner_request); 172 173 /* 174 * Initialize the TPM. If the developer mode state has changed 175 * since the last boot, we need to clear TPM ownership. If the 176 * TPM space is initialized by this call, the virtual 177 * dev-switch will be disabled by default) 178 */ 179 VBDEBUG(("TPM: Call RollbackFirmwareSetup(r%d, d%d)\n", 180 recovery, is_hw_dev)); 181 tpm_status = RollbackFirmwareSetup(is_hw_dev, 182 disable_dev_request, 183 clear_tpm_owner_request, 184 /* two outputs on success */ 185 &is_virt_dev, &tpm_version); 186 187 if (0 != tpm_status) { 188 VBDEBUG(("Unable to setup TPM and read " 189 "firmware version (0x%x)\n", tpm_status)); 190 191 if (TPM_E_MUST_REBOOT == tpm_status) { 192 /* 193 * TPM wants to reboot into the same mode we're 194 * in now 195 */ 196 VBDEBUG(("TPM requires a reboot.\n")); 197 if (!recovery) { 198 /* 199 * Not recovery mode. Just reboot (not 200 * into recovery). 201 */ 202 retval = VBERROR_TPM_REBOOT_REQUIRED; 203 goto VbInit_exit; 204 } else if (VBNV_RECOVERY_RO_TPM_REBOOT != 205 shared->recovery_reason) { 206 /* 207 * In recovery mode now, and we haven't 208 * requested a TPM reboot yet, so 209 * request one. 210 */ 211 VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, 212 VBNV_RECOVERY_RO_TPM_REBOOT); 213 retval = VBERROR_TPM_REBOOT_REQUIRED; 214 goto VbInit_exit; 215 } 216 } 217 218 if (!recovery) { 219 VbNvSet(&vnc, VBNV_RECOVERY_REQUEST, 220 VBNV_RECOVERY_RO_TPM_S_ERROR); 221 VbNvSet(&vnc, VBNV_RECOVERY_SUBCODE, 222 tpm_status); 223 retval = VBERROR_TPM_FIRMWARE_SETUP; 224 goto VbInit_exit; 225 } 226 } 227 228 /* TPM setup succeeded, or we're in recovery mode and ignoring 229 * errors. What did we learn? */ 230 shared->fw_version_tpm_start = tpm_version; 231 shared->fw_version_tpm = tpm_version; 232 if (is_hw_dev || (has_virt_dev_switch && is_virt_dev)) { 233 is_dev = 1; 234 shared->flags |= VBSD_BOOT_DEV_SWITCH_ON; 235 } 236 if (disable_dev_request && !is_virt_dev) 237 VbNvSet(&vnc, VBNV_DISABLE_DEV_REQUEST, 0); 238 if (clear_tpm_owner_request) { 239 VbNvSet(&vnc, VBNV_CLEAR_TPM_OWNER_REQUEST, 0); 240 VbNvSet(&vnc, VBNV_CLEAR_TPM_OWNER_DONE, 1); 241 } 242 } 243 244 /* Allow BIOS to load arbitrary option ROMs? */ 245 if (gbb->flags & GBB_FLAG_LOAD_OPTION_ROMS) 246 iparams->out_flags |= VB_INIT_OUT_ENABLE_OPROM; 247 248 /* Factory may need to boot custom OSes when the dev-switch is on */ 249 if (is_dev && (gbb->flags & GBB_FLAG_ENABLE_ALTERNATE_OS)) 250 iparams->out_flags |= VB_INIT_OUT_ENABLE_ALTERNATE_OS; 251 252 /* Set output flags */ 253 if (VBNV_RECOVERY_NOT_REQUESTED != recovery) { 254 /* Requesting recovery mode */ 255 iparams->out_flags |= (VB_INIT_OUT_ENABLE_RECOVERY | 256 VB_INIT_OUT_CLEAR_RAM | 257 VB_INIT_OUT_ENABLE_DISPLAY | 258 VB_INIT_OUT_ENABLE_USB_STORAGE); 259 } else if (is_dev) { 260 /* Developer switch is on, so need to support dev mode */ 261 iparams->out_flags |= (VB_INIT_OUT_ENABLE_DEVELOPER | 262 VB_INIT_OUT_CLEAR_RAM | 263 VB_INIT_OUT_ENABLE_DISPLAY | 264 VB_INIT_OUT_ENABLE_USB_STORAGE); 265 /* ... which may or may not include custom OSes */ 266 VbNvGet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, &require_official_os); 267 if (!require_official_os) 268 iparams->out_flags |= VB_INIT_OUT_ENABLE_ALTERNATE_OS; 269 270 /* 271 * Dev-mode needs the VGA option ROM to be loaded so it can 272 * display the scary boot screen. If we don't have it, we need 273 * to request it and reboot so it can be loaded. 274 */ 275 if ((iparams->flags & VB_INIT_FLAG_OPROM_MATTERS) && 276 !(iparams->flags & VB_INIT_FLAG_OPROM_LOADED)) { 277 VbNvSet(&vnc, VBNV_OPROM_NEEDED, 1); 278 retval = VBERROR_VGA_OPROM_MISMATCH; 279 VBDEBUG(("VbInit() needs oprom, doesn't have it\n")); 280 } 281 282 } else { 283 /* 284 * Normal mode, so disable dev_boot_* flags. This ensures they 285 * will be initially disabled if the user later transitions 286 * back into developer mode. 287 */ 288 VbNvSet(&vnc, VBNV_DEV_BOOT_USB, 0); 289 VbNvSet(&vnc, VBNV_DEV_BOOT_LEGACY, 0); 290 VbNvSet(&vnc, VBNV_DEV_BOOT_SIGNED_ONLY, 0); 291 292 /* 293 * If we don't need the VGA option ROM but got it anyway, stop 294 * asking for it and reboot in case there's some vulnerability 295 * in using it. 296 */ 297 if ((iparams->flags & VB_INIT_FLAG_OPROM_MATTERS) && 298 (iparams->flags & VB_INIT_FLAG_OPROM_LOADED)) { 299 VbNvSet(&vnc, VBNV_OPROM_NEEDED, 0); 300 retval = VBERROR_VGA_OPROM_MISMATCH; 301 VBDEBUG(("VbInit() has oprom, doesn't need it\n")); 302 } 303 } 304 305 VbInit_exit: 306 307 /* Tear down NV storage */ 308 VbNvTeardown(&vnc); 309 if (vnc.raw_changed) 310 VbExNvStorageWrite(vnc.raw); 311 312 VBDEBUG(("VbInit() output flags 0x%x\n", iparams->out_flags)); 313 314 shared->timer_vb_init_exit = VbExGetTimer(); 315 316 VBDEBUG(("VbInit() returning 0x%x\n", retval)); 317 318 return retval; 319} 320