mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-11-24 02:05:01 +00:00
No need to have two implementations of this now. BUG=chromium:611535 BRANCH=none TEST=make runtests; emerge-kevin coreboot depthcharge Change-Id: Id3348eae80c5d85451981a44729164ff59f88648 Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/399121 Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
480 lines
12 KiB
C
480 lines
12 KiB
C
/* Copyright (c) 2013 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 "sysincludes.h"
|
|
|
|
#include "2crc8.h"
|
|
#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.
|
|
*
|
|
* These constants must match the equivalent constants in 2lib/2nvstorage.c.
|
|
* (We currently don't share a common header file because we're tring to keep
|
|
* the two libs independent, and we hope to deprecate this one.)
|
|
*/
|
|
#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 HEADER_WIPEOUT 0x08
|
|
|
|
#define BOOT_OFFSET 1
|
|
#define BOOT_DEBUG_RESET_MODE 0x80
|
|
#define BOOT_DISABLE_DEV_REQUEST 0x40
|
|
#define BOOT_OPROM_NEEDED 0x20
|
|
#define BOOT_BACKUP_NVRAM 0x10
|
|
#define BOOT_TRY_B_COUNT_MASK 0x0F
|
|
|
|
#define RECOVERY_OFFSET 2
|
|
#define LOCALIZATION_OFFSET 3
|
|
|
|
#define DEV_FLAGS_OFFSET 4
|
|
#define DEV_BOOT_USB_MASK 0x01
|
|
#define DEV_BOOT_SIGNED_ONLY_MASK 0x02
|
|
#define DEV_BOOT_LEGACY_MASK 0x04
|
|
#define DEV_BOOT_FASTBOOT_FULL_CAP_MASK 0x08
|
|
#define DEV_DEFAULT_BOOT_MASK 0x30
|
|
#define DEV_DEFAULT_BOOT_SHIFT 4 /* Number of bits to shift */
|
|
|
|
#define TPM_FLAGS_OFFSET 5
|
|
#define TPM_CLEAR_OWNER_REQUEST 0x01
|
|
#define TPM_CLEAR_OWNER_DONE 0x02
|
|
#define TPM_REBOOTED 0x04
|
|
|
|
#define RECOVERY_SUBCODE_OFFSET 6
|
|
|
|
#define BOOT2_OFFSET 7
|
|
#define BOOT2_RESULT_MASK 0x03
|
|
#define BOOT2_TRIED 0x04
|
|
#define BOOT2_TRY_NEXT 0x08
|
|
#define BOOT2_PREV_RESULT_MASK 0x30
|
|
#define BOOT2_PREV_RESULT_SHIFT 4 /* Number of bits to shift result */
|
|
#define BOOT2_PREV_TRIED 0x40
|
|
|
|
#define MISC_OFFSET 8
|
|
#define MISC_UNLOCK_FASTBOOT 0x01
|
|
#define MISC_BOOT_ON_AC_DETECT 0x02
|
|
#define MISC_TRY_RO_SYNC 0x04
|
|
#define MISC_BATTERY_CUTOFF_REQUEST 0x08
|
|
|
|
#define KERNEL_FIELD_OFFSET 11
|
|
#define CRC_OFFSET 15
|
|
|
|
int VbNvSetup(VbNvContext *context)
|
|
{
|
|
uint8_t *raw = context->raw;
|
|
|
|
/* Nothing has changed yet. */
|
|
context->raw_changed = 0;
|
|
context->regenerate_crc = 0;
|
|
|
|
/* Check data for consistency */
|
|
if ((HEADER_SIGNATURE != (raw[HEADER_OFFSET] & HEADER_MASK))
|
|
|| (vb2_crc8(raw, CRC_OFFSET) != raw[CRC_OFFSET])) {
|
|
/* Data is inconsistent (bad CRC or header); reset defaults */
|
|
memset(raw, 0, VBNV_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 VbNvTeardown(VbNvContext *context)
|
|
{
|
|
if (context->regenerate_crc) {
|
|
context->raw[CRC_OFFSET] = vb2_crc8(context->raw, CRC_OFFSET);
|
|
context->regenerate_crc = 0;
|
|
context->raw_changed = 1;
|
|
}
|
|
|
|
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:
|
|
case VBNV_FW_TRY_COUNT:
|
|
*dest = raw[BOOT_OFFSET] & BOOT_TRY_B_COUNT_MASK;
|
|
return 0;
|
|
|
|
case VBNV_RECOVERY_REQUEST:
|
|
*dest = raw[RECOVERY_OFFSET];
|
|
return 0;
|
|
|
|
case VBNV_RECOVERY_SUBCODE:
|
|
*dest = raw[RECOVERY_SUBCODE_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;
|
|
|
|
case VBNV_DEV_BOOT_USB:
|
|
*dest = (raw[DEV_FLAGS_OFFSET] & DEV_BOOT_USB_MASK ? 1 : 0);
|
|
return 0;
|
|
|
|
case VBNV_DEV_BOOT_LEGACY:
|
|
*dest = (raw[DEV_FLAGS_OFFSET] & DEV_BOOT_LEGACY_MASK ? 1 : 0);
|
|
return 0;
|
|
|
|
case VBNV_DEV_DEFAULT_BOOT:
|
|
*dest = (raw[DEV_FLAGS_OFFSET] & DEV_DEFAULT_BOOT_MASK)
|
|
>> DEV_DEFAULT_BOOT_SHIFT;
|
|
return 0;
|
|
|
|
case VBNV_DEV_BOOT_SIGNED_ONLY:
|
|
*dest = (raw[DEV_FLAGS_OFFSET] & DEV_BOOT_SIGNED_ONLY_MASK ?
|
|
1 : 0);
|
|
return 0;
|
|
|
|
case VBNV_DEV_BOOT_FASTBOOT_FULL_CAP:
|
|
*dest = (raw[DEV_FLAGS_OFFSET] & DEV_BOOT_FASTBOOT_FULL_CAP_MASK
|
|
? 1 : 0);
|
|
return 0;
|
|
|
|
case VBNV_DISABLE_DEV_REQUEST:
|
|
*dest = (raw[BOOT_OFFSET] & BOOT_DISABLE_DEV_REQUEST ? 1 : 0);
|
|
return 0;
|
|
|
|
case VBNV_OPROM_NEEDED:
|
|
*dest = (raw[BOOT_OFFSET] & BOOT_OPROM_NEEDED ? 1 : 0);
|
|
return 0;
|
|
|
|
case VBNV_CLEAR_TPM_OWNER_REQUEST:
|
|
*dest = (raw[TPM_FLAGS_OFFSET] & TPM_CLEAR_OWNER_REQUEST ?
|
|
1 : 0);
|
|
return 0;
|
|
|
|
case VBNV_CLEAR_TPM_OWNER_DONE:
|
|
*dest = (raw[TPM_FLAGS_OFFSET] & TPM_CLEAR_OWNER_DONE ? 1 : 0);
|
|
return 0;
|
|
|
|
case VBNV_TPM_REQUESTED_REBOOT:
|
|
*dest = (raw[TPM_FLAGS_OFFSET] & TPM_REBOOTED ? 1 : 0);
|
|
return 0;
|
|
|
|
case VBNV_BACKUP_NVRAM_REQUEST:
|
|
*dest = (raw[BOOT_OFFSET] & BOOT_BACKUP_NVRAM ? 1 : 0);
|
|
return 0;
|
|
|
|
case VBNV_FW_TRY_NEXT:
|
|
*dest = (raw[BOOT2_OFFSET] & BOOT2_TRY_NEXT ? 1 : 0);
|
|
return 0;
|
|
|
|
case VBNV_FW_TRIED:
|
|
*dest = (raw[BOOT2_OFFSET] & BOOT2_TRIED ? 1 : 0);
|
|
return 0;
|
|
|
|
case VBNV_FW_RESULT:
|
|
*dest = raw[BOOT2_OFFSET] & BOOT2_RESULT_MASK;
|
|
return 0;
|
|
|
|
case VBNV_FW_PREV_TRIED:
|
|
*dest = (raw[BOOT2_OFFSET] & BOOT2_PREV_TRIED ? 1 : 0);
|
|
return 0;
|
|
|
|
case VBNV_FW_PREV_RESULT:
|
|
*dest = (raw[BOOT2_OFFSET] & BOOT2_PREV_RESULT_MASK)
|
|
>> BOOT2_PREV_RESULT_SHIFT;
|
|
return 0;
|
|
|
|
case VBNV_FW_REQ_WIPEOUT:
|
|
*dest = (raw[HEADER_OFFSET] & HEADER_WIPEOUT) ? 1 : 0;
|
|
return 0;
|
|
|
|
case VBNV_FASTBOOT_UNLOCK_IN_FW:
|
|
*dest = (raw[MISC_OFFSET] & MISC_UNLOCK_FASTBOOT) ? 1 : 0;
|
|
return 0;
|
|
|
|
case VBNV_BOOT_ON_AC_DETECT:
|
|
*dest = (raw[MISC_OFFSET] & MISC_BOOT_ON_AC_DETECT) ? 1 : 0;
|
|
return 0;
|
|
|
|
case VBNV_TRY_RO_SYNC:
|
|
*dest = (raw[MISC_OFFSET] & MISC_TRY_RO_SYNC) ? 1 : 0;
|
|
return 0;
|
|
|
|
case VBNV_BATTERY_CUTOFF_REQUEST:
|
|
*dest = (raw[MISC_OFFSET] & MISC_BATTERY_CUTOFF_REQUEST)
|
|
? 1 : 0;
|
|
return 0;
|
|
|
|
default:
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
int VbNvSet(VbNvContext *context, VbNvParam param, uint32_t value)
|
|
{
|
|
uint8_t *raw = context->raw;
|
|
uint32_t current;
|
|
|
|
/* If not changing the value, don't 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:
|
|
case VBNV_FW_TRY_COUNT:
|
|
/* Clip to valid range. */
|
|
if (value > BOOT_TRY_B_COUNT_MASK)
|
|
value = BOOT_TRY_B_COUNT_MASK;
|
|
|
|
raw[BOOT_OFFSET] &= ~BOOT_TRY_B_COUNT_MASK;
|
|
raw[BOOT_OFFSET] |= (uint8_t)value;
|
|
break;
|
|
|
|
case VBNV_RECOVERY_REQUEST:
|
|
/*
|
|
* Map values outside the valid range to the legacy reason,
|
|
* since we can't determine if we're called from kernel or user
|
|
* mode.
|
|
*/
|
|
if (value > 0xFF)
|
|
value = VBNV_RECOVERY_LEGACY;
|
|
raw[RECOVERY_OFFSET] = (uint8_t)value;
|
|
break;
|
|
|
|
case VBNV_RECOVERY_SUBCODE:
|
|
raw[RECOVERY_SUBCODE_OFFSET] = (uint8_t)value;
|
|
break;
|
|
|
|
case VBNV_LOCALIZATION_INDEX:
|
|
/* Map values outside the valid range to the default index. */
|
|
if (value > 0xFF)
|
|
value = 0;
|
|
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;
|
|
|
|
case VBNV_DEV_BOOT_USB:
|
|
if (value)
|
|
raw[DEV_FLAGS_OFFSET] |= DEV_BOOT_USB_MASK;
|
|
else
|
|
raw[DEV_FLAGS_OFFSET] &= ~DEV_BOOT_USB_MASK;
|
|
break;
|
|
|
|
case VBNV_DEV_BOOT_LEGACY:
|
|
if (value)
|
|
raw[DEV_FLAGS_OFFSET] |= DEV_BOOT_LEGACY_MASK;
|
|
else
|
|
raw[DEV_FLAGS_OFFSET] &= ~DEV_BOOT_LEGACY_MASK;
|
|
break;
|
|
|
|
case VBNV_DEV_DEFAULT_BOOT:
|
|
/* Map out of range values to boot disk */
|
|
if (value > (DEV_DEFAULT_BOOT_MASK >>
|
|
DEV_DEFAULT_BOOT_SHIFT))
|
|
value = VBNV_DEV_DEFAULT_BOOT_DISK;
|
|
|
|
raw[DEV_FLAGS_OFFSET] &= ~DEV_DEFAULT_BOOT_MASK;
|
|
raw[DEV_FLAGS_OFFSET] |= (uint8_t)value <<
|
|
DEV_DEFAULT_BOOT_SHIFT;
|
|
break;
|
|
|
|
case VBNV_DEV_BOOT_SIGNED_ONLY:
|
|
if (value)
|
|
raw[DEV_FLAGS_OFFSET] |= DEV_BOOT_SIGNED_ONLY_MASK;
|
|
else
|
|
raw[DEV_FLAGS_OFFSET] &= ~DEV_BOOT_SIGNED_ONLY_MASK;
|
|
break;
|
|
|
|
case VBNV_DEV_BOOT_FASTBOOT_FULL_CAP:
|
|
if (value)
|
|
raw[DEV_FLAGS_OFFSET] |=
|
|
DEV_BOOT_FASTBOOT_FULL_CAP_MASK;
|
|
else
|
|
raw[DEV_FLAGS_OFFSET] &=
|
|
~DEV_BOOT_FASTBOOT_FULL_CAP_MASK;
|
|
break;
|
|
|
|
case VBNV_DISABLE_DEV_REQUEST:
|
|
if (value)
|
|
raw[BOOT_OFFSET] |= BOOT_DISABLE_DEV_REQUEST;
|
|
else
|
|
raw[BOOT_OFFSET] &= ~BOOT_DISABLE_DEV_REQUEST;
|
|
break;
|
|
|
|
case VBNV_OPROM_NEEDED:
|
|
if (value)
|
|
raw[BOOT_OFFSET] |= BOOT_OPROM_NEEDED;
|
|
else
|
|
raw[BOOT_OFFSET] &= ~BOOT_OPROM_NEEDED;
|
|
break;
|
|
|
|
case VBNV_CLEAR_TPM_OWNER_REQUEST:
|
|
if (value)
|
|
raw[TPM_FLAGS_OFFSET] |= TPM_CLEAR_OWNER_REQUEST;
|
|
else
|
|
raw[TPM_FLAGS_OFFSET] &= ~TPM_CLEAR_OWNER_REQUEST;
|
|
break;
|
|
|
|
case VBNV_CLEAR_TPM_OWNER_DONE:
|
|
if (value)
|
|
raw[TPM_FLAGS_OFFSET] |= TPM_CLEAR_OWNER_DONE;
|
|
else
|
|
raw[TPM_FLAGS_OFFSET] &= ~TPM_CLEAR_OWNER_DONE;
|
|
break;
|
|
|
|
case VBNV_TPM_REQUESTED_REBOOT:
|
|
if (value)
|
|
raw[TPM_FLAGS_OFFSET] |= TPM_REBOOTED;
|
|
else
|
|
raw[TPM_FLAGS_OFFSET] &= ~TPM_REBOOTED;
|
|
break;
|
|
|
|
case VBNV_BACKUP_NVRAM_REQUEST:
|
|
if (value)
|
|
raw[BOOT_OFFSET] |= BOOT_BACKUP_NVRAM;
|
|
else
|
|
raw[BOOT_OFFSET] &= ~BOOT_BACKUP_NVRAM;
|
|
break;
|
|
|
|
case VBNV_FW_TRY_NEXT:
|
|
if (value)
|
|
raw[BOOT2_OFFSET] |= BOOT2_TRY_NEXT;
|
|
else
|
|
raw[BOOT2_OFFSET] &= ~BOOT2_TRY_NEXT;
|
|
break;
|
|
|
|
case VBNV_FW_TRIED:
|
|
if (value)
|
|
raw[BOOT2_OFFSET] |= BOOT2_TRIED;
|
|
else
|
|
raw[BOOT2_OFFSET] &= ~BOOT2_TRIED;
|
|
break;
|
|
|
|
case VBNV_FW_RESULT:
|
|
/* Map out of range values to unknown */
|
|
if (value > BOOT2_RESULT_MASK)
|
|
value = VBNV_FW_RESULT_UNKNOWN;
|
|
|
|
raw[BOOT2_OFFSET] &= ~BOOT2_RESULT_MASK;
|
|
raw[BOOT2_OFFSET] |= (uint8_t)value;
|
|
break;
|
|
|
|
case VBNV_FW_PREV_TRIED:
|
|
if (value)
|
|
raw[BOOT2_OFFSET] |= BOOT2_PREV_TRIED;
|
|
else
|
|
raw[BOOT2_OFFSET] &= ~BOOT2_PREV_TRIED;
|
|
break;
|
|
|
|
case VBNV_FW_PREV_RESULT:
|
|
/* Map out of range values to unknown */
|
|
if (value > BOOT2_RESULT_MASK)
|
|
value = VBNV_FW_RESULT_UNKNOWN;
|
|
|
|
raw[BOOT2_OFFSET] &= ~BOOT2_PREV_RESULT_MASK;
|
|
raw[BOOT2_OFFSET] |= (uint8_t)value << BOOT2_PREV_RESULT_SHIFT;
|
|
break;
|
|
|
|
case VBNV_FW_REQ_WIPEOUT:
|
|
if (value)
|
|
raw[HEADER_OFFSET] |= HEADER_WIPEOUT;
|
|
else
|
|
raw[HEADER_OFFSET] &= ~HEADER_WIPEOUT;
|
|
break;
|
|
|
|
case VBNV_FASTBOOT_UNLOCK_IN_FW:
|
|
if (value)
|
|
raw[MISC_OFFSET] |= MISC_UNLOCK_FASTBOOT;
|
|
else
|
|
raw[MISC_OFFSET] &= ~MISC_UNLOCK_FASTBOOT;
|
|
break;
|
|
|
|
case VBNV_BOOT_ON_AC_DETECT:
|
|
if (value)
|
|
raw[MISC_OFFSET] |= MISC_BOOT_ON_AC_DETECT;
|
|
else
|
|
raw[MISC_OFFSET] &= ~MISC_BOOT_ON_AC_DETECT;
|
|
break;
|
|
|
|
case VBNV_TRY_RO_SYNC:
|
|
if (value)
|
|
raw[MISC_OFFSET] |= MISC_TRY_RO_SYNC;
|
|
else
|
|
raw[MISC_OFFSET] &= ~MISC_TRY_RO_SYNC;
|
|
break;
|
|
|
|
case VBNV_BATTERY_CUTOFF_REQUEST:
|
|
if (value)
|
|
raw[MISC_OFFSET] |= MISC_BATTERY_CUTOFF_REQUEST;
|
|
else
|
|
raw[MISC_OFFSET] &= ~MISC_BATTERY_CUTOFF_REQUEST;
|
|
break;
|
|
|
|
default:
|
|
return 1;
|
|
}
|
|
|
|
/* Need to regenerate CRC, since the value changed. */
|
|
context->regenerate_crc = 1;
|
|
return 0;
|
|
}
|