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; }
/** * Update status of non-debounced switches. * * Note that deferred functions are called in the same context as lid and * power button changes, so we don't need a mutex. */ static void switch_update(void) { static uint8_t prev; /* Make sure this is safe to call before power_button_init() */ if (!memmap_switches) return; prev = *memmap_switches; if (power_button_is_pressed()) *memmap_switches |= EC_SWITCH_POWER_BUTTON_PRESSED; else *memmap_switches &= ~EC_SWITCH_POWER_BUTTON_PRESSED; if (lid_is_open()) *memmap_switches |= EC_SWITCH_LID_OPEN; else *memmap_switches &= ~EC_SWITCH_LID_OPEN; if ((flash_get_protect() & EC_FLASH_PROTECT_GPIO_ASSERTED) == 0) *memmap_switches |= EC_SWITCH_WRITE_PROTECT_DISABLED; else *memmap_switches &= ~EC_SWITCH_WRITE_PROTECT_DISABLED; #ifdef CONFIG_SWITCH_DEDICATED_RECOVERY if (gpio_get_level(GPIO_RECOVERY_L) == 0) *memmap_switches |= EC_SWITCH_DEDICATED_RECOVERY; else *memmap_switches &= ~EC_SWITCH_DEDICATED_RECOVERY; #endif if (prev != *memmap_switches) CPRINTS("SW 0x%02x", *memmap_switches); }
static int flash_command_protect(struct host_cmd_handler_args *args) { const struct ec_params_flash_protect *p = args->params; struct ec_response_flash_protect *r = args->response; /* * Handle requesting new flags. Note that we ignore the return code * from flash_set_protect(), since errors will be visible to the caller * via the flags in the response. (If we returned error, the caller * wouldn't get the response.) */ if (p->mask) flash_set_protect(p->mask, p->flags); /* * Retrieve the current flags. The caller can use this to determine * which of the requested flags could be set. This is cleaner than * simply returning error, because it provides information to the * caller about the actual result. */ r->flags = flash_get_protect(); /* Indicate which flags are valid on this platform */ r->valid_flags = EC_FLASH_PROTECT_GPIO_ASSERTED | EC_FLASH_PROTECT_ERROR_STUCK | EC_FLASH_PROTECT_ERROR_INCONSISTENT | flash_physical_get_valid_flags(); r->writable_flags = flash_physical_get_writable_flags(r->flags); args->response_size = sizeof(*r); return EC_RES_SUCCESS; }
int flash_pre_init(void) { uint32_t reset_flags = system_get_reset_flags(); uint32_t prot_flags = flash_get_protect(); int need_reset = 0; /* * If we have already jumped between images, an earlier image could * have applied write protection. Nothing additional needs to be done. */ if (reset_flags & RESET_FLAG_SYSJUMP) return EC_SUCCESS; if (prot_flags & EC_FLASH_PROTECT_GPIO_ASSERTED) { if ((prot_flags & EC_FLASH_PROTECT_RO_AT_BOOT) && !(prot_flags & EC_FLASH_PROTECT_RO_NOW)) { /* * Pstate wants RO protected at boot, but the write * protect register wasn't set to protect it. Force an * update to the write protect register and reboot so * it takes effect. */ flash_protect_at_boot(FLASH_WP_RO); need_reset = 1; } if (prot_flags & EC_FLASH_PROTECT_ERROR_INCONSISTENT) { /* * Write protect register was in an inconsistent state. * Set it back to a good state and reboot. */ flash_protect_at_boot( (prot_flags & EC_FLASH_PROTECT_RO_AT_BOOT) ? FLASH_WP_RO : FLASH_WP_NONE); need_reset = 1; } } else if (prot_flags & (EC_FLASH_PROTECT_RO_NOW | EC_FLASH_PROTECT_ERROR_INCONSISTENT)) { /* * Write protect pin unasserted but some section is * protected. Drop it and reboot. */ unlock(STM32_FLASH_PECR_OPT_LOCK); write_optb_wrp(0); lock(); need_reset = 1; } if (need_reset) system_reset(SYSTEM_RESET_HARD | SYSTEM_RESET_PRESERVE_FLAGS); return EC_SUCCESS; }
/** * Check if write protect register state is inconsistent with RO_AT_BOOT and * ALL_AT_BOOT state. * * @return zero if consistent, non-zero if inconsistent. */ static int registers_need_reset(void) { uint32_t flags = flash_get_protect(); int i; int ro_at_boot = (flags & EC_FLASH_PROTECT_RO_AT_BOOT) ? 1 : 0; int ro_wp_region_start = WP_BANK_OFFSET; int ro_wp_region_end = WP_BANK_OFFSET + WP_BANK_COUNT; for (i = ro_wp_region_start; i < ro_wp_region_end; i++) if (flash_physical_get_protect_at_boot(i) != ro_at_boot) return 1; return 0; }
static int flash_command_protect(struct host_cmd_handler_args *args) { const struct ec_params_flash_protect *p = args->params; struct ec_response_flash_protect *r = args->response; /* * Handle requesting new flags. Note that we ignore the return code * from flash_set_protect(), since errors will be visible to the caller * via the flags in the response. (If we returned error, the caller * wouldn't get the response.) */ if (p->mask) flash_set_protect(p->mask, p->flags); /* * Retrieve the current flags. The caller can use this to determine * which of the requested flags could be set. This is cleaner than * simply returning error, because it provides information to the * caller about the actual result. */ r->flags = flash_get_protect(); /* Indicate which flags are valid on this platform */ r->valid_flags = EC_FLASH_PROTECT_GPIO_ASSERTED | EC_FLASH_PROTECT_ERROR_STUCK | EC_FLASH_PROTECT_RO_AT_BOOT | EC_FLASH_PROTECT_RO_NOW | EC_FLASH_PROTECT_ALL_NOW | EC_FLASH_PROTECT_ERROR_INCONSISTENT; r->writable_flags = 0; /* If RO protection isn't enabled, its at-boot state can be changed. */ if (!(r->flags & EC_FLASH_PROTECT_RO_NOW)) r->writable_flags |= 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 (!(r->flags & EC_FLASH_PROTECT_ALL_NOW) && (r->flags & EC_FLASH_PROTECT_GPIO_ASSERTED)) r->writable_flags |= EC_FLASH_PROTECT_ALL_NOW; args->response_size = sizeof(*r); return EC_RES_SUCCESS; }
static int command_flash_erase(int argc, char **argv) { int offset = -1; int size = CONFIG_FLASH_ERASE_SIZE; int rv; if (flash_get_protect() & EC_FLASH_PROTECT_ALL_NOW) return EC_ERROR_ACCESS_DENIED; rv = parse_offset_size(argc, argv, 1, &offset, &size); if (rv) return rv; ccprintf("Erasing %d bytes at 0x%x...\n", size, offset, offset); return flash_erase(offset, size); }
/** * Flash write command * * Version 0 and 1 are equivalent from the EC-side; the only difference is * that the host can only send 64 bytes of data at a time in version 0. */ static int flash_command_write(struct host_cmd_handler_args *args) { const struct ec_params_flash_write *p = args->params; if (flash_get_protect() & EC_FLASH_PROTECT_ALL_NOW) return EC_RES_ACCESS_DENIED; if (p->size + sizeof(*p) > args->params_size) return EC_RES_INVALID_PARAM; if (system_unsafe_to_overwrite(p->offset, p->size)) return EC_RES_ACCESS_DENIED; if (flash_write(p->offset, p->size, (const uint8_t *)(p + 1))) return EC_RES_ERROR; return EC_RES_SUCCESS; }
static int command_flash_info(int argc, char **argv) { int i; ccprintf("Physical:%4d KB\n", CONFIG_FLASH_PHYSICAL_SIZE / 1024); ccprintf("Usable: %4d KB\n", CONFIG_FLASH_SIZE / 1024); ccprintf("Write: %4d B (ideal %d B)\n", CONFIG_FLASH_WRITE_SIZE, CONFIG_FLASH_WRITE_IDEAL_SIZE); ccprintf("Erase: %4d B (to %d-bits)\n", CONFIG_FLASH_ERASE_SIZE, CONFIG_FLASH_ERASED_VALUE32 ? 1 : 0); ccprintf("Protect: %4d B\n", CONFIG_FLASH_BANK_SIZE); i = flash_get_protect(); ccprintf("Flags: "); if (i & EC_FLASH_PROTECT_GPIO_ASSERTED) ccputs(" wp_gpio_asserted"); if (i & EC_FLASH_PROTECT_RO_AT_BOOT) ccputs(" ro_at_boot"); if (i & EC_FLASH_PROTECT_ALL_AT_BOOT) ccputs(" all_at_boot"); if (i & EC_FLASH_PROTECT_RO_NOW) ccputs(" ro_now"); if (i & EC_FLASH_PROTECT_ALL_NOW) ccputs(" all_now"); if (i & EC_FLASH_PROTECT_ERROR_STUCK) ccputs(" STUCK"); if (i & EC_FLASH_PROTECT_ERROR_INCONSISTENT) ccputs(" INCONSISTENT"); ccputs("\n"); ccputs("Protected now:"); for (i = 0; i < CONFIG_FLASH_PHYSICAL_SIZE / CONFIG_FLASH_BANK_SIZE; i++) { if (!(i & 31)) ccputs("\n "); else if (!(i & 7)) ccputs(" "); ccputs(flash_physical_get_protect(i) ? "Y" : "."); } ccputs("\n"); return EC_SUCCESS; }
static int flash_command_erase(struct host_cmd_handler_args *args) { const struct ec_params_flash_erase *p = args->params; if (flash_get_protect() & EC_FLASH_PROTECT_ALL_NOW) return EC_RES_ACCESS_DENIED; if (system_unsafe_to_overwrite(p->offset, p->size)) return EC_RES_ACCESS_DENIED; /* Indicate that we might be a while */ #if defined(HAS_TASK_HOSTCMD) && defined(CONFIG_HOST_COMMAND_STATUS) args->result = EC_RES_IN_PROGRESS; host_send_response(args); #endif if (flash_erase(p->offset, p->size)) return EC_RES_ERROR; return EC_RES_SUCCESS; }
static int command_flash_write(int argc, char **argv) { int offset = -1; int size = CONFIG_FLASH_ERASE_SIZE; int rv; char *data; int i; if (flash_get_protect() & EC_FLASH_PROTECT_ALL_NOW) return EC_ERROR_ACCESS_DENIED; rv = parse_offset_size(argc, argv, 1, &offset, &size); if (rv) return rv; if (size > shared_mem_size()) size = shared_mem_size(); /* Acquire the shared memory buffer */ rv = shared_mem_acquire(size, &data); if (rv) { ccputs("Can't get shared mem\n"); return rv; } /* Fill the data buffer with a pattern */ for (i = 0; i < size; i++) data[i] = i; ccprintf("Writing %d bytes to 0x%x...\n", size, offset, offset); rv = flash_write(offset, size, data); /* Free the buffer */ shared_mem_release(data); return rv; }
int flash_pre_init(void) { uint32_t reset_flags = system_get_reset_flags(); uint32_t prot_flags = flash_get_protect(); int need_reset = 0; if (flash_physical_restore_state()) return EC_SUCCESS; /* * If we have already jumped between images, an earlier image could * have applied write protection. Nothing additional needs to be done. */ if (reset_flags & RESET_FLAG_SYSJUMP) return EC_SUCCESS; if (prot_flags & EC_FLASH_PROTECT_GPIO_ASSERTED) { if ((prot_flags & EC_FLASH_PROTECT_RO_AT_BOOT) && !(prot_flags & EC_FLASH_PROTECT_RO_NOW)) { /* * Pstate wants RO protected at boot, but the write * protect register wasn't set to protect it. Force an * update to the write protect register and reboot so * it takes effect. */ flash_physical_protect_at_boot(FLASH_WP_RO); need_reset = 1; } if (registers_need_reset()) { /* * Write protect register was in an inconsistent state. * Set it back to a good state and reboot. * * TODO(crosbug.com/p/23798): this seems really similar * to the check above. One of them should be able to * go away. */ flash_protect_at_boot( (prot_flags & EC_FLASH_PROTECT_RO_AT_BOOT) ? FLASH_WP_RO : FLASH_WP_NONE); need_reset = 1; } } else { if (prot_flags & EC_FLASH_PROTECT_RO_NOW) { /* * Write protect pin unasserted but some section is * protected. Drop it and reboot. */ unprotect_all_blocks(); need_reset = 1; } } if ((flash_physical_get_valid_flags() & EC_FLASH_PROTECT_ALL_AT_BOOT) && (!!(prot_flags & EC_FLASH_PROTECT_ALL_AT_BOOT) != !!(prot_flags & EC_FLASH_PROTECT_ALL_NOW))) { /* * ALL_AT_BOOT and ALL_NOW should be both set or both unset * at boot. If they are not, it must be that the chip requires * OBL_LAUNCH to be set to reload option bytes. Let's reset * the system with OBL_LAUNCH set. * This assumes OBL_LAUNCH is used for hard reset in * chip/stm32/system.c. */ need_reset = 1; } if (need_reset) system_reset(SYSTEM_RESET_HARD | SYSTEM_RESET_PRESERVE_FLAGS); return EC_SUCCESS; }
int flash_set_protect(uint32_t mask, uint32_t flags) { int retval = EC_SUCCESS; int rv; enum flash_wp_range range = FLASH_WP_NONE; int need_set_protect = 0; /* * Process flags we can set. Track the most recent error, but process * all flags before returning. */ /* * AT_BOOT flags are trickier than NOW flags, as they can be set * when HW write protection is disabled and can be unset without * a reboot. * * If we are only setting/clearing RO_AT_BOOT, things are simple. * Setting ALL_AT_BOOT is processed only if HW write protection is * enabled and RO_AT_BOOT is set, so it's also simple. * * The most tricky one is when we want to clear ALL_AT_BOOT. We need * to determine whether to clear protection for the entire flash or * leave RO protected. There are two cases that we want to keep RO * protected: * 1. RO_AT_BOOT was already set before flash_set_protect() is * called. * 2. RO_AT_BOOT was not set, but it's requested to be set by * the caller of flash_set_protect(). */ if (mask & EC_FLASH_PROTECT_RO_AT_BOOT) { range = (flags & EC_FLASH_PROTECT_RO_AT_BOOT) ? FLASH_WP_RO : FLASH_WP_NONE; need_set_protect = 1; } if ((mask & EC_FLASH_PROTECT_ALL_AT_BOOT) && !(flags & EC_FLASH_PROTECT_ALL_AT_BOOT)) { if (flash_get_protect() & EC_FLASH_PROTECT_RO_AT_BOOT) range = FLASH_WP_RO; need_set_protect = 1; } if (need_set_protect) { rv = flash_protect_at_boot(range); if (rv) retval = rv; } /* * All subsequent flags only work if write protect is enabled (that is, * hardware WP flag) *and* RO is protected at boot (software WP flag). */ if ((~flash_get_protect()) & (EC_FLASH_PROTECT_GPIO_ASSERTED | EC_FLASH_PROTECT_RO_AT_BOOT)) return retval; if ((mask & EC_FLASH_PROTECT_ALL_AT_BOOT) && (flags & EC_FLASH_PROTECT_ALL_AT_BOOT)) { rv = flash_protect_at_boot(FLASH_WP_ALL); if (rv) retval = rv; } if ((mask & EC_FLASH_PROTECT_RO_NOW) && (flags & EC_FLASH_PROTECT_RO_NOW)) { rv = flash_physical_protect_now(0); if (rv) retval = rv; } if ((mask & EC_FLASH_PROTECT_ALL_NOW) && (flags & EC_FLASH_PROTECT_ALL_NOW)) { rv = flash_physical_protect_now(1); if (rv) retval = rv; } return retval; }