/* * Copyright (c) 2012 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. */ #include #include "common.h" #include "rwsig.h" #include "util.h" #include "version.h" /* FMAP structs. See http://code.google.com/p/flashmap/wiki/FmapSpec */ #define FMAP_NAMELEN 32 #define FMAP_SIGNATURE "__FMAP__" #define FMAP_SIGNATURE_SIZE 8 #define FMAP_VER_MAJOR 1 #define FMAP_VER_MINOR 0 /* * For address containing CONFIG_PROGRAM_MEMORY_BASE (symbols in *.RO.lds.S and * variable), this computes the offset to the start of the image on flash. */ #define RELATIVE_RO(addr) ((addr) - CONFIG_PROGRAM_MEMORY_BASE - \ CONFIG_RO_MEM_OFF) /* * All internal EC code assumes that offsets are provided relative to * physical address zero of storage. In some cases, the region of storage * belonging to the EC is not physical address zero - a non-zero fmap_base * indicates so. Since fmap_base is not yet handled correctly by external * code, we must perform the adjustment in our host command handlers - * adjust all offsets so they are relative to the beginning of the storage * region belonging to the EC. TODO(crbug.com/529365): Handle fmap_base * correctly in flashrom, dump_fmap, etc. and remove EC_FLASH_REGION_START. */ #if CONFIG_EC_WRITABLE_STORAGE_OFF < CONFIG_EC_PROTECTED_STORAGE_OFF #define FMAP_REGION_START CONFIG_EC_WRITABLE_STORAGE_OFF #else #define FMAP_REGION_START CONFIG_EC_PROTECTED_STORAGE_OFF #endif struct fmap_header { char fmap_signature[FMAP_SIGNATURE_SIZE]; uint8_t fmap_ver_major; uint8_t fmap_ver_minor; uint64_t fmap_base; uint32_t fmap_size; char fmap_name[FMAP_NAMELEN]; uint16_t fmap_nareas; } __packed; #define FMAP_AREA_STATIC (1 << 0) /* can be checksummed */ #define FMAP_AREA_COMPRESSED (1 << 1) /* may be compressed */ #define FMAP_AREA_RO (1 << 2) /* writes may fail */ struct fmap_area_header { uint32_t area_offset; uint32_t area_size; char area_name[FMAP_NAMELEN]; uint16_t area_flags; } __packed; #ifdef CONFIG_RWSIG_TYPE_RWSIG #define NUM_EC_FMAP_AREAS_RWSIG 2 #else #define NUM_EC_FMAP_AREAS_RWSIG 0 #endif #ifdef CONFIG_ROLLBACK #define NUM_EC_FMAP_AREAS_ROLLBACK 1 #else #define NUM_EC_FMAP_AREAS_ROLLBACK 0 #endif #ifdef CONFIG_RW_B # ifdef CONFIG_RWSIG_TYPE_RWSIG # define NUM_EC_FMAP_AREAS_RW_B 2 # else # define NUM_EC_FMAP_AREAS_RW_B 1 # endif #else #define NUM_EC_FMAP_AREAS_RW_B 0 #endif #define NUM_EC_FMAP_AREAS (7 + \ NUM_EC_FMAP_AREAS_RWSIG + \ NUM_EC_FMAP_AREAS_ROLLBACK + \ NUM_EC_FMAP_AREAS_RW_B) const struct _ec_fmap { struct fmap_header header; struct fmap_area_header area[NUM_EC_FMAP_AREAS]; } ec_fmap __keep __attribute__((section(".google"))) = { /* Header */ { .fmap_signature = {'_', '_', 'F', 'M', 'A', 'P', '_', '_'}, .fmap_ver_major = FMAP_VER_MAJOR, .fmap_ver_minor = FMAP_VER_MINOR, .fmap_base = CONFIG_PROGRAM_MEMORY_BASE, .fmap_size = CONFIG_FLASH_SIZE, /* Used to distinguish the EC FMAP from other FMAPs */ .fmap_name = "EC_FMAP", .fmap_nareas = NUM_EC_FMAP_AREAS, }, { /* RO Firmware */ { /* * Range of RO firmware to be updated. Verified in * factory finalization by hash. Should not have * volatile data (ex, calibration results). */ .area_name = "EC_RO", .area_offset = CONFIG_EC_PROTECTED_STORAGE_OFF - FMAP_REGION_START + CONFIG_RO_STORAGE_OFF, .area_size = CONFIG_RO_SIZE, .area_flags = FMAP_AREA_STATIC | FMAP_AREA_RO, }, { /* (Optional) RO firmware code. */ .area_name = "FR_MAIN", .area_offset = CONFIG_EC_PROTECTED_STORAGE_OFF - FMAP_REGION_START + CONFIG_RO_STORAGE_OFF, .area_size = CONFIG_RO_SIZE, .area_flags = FMAP_AREA_STATIC | FMAP_AREA_RO, }, { /* * RO firmware version ID. Must be NULL terminated * ASCII, and padded with \0. */ .area_name = "RO_FRID", .area_offset = CONFIG_EC_PROTECTED_STORAGE_OFF - FMAP_REGION_START + CONFIG_RO_STORAGE_OFF + RELATIVE_RO((uint32_t)__image_data_offset) + offsetof(struct image_data, version), .area_size = sizeof(current_image_data.version), .area_flags = FMAP_AREA_STATIC | FMAP_AREA_RO, }, /* Other RO stuff: FMAP, WP, KEYS, etc. */ { .area_name = "FMAP", .area_offset = CONFIG_EC_PROTECTED_STORAGE_OFF - FMAP_REGION_START + CONFIG_RO_STORAGE_OFF + RELATIVE_RO((uint32_t)&ec_fmap), .area_size = sizeof(ec_fmap), .area_flags = FMAP_AREA_STATIC | FMAP_AREA_RO, }, { /* * The range for write protection, for factory * finalization. Should include (may be identical to) * EC_RO and aligned to hardware specification. */ .area_name = "WP_RO", .area_offset = CONFIG_WP_STORAGE_OFF - FMAP_REGION_START, .area_size = CONFIG_WP_STORAGE_SIZE, .area_flags = FMAP_AREA_STATIC | FMAP_AREA_RO, }, #ifdef CONFIG_RWSIG_TYPE_RWSIG { /* RO public key address, for RW verification */ .area_name = "KEY_RO", .area_offset = CONFIG_EC_PROTECTED_STORAGE_OFF - FMAP_REGION_START + CONFIG_RO_PUBKEY_ADDR - CONFIG_PROGRAM_MEMORY_BASE, .area_size = CONFIG_RO_PUBKEY_SIZE, .area_flags = FMAP_AREA_STATIC | FMAP_AREA_RO, }, #endif /* RW Firmware */ { /* The range of RW firmware to be auto-updated. */ .area_name = "EC_RW", .area_offset = CONFIG_EC_WRITABLE_STORAGE_OFF - FMAP_REGION_START + CONFIG_RW_STORAGE_OFF, .area_size = CONFIG_RW_SIZE, .area_flags = FMAP_AREA_STATIC | FMAP_AREA_RO, }, { /* * RW firmware version ID. Must be NULL terminated * ASCII, and padded with \0. * TODO: Get the relative offset of * __image_data_offset within our RW image to * accommodate image asymmetry. */ .area_name = "RW_FWID", .area_offset = CONFIG_EC_WRITABLE_STORAGE_OFF - FMAP_REGION_START + CONFIG_RW_STORAGE_OFF + RELATIVE_RO((uint32_t)__image_data_offset) + offsetof(struct image_data, version), .area_size = sizeof(current_image_data.version), .area_flags = FMAP_AREA_STATIC, }, #ifdef CONFIG_ROLLBACK { /* * RW rollback version, 32-bit unsigned integer. * TODO: Get the relative offset of * __image_data_offset within our RW image to * accommodate image asymmetry. */ .area_name = "RW_RBVER", .area_offset = CONFIG_EC_WRITABLE_STORAGE_OFF - FMAP_REGION_START + CONFIG_RW_STORAGE_OFF + RELATIVE_RO((uint32_t)__image_data_offset) + offsetof(struct image_data, rollback_version), .area_size = sizeof( current_image_data.rollback_version), .area_flags = FMAP_AREA_STATIC, }, #endif #ifdef CONFIG_RWSIG_TYPE_RWSIG { /* RW image signature */ .area_name = "SIG_RW", .area_offset = CONFIG_EC_PROTECTED_STORAGE_OFF - FMAP_REGION_START + CONFIG_RW_SIG_ADDR - CONFIG_PROGRAM_MEMORY_BASE, .area_size = CONFIG_RW_SIG_SIZE, .area_flags = FMAP_AREA_STATIC | FMAP_AREA_RO, }, #endif #ifdef CONFIG_RW_B /* RW Firmware */ { /* The range of RW firmware to be auto-updated. */ .area_name = "EC_RW_B", .area_offset = CONFIG_EC_WRITABLE_STORAGE_OFF - FMAP_REGION_START + CONFIG_RW_STORAGE_OFF + CONFIG_RW_SIZE, .area_size = CONFIG_RW_SIZE, .area_flags = FMAP_AREA_STATIC | FMAP_AREA_RO, }, #ifdef CONFIG_RWSIG_TYPE_RWSIG { /* RW_B image signature */ .area_name = "SIG_RW_B", .area_offset = CONFIG_EC_PROTECTED_STORAGE_OFF - FMAP_REGION_START + CONFIG_RW_B_SIG_ADDR - CONFIG_PROGRAM_MEMORY_BASE, .area_size = CONFIG_RW_SIG_SIZE, .area_flags = FMAP_AREA_STATIC | FMAP_AREA_RO, }, #endif #endif } };