From 1974403c14e666a3822db545786b9b7b6a05694f Mon Sep 17 00:00:00 2001 From: Alexandre d Alton Date: Mon, 3 Jun 2019 21:06:36 +0200 Subject: [PATCH 1/5] support saving into SmartEEPROM Signed-off-by: Alexandre d Alton --- tmk_core/common/arm_atsam/eeprom.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/tmk_core/common/arm_atsam/eeprom.c b/tmk_core/common/arm_atsam/eeprom.c index ccd5d15a5478..ae1763b592e4 100644 --- a/tmk_core/common/arm_atsam/eeprom.c +++ b/tmk_core/common/arm_atsam/eeprom.c @@ -13,8 +13,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - +#include "samd51j18a.h" #include "eeprom.h" +#include "core_cm4.h" +#include "component/nvmctrl.h" #ifndef EEPROM_SIZE # include "eeconfig.h" @@ -22,15 +24,33 @@ #endif __attribute__((aligned(4))) static uint8_t buffer[EEPROM_SIZE]; +volatile uint8_t *SmartEEPROM8 = (uint8_t *) 0x44000000; uint8_t eeprom_read_byte(const uint8_t *addr) { uintptr_t offset = (uintptr_t)addr; - return buffer[offset]; + + if (NVMCTRL->SEESTAT.bit.PSZ == 0 || NVMCTRL->SEESTAT.bit.SBLK == 0) + return buffer[offset]; + + int timeout = 10000; + while (NVMCTRL->SEESTAT.bit.BUSY && timeout-- > 0) + ; + return SmartEEPROM8[offset]; } void eeprom_write_byte(uint8_t *addr, uint8_t value) { uintptr_t offset = (uintptr_t)addr; - buffer[offset] = value; + + if (NVMCTRL->SEESTAT.bit.PSZ == 0 || NVMCTRL->SEESTAT.bit.SBLK == 0) { + buffer[offset] = value; + return; + } + + int timeout = 10000; + while (NVMCTRL->SEESTAT.bit.BUSY && timeout-- > 0) + ; + + SmartEEPROM8[offset] = value; } uint16_t eeprom_read_word(const uint16_t *addr) { From 2011bb3f870ca8fc8e887aa58b63a741dddfb733 Mon Sep 17 00:00:00 2001 From: Alexandre d'Alton Date: Tue, 4 Feb 2020 06:43:06 +0100 Subject: [PATCH 2/5] atsam: update smarteeprom implementation - Use define for SmartEEPROM buffer address - Check buffer overflow - Do not perform operation when timeout occurs Signed-off-by: Alexandre d'Alton --- tmk_core/common/arm_atsam/eeprom.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/tmk_core/common/arm_atsam/eeprom.c b/tmk_core/common/arm_atsam/eeprom.c index ae1763b592e4..fd3c24dbc4cb 100644 --- a/tmk_core/common/arm_atsam/eeprom.c +++ b/tmk_core/common/arm_atsam/eeprom.c @@ -24,10 +24,12 @@ #endif __attribute__((aligned(4))) static uint8_t buffer[EEPROM_SIZE]; -volatile uint8_t *SmartEEPROM8 = (uint8_t *) 0x44000000; +volatile uint8_t *SmartEEPROM8 = (uint8_t *) SEEPROM_ADDR; uint8_t eeprom_read_byte(const uint8_t *addr) { uintptr_t offset = (uintptr_t)addr; + if (offset >= EEPROM_SIZE) + return 0xff; if (NVMCTRL->SEESTAT.bit.PSZ == 0 || NVMCTRL->SEESTAT.bit.SBLK == 0) return buffer[offset]; @@ -35,11 +37,16 @@ uint8_t eeprom_read_byte(const uint8_t *addr) { int timeout = 10000; while (NVMCTRL->SEESTAT.bit.BUSY && timeout-- > 0) ; - return SmartEEPROM8[offset]; + if (!NVMCTRL->SEESTAT.bit.BUSY) + return SmartEEPROM8[offset]; + + return 0xff; } void eeprom_write_byte(uint8_t *addr, uint8_t value) { uintptr_t offset = (uintptr_t)addr; + if (offset >= EEPROM_SIZE) + return; if (NVMCTRL->SEESTAT.bit.PSZ == 0 || NVMCTRL->SEESTAT.bit.SBLK == 0) { buffer[offset] = value; @@ -49,8 +56,8 @@ void eeprom_write_byte(uint8_t *addr, uint8_t value) { int timeout = 10000; while (NVMCTRL->SEESTAT.bit.BUSY && timeout-- > 0) ; - - SmartEEPROM8[offset] = value; + if (!NVMCTRL->SEESTAT.bit.BUSY) + SmartEEPROM8[offset] = value; } uint16_t eeprom_read_word(const uint16_t *addr) { From 8a99a38fec965e272d0eb727cef758ca7af1be7c Mon Sep 17 00:00:00 2001 From: Alexandre d'Alton Date: Tue, 4 Feb 2020 21:06:39 +0100 Subject: [PATCH 3/5] return 0 instead of ff for invalid address or timeout Signed-off-by: Alexandre d'Alton --- tmk_core/common/arm_atsam/eeprom.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tmk_core/common/arm_atsam/eeprom.c b/tmk_core/common/arm_atsam/eeprom.c index fd3c24dbc4cb..082553c31817 100644 --- a/tmk_core/common/arm_atsam/eeprom.c +++ b/tmk_core/common/arm_atsam/eeprom.c @@ -29,7 +29,7 @@ volatile uint8_t *SmartEEPROM8 = (uint8_t *) SEEPROM_ADDR; uint8_t eeprom_read_byte(const uint8_t *addr) { uintptr_t offset = (uintptr_t)addr; if (offset >= EEPROM_SIZE) - return 0xff; + return 0x0; if (NVMCTRL->SEESTAT.bit.PSZ == 0 || NVMCTRL->SEESTAT.bit.SBLK == 0) return buffer[offset]; @@ -40,7 +40,7 @@ uint8_t eeprom_read_byte(const uint8_t *addr) { if (!NVMCTRL->SEESTAT.bit.BUSY) return SmartEEPROM8[offset]; - return 0xff; + return 0; } void eeprom_write_byte(uint8_t *addr, uint8_t value) { From 502e5b3954eeb595782be9dca2864f9137727e6a Mon Sep 17 00:00:00 2001 From: zvecr Date: Mon, 27 Sep 2021 01:23:23 +0100 Subject: [PATCH 4/5] clang-format --- tmk_core/common/arm_atsam/eeprom.c | 31 ++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/tmk_core/common/arm_atsam/eeprom.c b/tmk_core/common/arm_atsam/eeprom.c index 082553c31817..170fd97b5f7e 100644 --- a/tmk_core/common/arm_atsam/eeprom.c +++ b/tmk_core/common/arm_atsam/eeprom.c @@ -23,41 +23,52 @@ # define EEPROM_SIZE (((EECONFIG_SIZE + 3) / 4) * 4) // based off eeconfig's current usage, aligned to 4-byte sizes, to deal with LTO #endif +#ifndef BUSY_RETRIES +# define BUSY_RETRIES 10000 +#endif + __attribute__((aligned(4))) static uint8_t buffer[EEPROM_SIZE]; -volatile uint8_t *SmartEEPROM8 = (uint8_t *) SEEPROM_ADDR; +volatile uint8_t * SmartEEPROM8 = (uint8_t *)SEEPROM_ADDR; uint8_t eeprom_read_byte(const uint8_t *addr) { uintptr_t offset = (uintptr_t)addr; - if (offset >= EEPROM_SIZE) + if (offset >= EEPROM_SIZE) { return 0x0; + } - if (NVMCTRL->SEESTAT.bit.PSZ == 0 || NVMCTRL->SEESTAT.bit.SBLK == 0) + if (NVMCTRL->SEESTAT.bit.PSZ == 0 || NVMCTRL->SEESTAT.bit.SBLK == 0) { return buffer[offset]; + } - int timeout = 10000; + int timeout = BUSY_RETRIES; while (NVMCTRL->SEESTAT.bit.BUSY && timeout-- > 0) ; - if (!NVMCTRL->SEESTAT.bit.BUSY) + + if (!NVMCTRL->SEESTAT.bit.BUSY) { return SmartEEPROM8[offset]; + } - return 0; + return 0x0; } void eeprom_write_byte(uint8_t *addr, uint8_t value) { uintptr_t offset = (uintptr_t)addr; - if (offset >= EEPROM_SIZE) - return; + if (offset >= EEPROM_SIZE) { + return 0x0; + } if (NVMCTRL->SEESTAT.bit.PSZ == 0 || NVMCTRL->SEESTAT.bit.SBLK == 0) { buffer[offset] = value; return; } - int timeout = 10000; + int timeout = BUSY_RETRIES; while (NVMCTRL->SEESTAT.bit.BUSY && timeout-- > 0) ; - if (!NVMCTRL->SEESTAT.bit.BUSY) + + if (!NVMCTRL->SEESTAT.bit.BUSY) { SmartEEPROM8[offset] = value; + } } uint16_t eeprom_read_word(const uint16_t *addr) { From 936de675bb45ef554d19675984843d4d05f9c295 Mon Sep 17 00:00:00 2001 From: zvecr Date: Mon, 27 Sep 2021 08:07:29 +0100 Subject: [PATCH 5/5] Add extra bounds checks --- tmk_core/common/arm_atsam/eeprom.c | 90 +++++++++++++++++++++++------- 1 file changed, 69 insertions(+), 21 deletions(-) diff --git a/tmk_core/common/arm_atsam/eeprom.c b/tmk_core/common/arm_atsam/eeprom.c index 170fd97b5f7e..ff1a692623a1 100644 --- a/tmk_core/common/arm_atsam/eeprom.c +++ b/tmk_core/common/arm_atsam/eeprom.c @@ -13,8 +13,9 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -#include "samd51j18a.h" #include "eeprom.h" +#include "debug.h" +#include "samd51j18a.h" #include "core_cm4.h" #include "component/nvmctrl.h" @@ -23,52 +24,99 @@ # define EEPROM_SIZE (((EECONFIG_SIZE + 3) / 4) * 4) // based off eeconfig's current usage, aligned to 4-byte sizes, to deal with LTO #endif +#ifndef MAX +# define MAX(X, Y) ((X) > (Y) ? (X) : (Y)) +#endif + #ifndef BUSY_RETRIES # define BUSY_RETRIES 10000 #endif -__attribute__((aligned(4))) static uint8_t buffer[EEPROM_SIZE]; -volatile uint8_t * SmartEEPROM8 = (uint8_t *)SEEPROM_ADDR; +// #define DEBUG_EEPROM_OUTPUT + +/* + * Debug print utils + */ +#if defined(DEBUG_EEPROM_OUTPUT) +# define eeprom_printf(fmt, ...) xprintf(fmt, ##__VA_ARGS__); +#else /* NO_DEBUG */ +# define eeprom_printf(fmt, ...) +#endif /* NO_DEBUG */ + +__attribute__((aligned(4))) static uint8_t buffer[EEPROM_SIZE] = {0}; +volatile uint8_t * SmartEEPROM8 = (uint8_t *)SEEPROM_ADDR; + +static inline bool eeprom_is_busy(void) { + int timeout = BUSY_RETRIES; + while (NVMCTRL->SEESTAT.bit.BUSY && timeout-- > 0) + ; + + return NVMCTRL->SEESTAT.bit.BUSY; +} + +static uint32_t get_virtual_eeprom_size(void) { + // clang-format off + static const uint32_t VIRTUAL_EEPROM_MAP[11][8] = { + /* 4 8 16 32 64 128 256 512 */ + /* 0*/ { 0, 0, 0, 0, 0, 0, 0, 0 }, + /* 1*/ { 512, 1024, 2048, 4096, 4096, 4096, 4096, 4096 }, + /* 2*/ { 512, 1024, 2048, 4096, 8192, 8192, 8192, 8192 }, + /* 3*/ { 512, 1024, 2048, 4096, 8192, 16384, 16384, 16384 }, + /* 4*/ { 512, 1024, 2048, 4096, 8192, 16384, 16384, 16384 }, + /* 5*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 32768 }, + /* 6*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 32768 }, + /* 7*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 32768 }, + /* 8*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 32768 }, + /* 9*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536 }, + /*10*/ { 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536 }, + }; + // clang-format on + + static uint32_t virtual_eeprom_size = UINT32_MAX; + if (virtual_eeprom_size == UINT32_MAX) { + virtual_eeprom_size = VIRTUAL_EEPROM_MAP[NVMCTRL->SEESTAT.bit.PSZ][NVMCTRL->SEESTAT.bit.SBLK]; + } + // eeprom_printf("get_virtual_eeprom_size:: %d:%d:%d\n", NVMCTRL->SEESTAT.bit.PSZ, NVMCTRL->SEESTAT.bit.SBLK, virtual_eeprom_size); + return virtual_eeprom_size; +} uint8_t eeprom_read_byte(const uint8_t *addr) { uintptr_t offset = (uintptr_t)addr; - if (offset >= EEPROM_SIZE) { + if (offset >= MAX(EEPROM_SIZE, get_virtual_eeprom_size())) { + eeprom_printf("eeprom_read_byte:: out of bounds\n"); return 0x0; } - if (NVMCTRL->SEESTAT.bit.PSZ == 0 || NVMCTRL->SEESTAT.bit.SBLK == 0) { + if (get_virtual_eeprom_size() == 0) { return buffer[offset]; } - int timeout = BUSY_RETRIES; - while (NVMCTRL->SEESTAT.bit.BUSY && timeout-- > 0) - ; - - if (!NVMCTRL->SEESTAT.bit.BUSY) { - return SmartEEPROM8[offset]; + if (eeprom_is_busy()) { + eeprom_printf("eeprom_write_byte:: timeout\n"); + return 0x0; } - return 0x0; + return SmartEEPROM8[offset]; } void eeprom_write_byte(uint8_t *addr, uint8_t value) { uintptr_t offset = (uintptr_t)addr; - if (offset >= EEPROM_SIZE) { - return 0x0; + if (offset >= MAX(EEPROM_SIZE, get_virtual_eeprom_size())) { + eeprom_printf("eeprom_write_byte:: out of bounds\n"); + return; } - if (NVMCTRL->SEESTAT.bit.PSZ == 0 || NVMCTRL->SEESTAT.bit.SBLK == 0) { + if (get_virtual_eeprom_size() == 0) { buffer[offset] = value; return; } - int timeout = BUSY_RETRIES; - while (NVMCTRL->SEESTAT.bit.BUSY && timeout-- > 0) - ; - - if (!NVMCTRL->SEESTAT.bit.BUSY) { - SmartEEPROM8[offset] = value; + if (eeprom_is_busy()) { + eeprom_printf("eeprom_write_byte:: timeout\n"); + return; } + + SmartEEPROM8[offset] = value; } uint16_t eeprom_read_word(const uint16_t *addr) {