vboot_nvstorage.c revision 17b8224ea582b2ba90b30a3e8e2d913e49c7818a
1/* Copyright (c) 2012 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 9#include "crc8.h" 10#include "utility.h" 11#include "vboot_common.h" 12#include "vboot_nvstorage.h" 13 14/* Constants for NV storage. We use this rather than structs and 15 * bitfields so the data format is consistent across platforms and 16 * compilers. */ 17#define HEADER_OFFSET 0 18#define HEADER_MASK 0xC0 19#define HEADER_SIGNATURE 0x40 20#define HEADER_FIRMWARE_SETTINGS_RESET 0x20 21#define HEADER_KERNEL_SETTINGS_RESET 0x10 22 23#define BOOT_OFFSET 1 24#define BOOT_DEBUG_RESET_MODE 0x80 25#define BOOT_DISABLE_DEV_REQUEST 0x40 26#define BOOT_OPROM_NEEDED 0x20 27#define BOOT_TRY_B_COUNT_MASK 0x0F 28 29#define RECOVERY_OFFSET 2 30#define LOCALIZATION_OFFSET 3 31 32#define DEV_FLAGS_OFFSET 4 33#define DEV_BOOT_USB_MASK 0x01 34#define DEV_BOOT_SIGNED_ONLY_MASK 0x02 35 36#define KERNEL_FIELD_OFFSET 11 37#define CRC_OFFSET 15 38 39 40int VbNvSetup(VbNvContext* context) { 41 uint8_t* raw = context->raw; 42 43 /* Nothing has changed yet. */ 44 context->raw_changed = 0; 45 context->regenerate_crc = 0; 46 47 /* Check data for consistency */ 48 if ((HEADER_SIGNATURE != (raw[HEADER_OFFSET] & HEADER_MASK)) 49 || (Crc8(raw, CRC_OFFSET) != raw[CRC_OFFSET])) { 50 51 /* Data is inconsistent (bad CRC or header), so reset defaults */ 52 Memset(raw, 0, VBNV_BLOCK_SIZE); 53 raw[HEADER_OFFSET] = (HEADER_SIGNATURE | HEADER_FIRMWARE_SETTINGS_RESET | 54 HEADER_KERNEL_SETTINGS_RESET); 55 56 /* Regenerate CRC on exit */ 57 context->regenerate_crc = 1; 58 } 59 60 return 0; 61} 62 63 64int VbNvTeardown(VbNvContext* context) { 65 66 if (context->regenerate_crc) { 67 context->raw[CRC_OFFSET] = Crc8(context->raw, CRC_OFFSET); 68 context->regenerate_crc = 0; 69 context->raw_changed = 1; 70 } 71 72 return 0; 73} 74 75 76int VbNvGet(VbNvContext* context, VbNvParam param, uint32_t* dest) { 77 const uint8_t* raw = context->raw; 78 79 switch (param) { 80 case VBNV_FIRMWARE_SETTINGS_RESET: 81 *dest = (raw[HEADER_OFFSET] & HEADER_FIRMWARE_SETTINGS_RESET ? 1 : 0); 82 return 0; 83 84 case VBNV_KERNEL_SETTINGS_RESET: 85 *dest = (raw[HEADER_OFFSET] & HEADER_KERNEL_SETTINGS_RESET ? 1 : 0); 86 return 0; 87 88 case VBNV_DEBUG_RESET_MODE: 89 *dest = (raw[BOOT_OFFSET] & BOOT_DEBUG_RESET_MODE ? 1 : 0); 90 return 0; 91 92 case VBNV_TRY_B_COUNT: 93 *dest = raw[BOOT_OFFSET] & BOOT_TRY_B_COUNT_MASK; 94 return 0; 95 96 case VBNV_RECOVERY_REQUEST: 97 *dest = raw[RECOVERY_OFFSET]; 98 return 0; 99 100 case VBNV_LOCALIZATION_INDEX: 101 *dest = raw[LOCALIZATION_OFFSET]; 102 return 0; 103 104 case VBNV_KERNEL_FIELD: 105 *dest = (raw[KERNEL_FIELD_OFFSET] 106 | (raw[KERNEL_FIELD_OFFSET + 1] << 8) 107 | (raw[KERNEL_FIELD_OFFSET + 2] << 16) 108 | (raw[KERNEL_FIELD_OFFSET + 3] << 24)); 109 return 0; 110 111 case VBNV_DEV_BOOT_USB: 112 *dest = (raw[DEV_FLAGS_OFFSET] & DEV_BOOT_USB_MASK ? 1 : 0); 113 return 0; 114 115 case VBNV_DEV_BOOT_SIGNED_ONLY: 116 *dest = (raw[DEV_FLAGS_OFFSET] & DEV_BOOT_SIGNED_ONLY_MASK ? 1 : 0); 117 return 0; 118 119 case VBNV_DISABLE_DEV_REQUEST: 120 *dest = (raw[BOOT_OFFSET] & BOOT_DISABLE_DEV_REQUEST ? 1 : 0); 121 return 0; 122 123 case VBNV_OPROM_NEEDED: 124 *dest = (raw[BOOT_OFFSET] & BOOT_OPROM_NEEDED ? 1 : 0); 125 return 0; 126 127 default: 128 return 1; 129 } 130} 131 132 133int VbNvSet(VbNvContext* context, VbNvParam param, uint32_t value) { 134 uint8_t* raw = context->raw; 135 uint32_t current; 136 137 /* If we're not changing the value, we don't need to regenerate the CRC. */ 138 if (0 == VbNvGet(context, param, ¤t) && current == value) 139 return 0; 140 141 switch (param) { 142 case VBNV_FIRMWARE_SETTINGS_RESET: 143 if (value) 144 raw[HEADER_OFFSET] |= HEADER_FIRMWARE_SETTINGS_RESET; 145 else 146 raw[HEADER_OFFSET] &= ~HEADER_FIRMWARE_SETTINGS_RESET; 147 break; 148 149 case VBNV_KERNEL_SETTINGS_RESET: 150 if (value) 151 raw[HEADER_OFFSET] |= HEADER_KERNEL_SETTINGS_RESET; 152 else 153 raw[HEADER_OFFSET] &= ~HEADER_KERNEL_SETTINGS_RESET; 154 break; 155 156 case VBNV_DEBUG_RESET_MODE: 157 if (value) 158 raw[BOOT_OFFSET] |= BOOT_DEBUG_RESET_MODE; 159 else 160 raw[BOOT_OFFSET] &= ~BOOT_DEBUG_RESET_MODE; 161 break; 162 163 case VBNV_TRY_B_COUNT: 164 /* Clip to valid range. */ 165 if (value > BOOT_TRY_B_COUNT_MASK) 166 value = BOOT_TRY_B_COUNT_MASK; 167 168 raw[BOOT_OFFSET] &= ~BOOT_TRY_B_COUNT_MASK; 169 raw[BOOT_OFFSET] |= (uint8_t)value; 170 break; 171 172 case VBNV_RECOVERY_REQUEST: 173 /* Map values outside the valid range to the legacy reason, since we 174 * can't determine if we're called from kernel or user mode. */ 175 if (value > 0xFF) 176 value = VBNV_RECOVERY_LEGACY; 177 raw[RECOVERY_OFFSET] = (uint8_t)value; 178 break; 179 180 case VBNV_LOCALIZATION_INDEX: 181 /* Map values outside the valid range to the default index. */ 182 if (value > 0xFF) 183 value = 0; 184 raw[LOCALIZATION_OFFSET] = (uint8_t)value; 185 break; 186 187 case VBNV_KERNEL_FIELD: 188 raw[KERNEL_FIELD_OFFSET] = (uint8_t)(value); 189 raw[KERNEL_FIELD_OFFSET + 1] = (uint8_t)(value >> 8); 190 raw[KERNEL_FIELD_OFFSET + 2] = (uint8_t)(value >> 16); 191 raw[KERNEL_FIELD_OFFSET + 3] = (uint8_t)(value >> 24); 192 break; 193 194 case VBNV_DEV_BOOT_USB: 195 if (value) 196 raw[DEV_FLAGS_OFFSET] |= DEV_BOOT_USB_MASK; 197 else 198 raw[DEV_FLAGS_OFFSET] &= ~DEV_BOOT_USB_MASK; 199 break; 200 201 case VBNV_DEV_BOOT_SIGNED_ONLY: 202 if (value) 203 raw[DEV_FLAGS_OFFSET] |= DEV_BOOT_SIGNED_ONLY_MASK; 204 else 205 raw[DEV_FLAGS_OFFSET] &= ~DEV_BOOT_SIGNED_ONLY_MASK; 206 break; 207 208 case VBNV_DISABLE_DEV_REQUEST: 209 if (value) 210 raw[BOOT_OFFSET] |= BOOT_DISABLE_DEV_REQUEST; 211 else 212 raw[BOOT_OFFSET] &= ~BOOT_DISABLE_DEV_REQUEST; 213 break; 214 215 case VBNV_OPROM_NEEDED: 216 if (value) 217 raw[BOOT_OFFSET] |= BOOT_OPROM_NEEDED; 218 else 219 raw[BOOT_OFFSET] &= ~BOOT_OPROM_NEEDED; 220 break; 221 222 default: 223 return 1; 224 } 225 226 /* Need to regenerate CRC, since the value changed. */ 227 context->regenerate_crc = 1; 228 return 0; 229} 230