From 4aaaeca130a701a06cb898d9a17eddf67daa3617 Mon Sep 17 00:00:00 2001 From: Randall Spangler Date: Fri, 20 Oct 2017 12:38:40 -0700 Subject: [PATCH] nvstorage: Add kernel max rollforward NV storage field This just adds the kernel_max_rollforward field to the nvstorage libraries and crossystem. The firmware does not use it yet; that's coming in a subsequent CL. 16 of the fields's 32 bits are taken from unused bytes of the kernel field. This has no effect on existing usage. BUG=chromium:783997 BRANCH=none TEST=make runtests Also manual testing. In a root shell: crossystem kernel_max_rollforward --> Should default to 0 crossystem kernel_max_rollforward=0xfffffffe crossystem kernel_max_rollforward --> Should be 0xfffffffe (Note that setting it to 0xffffffff is indistinguishable from the -1 value that the crossystem library uses to indicate error, so 0xffffffff isn't actually usable as a max rollforward limit. But 0xfffffffe is, and if we ever get so close to the limit that we need to use 0xffffffff, something has already gone horribly wrong with our versioning strategy...) Change-Id: I008f412e6ed3c0b59beb9881268585af69d1ff2e Signed-off-by: Randall Spangler Reviewed-on: https://chromium-review.googlesource.com/765572 Reviewed-by: Julius Werner --- firmware/2lib/2nvstorage.c | 24 ++++++++++------ firmware/2lib/include/2nvstorage.h | 9 ++++-- firmware/2lib/include/2nvstorage_fields.h | 8 ++++-- firmware/include/vboot_nvstorage.h | 5 +++- firmware/lib/vboot_nvstorage.c | 35 +++++++++++++++++------ host/lib/crossystem.c | 12 +++++--- tests/vb2_nvstorage_tests.c | 4 ++- tests/vboot_nvstorage_test.c | 4 ++- utility/crossystem.c | 4 ++- 9 files changed, 76 insertions(+), 29 deletions(-) diff --git a/firmware/2lib/2nvstorage.c b/firmware/2lib/2nvstorage.c index b40bbe78df..083633629c 100644 --- a/firmware/2lib/2nvstorage.c +++ b/firmware/2lib/2nvstorage.c @@ -121,10 +121,7 @@ uint32_t vb2_nv_get(struct vb2_context *ctx, enum vb2_nv_param param) return p[VB2_NV_OFFS_LOCALIZATION]; case VB2_NV_KERNEL_FIELD: - return (p[VB2_NV_OFFS_KERNEL] - | (p[VB2_NV_OFFS_KERNEL + 1] << 8) - | (p[VB2_NV_OFFS_KERNEL + 2] << 16) - | (p[VB2_NV_OFFS_KERNEL + 3] << 24)); + return p[VB2_NV_OFFS_KERNEL1] | (p[VB2_NV_OFFS_KERNEL2] << 8); case VB2_NV_DEV_BOOT_USB: return GETBIT(VB2_NV_OFFS_DEV, VB2_NV_DEV_FLAG_USB); @@ -175,6 +172,12 @@ uint32_t vb2_nv_get(struct vb2_context *ctx, enum vb2_nv_param param) case VB2_NV_BATTERY_CUTOFF_REQUEST: return GETBIT(VB2_NV_OFFS_MISC, VB2_NV_MISC_BATTERY_CUTOFF); + + case VB2_NV_KERNEL_MAX_ROLLFORWARD: + return (p[VB2_NV_OFFS_KERNEL_MAX_ROLLFORWARD1] + | (p[VB2_NV_OFFS_KERNEL_MAX_ROLLFORWARD2] << 8) + | (p[VB2_NV_OFFS_KERNEL_MAX_ROLLFORWARD3] << 16) + | (p[VB2_NV_OFFS_KERNEL_MAX_ROLLFORWARD4] << 24)); } /* @@ -280,10 +283,8 @@ void vb2_nv_set(struct vb2_context *ctx, break; case VB2_NV_KERNEL_FIELD: - p[VB2_NV_OFFS_KERNEL] = (uint8_t)(value); - p[VB2_NV_OFFS_KERNEL + 1] = (uint8_t)(value >> 8); - p[VB2_NV_OFFS_KERNEL + 2] = (uint8_t)(value >> 16); - p[VB2_NV_OFFS_KERNEL + 3] = (uint8_t)(value >> 24); + p[VB2_NV_OFFS_KERNEL1] = (uint8_t)(value); + p[VB2_NV_OFFS_KERNEL2] = (uint8_t)(value >> 8); break; case VB2_NV_DEV_BOOT_USB: @@ -356,6 +357,13 @@ void vb2_nv_set(struct vb2_context *ctx, case VB2_NV_BATTERY_CUTOFF_REQUEST: SETBIT(VB2_NV_OFFS_MISC, VB2_NV_MISC_BATTERY_CUTOFF); break; + + case VB2_NV_KERNEL_MAX_ROLLFORWARD: + p[VB2_NV_OFFS_KERNEL_MAX_ROLLFORWARD1] = (uint8_t)(value); + p[VB2_NV_OFFS_KERNEL_MAX_ROLLFORWARD2] = (uint8_t)(value >> 8); + p[VB2_NV_OFFS_KERNEL_MAX_ROLLFORWARD3] = (uint8_t)(value >> 16); + p[VB2_NV_OFFS_KERNEL_MAX_ROLLFORWARD4] = (uint8_t)(value >> 24); + break; } /* diff --git a/firmware/2lib/include/2nvstorage.h b/firmware/2lib/include/2nvstorage.h index 66a5fdf13a..e3226a5889 100644 --- a/firmware/2lib/include/2nvstorage.h +++ b/firmware/2lib/include/2nvstorage.h @@ -42,7 +42,7 @@ enum vb2_nv_param { * 8-bit value. */ VB2_NV_LOCALIZATION_INDEX, - /* Field reserved for kernel/user-mode use; 32-bit value. */ + /* Field reserved for kernel/user-mode use; 16-bit value. */ VB2_NV_KERNEL_FIELD, /* Allow booting from USB in developer mode. 0=no, 1=yes. */ VB2_NV_DEV_BOOT_USB, @@ -94,10 +94,15 @@ enum vb2_nv_param { VB2_NV_FASTBOOT_UNLOCK_IN_FW, /* Boot system when AC detected (0=no, 1=yes). */ VB2_NV_BOOT_ON_AC_DETECT, - /* Try to update the EC-RO image after updating the EC-RW image(0=no, 1=yes). */ + /* + * Try to update the EC-RO image after updating the EC-RW image + * (0=no, 1=yes). + */ VB2_NV_TRY_RO_SYNC, /* Cut off battery and shutdown on next boot. */ VB2_NV_BATTERY_CUTOFF_REQUEST, + /* Maximum kernel version to roll forward to */ + VB2_NV_KERNEL_MAX_ROLLFORWARD, }; /* Set default boot in developer mode */ diff --git a/firmware/2lib/include/2nvstorage_fields.h b/firmware/2lib/include/2nvstorage_fields.h index 018bdeb729..0ed3325aa4 100644 --- a/firmware/2lib/include/2nvstorage_fields.h +++ b/firmware/2lib/include/2nvstorage_fields.h @@ -29,8 +29,12 @@ enum vb2_nv_offset { VB2_NV_OFFS_RECOVERY_SUBCODE = 6, VB2_NV_OFFS_BOOT2 = 7, VB2_NV_OFFS_MISC = 8, - /* Offsets 9-10 are currently unused */ - VB2_NV_OFFS_KERNEL = 11, /* 11-14; field is 32 bits */ + VB2_NV_OFFS_KERNEL_MAX_ROLLFORWARD1 = 9, /* bits 0-7 of 32 */ + VB2_NV_OFFS_KERNEL_MAX_ROLLFORWARD2 = 10, /* bits 8-15 of 32 */ + VB2_NV_OFFS_KERNEL1 = 11, /* bits 0-7 of 16 */ + VB2_NV_OFFS_KERNEL2 = 12, /* bits 8-15 of 16 */ + VB2_NV_OFFS_KERNEL_MAX_ROLLFORWARD3 = 13, /* bits 16-23 of 32 */ + VB2_NV_OFFS_KERNEL_MAX_ROLLFORWARD4 = 14, /* bits 24-31 of 32 */ /* CRC must be last field */ VB2_NV_OFFS_CRC = 15 }; diff --git a/firmware/include/vboot_nvstorage.h b/firmware/include/vboot_nvstorage.h index 8c7ff9d357..ecb5d0075e 100644 --- a/firmware/include/vboot_nvstorage.h +++ b/firmware/include/vboot_nvstorage.h @@ -122,8 +122,11 @@ typedef enum VbNvParam { VBNV_TRY_RO_SYNC, /* * Finish mode transition (if requested), perform battery cut-off and - * shutdown in next boot. */ + * shutdown in next boot. + */ VBNV_BATTERY_CUTOFF_REQUEST, + /* Maximum kernel version to roll forward to */ + VBNV_KERNEL_MAX_ROLLFORWARD, } VbNvParam; /* Set default boot in developer mode */ diff --git a/firmware/lib/vboot_nvstorage.c b/firmware/lib/vboot_nvstorage.c index 3d6a65d7b9..9dc9dc3d12 100644 --- a/firmware/lib/vboot_nvstorage.c +++ b/firmware/lib/vboot_nvstorage.c @@ -66,7 +66,14 @@ #define MISC_TRY_RO_SYNC 0x04 #define MISC_BATTERY_CUTOFF_REQUEST 0x08 -#define KERNEL_FIELD_OFFSET 11 +#define KERNEL_MAX_ROLLFORWARD1_OFFSET 9 /* Low bits */ +#define KERNEL_MAX_ROLLFORWARD2_OFFSET 10 +#define KERNEL_MAX_ROLLFORWARD3_OFFSET 13 +#define KERNEL_MAX_ROLLFORWARD4_OFFSET 14 /* High bits */ + +#define KERNEL_FIELD1_OFFSET 11 /* Low bits */ +#define KERNEL_FIELD2_OFFSET 12 /* Low bits */ + #define CRC_OFFSET 15 int VbNvSetup(VbNvContext *context) @@ -141,10 +148,8 @@ int VbNvGet(VbNvContext *context, VbNvParam param, uint32_t *dest) 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)); + *dest = (raw[KERNEL_FIELD1_OFFSET] + | (raw[KERNEL_FIELD2_OFFSET] << 8)); return 0; case VBNV_DEV_BOOT_USB: @@ -237,6 +242,13 @@ int VbNvGet(VbNvContext *context, VbNvParam param, uint32_t *dest) ? 1 : 0; return 0; + case VBNV_KERNEL_MAX_ROLLFORWARD: + *dest = (raw[KERNEL_MAX_ROLLFORWARD1_OFFSET] + | (raw[KERNEL_MAX_ROLLFORWARD2_OFFSET] << 8) + | (raw[KERNEL_MAX_ROLLFORWARD3_OFFSET] << 16) + | (raw[KERNEL_MAX_ROLLFORWARD4_OFFSET] << 24)); + return 0; + default: return 1; } @@ -306,10 +318,8 @@ int VbNvSet(VbNvContext *context, VbNvParam param, uint32_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); + raw[KERNEL_FIELD1_OFFSET] = (uint8_t)(value); + raw[KERNEL_FIELD2_OFFSET] = (uint8_t)(value >> 8); break; case VBNV_DEV_BOOT_USB: @@ -469,6 +479,13 @@ int VbNvSet(VbNvContext *context, VbNvParam param, uint32_t value) raw[MISC_OFFSET] &= ~MISC_BATTERY_CUTOFF_REQUEST; break; + case VBNV_KERNEL_MAX_ROLLFORWARD: + raw[KERNEL_MAX_ROLLFORWARD1_OFFSET] = (uint8_t)(value); + raw[KERNEL_MAX_ROLLFORWARD2_OFFSET] = (uint8_t)(value >> 8); + raw[KERNEL_MAX_ROLLFORWARD3_OFFSET] = (uint8_t)(value >> 16); + raw[KERNEL_MAX_ROLLFORWARD4_OFFSET] = (uint8_t)(value >> 24); + break; + default: return 1; } diff --git a/host/lib/crossystem.c b/host/lib/crossystem.c index 16ba211691..216ff32ce3 100644 --- a/host/lib/crossystem.c +++ b/host/lib/crossystem.c @@ -72,14 +72,14 @@ static const char *fw_results[] = {"unknown", "trying", "success", "failure"}; static const char *default_boot[] = {"disk", "usb", "legacy"}; /* Masks for kern_nv usage by kernel. */ -#define KERN_NV_FWUPDATE_TRIES_MASK 0x0000000F -#define KERN_NV_BLOCK_DEVMODE_FLAG 0x00000010 -#define KERN_NV_TPM_ATTACK_FLAG 0x00000020 +#define KERN_NV_FWUPDATE_TRIES_MASK 0x000F +#define KERN_NV_BLOCK_DEVMODE_FLAG 0x0010 +#define KERN_NV_TPM_ATTACK_FLAG 0x0020 /* If you want to use the remaining currently-unused bits in kern_nv * for something kernel-y, define a new field (the way we did for * fwupdate_tries). Don't just modify kern_nv directly, because that * makes it too easy to accidentally corrupt other sub-fields. */ -#define KERN_NV_CURRENTLY_UNUSED 0xFFFFFFC0 +#define KERN_NV_CURRENTLY_UNUSED 0xFFC0 /* Return true if the FWID starts with the specified string. */ int FwidStartsWith(const char *start) @@ -523,6 +523,8 @@ int VbGetSystemPropertyInt(const char *name) value = VbGetNvStorage(VBNV_RECOVERY_SUBCODE); } else if (!strcasecmp(name,"wipeout_request")) { value = VbGetNvStorage(VBNV_FW_REQ_WIPEOUT); + } else if (!strcasecmp(name,"kernel_max_rollforward")) { + value = VbGetNvStorage(VBNV_KERNEL_MAX_ROLLFORWARD); } /* Other parameters */ else if (!strcasecmp(name,"cros_debug")) { @@ -716,6 +718,8 @@ int VbSetSystemPropertyInt(const char *name, int value) return VbSetNvStorage_WithBackup(VBNV_TRY_RO_SYNC, value); } else if (!strcasecmp(name, "battery_cutoff_request")) { return VbSetNvStorage(VBNV_BATTERY_CUTOFF_REQUEST, value); + } else if (!strcasecmp(name,"kernel_max_rollforward")) { + return VbSetNvStorage(VBNV_KERNEL_MAX_ROLLFORWARD, value); } return -1; diff --git a/tests/vb2_nvstorage_tests.c b/tests/vb2_nvstorage_tests.c index 2056f1017e..fe31a5eeef 100644 --- a/tests/vb2_nvstorage_tests.c +++ b/tests/vb2_nvstorage_tests.c @@ -41,7 +41,7 @@ static struct nv_field nvfields[] = { {VB2_NV_RECOVERY_REQUEST, 0, 0x42, 0xED, "recovery request"}, {VB2_NV_RECOVERY_SUBCODE, 0, 0x56, 0xAC, "recovery subcode"}, {VB2_NV_LOCALIZATION_INDEX, 0, 0x69, 0xB0, "localization index"}, - {VB2_NV_KERNEL_FIELD, 0, 0x12345678, 0xFEDCBA98, "kernel field"}, + {VB2_NV_KERNEL_FIELD, 0, 0x1234, 0xFEDC, "kernel field"}, {VB2_NV_DEV_BOOT_USB, 0, 1, 0, "dev boot usb"}, {VB2_NV_DEV_BOOT_LEGACY, 0, 1, 0, "dev boot legacy"}, {VB2_NV_DEV_BOOT_SIGNED_ONLY, 0, 1, 0, "dev boot custom"}, @@ -56,6 +56,8 @@ static struct nv_field nvfields[] = { {VB2_NV_FASTBOOT_UNLOCK_IN_FW, 0, 1, 0, "fastboot unlock in fw"}, {VB2_NV_BOOT_ON_AC_DETECT, 0, 1, 0, "boot on ac detect"}, {VB2_NV_TRY_RO_SYNC, 0, 1, 0, "try read only software sync"}, + {VB2_NV_KERNEL_MAX_ROLLFORWARD, 0, 0x12345678, 0xFEDCBA98, + "kernel max rollforward"}, {0, 0, 0, 0, NULL} }; diff --git a/tests/vboot_nvstorage_test.c b/tests/vboot_nvstorage_test.c index 687048e16c..c461978fb4 100644 --- a/tests/vboot_nvstorage_test.c +++ b/tests/vboot_nvstorage_test.c @@ -29,7 +29,7 @@ static VbNvField nvfields[] = { {VBNV_TRY_B_COUNT, 0, 6, 15, "try B count"}, {VBNV_RECOVERY_REQUEST, 0, 0x42, 0xED, "recovery request"}, {VBNV_LOCALIZATION_INDEX, 0, 0x69, 0xB0, "localization index"}, - {VBNV_KERNEL_FIELD, 0, 0x12345678, 0xFEDCBA98, "kernel field"}, + {VBNV_KERNEL_FIELD, 0, 0x1234, 0xFEDC, "kernel field"}, {VBNV_DEV_BOOT_USB, 0, 1, 0, "dev boot usb"}, {VBNV_DEV_BOOT_LEGACY, 0, 1, 0, "dev boot legacy"}, {VBNV_DEV_BOOT_SIGNED_ONLY, 0, 1, 0, "dev boot custom"}, @@ -49,6 +49,8 @@ static VbNvField nvfields[] = { {VBNV_FASTBOOT_UNLOCK_IN_FW, 0, 1, 0, "fastboot unlock in firmware"}, {VBNV_BOOT_ON_AC_DETECT, 0, 1, 0, "boot on ac detect"}, {VBNV_TRY_RO_SYNC, 0, 1, 0, "try read only software sync"}, + {VBNV_KERNEL_MAX_ROLLFORWARD, 0, 0x12345678, 0xFEDCBA98, + "kernel max rollforward"}, {0, 0, 0, 0, NULL} }; diff --git a/utility/crossystem.c b/utility/crossystem.c index 62e8a92176..911d585d52 100644 --- a/utility/crossystem.c +++ b/utility/crossystem.c @@ -70,7 +70,9 @@ const Param sys_param_list[] = { {"fw_prev_result", IS_STRING, "Firmware result of previous boot (vboot2)"}, {"hwid", IS_STRING, "Hardware ID"}, {"inside_vm", 0, "Running in a VM?"}, - {"kern_nv", 0, "Non-volatile field for kernel use", "0x%08x"}, + {"kern_nv", 0, "Non-volatile field for kernel use", "0x%04x"}, + {"kernel_max_rollforward", CAN_WRITE, "Max kernel version to store into TPM", + "0x%08x"}, {"kernkey_vfy", IS_STRING, "Type of verification done on kernel key block"}, {"loc_idx", CAN_WRITE, "Localization index for firmware screens (writable)"}, {"mainfw_act", IS_STRING, "Active main firmware"},