| Index: firmware/lib/vboot_nvstorage.c
|
| diff --git a/firmware/lib/vboot_nvstorage.c b/firmware/lib/vboot_nvstorage.c
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..2222ac21ed43c0ac27e3f86116079b83a7945933
|
| --- /dev/null
|
| +++ b/firmware/lib/vboot_nvstorage.c
|
| @@ -0,0 +1,189 @@
|
| +/* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
|
| + * Use of this source code is governed by a BSD-style license that can be
|
| + * found in the LICENSE file.
|
| + */
|
| +
|
| +/* Non-volatile storage routines.
|
| + */
|
| +
|
| +#include "utility.h"
|
| +#include "vboot_common.h"
|
| +#include "vboot_nvstorage.h"
|
| +
|
| +/* Constants for NV storage. We use this rather than structs and
|
| + * bitfields so the data format is consistent across platforms and
|
| + * compilers. */
|
| +#define HEADER_OFFSET 0
|
| +#define HEADER_MASK 0xC0
|
| +#define HEADER_SIGNATURE 0x40
|
| +#define HEADER_FIRMWARE_SETTINGS_RESET 0x20
|
| +#define HEADER_KERNEL_SETTINGS_RESET 0x10
|
| +
|
| +#define BOOT_OFFSET 1
|
| +#define BOOT_DEBUG_RESET_MODE 0x80
|
| +#define BOOT_TRY_B_COUNT 0x0F
|
| +
|
| +#define RECOVERY_OFFSET 2
|
| +#define LOCALIZATION_OFFSET 3
|
| +#define KERNEL_FIELD_OFFSET 11
|
| +#define CRC_OFFSET 15
|
| +
|
| +
|
| +/* Return CRC-8 of the data, using x^8 + x^2 + x + 1 polynomial. A
|
| + * table-based algorithm would be faster, but for only 15 bytes isn't
|
| + * worth the code size. */
|
| +static uint8_t Crc8(const uint8_t* data, int len) {
|
| + unsigned crc = 0;
|
| + int i, j;
|
| +
|
| + for (j = len; j; j--, data++) {
|
| + crc ^= (*data << 8);
|
| + for(i = 8; i; i--) {
|
| + if (crc & 0x8000)
|
| + crc ^= (0x1070 << 3);
|
| + crc <<= 1;
|
| + }
|
| + }
|
| +
|
| + return (uint8_t)(crc >> 8);
|
| +}
|
| +
|
| +
|
| +int VbNvOpen(VbNvContext* context) {
|
| + uint8_t* raw = context->raw;
|
| +
|
| + /* TODO: implement locking when called from OS */
|
| +
|
| + /* Nothing has changed yet. */
|
| + context->raw_changed = 0;
|
| + context->regenerate_crc = 0;
|
| +
|
| + /* Check data for consistency */
|
| + if ((HEADER_SIGNATURE != (raw[HEADER_OFFSET] & HEADER_MASK))
|
| + || (Crc8(raw, CRC_OFFSET) != raw[CRC_OFFSET])) {
|
| +
|
| + /* Data is inconsistent (bad CRC or header), so reset defaults */
|
| + Memset(raw, 0, NV_BLOCK_SIZE);
|
| + raw[HEADER_OFFSET] = (HEADER_SIGNATURE | HEADER_FIRMWARE_SETTINGS_RESET |
|
| + HEADER_KERNEL_SETTINGS_RESET);
|
| +
|
| + /* Regenerate CRC on exit */
|
| + context->regenerate_crc = 1;
|
| + }
|
| +
|
| + return 0;
|
| +}
|
| +
|
| +
|
| +int VbNvClose(VbNvContext* context) {
|
| +
|
| + if (context->regenerate_crc) {
|
| + context->raw[CRC_OFFSET] = Crc8(context->raw, CRC_OFFSET);
|
| + context->regenerate_crc = 0;
|
| + context->raw_changed = 1;
|
| + }
|
| +
|
| + /* TODO: implement locking when called from OS */
|
| + return 0;
|
| +}
|
| +
|
| +
|
| +int VbNvGet(VbNvContext* context, VbNvParam param, uint32_t* dest) {
|
| + const uint8_t* raw = context->raw;
|
| +
|
| + switch (param) {
|
| + case VBNV_FIRMWARE_SETTINGS_RESET:
|
| + *dest = (raw[HEADER_OFFSET] & HEADER_FIRMWARE_SETTINGS_RESET ? 1 : 0);
|
| + return 0;
|
| +
|
| + case VBNV_KERNEL_SETTINGS_RESET:
|
| + *dest = (raw[HEADER_OFFSET] & HEADER_KERNEL_SETTINGS_RESET ? 1 : 0);
|
| + return 0;
|
| +
|
| + case VBNV_DEBUG_RESET_MODE:
|
| + *dest = (raw[BOOT_OFFSET] & BOOT_DEBUG_RESET_MODE ? 1 : 0);
|
| + return 0;
|
| +
|
| + case VBNV_TRY_B_COUNT:
|
| + *dest = raw[BOOT_OFFSET] & BOOT_TRY_B_COUNT;
|
| + return 0;
|
| +
|
| + case VBNV_RECOVERY_REQUEST:
|
| + *dest = raw[RECOVERY_OFFSET];
|
| + return 0;
|
| +
|
| + case VBNV_LOCALIZATION_INDEX:
|
| + *dest = raw[LOCALIZATION_OFFSET];
|
| + return 0;
|
| +
|
| + case VBNV_KERNEL_FIELD:
|
| + *dest = (raw[KERNEL_FIELD_OFFSET]
|
| + | (raw[KERNEL_FIELD_OFFSET + 1] << 8)
|
| + | (raw[KERNEL_FIELD_OFFSET + 2] << 16)
|
| + | (raw[KERNEL_FIELD_OFFSET + 3] << 24));
|
| + return 0;
|
| +
|
| + default:
|
| + return 1;
|
| + }
|
| +}
|
| +
|
| +
|
| +int VbNvSet(VbNvContext* context, VbNvParam param, uint32_t value) {
|
| + uint8_t* raw = context->raw;
|
| + uint32_t current;
|
| +
|
| + /* If we're not changing the value, we don't need to regenerate the CRC. */
|
| + if (0 == VbNvGet(context, param, ¤t) && current == value)
|
| + return 0;
|
| +
|
| + switch (param) {
|
| + case VBNV_FIRMWARE_SETTINGS_RESET:
|
| + if (value)
|
| + raw[HEADER_OFFSET] |= HEADER_FIRMWARE_SETTINGS_RESET;
|
| + else
|
| + raw[HEADER_OFFSET] &= ~HEADER_FIRMWARE_SETTINGS_RESET;
|
| + break;
|
| +
|
| + case VBNV_KERNEL_SETTINGS_RESET:
|
| + if (value)
|
| + raw[HEADER_OFFSET] |= HEADER_KERNEL_SETTINGS_RESET;
|
| + else
|
| + raw[HEADER_OFFSET] &= ~HEADER_KERNEL_SETTINGS_RESET;
|
| + break;
|
| +
|
| + case VBNV_DEBUG_RESET_MODE:
|
| + if (value)
|
| + raw[BOOT_OFFSET] |= BOOT_DEBUG_RESET_MODE;
|
| + else
|
| + raw[BOOT_OFFSET] &= BOOT_DEBUG_RESET_MODE;
|
| + break;
|
| +
|
| + case VBNV_TRY_B_COUNT:
|
| + raw[BOOT_OFFSET] &= ~BOOT_TRY_B_COUNT;
|
| + raw[BOOT_OFFSET] |= (uint8_t)(value & BOOT_TRY_B_COUNT);
|
| + break;
|
| +
|
| + case VBNV_RECOVERY_REQUEST:
|
| + raw[RECOVERY_OFFSET] = (uint8_t)value;
|
| + break;
|
| +
|
| + case VBNV_LOCALIZATION_INDEX:
|
| + raw[LOCALIZATION_OFFSET] = (uint8_t)value;
|
| + break;
|
| +
|
| + case VBNV_KERNEL_FIELD:
|
| + raw[KERNEL_FIELD_OFFSET] = (uint8_t)(value);
|
| + raw[KERNEL_FIELD_OFFSET + 1] = (uint8_t)(value >> 8);
|
| + raw[KERNEL_FIELD_OFFSET + 2] = (uint8_t)(value >> 16);
|
| + raw[KERNEL_FIELD_OFFSET + 3] = (uint8_t)(value >> 24);
|
| + break;
|
| +
|
| + default:
|
| + return 1;
|
| + }
|
| +
|
| + /* Need to regenerate CRC, since the value changed. */
|
| + context->regenerate_crc = 1;
|
| + return 0;
|
| +}
|
|
|