| /* Copyright 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. |
| */ |
| |
| /* Flash module for emulator */ |
| |
| #include <stdio.h> |
| |
| #include "common.h" |
| #include "config_chip.h" |
| #include "flash.h" |
| #include "persistence.h" |
| #include "util.h" |
| |
| /* This needs to be aligned to the erase bank size for NVCTR. */ |
| __aligned(CONFIG_FLASH_ERASE_SIZE) char __host_flash[CONFIG_FLASH_SIZE]; |
| uint8_t __host_flash_protect[PHYSICAL_BANKS]; |
| |
| /* Override this function to make flash erase/write operation fail */ |
| test_mockable int flash_pre_op(void) |
| { |
| return EC_SUCCESS; |
| } |
| |
| static int flash_check_protect(int offset, int size) |
| { |
| int first_bank = offset / CONFIG_FLASH_BANK_SIZE; |
| int last_bank = DIV_ROUND_UP(offset + size, |
| CONFIG_FLASH_BANK_SIZE); |
| int bank; |
| |
| for (bank = first_bank; bank < last_bank; ++bank) |
| if (__host_flash_protect[bank]) |
| return 1; |
| return 0; |
| } |
| |
| static void flash_set_persistent(void) |
| { |
| FILE *f = get_persistent_storage("flash", "wb"); |
| int sz; |
| |
| ASSERT(f != NULL); |
| |
| sz = fwrite(__host_flash, sizeof(__host_flash), 1, f); |
| ASSERT(sz == 1); |
| |
| release_persistent_storage(f); |
| } |
| |
| static void flash_get_persistent(void) |
| { |
| FILE *f = get_persistent_storage("flash", "rb"); |
| |
| if (f == NULL) { |
| fprintf(stderr, |
| "No flash storage found. Initializing to 0xff.\n"); |
| memset(__host_flash, 0xff, sizeof(__host_flash)); |
| return; |
| } |
| |
| fread(__host_flash, sizeof(__host_flash), 1, f); |
| |
| release_persistent_storage(f); |
| } |
| |
| int flash_physical_write(int offset, int size, const char *data) |
| { |
| ASSERT((size & (CONFIG_FLASH_WRITE_SIZE - 1)) == 0); |
| |
| if (flash_pre_op() != EC_SUCCESS) |
| return EC_ERROR_UNKNOWN; |
| |
| if (flash_check_protect(offset, size)) |
| return EC_ERROR_ACCESS_DENIED; |
| |
| memcpy(__host_flash + offset, data, size); |
| flash_set_persistent(); |
| |
| return EC_SUCCESS; |
| } |
| |
| int flash_physical_erase(int offset, int size) |
| { |
| ASSERT((size & (CONFIG_FLASH_ERASE_SIZE - 1)) == 0); |
| |
| if (flash_pre_op() != EC_SUCCESS) |
| return EC_ERROR_UNKNOWN; |
| |
| if (flash_check_protect(offset, size)) |
| return EC_ERROR_ACCESS_DENIED; |
| |
| memset(__host_flash + offset, 0xff, size); |
| flash_set_persistent(); |
| |
| return EC_SUCCESS; |
| } |
| |
| int flash_physical_get_protect(int bank) |
| { |
| return __host_flash_protect[bank]; |
| } |
| |
| uint32_t flash_physical_get_protect_flags(void) |
| { |
| int i; |
| uint32_t flags = EC_FLASH_PROTECT_ALL_NOW; |
| |
| for (i = 0; i < PHYSICAL_BANKS; ++i) |
| if (__host_flash_protect[i] == 0) |
| flags = 0; |
| |
| return flags; |
| } |
| |
| int flash_physical_protect_now(int all) |
| { |
| memset(__host_flash_protect, 1, all ? PHYSICAL_BANKS : WP_BANK_COUNT); |
| return EC_SUCCESS; |
| } |
| |
| uint32_t flash_physical_get_valid_flags(void) |
| { |
| return EC_FLASH_PROTECT_RO_AT_BOOT | |
| EC_FLASH_PROTECT_RO_NOW | |
| EC_FLASH_PROTECT_ALL_NOW; |
| } |
| |
| uint32_t flash_physical_get_writable_flags(uint32_t cur_flags) |
| { |
| uint32_t ret = 0; |
| |
| /* If RO protection isn't enabled, its at-boot state can be changed. */ |
| if (!(cur_flags & EC_FLASH_PROTECT_RO_NOW)) |
| ret |= EC_FLASH_PROTECT_RO_AT_BOOT; |
| |
| /* |
| * If entire flash isn't protected at this boot, it can be enabled if |
| * the WP GPIO is asserted. |
| */ |
| if (!(cur_flags & EC_FLASH_PROTECT_ALL_NOW) && |
| (cur_flags & EC_FLASH_PROTECT_GPIO_ASSERTED)) |
| ret |= EC_FLASH_PROTECT_ALL_NOW; |
| |
| return ret; |
| } |
| |
| int flash_pre_init(void) |
| { |
| uint32_t prot_flags; |
| |
| flash_get_persistent(); |
| |
| prot_flags = flash_get_protect(); |
| |
| if (prot_flags & EC_FLASH_PROTECT_GPIO_ASSERTED) { |
| /* |
| * Write protect is asserted. If we want RO flash protected, |
| * protect it now. |
| */ |
| if ((prot_flags & EC_FLASH_PROTECT_RO_AT_BOOT) && |
| !(prot_flags & EC_FLASH_PROTECT_RO_NOW)) { |
| int rv = flash_set_protect(EC_FLASH_PROTECT_RO_NOW, |
| EC_FLASH_PROTECT_RO_NOW); |
| if (rv) |
| return rv; |
| |
| /* Re-read flags */ |
| prot_flags = flash_get_protect(); |
| } |
| } |
| |
| return EC_SUCCESS; |
| } |