parent
271bed8bf6
commit
4cf781abb2
@ -0,0 +1,18 @@
|
||||
#ifndef TREZORHAL_FLASH_OTP_H
|
||||
#define TREZORHAL_FLASH_OTP_H
|
||||
|
||||
#include <common.h>
|
||||
|
||||
#define FLASH_OTP_NUM_BLOCKS 16
|
||||
#define FLASH_OTP_BLOCK_SIZE 32
|
||||
|
||||
void flash_otp_init(void);
|
||||
|
||||
secbool __wur flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data,
|
||||
uint8_t datalen);
|
||||
secbool __wur flash_otp_write(uint8_t block, uint8_t offset,
|
||||
const uint8_t *data, uint8_t datalen);
|
||||
secbool __wur flash_otp_lock(uint8_t block);
|
||||
secbool __wur flash_otp_is_locked(uint8_t block);
|
||||
|
||||
#endif // TREZORHAL_FLASH_OTP_H
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include STM32_HAL_H
|
||||
|
||||
#include "flash_otp.h"
|
||||
#include "common.h"
|
||||
#include "flash.h"
|
||||
|
||||
#define FLASH_OTP_LOCK_BASE 0x1FFF7A00U
|
||||
|
||||
void flash_otp_init() {
|
||||
// intentionally left empty
|
||||
}
|
||||
|
||||
secbool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data,
|
||||
uint8_t datalen) {
|
||||
if (block >= FLASH_OTP_NUM_BLOCKS ||
|
||||
offset + datalen > FLASH_OTP_BLOCK_SIZE) {
|
||||
return secfalse;
|
||||
}
|
||||
for (uint8_t i = 0; i < datalen; i++) {
|
||||
data[i] = *(__IO uint8_t *)(FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE +
|
||||
offset + i);
|
||||
}
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
secbool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data,
|
||||
uint8_t datalen) {
|
||||
if (block >= FLASH_OTP_NUM_BLOCKS ||
|
||||
offset + datalen > FLASH_OTP_BLOCK_SIZE) {
|
||||
return secfalse;
|
||||
}
|
||||
ensure(flash_unlock_write(), NULL);
|
||||
for (uint8_t i = 0; i < datalen; i++) {
|
||||
uint32_t address =
|
||||
FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + offset + i;
|
||||
ensure(sectrue * (HAL_OK == HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE,
|
||||
address, data[i])),
|
||||
NULL);
|
||||
}
|
||||
ensure(flash_lock_write(), NULL);
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
secbool flash_otp_lock(uint8_t block) {
|
||||
if (block >= FLASH_OTP_NUM_BLOCKS) {
|
||||
return secfalse;
|
||||
}
|
||||
ensure(flash_unlock_write(), NULL);
|
||||
HAL_StatusTypeDef ret = HAL_FLASH_Program(FLASH_TYPEPROGRAM_BYTE,
|
||||
FLASH_OTP_LOCK_BASE + block, 0x00);
|
||||
ensure(flash_lock_write(), NULL);
|
||||
return sectrue * (ret == HAL_OK);
|
||||
}
|
||||
|
||||
secbool flash_otp_is_locked(uint8_t block) {
|
||||
return sectrue * (0x00 == *(__IO uint8_t *)(FLASH_OTP_LOCK_BASE + block));
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include STM32_HAL_H
|
||||
|
||||
#include "flash_otp.h"
|
||||
#include "common.h"
|
||||
#include "flash.h"
|
||||
|
||||
void flash_otp_init() {
|
||||
// intentionally left empty
|
||||
}
|
||||
|
||||
secbool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data,
|
||||
uint8_t datalen) {
|
||||
if (block >= FLASH_OTP_NUM_BLOCKS ||
|
||||
offset + datalen > FLASH_OTP_BLOCK_SIZE) {
|
||||
return secfalse;
|
||||
}
|
||||
for (uint8_t i = 0; i < datalen; i++) {
|
||||
data[i] = *(__IO uint8_t *)(FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE +
|
||||
offset + i);
|
||||
}
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
secbool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data,
|
||||
uint8_t datalen) {
|
||||
if (datalen % 16 != 0) {
|
||||
return secfalse;
|
||||
}
|
||||
if (block >= FLASH_OTP_NUM_BLOCKS ||
|
||||
offset + datalen > FLASH_OTP_BLOCK_SIZE) {
|
||||
return secfalse;
|
||||
}
|
||||
ensure(flash_unlock_write(), NULL);
|
||||
for (uint8_t i = 0; i < datalen; i++) {
|
||||
uint32_t address =
|
||||
FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE + offset + i;
|
||||
ensure(sectrue * (HAL_OK == HAL_FLASH_Program(FLASH_TYPEPROGRAM_QUADWORD,
|
||||
address, (uint32_t)data)),
|
||||
NULL);
|
||||
}
|
||||
ensure(flash_lock_write(), NULL);
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
secbool flash_otp_lock(uint8_t block) {
|
||||
// check that all quadwords in the block have been written to
|
||||
volatile uint8_t *addr =
|
||||
(__IO uint8_t *)(FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE);
|
||||
|
||||
secbool qw_locked = secfalse;
|
||||
for (uint8_t i = 0; i < FLASH_OTP_BLOCK_SIZE; i++) {
|
||||
if (addr[i] != 0xFF) {
|
||||
qw_locked = sectrue;
|
||||
}
|
||||
if (i % 16 == 15 && qw_locked == secfalse) {
|
||||
return secfalse;
|
||||
}
|
||||
}
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
secbool flash_otp_is_locked(uint8_t block) {
|
||||
// considering block locked if any quadword in the block is non-0xFF
|
||||
volatile uint8_t *addr =
|
||||
(__IO uint8_t *)(FLASH_OTP_BASE + block * FLASH_OTP_BLOCK_SIZE);
|
||||
|
||||
for (uint8_t i = 0; i < FLASH_OTP_BLOCK_SIZE; i++) {
|
||||
if (addr[i] != 0xFF) {
|
||||
return sectrue;
|
||||
}
|
||||
}
|
||||
return secfalse;
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "../flash_otp.h"
|
||||
|
||||
#define OTP_BLOCK_SIZE 32
|
||||
#define FLASH_SECTOR_OTP (FLASH_SECTOR_COUNT)
|
||||
|
||||
static uint8_t OTP_BUFFER[OTP_BLOCK_SIZE * 64];
|
||||
|
||||
void flash_otp_init(void) {
|
||||
// fill OTP buffer with ones
|
||||
memset(OTP_BUFFER, 0xFF, sizeof(OTP_BUFFER));
|
||||
}
|
||||
|
||||
secbool flash_otp_read(uint8_t block, uint8_t offset, uint8_t *data,
|
||||
uint8_t datalen) {
|
||||
if (offset + datalen > OTP_BLOCK_SIZE) {
|
||||
return secfalse;
|
||||
}
|
||||
uint32_t offset_in_sector = block * OTP_BLOCK_SIZE + offset;
|
||||
memcpy(data, OTP_BUFFER + offset_in_sector, datalen);
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
secbool flash_otp_write(uint8_t block, uint8_t offset, const uint8_t *data,
|
||||
uint8_t datalen) {
|
||||
if (offset + datalen > OTP_BLOCK_SIZE) {
|
||||
return secfalse;
|
||||
}
|
||||
uint32_t offset_in_sector = block * OTP_BLOCK_SIZE + offset;
|
||||
uint8_t *flash = OTP_BUFFER + offset_in_sector;
|
||||
for (int i = 0; i < datalen; i++) {
|
||||
if ((flash[i] & data[i]) != data[i]) {
|
||||
return secfalse; // we cannot change zeroes to ones
|
||||
}
|
||||
flash[i] = data[i];
|
||||
}
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
secbool flash_otp_lock(uint8_t block) { return secfalse; }
|
||||
|
||||
secbool flash_otp_is_locked(uint8_t block) { return secfalse; }
|
@ -0,0 +1,244 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "flash_area.h"
|
||||
#include <stddef.h>
|
||||
|
||||
uint32_t flash_area_get_size(const flash_area_t *area) {
|
||||
uint32_t size = 0;
|
||||
for (int i = 0; i < area->num_subareas; i++) {
|
||||
size += flash_sector_size(area->subarea[i].first_sector,
|
||||
area->subarea[i].num_sectors);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
uint16_t flash_area_total_sectors(const flash_area_t *area) {
|
||||
uint16_t total = 0;
|
||||
for (int i = 0; i < area->num_subareas; i++) {
|
||||
total += area->subarea[i].num_sectors;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
static secbool get_sector_and_offset(const flash_area_t *area, uint32_t offset,
|
||||
uint16_t *sector_out,
|
||||
uint32_t *offset_out) {
|
||||
for (int i = 0; i < area->num_subareas; i++) {
|
||||
// Get the sub-area parameters
|
||||
uint16_t first_sector = area->subarea[i].first_sector;
|
||||
uint16_t num_sectors = area->subarea[i].num_sectors;
|
||||
uint32_t subarea_size = flash_sector_size(first_sector, num_sectors);
|
||||
// Does the requested offset start in the sub-area?
|
||||
if (offset < subarea_size) {
|
||||
uint16_t found_sector = flash_sector_find(first_sector, offset);
|
||||
*sector_out = found_sector;
|
||||
*offset_out =
|
||||
offset - flash_sector_size(first_sector, found_sector - first_sector);
|
||||
return sectrue;
|
||||
}
|
||||
offset -= subarea_size;
|
||||
}
|
||||
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
const void *flash_area_get_address(const flash_area_t *area, uint32_t offset,
|
||||
uint32_t size) {
|
||||
for (int i = 0; i < area->num_subareas; i++) {
|
||||
// Get sub-area parameters
|
||||
uint16_t first_sector = area->subarea[i].first_sector;
|
||||
uint16_t num_sectors = area->subarea[i].num_sectors;
|
||||
uint32_t subarea_size = flash_sector_size(first_sector, num_sectors);
|
||||
// Does the requested block start in the sub-area?
|
||||
if (offset < subarea_size) {
|
||||
// Does the requested block fit in the sub-area?
|
||||
if (offset + size <= subarea_size) {
|
||||
const uint8_t *ptr =
|
||||
(const uint8_t *)flash_get_address(first_sector, 0, 0);
|
||||
// We expect that all sectors/pages in the sub-area make
|
||||
// a continuous block of adresses with the same security atributes
|
||||
return ptr + offset;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
offset -= subarea_size;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if defined FLASH_BIT_ACCESS
|
||||
|
||||
secbool flash_area_write_byte(const flash_area_t *area, uint32_t offset,
|
||||
uint8_t data) {
|
||||
uint16_t sector;
|
||||
uint32_t sector_offset;
|
||||
if (get_sector_and_offset(area, offset, §or, §or_offset) != sectrue) {
|
||||
return secfalse;
|
||||
}
|
||||
return flash_write_byte(sector, sector_offset, data);
|
||||
}
|
||||
|
||||
secbool flash_area_write_word(const flash_area_t *area, uint32_t offset,
|
||||
uint32_t data) {
|
||||
uint16_t sector;
|
||||
uint32_t sector_offset;
|
||||
if (get_sector_and_offset(area, offset, §or, §or_offset) != sectrue) {
|
||||
return secfalse;
|
||||
}
|
||||
return flash_write_word(sector, sector_offset, data);
|
||||
}
|
||||
|
||||
secbool flash_area_write_burst(const flash_area_t *area, uint32_t offset,
|
||||
const uint32_t *data) {
|
||||
if (offset % (8 * 16) != 0) {
|
||||
return secfalse;
|
||||
}
|
||||
for (int i = 0; i < (8 * 4); i++) {
|
||||
if (sectrue !=
|
||||
flash_area_write_word(area, offset + i * sizeof(uint32_t), data[i])) {
|
||||
return secfalse;
|
||||
}
|
||||
}
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
#else // not defined FLASH_BIT_ACCESS
|
||||
|
||||
secbool flash_area_write_quadword(const flash_area_t *area, uint32_t offset,
|
||||
const uint32_t *data) {
|
||||
uint16_t sector;
|
||||
uint32_t sector_offset;
|
||||
if (get_sector_and_offset(area, offset, §or, §or_offset) != sectrue) {
|
||||
return secfalse;
|
||||
}
|
||||
return flash_write_quadword(sector, sector_offset, data);
|
||||
}
|
||||
|
||||
secbool flash_area_write_burst(const flash_area_t *area, uint32_t offset,
|
||||
const uint32_t *data) {
|
||||
uint16_t sector;
|
||||
uint32_t sector_offset;
|
||||
if (get_sector_and_offset(area, offset, §or, §or_offset) != sectrue) {
|
||||
return secfalse;
|
||||
}
|
||||
return flash_write_burst(sector, sector_offset, data);
|
||||
}
|
||||
|
||||
#endif // not defined FLASH_BIT_ACCESS
|
||||
|
||||
secbool flash_area_write_block(const flash_area_t *area, uint32_t offset,
|
||||
const flash_block_t block) {
|
||||
if (!FLASH_IS_ALIGNED(offset)) {
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
uint16_t sector;
|
||||
uint32_t sector_offset;
|
||||
if (sectrue != get_sector_and_offset(area, offset, §or, §or_offset)) {
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
return flash_write_block(sector, sector_offset, block);
|
||||
}
|
||||
|
||||
secbool flash_area_erase(const flash_area_t *area,
|
||||
void (*progress)(int pos, int len)) {
|
||||
return flash_area_erase_bulk(area, 1, progress);
|
||||
}
|
||||
|
||||
static secbool erase_sector(uint16_t sector) {
|
||||
secbool result = secfalse;
|
||||
|
||||
if (sectrue != flash_unlock_write()) {
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
result = flash_sector_erase(sector);
|
||||
|
||||
if (sectrue != flash_lock_write()) {
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
secbool flash_area_erase_bulk(const flash_area_t *area, int count,
|
||||
void (*progress)(int pos, int len)) {
|
||||
int total_sectors = 0;
|
||||
int done_sectors = 0;
|
||||
for (int a = 0; a < count; a++) {
|
||||
for (int i = 0; i < area[a].num_subareas; i++) {
|
||||
total_sectors += area[a].subarea[i].num_sectors;
|
||||
}
|
||||
}
|
||||
if (progress) {
|
||||
progress(0, total_sectors);
|
||||
}
|
||||
|
||||
for (int a = 0; a < count; a++) {
|
||||
for (int s = 0; s < area[a].num_subareas; s++) {
|
||||
for (int i = 0; i < area[a].subarea[s].num_sectors; i++) {
|
||||
int sector = area[a].subarea[s].first_sector + i;
|
||||
|
||||
if (sectrue != erase_sector(sector)) {
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
done_sectors++;
|
||||
if (progress) {
|
||||
progress(done_sectors, total_sectors);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
secbool flash_area_erase_partial(const flash_area_t *area, uint32_t offset,
|
||||
uint32_t *bytes_erased) {
|
||||
uint32_t sector_offset = 0;
|
||||
*bytes_erased = 0;
|
||||
|
||||
for (int s = 0; s < area->num_subareas; s++) {
|
||||
for (int i = 0; i < area->subarea[s].num_sectors; i++) {
|
||||
uint32_t sector = area->subarea[s].first_sector + i;
|
||||
uint32_t sector_size = flash_sector_size(sector, 1);
|
||||
|
||||
if (offset == sector_offset) {
|
||||
if (sectrue != erase_sector(sector)) {
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
*bytes_erased = sector_size;
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
sector_offset += sector_size;
|
||||
}
|
||||
}
|
||||
|
||||
if (offset == sector_offset) {
|
||||
return sectrue;
|
||||
}
|
||||
|
||||
return secfalse;
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FLASH_AREA_H
|
||||
#define FLASH_AREA_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "secbool.h"
|
||||
|
||||
#include "flash.h"
|
||||
|
||||
/**
|
||||
* Flash driver interface is designed to abstract away differences between
|
||||
* various MCUs used in Trezor devices.
|
||||
*
|
||||
* Generally, flash memory is divided into sectors. On different MCUs, sectors
|
||||
* may have different sizes, and therefore, different number of sectors are used
|
||||
* for a given purpose. For example, on STM32F4, the sectors are relatively
|
||||
* large so we use single sector for Storage. On STM32U5, the sectors are
|
||||
* smaller, so we use multiple sectors for the Storage. Storage implementation
|
||||
* should not care about this, and should use flash_area_t interface to access
|
||||
* the flash memory.
|
||||
*
|
||||
* flash_area_t represents a location in flash memory. It may be contiguous, or
|
||||
* it may be composed of multiple non-contiguous subareas.
|
||||
*
|
||||
* flash_subarea_t represents a contiguous area in flash memory, specified by
|
||||
* first_sector and num_sectors.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
uint16_t first_sector;
|
||||
uint16_t num_sectors;
|
||||
} flash_subarea_t;
|
||||
|
||||
typedef struct {
|
||||
flash_subarea_t subarea[4];
|
||||
uint8_t num_subareas;
|
||||
} flash_area_t;
|
||||
|
||||
uint32_t flash_area_get_size(const flash_area_t *area);
|
||||
|
||||
uint16_t flash_area_total_sectors(const flash_area_t *area);
|
||||
|
||||
const void *flash_area_get_address(const flash_area_t *area, uint32_t offset,
|
||||
uint32_t size);
|
||||
|
||||
#if defined FLASH_BIT_ACCESS
|
||||
secbool __wur flash_area_write_byte(const flash_area_t *area, uint32_t offset,
|
||||
uint8_t data);
|
||||
secbool __wur flash_area_write_word(const flash_area_t *area, uint32_t offset,
|
||||
uint32_t data);
|
||||
#endif
|
||||
secbool __wur flash_area_write_quadword(const flash_area_t *area,
|
||||
uint32_t offset, const uint32_t *data);
|
||||
|
||||
secbool __wur flash_area_write_burst(const flash_area_t *area, uint32_t offset,
|
||||
const uint32_t *data);
|
||||
|
||||
secbool __wur flash_area_write_block(const flash_area_t *area, uint32_t offset,
|
||||
const flash_block_t block);
|
||||
|
||||
secbool __wur flash_area_erase(const flash_area_t *area,
|
||||
void (*progress)(int pos, int len));
|
||||
secbool __wur flash_area_erase_bulk(const flash_area_t *area, int count,
|
||||
void (*progress)(int pos, int len));
|
||||
|
||||
// Erases the single sector in the designated flash area
|
||||
// The 'offset' parameter must indicate the relative sector offset within the
|
||||
// flash area If 'offset' is outside the bounds of the flash area,
|
||||
// 'bytes_erased' is set to 0 otherwise, 'bytes_erased' is set to the size of
|
||||
// the erased sector
|
||||
secbool __wur flash_area_erase_partial(const flash_area_t *area,
|
||||
uint32_t offset, uint32_t *bytes_erased);
|
||||
|
||||
#endif // FLASH_AREA_H
|
@ -1,67 +0,0 @@
|
||||
#ifndef FLASH_COMMON_H
|
||||
#define FLASH_COMMON_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "secbool.h"
|
||||
|
||||
typedef struct {
|
||||
uint16_t first_sector;
|
||||
uint16_t num_sectors;
|
||||
} flash_subarea_t;
|
||||
|
||||
typedef struct {
|
||||
flash_subarea_t subarea[4];
|
||||
uint8_t num_subareas;
|
||||
bool secure_area;
|
||||
} flash_area_t;
|
||||
|
||||
#define FLASH_BLOCK_SIZE (sizeof(uint32_t) * FLASH_BLOCK_WORDS)
|
||||
|
||||
typedef uint32_t flash_block_t[FLASH_BLOCK_WORDS];
|
||||
|
||||
#if FLASH_BLOCK_WORDS == 1
|
||||
#define FLASH_ALIGN(X) (((X) + 3) & ~3)
|
||||
#define FLASH_IS_ALIGNED(X) (((X)&3) == 0)
|
||||
#elif FLASH_BLOCK_WORDS == 4
|
||||
#define FLASH_ALIGN(X) (((X) + 0xF) & ~0xF)
|
||||
#define FLASH_IS_ALIGNED(X) (((X)&0xF) == 0)
|
||||
#else
|
||||
#error Unsupported number of FLASH_BLOCK_WORDS.
|
||||
#endif
|
||||
|
||||
void flash_init(void);
|
||||
|
||||
secbool __wur flash_unlock_write(void);
|
||||
secbool __wur flash_lock_write(void);
|
||||
|
||||
uint32_t flash_sector_size(uint16_t sector);
|
||||
uint16_t flash_total_sectors(const flash_area_t *area);
|
||||
int32_t flash_get_sector_num(const flash_area_t *area,
|
||||
uint32_t sector_inner_num);
|
||||
|
||||
const void *flash_area_get_address(const flash_area_t *area, uint32_t offset,
|
||||
uint32_t size);
|
||||
uint32_t flash_area_get_size(const flash_area_t *area);
|
||||
|
||||
secbool __wur flash_area_erase(const flash_area_t *area,
|
||||
void (*progress)(int pos, int len));
|
||||
secbool __wur flash_area_erase_bulk(const flash_area_t *area, int count,
|
||||
void (*progress)(int pos, int len));
|
||||
|
||||
#if defined FLASH_BIT_ACCESS
|
||||
secbool __wur flash_area_write_byte(const flash_area_t *area, uint32_t offset,
|
||||
uint8_t data);
|
||||
secbool __wur flash_area_write_word(const flash_area_t *area, uint32_t offset,
|
||||
uint32_t data);
|
||||
#endif
|
||||
secbool __wur flash_area_write_block(const flash_area_t *area, uint32_t offset,
|
||||
const flash_block_t block);
|
||||
|
||||
secbool flash_write_block(uint16_t sector, uint32_t offset,
|
||||
const flash_block_t block);
|
||||
|
||||
secbool __wur flash_area_write_burst(const flash_area_t *area, uint32_t offset,
|
||||
const uint32_t *data);
|
||||
|
||||
#endif
|
@ -1,153 +0,0 @@
|
||||
#include "flash_common.h"
|
||||
|
||||
#include "flash.h"
|
||||
|
||||
secbool flash_write_byte(uint16_t sector, uint32_t offset, uint8_t data);
|
||||
|
||||
secbool flash_write_word(uint16_t sector, uint32_t offset, uint32_t data);
|
||||
|
||||
const void *flash_get_address(uint16_t sector, uint32_t offset, uint32_t size);
|
||||
|
||||
static uint32_t flash_subarea_get_size(const flash_subarea_t *subarea) {
|
||||
uint32_t size = 0;
|
||||
for (int s = 0; s < subarea->num_sectors; s++) {
|
||||
size += flash_sector_size(subarea->first_sector + s);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
static secbool subarea_get_sector_and_offset(const flash_subarea_t *subarea,
|
||||
uint32_t offset,
|
||||
uint16_t *sector_out,
|
||||
uint32_t *offset_out) {
|
||||
uint32_t tmp_offset = offset;
|
||||
uint16_t sector = subarea->first_sector;
|
||||
|
||||
// in correct subarea
|
||||
for (int s = 0; s < subarea->num_sectors; s++) {
|
||||
const uint32_t sector_size = flash_sector_size(sector);
|
||||
if (tmp_offset < sector_size) {
|
||||
*sector_out = sector;
|
||||
*offset_out = tmp_offset;
|
||||
return sectrue;
|
||||
}
|
||||
tmp_offset -= sector_size;
|
||||
sector++;
|
||||
}
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
uint32_t flash_area_get_size(const flash_area_t *area) {
|
||||
uint32_t size = 0;
|
||||
for (int i = 0; i < area->num_subareas; i++) {
|
||||
size += flash_subarea_get_size(&area->subarea[i]);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
uint16_t flash_total_sectors(const flash_area_t *area) {
|
||||
uint16_t total = 0;
|
||||
for (int i = 0; i < area->num_subareas; i++) {
|
||||
total += area->subarea[i].num_sectors;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
int32_t flash_get_sector_num(const flash_area_t *area,
|
||||
uint32_t sector_inner_num) {
|
||||
uint16_t sector = 0;
|
||||
uint16_t remaining = sector_inner_num;
|
||||
for (int i = 0; i < area->num_subareas; i++) {
|
||||
if (remaining < area->subarea[i].num_sectors) {
|
||||
sector = area->subarea[i].first_sector + remaining;
|
||||
return sector;
|
||||
} else {
|
||||
remaining -= area->subarea[i].num_sectors;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static secbool get_sector_and_offset(const flash_area_t *area, uint32_t offset,
|
||||
uint16_t *sector_out,
|
||||
uint32_t *offset_out) {
|
||||
uint32_t tmp_offset = offset;
|
||||
for (int i = 0; i < area->num_subareas; i++) {
|
||||
uint32_t sub_size = flash_subarea_get_size(&area->subarea[i]);
|
||||
if (tmp_offset >= sub_size) {
|
||||
tmp_offset -= sub_size;
|
||||
continue;
|
||||
}
|
||||
|
||||
return subarea_get_sector_and_offset(&area->subarea[i], tmp_offset,
|
||||
sector_out, offset_out);
|
||||
}
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
const void *flash_area_get_address(const flash_area_t *area, uint32_t offset,
|
||||
uint32_t size) {
|
||||
uint16_t sector;
|
||||
uint32_t sector_offset;
|
||||
|
||||
if (!get_sector_and_offset(area, offset, §or, §or_offset)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return flash_get_address(sector, sector_offset, size);
|
||||
}
|
||||
|
||||
secbool flash_area_erase(const flash_area_t *area,
|
||||
void (*progress)(int pos, int len)) {
|
||||
return flash_area_erase_bulk(area, 1, progress);
|
||||
}
|
||||
|
||||
secbool flash_area_write_byte(const flash_area_t *area, uint32_t offset,
|
||||
uint8_t data) {
|
||||
uint16_t sector;
|
||||
uint32_t sector_offset;
|
||||
if (get_sector_and_offset(area, offset, §or, §or_offset) != sectrue) {
|
||||
return secfalse;
|
||||
}
|
||||
return flash_write_byte(sector, sector_offset, data);
|
||||
}
|
||||
|
||||
secbool flash_area_write_word(const flash_area_t *area, uint32_t offset,
|
||||
uint32_t data) {
|
||||
uint16_t sector;
|
||||
uint32_t sector_offset;
|
||||
if (get_sector_and_offset(area, offset, §or, §or_offset) != sectrue) {
|
||||
return secfalse;
|
||||
}
|
||||
return flash_write_word(sector, sector_offset, data);
|
||||
}
|
||||
|
||||
secbool flash_area_write_block(const flash_area_t *area, uint32_t offset,
|
||||
const flash_block_t block) {
|
||||
if (!FLASH_IS_ALIGNED(offset)) {
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
uint16_t sector;
|
||||
uint32_t sector_offset;
|
||||
if (sectrue != get_sector_and_offset(area, offset, §or, §or_offset)) {
|
||||
return secfalse;
|
||||
}
|
||||
|
||||
return flash_write_block(sector, sector_offset, block);
|
||||
}
|
||||
|
||||
secbool flash_area_write_burst(const flash_area_t *area, uint32_t offset,
|
||||
const uint32_t *data) {
|
||||
if (offset % (8 * 16) != 0) {
|
||||
return secfalse;
|
||||
}
|
||||
for (int i = 0; i < (8 * 4); i++) {
|
||||
if (sectrue !=
|
||||
flash_area_write_word(area, offset + i * sizeof(uint32_t), data[i])) {
|
||||
return secfalse;
|
||||
}
|
||||
}
|
||||
return sectrue;
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef FLASH_LL_H_
|
||||
#define FLASH_LL_H_
|
||||
|
||||
#include <secbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// Flash memory low-level API, providing abstraction for
|
||||
// various flash archictures found on STM32 MCUs
|
||||
|
||||
// The 'sector' parameter in this API can represent
|
||||
// 1. Non-uniform sector number on STM32F4
|
||||
// 2. Uniform page number on STM32U5
|
||||
|
||||
#define FLASH_BLOCK_SIZE (sizeof(uint32_t) * FLASH_BLOCK_WORDS)
|
||||
|
||||
typedef uint32_t flash_block_t[FLASH_BLOCK_WORDS];
|
||||
|
||||
#if FLASH_BLOCK_WORDS == 1
|
||||
#define FLASH_ALIGN(X) (((X) + 3) & ~3)
|
||||
#define FLASH_IS_ALIGNED(X) (((X)&3) == 0)
|
||||
#elif FLASH_BLOCK_WORDS == 4
|
||||
#define FLASH_ALIGN(X) (((X) + 0xF) & ~0xF)
|
||||
#define FLASH_IS_ALIGNED(X) (((X)&0xF) == 0)
|
||||
#else
|
||||
#error Unsupported number of FLASH_BLOCK_WORDS.
|
||||
#endif
|
||||
|
||||
// Returns the size of the a continuous area of sectors
|
||||
// Returns 0 if any of the sectors is out of range
|
||||
uint32_t flash_sector_size(uint16_t first_sector, uint16_t sector_count);
|
||||
|
||||
// Returns number of the sector/page at specified byte 'offset'
|
||||
// from the beginning of the 'first_sector'
|
||||
uint16_t flash_sector_find(uint16_t first_sector, uint32_t offset);
|
||||
|
||||
// Returns the physical address of a byte on specified 'offset' in the specified
|
||||
// 'sector'. Checks if it's possible to access continues space of 'size' bytes
|
||||
// Returns NULL i [offset, offset + size] is of out of the specified sector
|
||||
const void *flash_get_address(uint16_t sector, uint32_t offset, uint32_t size);
|
||||
|
||||
// Unlocks the flash memory for writes/erase operations
|
||||
// Flash must be locked again as soon as possible
|
||||
secbool __wur flash_unlock_write(void);
|
||||
|
||||
// Locks the flash memory for writes/erase operations
|
||||
secbool __wur flash_lock_write(void);
|
||||
|
||||
#if defined FLASH_BIT_ACCESS
|
||||
|
||||
// Writes a single byte to the specified 'offset' inside a flash 'sector'
|
||||
secbool __wur flash_write_byte(uint16_t sector, uint32_t offset, uint8_t data);
|
||||
|
||||
// Writes a single 32-bit word to the specified 'offset' inside a flash 'sector'
|
||||
secbool __wur flash_write_word(uint16_t sector, uint32_t offset, uint32_t data);
|
||||
|
||||
#endif
|
||||
|
||||
// Writes a 16-byte block to specified 'offset' inside a flash 'sector'
|
||||
secbool __wur flash_write_quadword(uint16_t sector, uint32_t offset,
|
||||
const uint32_t *data);
|
||||
|
||||
// Writes a 128-byte burst to specified 'offset' inside a flash 'sector'
|
||||
secbool __wur flash_write_burst(uint16_t sector, uint32_t offset,
|
||||
const uint32_t *data);
|
||||
|
||||
// Erases a single sector/page of flash memory
|
||||
secbool __wur flash_sector_erase(uint16_t sector);
|
||||
|
||||
// Writes a block to specified 'offset' inside a flash 'sector'
|
||||
// Block represents a natural unit of the given flash memory
|
||||
secbool flash_write_block(uint16_t sector, uint32_t offset,
|
||||
const flash_block_t block);
|
||||
|
||||
#endif // FLASH_LL_H
|
Loading…
Reference in new issue