Home | History | Annotate | Download | only in lib
      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, &current) && 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