/* * Copyright (c) 2023 Google Inc * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #ifdef CONFIG_USERSPACE #include #include #endif #include #include "flash_stm32.h" LOG_MODULE_REGISTER(flash_stm32_ex_op, CONFIG_FLASH_LOG_LEVEL); #if defined(CONFIG_FLASH_STM32_WRITE_PROTECT) int flash_stm32_ex_op_sector_wp(const struct device *dev, const uintptr_t in, void *out) { const struct flash_stm32_ex_op_sector_wp_in *request = (const struct flash_stm32_ex_op_sector_wp_in *)in; struct flash_stm32_ex_op_sector_wp_out *result = (struct flash_stm32_ex_op_sector_wp_out *)out; uint32_t change_mask; int rc = 0, rc2 = 0; #ifdef CONFIG_USERSPACE bool syscall_trap = z_syscall_trap(); #endif if (request != NULL) { #ifdef CONFIG_USERSPACE struct flash_stm32_ex_op_sector_wp_in in_copy; if (syscall_trap) { K_OOPS(k_usermode_from_copy(&in_copy, request, sizeof(in_copy))); request = &in_copy; } #endif change_mask = request->enable_mask; if (!IS_ENABLED( CONFIG_FLASH_STM32_WRITE_PROTECT_DISABLE_PREVENTION)) { change_mask |= request->disable_mask; } rc = flash_stm32_option_bytes_lock(dev, false); if (rc == 0) { rc = flash_stm32_update_wp_sectors( dev, change_mask, request->enable_mask); } rc2 = flash_stm32_option_bytes_lock(dev, true); if (!rc) { rc = rc2; } } if (result != NULL) { #ifdef CONFIG_USERSPACE struct flash_stm32_ex_op_sector_wp_out out_copy; if (syscall_trap) { result = &out_copy; } #endif rc2 = flash_stm32_get_wp_sectors(dev, &result->protected_mask); if (!rc) { rc = rc2; } #ifdef CONFIG_USERSPACE if (syscall_trap) { K_OOPS(k_usermode_to_copy(out, result, sizeof(out_copy))); } #endif } return rc; } #endif /* CONFIG_FLASH_STM32_WRITE_PROTECT */ #if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION) int flash_stm32_ex_op_update_rdp(const struct device *dev, bool enable, bool permanent) { uint8_t current_level, target_level; current_level = flash_stm32_get_rdp_level(dev); target_level = current_level; /* * 0xAA = RDP level 0 (no protection) * 0xCC = RDP level 2 (permanent protection) * others = RDP level 1 (protection active) */ switch (current_level) { case FLASH_STM32_RDP2: if (!enable || !permanent) { LOG_DBG("RDP level 2 is permanent and can't be changed!"); return -ENOTSUP; } break; case FLASH_STM32_RDP0: if (enable) { target_level = FLASH_STM32_RDP1; if (permanent) { #if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_PERMANENT_ALLOW) target_level = FLASH_STM32_RDP2; #else LOG_DBG("Permanent readout protection (RDP " "level 0 -> 2) not allowed"); return -ENOTSUP; #endif } } break; default: /* FLASH_STM32_RDP1 */ if (enable && permanent) { #if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_PERMANENT_ALLOW) target_level = FLASH_STM32_RDP2; #else LOG_DBG("Permanent readout protection (RDP " "level 1 -> 2) not allowed"); return -ENOTSUP; #endif } if (!enable) { #if defined(CONFIG_FLASH_STM32_READOUT_PROTECTION_DISABLE_ALLOW) target_level = FLASH_STM32_RDP0; #else LOG_DBG("Disabling readout protection (RDP " "level 1 -> 0) not allowed"); return -EACCES; #endif } } /* Update RDP level if needed */ if (current_level != target_level) { LOG_INF("RDP changed from 0x%02x to 0x%02x", current_level, target_level); flash_stm32_set_rdp_level(dev, target_level); } return 0; } int flash_stm32_ex_op_rdp(const struct device *dev, const uintptr_t in, void *out) { const struct flash_stm32_ex_op_rdp *request = (const struct flash_stm32_ex_op_rdp *)in; struct flash_stm32_ex_op_rdp *result = (struct flash_stm32_ex_op_rdp *)out; uint8_t current_level; #ifdef CONFIG_USERSPACE struct flash_stm32_ex_op_rdp copy; bool syscall_trap = z_syscall_trap(); #endif int rc = 0, rc2 = 0; if (request != NULL) { #ifdef CONFIG_USERSPACE if (syscall_trap) { K_OOPS(k_usermode_from_copy(©, request, sizeof(copy))); request = © } #endif rc = flash_stm32_option_bytes_lock(dev, false); if (rc == 0) { rc = flash_stm32_ex_op_update_rdp(dev, request->enable, request->permanent); } rc2 = flash_stm32_option_bytes_lock(dev, true); if (!rc) { rc = rc2; } } if (result != NULL) { #ifdef CONFIG_USERSPACE if (syscall_trap) { result = © } #endif current_level = flash_stm32_get_rdp_level(dev); /* * 0xAA = RDP level 0 (no protection) * 0xCC = RDP level 2 (permanent protection) * others = RDP level 1 (protection active) */ switch (current_level) { case FLASH_STM32_RDP2: result->enable = true; result->permanent = true; break; case FLASH_STM32_RDP0: result->enable = false; result->permanent = false; break; default: /* FLASH_STM32_RDP1 */ result->enable = true; result->permanent = false; } #ifdef CONFIG_USERSPACE if (syscall_trap) { K_OOPS(k_usermode_to_copy(out, result, sizeof(copy))); } #endif } return rc; } #endif /* CONFIG_FLASH_STM32_READOUT_PROTECTION */