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