zephyr/drivers/flash/flash_stm32_ex_op.c
Patryk Duda d652da5acb drivers: flash: Introduce readout protection support for STM32F4
This patch adds flash readout protection support for STM32F4 devices
family. These devices can enable protection on entire flash content.

Readout protection functionality was exposed as vendor extended
operation. To change readout protection state, caller should provide a
structure which describes desired RDP state.

Enabling readout protection permanently or disabling readout protection
(changing from level 1 to level 0) is guarded by
CONFIG_FLASH_STM32_READOUT_PROTECTION_PERMANENT_ALLOW and
CONFIG_FLASH_STM32_READOUT_PROTECTION_DISABLE_ALLOW respectively.

Signed-off-by: Patryk Duda <pdk@semihalf.com>
2023-03-28 15:43:16 +00:00

143 lines
3 KiB
C

/*
* Copyright (c) 2023 Google Inc
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <sys/types.h>
#include <zephyr/device.h>
#include <zephyr/drivers/flash/stm32_flash_api_extensions.h>
#include <zephyr/kernel.h>
#ifdef CONFIG_USERSPACE
#include <zephyr/syscall.h>
#include <zephyr/syscall_handler.h>
#endif
#include <soc.h>
#include "flash_stm32.h"
#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) {
Z_OOPS(z_user_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) {
Z_OOPS(z_user_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_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;
#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) {
Z_OOPS(z_user_from_copy(&copy, request, sizeof(copy)));
request = &copy;
}
#endif
rc = flash_stm32_option_bytes_lock(dev, false);
if (rc == 0) {
rc = flash_stm32_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 = &copy;
}
#endif
rc2 = flash_stm32_get_rdp(dev, &result->enable,
&result->permanent);
if (!rc) {
rc = rc2;
}
#ifdef CONFIG_USERSPACE
if (syscall_trap) {
Z_OOPS(z_user_to_copy(out, result, sizeof(copy)));
}
#endif
}
return rc;
}
#endif /* CONFIG_FLASH_STM32_READOUT_PROTECTION */