Randall Spangler | 3333e57 | 2014-05-14 11:37:52 -0700 | [diff] [blame] | 1 | /* Copyright (c) 2014 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 "2sysincludes.h" |
| 9 | #include "2common.h" |
| 10 | #include "2crc8.h" |
| 11 | #include "2misc.h" |
| 12 | #include "2nvstorage.h" |
| 13 | |
| 14 | /* |
| 15 | * Constants for NV storage. We use this rather than structs and bitfields so |
| 16 | * the data format is consistent across platforms and compilers. Total NV |
| 17 | * storage size is VB2_NVDATA_SIZE = 16 bytes. |
Randall Spangler | 9e1da78 | 2014-06-24 15:31:04 -0700 | [diff] [blame] | 18 | * |
| 19 | * These constants must match the equivalent constants in |
| 20 | * lib/vboot_nvstorage.c. (We currently don't share a common header file |
| 21 | * because we're tring to keep the two libs independent, and we hope to |
| 22 | * deprecate that one.) |
Randall Spangler | 3333e57 | 2014-05-14 11:37:52 -0700 | [diff] [blame] | 23 | */ |
| 24 | |
| 25 | enum vb2_nv_offset { |
| 26 | VB2_NV_OFFS_HEADER = 0, |
| 27 | VB2_NV_OFFS_BOOT = 1, |
| 28 | VB2_NV_OFFS_RECOVERY = 2, |
| 29 | VB2_NV_OFFS_LOCALIZATION = 3, |
| 30 | VB2_NV_OFFS_DEV = 4, |
| 31 | VB2_NV_OFFS_TPM = 5, |
| 32 | VB2_NV_OFFS_RECOVERY_SUBCODE = 6, |
| 33 | VB2_NV_OFFS_BOOT2 = 7, |
| 34 | /* Offsets 7-10 are currently unused */ |
| 35 | VB2_NV_OFFS_KERNEL = 11, /* 11-14; field is 32 bits */ |
| 36 | /* CRC must be last field */ |
| 37 | VB2_NV_OFFS_CRC = 15 |
| 38 | }; |
| 39 | |
| 40 | /* Fields in VB2_NV_OFFS_HEADER (unused = 0x0f) */ |
| 41 | #define VB2_NV_HEADER_KERNEL_SETTINGS_RESET 0x10 |
| 42 | #define VB2_NV_HEADER_FW_SETTINGS_RESET 0x20 |
| 43 | #define VB2_NV_HEADER_SIGNATURE 0x40 |
| 44 | #define VB2_NV_HEADER_MASK 0xc0 |
| 45 | |
| 46 | /* Fields in VB2_NV_OFFS_BOOT */ |
| 47 | #define VB2_NV_BOOT_TRY_COUNT_MASK 0x0f |
Randall Spangler | 8de992c | 2014-06-24 13:11:02 -0700 | [diff] [blame] | 48 | #define VB2_NV_BOOT_BACKUP_NVRAM 0x10 |
Randall Spangler | 3333e57 | 2014-05-14 11:37:52 -0700 | [diff] [blame] | 49 | #define VB2_NV_BOOT_OPROM_NEEDED 0x20 |
| 50 | #define VB2_NV_BOOT_DISABLE_DEV 0x40 |
| 51 | #define VB2_NV_BOOT_DEBUG_RESET 0x80 |
| 52 | |
Randall Spangler | 8de992c | 2014-06-24 13:11:02 -0700 | [diff] [blame] | 53 | /* Fields in VB2_NV_OFFS_BOOT2 (unused = 0xf0) */ |
Randall Spangler | 3333e57 | 2014-05-14 11:37:52 -0700 | [diff] [blame] | 54 | #define VB2_NV_BOOT2_RESULT_MASK 0x03 |
| 55 | #define VB2_NV_BOOT2_TRIED 0x04 |
Randall Spangler | 8de992c | 2014-06-24 13:11:02 -0700 | [diff] [blame] | 56 | #define VB2_NV_BOOT2_TRY_NEXT 0x08 |
Randall Spangler | 3333e57 | 2014-05-14 11:37:52 -0700 | [diff] [blame] | 57 | |
| 58 | /* Fields in VB2_NV_OFFS_DEV (unused = 0xf8) */ |
| 59 | #define VB2_NV_DEV_FLAG_USB 0x01 |
| 60 | #define VB2_NV_DEV_FLAG_SIGNED_ONLY 0x02 |
| 61 | #define VB2_NV_DEV_FLAG_LEGACY 0x04 |
| 62 | |
| 63 | /* Fields in VB2_NV_OFFS_TPM (unused = 0xfc) */ |
| 64 | #define VB2_NV_TPM_CLEAR_OWNER_REQUEST 0x01 |
| 65 | #define VB2_NV_TPM_CLEAR_OWNER_DONE 0x02 |
| 66 | |
| 67 | static void vb2_nv_regen_crc(struct vb2_context *ctx) |
| 68 | { |
| 69 | ctx->nvdata[VB2_NV_OFFS_CRC] = vb2_crc8(ctx->nvdata, VB2_NV_OFFS_CRC); |
| 70 | ctx->flags |= VB2_CONTEXT_NVDATA_CHANGED; |
| 71 | } |
| 72 | |
| 73 | /** |
| 74 | * Check the CRC of the non-volatile storage context. |
| 75 | * |
| 76 | * Use this if reading from non-volatile storage may be flaky, and you want to |
| 77 | * retry reading it several times. |
| 78 | * |
| 79 | * This may be called before vb2_context_init(). |
| 80 | * |
| 81 | * @param ctx Context pointer |
| 82 | * @return VB2_SUCCESS, or non-zero error code if error. |
| 83 | */ |
| 84 | int vb2_nv_check_crc(const struct vb2_context *ctx) |
| 85 | { |
| 86 | const uint8_t *p = ctx->nvdata; |
| 87 | |
| 88 | /* Check header */ |
| 89 | if (VB2_NV_HEADER_SIGNATURE != |
| 90 | (p[VB2_NV_OFFS_HEADER] & VB2_NV_HEADER_MASK)) |
Randall Spangler | b9be536 | 2014-06-05 13:32:11 -0700 | [diff] [blame] | 91 | return VB2_ERROR_NV_HEADER; |
Randall Spangler | 3333e57 | 2014-05-14 11:37:52 -0700 | [diff] [blame] | 92 | |
| 93 | /* Check CRC */ |
| 94 | if (vb2_crc8(p, VB2_NV_OFFS_CRC) != p[VB2_NV_OFFS_CRC]) |
Randall Spangler | b9be536 | 2014-06-05 13:32:11 -0700 | [diff] [blame] | 95 | return VB2_ERROR_NV_CRC; |
Randall Spangler | 3333e57 | 2014-05-14 11:37:52 -0700 | [diff] [blame] | 96 | |
| 97 | return VB2_SUCCESS; |
| 98 | } |
| 99 | |
| 100 | void vb2_nv_init(struct vb2_context *ctx) |
| 101 | { |
| 102 | struct vb2_shared_data *sd = vb2_get_sd(ctx); |
| 103 | uint8_t *p = ctx->nvdata; |
| 104 | |
| 105 | /* Check data for consistency */ |
| 106 | if (vb2_nv_check_crc(ctx) != VB2_SUCCESS) { |
| 107 | /* Data is inconsistent (bad CRC or header); reset defaults */ |
| 108 | memset(p, 0, VB2_NVDATA_SIZE); |
| 109 | p[VB2_NV_OFFS_HEADER] = (VB2_NV_HEADER_SIGNATURE | |
| 110 | VB2_NV_HEADER_FW_SETTINGS_RESET | |
| 111 | VB2_NV_HEADER_KERNEL_SETTINGS_RESET); |
| 112 | |
| 113 | /* Regenerate CRC */ |
| 114 | vb2_nv_regen_crc(ctx); |
| 115 | |
| 116 | /* Set status flag */ |
| 117 | sd->status |= VB2_SD_STATUS_NV_REINIT; |
| 118 | // TODO: unit test for status flag being set |
| 119 | } |
| 120 | |
| 121 | sd->status |= VB2_SD_STATUS_NV_INIT; |
| 122 | } |
| 123 | |
| 124 | /* Macro for vb2_nv_get() single-bit settings to reduce duplicate code. */ |
| 125 | #define GETBIT(offs, mask) (p[offs] & mask ? 1 : 0) |
| 126 | |
| 127 | uint32_t vb2_nv_get(struct vb2_context *ctx, enum vb2_nv_param param) |
| 128 | { |
| 129 | const uint8_t *p = ctx->nvdata; |
| 130 | |
| 131 | /* |
| 132 | * TODO: We could reduce the binary size for this code by #ifdef'ing |
| 133 | * out the params not used by firmware verification. |
| 134 | */ |
| 135 | switch (param) { |
| 136 | case VB2_NV_FIRMWARE_SETTINGS_RESET: |
| 137 | return GETBIT(VB2_NV_OFFS_HEADER, |
| 138 | VB2_NV_HEADER_FW_SETTINGS_RESET); |
| 139 | |
| 140 | case VB2_NV_KERNEL_SETTINGS_RESET: |
| 141 | return GETBIT(VB2_NV_OFFS_HEADER, |
| 142 | VB2_NV_HEADER_KERNEL_SETTINGS_RESET); |
| 143 | |
| 144 | case VB2_NV_DEBUG_RESET_MODE: |
| 145 | return GETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_DEBUG_RESET); |
| 146 | |
| 147 | case VB2_NV_TRY_NEXT: |
Randall Spangler | 8de992c | 2014-06-24 13:11:02 -0700 | [diff] [blame] | 148 | return GETBIT(VB2_NV_OFFS_BOOT2, VB2_NV_BOOT2_TRY_NEXT); |
Randall Spangler | 3333e57 | 2014-05-14 11:37:52 -0700 | [diff] [blame] | 149 | |
| 150 | case VB2_NV_TRY_COUNT: |
| 151 | return p[VB2_NV_OFFS_BOOT] & VB2_NV_BOOT_TRY_COUNT_MASK; |
| 152 | |
| 153 | case VB2_NV_FW_TRIED: |
| 154 | return GETBIT(VB2_NV_OFFS_BOOT2, VB2_NV_BOOT2_TRIED); |
| 155 | |
| 156 | case VB2_NV_FW_RESULT: |
| 157 | return p[VB2_NV_OFFS_BOOT2] & VB2_NV_BOOT2_RESULT_MASK; |
| 158 | |
| 159 | case VB2_NV_RECOVERY_REQUEST: |
| 160 | return p[VB2_NV_OFFS_RECOVERY]; |
| 161 | |
| 162 | case VB2_NV_RECOVERY_SUBCODE: |
| 163 | return p[VB2_NV_OFFS_RECOVERY_SUBCODE]; |
| 164 | |
| 165 | case VB2_NV_LOCALIZATION_INDEX: |
| 166 | return p[VB2_NV_OFFS_LOCALIZATION]; |
| 167 | |
| 168 | case VB2_NV_KERNEL_FIELD: |
| 169 | return (p[VB2_NV_OFFS_KERNEL] |
| 170 | | (p[VB2_NV_OFFS_KERNEL + 1] << 8) |
| 171 | | (p[VB2_NV_OFFS_KERNEL + 2] << 16) |
| 172 | | (p[VB2_NV_OFFS_KERNEL + 3] << 24)); |
| 173 | |
| 174 | case VB2_NV_DEV_BOOT_USB: |
| 175 | return GETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_USB); |
| 176 | |
| 177 | case VB2_NV_DEV_BOOT_LEGACY: |
| 178 | return GETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_LEGACY); |
| 179 | |
| 180 | case VB2_NV_DEV_BOOT_SIGNED_ONLY: |
| 181 | return GETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_SIGNED_ONLY); |
| 182 | |
| 183 | case VB2_NV_DISABLE_DEV_REQUEST: |
| 184 | return GETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_DISABLE_DEV); |
| 185 | |
| 186 | case VB2_NV_OPROM_NEEDED: |
| 187 | return GETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_OPROM_NEEDED); |
| 188 | |
Randall Spangler | 8de992c | 2014-06-24 13:11:02 -0700 | [diff] [blame] | 189 | case VB2_NV_BACKUP_NVRAM_REQUEST: |
| 190 | return GETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_BACKUP_NVRAM); |
| 191 | |
Randall Spangler | 3333e57 | 2014-05-14 11:37:52 -0700 | [diff] [blame] | 192 | case VB2_NV_CLEAR_TPM_OWNER_REQUEST: |
| 193 | return GETBIT(VB2_NV_OFFS_TPM, VB2_NV_TPM_CLEAR_OWNER_REQUEST); |
| 194 | |
| 195 | case VB2_NV_CLEAR_TPM_OWNER_DONE: |
| 196 | return GETBIT(VB2_NV_OFFS_TPM, VB2_NV_TPM_CLEAR_OWNER_DONE); |
| 197 | } |
| 198 | |
| 199 | /* |
| 200 | * Put default return outside the switch() instead of in default:, so |
| 201 | * that adding a new param will cause a compiler warning. |
| 202 | */ |
| 203 | return 0; |
| 204 | } |
| 205 | |
| 206 | #undef GETBIT |
| 207 | |
| 208 | /* Macro for vb2_nv_set() single-bit settings to reduce duplicate code. */ |
| 209 | #define SETBIT(offs, mask) \ |
| 210 | { if (value) p[offs] |= mask; else p[offs] &= ~mask; } |
| 211 | |
| 212 | void vb2_nv_set(struct vb2_context *ctx, |
| 213 | enum vb2_nv_param param, |
| 214 | uint32_t value) |
| 215 | { |
| 216 | uint8_t *p = ctx->nvdata; |
| 217 | |
| 218 | /* If not changing the value, don't regenerate the CRC. */ |
| 219 | if (vb2_nv_get(ctx, param) == value) |
| 220 | return; |
| 221 | |
| 222 | /* |
| 223 | * TODO: We could reduce the binary size for this code by #ifdef'ing |
| 224 | * out the params not used by firmware verification. |
| 225 | */ |
| 226 | switch (param) { |
| 227 | case VB2_NV_FIRMWARE_SETTINGS_RESET: |
| 228 | SETBIT(VB2_NV_OFFS_HEADER, VB2_NV_HEADER_FW_SETTINGS_RESET); |
| 229 | break; |
| 230 | |
| 231 | case VB2_NV_KERNEL_SETTINGS_RESET: |
| 232 | SETBIT(VB2_NV_OFFS_HEADER, VB2_NV_HEADER_KERNEL_SETTINGS_RESET); |
| 233 | break; |
| 234 | |
| 235 | case VB2_NV_DEBUG_RESET_MODE: |
| 236 | SETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_DEBUG_RESET); |
| 237 | break; |
| 238 | |
| 239 | case VB2_NV_TRY_NEXT: |
Randall Spangler | 8de992c | 2014-06-24 13:11:02 -0700 | [diff] [blame] | 240 | SETBIT(VB2_NV_OFFS_BOOT2, VB2_NV_BOOT2_TRY_NEXT); |
Randall Spangler | 3333e57 | 2014-05-14 11:37:52 -0700 | [diff] [blame] | 241 | break; |
| 242 | |
| 243 | case VB2_NV_TRY_COUNT: |
| 244 | /* Clip to valid range. */ |
| 245 | if (value > VB2_NV_BOOT_TRY_COUNT_MASK) |
| 246 | value = VB2_NV_BOOT_TRY_COUNT_MASK; |
| 247 | |
| 248 | p[VB2_NV_OFFS_BOOT] &= ~VB2_NV_BOOT_TRY_COUNT_MASK; |
| 249 | p[VB2_NV_OFFS_BOOT] |= (uint8_t)value; |
| 250 | break; |
| 251 | |
| 252 | case VB2_NV_FW_TRIED: |
| 253 | SETBIT(VB2_NV_OFFS_BOOT2, VB2_NV_BOOT2_TRIED); |
| 254 | break; |
| 255 | |
| 256 | case VB2_NV_FW_RESULT: |
| 257 | /* Map out of range values to unknown */ |
| 258 | if (value > VB2_NV_BOOT2_RESULT_MASK) |
| 259 | value = VB2_FW_RESULT_UNKNOWN; |
| 260 | |
| 261 | p[VB2_NV_OFFS_BOOT2] &= ~VB2_NV_BOOT2_RESULT_MASK; |
| 262 | p[VB2_NV_OFFS_BOOT2] |= (uint8_t)value; |
| 263 | break; |
| 264 | |
| 265 | case VB2_NV_RECOVERY_REQUEST: |
| 266 | /* |
| 267 | * Map values outside the valid range to the legacy reason, |
| 268 | * since we can't determine if we're called from kernel or user |
| 269 | * mode. |
| 270 | */ |
| 271 | if (value > 0xff) |
| 272 | value = VB2_RECOVERY_LEGACY; |
| 273 | p[VB2_NV_OFFS_RECOVERY] = (uint8_t)value; |
| 274 | break; |
| 275 | |
| 276 | case VB2_NV_RECOVERY_SUBCODE: |
| 277 | p[VB2_NV_OFFS_RECOVERY_SUBCODE] = (uint8_t)value; |
| 278 | break; |
| 279 | |
| 280 | case VB2_NV_LOCALIZATION_INDEX: |
| 281 | /* Map values outside the valid range to the default index. */ |
| 282 | if (value > 0xFF) |
| 283 | value = 0; |
| 284 | p[VB2_NV_OFFS_LOCALIZATION] = (uint8_t)value; |
| 285 | break; |
| 286 | |
| 287 | case VB2_NV_KERNEL_FIELD: |
| 288 | p[VB2_NV_OFFS_KERNEL] = (uint8_t)(value); |
| 289 | p[VB2_NV_OFFS_KERNEL + 1] = (uint8_t)(value >> 8); |
| 290 | p[VB2_NV_OFFS_KERNEL + 2] = (uint8_t)(value >> 16); |
| 291 | p[VB2_NV_OFFS_KERNEL + 3] = (uint8_t)(value >> 24); |
| 292 | break; |
| 293 | |
| 294 | case VB2_NV_DEV_BOOT_USB: |
| 295 | SETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_USB); |
| 296 | break; |
| 297 | |
| 298 | case VB2_NV_DEV_BOOT_LEGACY: |
| 299 | SETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_LEGACY); |
| 300 | break; |
| 301 | |
| 302 | case VB2_NV_DEV_BOOT_SIGNED_ONLY: |
| 303 | SETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_SIGNED_ONLY); |
| 304 | break; |
| 305 | |
| 306 | case VB2_NV_DISABLE_DEV_REQUEST: |
| 307 | SETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_DISABLE_DEV); |
| 308 | break; |
| 309 | |
| 310 | case VB2_NV_OPROM_NEEDED: |
| 311 | SETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_OPROM_NEEDED); |
| 312 | break; |
| 313 | |
Randall Spangler | 8de992c | 2014-06-24 13:11:02 -0700 | [diff] [blame] | 314 | case VB2_NV_BACKUP_NVRAM_REQUEST: |
| 315 | SETBIT(VB2_NV_OFFS_BOOT, VB2_NV_BOOT_BACKUP_NVRAM); |
| 316 | break; |
| 317 | |
Randall Spangler | 3333e57 | 2014-05-14 11:37:52 -0700 | [diff] [blame] | 318 | case VB2_NV_CLEAR_TPM_OWNER_REQUEST: |
| 319 | SETBIT(VB2_NV_OFFS_TPM, VB2_NV_TPM_CLEAR_OWNER_REQUEST); |
| 320 | break; |
| 321 | |
| 322 | case VB2_NV_CLEAR_TPM_OWNER_DONE: |
| 323 | SETBIT(VB2_NV_OFFS_TPM, VB2_NV_TPM_CLEAR_OWNER_DONE); |
| 324 | break; |
| 325 | } |
| 326 | |
| 327 | /* |
| 328 | * Note there is no default case. This causes a compiler warning if |
| 329 | * a new param is added to the enum without adding support here. |
| 330 | */ |
| 331 | |
| 332 | /* Need to regenerate CRC, since the value changed. */ |
| 333 | vb2_nv_regen_crc(ctx); |
| 334 | } |
| 335 | |
| 336 | #undef SETBIT |