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 6 /* Non-volatile storage routines. 7 */ 8 #include "sysincludes.h" 9 10 #include "crc8.h" 11 #include "utility.h" 12 #include "vboot_common.h" 13 #include "vboot_nvstorage.h" 14 15 /* 16 * Constants for NV storage. We use this rather than structs and bitfields so 17 * the data format is consistent across platforms and compilers. 18 * 19 * These constants must match the equivalent constants in 2lib/2nvstorage.c. 20 * (We currently don't share a common header file because we're tring to keep 21 * the two libs independent, and we hope to deprecate this one.) 22 */ 23 #define HEADER_OFFSET 0 24 #define HEADER_MASK 0xC0 25 #define HEADER_SIGNATURE 0x40 26 #define HEADER_FIRMWARE_SETTINGS_RESET 0x20 27 #define HEADER_KERNEL_SETTINGS_RESET 0x10 28 29 #define BOOT_OFFSET 1 30 #define BOOT_DEBUG_RESET_MODE 0x80 31 #define BOOT_DISABLE_DEV_REQUEST 0x40 32 #define BOOT_OPROM_NEEDED 0x20 33 #define BOOT_BACKUP_NVRAM 0x10 34 #define BOOT_TRY_B_COUNT_MASK 0x0F 35 36 #define RECOVERY_OFFSET 2 37 #define LOCALIZATION_OFFSET 3 38 39 #define DEV_FLAGS_OFFSET 4 40 #define DEV_BOOT_USB_MASK 0x01 41 #define DEV_BOOT_SIGNED_ONLY_MASK 0x02 42 #define DEV_BOOT_LEGACY_MASK 0x04 43 44 #define TPM_FLAGS_OFFSET 5 45 #define TPM_CLEAR_OWNER_REQUEST 0x01 46 #define TPM_CLEAR_OWNER_DONE 0x02 47 48 #define RECOVERY_SUBCODE_OFFSET 6 49 50 #define BOOT2_OFFSET 7 51 #define BOOT2_RESULT_MASK 0x03 52 #define BOOT2_TRIED 0x04 53 #define BOOT2_TRY_NEXT 0x08 54 #define BOOT2_PREV_RESULT_MASK 0x30 55 #define BOOT2_PREV_RESULT_SHIFT 4 /* Number of bits to shift result */ 56 #define BOOT2_PREV_TRIED 0x40 57 58 #define KERNEL_FIELD_OFFSET 11 59 #define CRC_OFFSET 15 60 61 int VbNvSetup(VbNvContext *context) 62 { 63 uint8_t *raw = context->raw; 64 65 /* Nothing has changed yet. */ 66 context->raw_changed = 0; 67 context->regenerate_crc = 0; 68 69 /* Check data for consistency */ 70 if ((HEADER_SIGNATURE != (raw[HEADER_OFFSET] & HEADER_MASK)) 71 || (Crc8(raw, CRC_OFFSET) != raw[CRC_OFFSET])) { 72 /* Data is inconsistent (bad CRC or header); reset defaults */ 73 Memset(raw, 0, VBNV_BLOCK_SIZE); 74 raw[HEADER_OFFSET] = (HEADER_SIGNATURE | 75 HEADER_FIRMWARE_SETTINGS_RESET | 76 HEADER_KERNEL_SETTINGS_RESET); 77 78 /* Regenerate CRC on exit */ 79 context->regenerate_crc = 1; 80 } 81 82 return 0; 83 } 84 85 int VbNvTeardown(VbNvContext *context) 86 { 87 if (context->regenerate_crc) { 88 context->raw[CRC_OFFSET] = Crc8(context->raw, CRC_OFFSET); 89 context->regenerate_crc = 0; 90 context->raw_changed = 1; 91 } 92 93 return 0; 94 } 95 96 int VbNvGet(VbNvContext *context, VbNvParam param, uint32_t *dest) 97 { 98 const uint8_t *raw = context->raw; 99 100 switch (param) { 101 case VBNV_FIRMWARE_SETTINGS_RESET: 102 *dest = (raw[HEADER_OFFSET] & HEADER_FIRMWARE_SETTINGS_RESET ? 103 1 : 0); 104 return 0; 105 106 case VBNV_KERNEL_SETTINGS_RESET: 107 *dest = (raw[HEADER_OFFSET] & HEADER_KERNEL_SETTINGS_RESET ? 108 1 : 0); 109 return 0; 110 111 case VBNV_DEBUG_RESET_MODE: 112 *dest = (raw[BOOT_OFFSET] & BOOT_DEBUG_RESET_MODE ? 1 : 0); 113 return 0; 114 115 case VBNV_TRY_B_COUNT: 116 case VBNV_FW_TRY_COUNT: 117 *dest = raw[BOOT_OFFSET] & BOOT_TRY_B_COUNT_MASK; 118 return 0; 119 120 case VBNV_RECOVERY_REQUEST: 121 *dest = raw[RECOVERY_OFFSET]; 122 return 0; 123 124 case VBNV_RECOVERY_SUBCODE: 125 *dest = raw[RECOVERY_SUBCODE_OFFSET]; 126 return 0; 127 128 case VBNV_LOCALIZATION_INDEX: 129 *dest = raw[LOCALIZATION_OFFSET]; 130 return 0; 131 132 case VBNV_KERNEL_FIELD: 133 *dest = (raw[KERNEL_FIELD_OFFSET] 134 | (raw[KERNEL_FIELD_OFFSET + 1] << 8) 135 | (raw[KERNEL_FIELD_OFFSET + 2] << 16) 136 | (raw[KERNEL_FIELD_OFFSET + 3] << 24)); 137 return 0; 138 139 case VBNV_DEV_BOOT_USB: 140 *dest = (raw[DEV_FLAGS_OFFSET] & DEV_BOOT_USB_MASK ? 1 : 0); 141 return 0; 142 143 case VBNV_DEV_BOOT_LEGACY: 144 *dest = (raw[DEV_FLAGS_OFFSET] & DEV_BOOT_LEGACY_MASK ? 1 : 0); 145 return 0; 146 147 case VBNV_DEV_BOOT_SIGNED_ONLY: 148 *dest = (raw[DEV_FLAGS_OFFSET] & DEV_BOOT_SIGNED_ONLY_MASK ? 149 1 : 0); 150 return 0; 151 152 case VBNV_DISABLE_DEV_REQUEST: 153 *dest = (raw[BOOT_OFFSET] & BOOT_DISABLE_DEV_REQUEST ? 1 : 0); 154 return 0; 155 156 case VBNV_OPROM_NEEDED: 157 *dest = (raw[BOOT_OFFSET] & BOOT_OPROM_NEEDED ? 1 : 0); 158 return 0; 159 160 case VBNV_CLEAR_TPM_OWNER_REQUEST: 161 *dest = (raw[TPM_FLAGS_OFFSET] & TPM_CLEAR_OWNER_REQUEST ? 162 1 : 0); 163 return 0; 164 165 case VBNV_CLEAR_TPM_OWNER_DONE: 166 *dest = (raw[TPM_FLAGS_OFFSET] & TPM_CLEAR_OWNER_DONE ? 1 : 0); 167 return 0; 168 169 case VBNV_BACKUP_NVRAM_REQUEST: 170 *dest = (raw[BOOT_OFFSET] & BOOT_BACKUP_NVRAM ? 1 : 0); 171 return 0; 172 173 case VBNV_FW_TRY_NEXT: 174 *dest = (raw[BOOT2_OFFSET] & BOOT2_TRY_NEXT ? 1 : 0); 175 return 0; 176 177 case VBNV_FW_TRIED: 178 *dest = (raw[BOOT2_OFFSET] & BOOT2_TRIED ? 1 : 0); 179 return 0; 180 181 case VBNV_FW_RESULT: 182 *dest = raw[BOOT2_OFFSET] & BOOT2_RESULT_MASK; 183 return 0; 184 185 case VBNV_FW_PREV_TRIED: 186 *dest = (raw[BOOT2_OFFSET] & BOOT2_PREV_TRIED ? 1 : 0); 187 return 0; 188 189 case VBNV_FW_PREV_RESULT: 190 *dest = (raw[BOOT2_OFFSET] & BOOT2_PREV_RESULT_MASK) 191 >> BOOT2_PREV_RESULT_SHIFT; 192 return 0; 193 194 default: 195 return 1; 196 } 197 } 198 199 int VbNvSet(VbNvContext *context, VbNvParam param, uint32_t value) 200 { 201 uint8_t *raw = context->raw; 202 uint32_t current; 203 204 /* If not changing the value, don't regenerate the CRC. */ 205 if (0 == VbNvGet(context, param, ¤t) && current == value) 206 return 0; 207 208 switch (param) { 209 case VBNV_FIRMWARE_SETTINGS_RESET: 210 if (value) 211 raw[HEADER_OFFSET] |= HEADER_FIRMWARE_SETTINGS_RESET; 212 else 213 raw[HEADER_OFFSET] &= ~HEADER_FIRMWARE_SETTINGS_RESET; 214 break; 215 216 case VBNV_KERNEL_SETTINGS_RESET: 217 if (value) 218 raw[HEADER_OFFSET] |= HEADER_KERNEL_SETTINGS_RESET; 219 else 220 raw[HEADER_OFFSET] &= ~HEADER_KERNEL_SETTINGS_RESET; 221 break; 222 223 case VBNV_DEBUG_RESET_MODE: 224 if (value) 225 raw[BOOT_OFFSET] |= BOOT_DEBUG_RESET_MODE; 226 else 227 raw[BOOT_OFFSET] &= ~BOOT_DEBUG_RESET_MODE; 228 break; 229 230 case VBNV_TRY_B_COUNT: 231 case VBNV_FW_TRY_COUNT: 232 /* Clip to valid range. */ 233 if (value > BOOT_TRY_B_COUNT_MASK) 234 value = BOOT_TRY_B_COUNT_MASK; 235 236 raw[BOOT_OFFSET] &= ~BOOT_TRY_B_COUNT_MASK; 237 raw[BOOT_OFFSET] |= (uint8_t)value; 238 break; 239 240 case VBNV_RECOVERY_REQUEST: 241 /* 242 * Map values outside the valid range to the legacy reason, 243 * since we can't determine if we're called from kernel or user 244 * mode. 245 */ 246 if (value > 0xFF) 247 value = VBNV_RECOVERY_LEGACY; 248 raw[RECOVERY_OFFSET] = (uint8_t)value; 249 break; 250 251 case VBNV_RECOVERY_SUBCODE: 252 raw[RECOVERY_SUBCODE_OFFSET] = (uint8_t)value; 253 break; 254 255 case VBNV_LOCALIZATION_INDEX: 256 /* Map values outside the valid range to the default index. */ 257 if (value > 0xFF) 258 value = 0; 259 raw[LOCALIZATION_OFFSET] = (uint8_t)value; 260 break; 261 262 case VBNV_KERNEL_FIELD: 263 raw[KERNEL_FIELD_OFFSET] = (uint8_t)(value); 264 raw[KERNEL_FIELD_OFFSET + 1] = (uint8_t)(value >> 8); 265 raw[KERNEL_FIELD_OFFSET + 2] = (uint8_t)(value >> 16); 266 raw[KERNEL_FIELD_OFFSET + 3] = (uint8_t)(value >> 24); 267 break; 268 269 case VBNV_DEV_BOOT_USB: 270 if (value) 271 raw[DEV_FLAGS_OFFSET] |= DEV_BOOT_USB_MASK; 272 else 273 raw[DEV_FLAGS_OFFSET] &= ~DEV_BOOT_USB_MASK; 274 break; 275 276 case VBNV_DEV_BOOT_LEGACY: 277 if (value) 278 raw[DEV_FLAGS_OFFSET] |= DEV_BOOT_LEGACY_MASK; 279 else 280 raw[DEV_FLAGS_OFFSET] &= ~DEV_BOOT_LEGACY_MASK; 281 break; 282 283 case VBNV_DEV_BOOT_SIGNED_ONLY: 284 if (value) 285 raw[DEV_FLAGS_OFFSET] |= DEV_BOOT_SIGNED_ONLY_MASK; 286 else 287 raw[DEV_FLAGS_OFFSET] &= ~DEV_BOOT_SIGNED_ONLY_MASK; 288 break; 289 290 case VBNV_DISABLE_DEV_REQUEST: 291 if (value) 292 raw[BOOT_OFFSET] |= BOOT_DISABLE_DEV_REQUEST; 293 else 294 raw[BOOT_OFFSET] &= ~BOOT_DISABLE_DEV_REQUEST; 295 break; 296 297 case VBNV_OPROM_NEEDED: 298 if (value) 299 raw[BOOT_OFFSET] |= BOOT_OPROM_NEEDED; 300 else 301 raw[BOOT_OFFSET] &= ~BOOT_OPROM_NEEDED; 302 break; 303 304 case VBNV_CLEAR_TPM_OWNER_REQUEST: 305 if (value) 306 raw[TPM_FLAGS_OFFSET] |= TPM_CLEAR_OWNER_REQUEST; 307 else 308 raw[TPM_FLAGS_OFFSET] &= ~TPM_CLEAR_OWNER_REQUEST; 309 break; 310 311 case VBNV_CLEAR_TPM_OWNER_DONE: 312 if (value) 313 raw[TPM_FLAGS_OFFSET] |= TPM_CLEAR_OWNER_DONE; 314 else 315 raw[TPM_FLAGS_OFFSET] &= ~TPM_CLEAR_OWNER_DONE; 316 break; 317 318 case VBNV_BACKUP_NVRAM_REQUEST: 319 if (value) 320 raw[BOOT_OFFSET] |= BOOT_BACKUP_NVRAM; 321 else 322 raw[BOOT_OFFSET] &= ~BOOT_BACKUP_NVRAM; 323 break; 324 325 case VBNV_FW_TRY_NEXT: 326 if (value) 327 raw[BOOT2_OFFSET] |= BOOT2_TRY_NEXT; 328 else 329 raw[BOOT2_OFFSET] &= ~BOOT2_TRY_NEXT; 330 break; 331 332 case VBNV_FW_TRIED: 333 if (value) 334 raw[BOOT2_OFFSET] |= BOOT2_TRIED; 335 else 336 raw[BOOT2_OFFSET] &= ~BOOT2_TRIED; 337 break; 338 339 case VBNV_FW_RESULT: 340 /* Map out of range values to unknown */ 341 if (value > BOOT2_RESULT_MASK) 342 value = VBNV_FW_RESULT_UNKNOWN; 343 344 raw[BOOT2_OFFSET] &= ~BOOT2_RESULT_MASK; 345 raw[BOOT2_OFFSET] |= (uint8_t)value; 346 break; 347 348 case VBNV_FW_PREV_TRIED: 349 if (value) 350 raw[BOOT2_OFFSET] |= BOOT2_PREV_TRIED; 351 else 352 raw[BOOT2_OFFSET] &= ~BOOT2_PREV_TRIED; 353 break; 354 355 case VBNV_FW_PREV_RESULT: 356 /* Map out of range values to unknown */ 357 if (value > BOOT2_RESULT_MASK) 358 value = VBNV_FW_RESULT_UNKNOWN; 359 360 raw[BOOT2_OFFSET] &= ~BOOT2_PREV_RESULT_MASK; 361 raw[BOOT2_OFFSET] |= (uint8_t)value << BOOT2_PREV_RESULT_SHIFT; 362 break; 363 364 default: 365 return 1; 366 } 367 368 /* Need to regenerate CRC, since the value changed. */ 369 context->regenerate_crc = 1; 370 return 0; 371 } 372