From 07db20ecb68a314d700755c711593418d934147a Mon Sep 17 00:00:00 2001 From: sys64738 Date: Thu, 26 Aug 2021 20:09:23 +0200 Subject: [PATCH] get storage to work now --- bsp/rp2040/bsp-storage.h | 59 +++------------------------------------- host/dpctl/__init__.py | 34 +++++++---------------- host/dpctl/commands.py | 15 ++++++++-- host/dpctl/protocol.py | 13 +++++---- src/storage.c | 7 +++-- src/storage_save.c | 18 ++++++------ 6 files changed, 46 insertions(+), 100 deletions(-) diff --git a/bsp/rp2040/bsp-storage.h b/bsp/rp2040/bsp-storage.h index 23ce8e8..30c6107 100644 --- a/bsp/rp2040/bsp-storage.h +++ b/bsp/rp2040/bsp-storage.h @@ -16,13 +16,12 @@ #include #include #include +#include #ifndef PICO_FLASH_SIZE_BYTES #error "PICO_FLASH_SIZE_BYTES not defined" #endif -#define STORAGE_RAM_FUNC(x) __no_inline_not_in_flash_func(x) - static inline size_t storage_get_program_size(void) { extern uint8_t __flash_binary_start, __flash_binary_end; @@ -47,68 +46,18 @@ static inline void storage_read(void* dest, size_t offset, size_t size) { // * SSI DMA: blocking & fast, code needs to run from RAM. a bit unwieldy memcpy(dest, (uint8_t*)(XIP_BASE+offset), size); } -static bool STORAGE_RAM_FUNC(storage_erasewrite)(size_t offset, const void* src, size_t size) { +static bool storage_erasewrite(size_t offset, const void* src, size_t size) { // bad alignment => give an error in advance if (offset & (FLASH_SECTOR_SIZE - 1)) return false; if (size & (FLASH_SECTOR_SIZE - 1)) return false; // memcmp pre: if no changes, don't flash - for (size_t i = 0; i < size; ++i) { - if (*(uint8_t*)(XIP_BASE + offset + i) != ((const uint8_t*)src)[i]) { - goto do_flash; - } + if (!memcmp(src, (uint8_t*)(XIP_BASE+offset), size)) return true; - asm volatile("":::"memory"); // make sure the compiler won't turn this into a memcmp call - } - - return true; // all equal, nothing to do, all is fine - -do_flash: - // these functions are RAM-only-safe flash_range_erase(offset, size); - // TODO: only program ranges written to? flash_range_program(offset, src, size); - // now do a memcmp, kinda badly but we can't call newlib memcmp - - for (size_t i = 0; i < size; ++i) { - if (*(uint8_t*)(XIP_BASE + offset + i) != ((const uint8_t*)src)[i]) { - return false; // welp - } - - asm volatile("":::"memory"); // make sure the compiler won't turn this into a memcmp call - } - - return true; -} - -static void* STORAGE_RAM_FUNC(storage_extra_ram_get_base)(void) { - return (void*)XIP_SRAM_BASE; -} - -typedef uint32_t storage_extra_ram_temp_t; - -static storage_extra_ram_temp_t STORAGE_RAM_FUNC(storage_extra_ram_enable)(void) { - uint32_t flags = save_and_disable_interrupts(); - - xip_ctrl_hw->flush = 1; // flush XIP stuff - // wait until flush is done - while (!(xip_ctrl_hw->stat & XIP_STAT_FLUSH_RDY)) - asm volatile("nop":::"memory"); - - xip_ctrl_hw->ctrl &= ~(io_rw_32)XIP_CTRL_EN_BITS; // disable XIP cache -> can now use it as SRAM - - // interrupts may access flash - //restore_interrupts(flags); - - return flags; -} -static void STORAGE_RAM_FUNC(storage_extra_ram_disable)(storage_extra_ram_temp_t flags) { - //uint32_t flags = save_and_disable_interrupts(); - - xip_ctrl_hw->ctrl |= XIP_CTRL_EN_BITS; // reenable XIP cache - - restore_interrupts(flags); + return !memcmp(src, (uint8_t*)(XIP_BASE+offset), size); } #endif diff --git a/host/dpctl/__init__.py b/host/dpctl/__init__.py index f65eb1b..55393aa 100644 --- a/host/dpctl/__init__.py +++ b/host/dpctl/__init__.py @@ -57,21 +57,7 @@ def dpctl_do(args: Any) -> int: def sto_flush(conn, args): return devcmds.storage_flush(conn) def sto_get(conn, args): - return devcmds.storage_get(mode) - - def storage(conn, args): - scmds = { - 'info', sto_info, - 'flush', sto_flush, - 'get', sto_get - } - - ssubfn = stocmds.get(args.storage, None) - if ssubfn is None: - print("Unknown 'storage' subcommand '%s'" % args.storage) - return 1 - - return ssubfn(conn, args) + return devcmds.storage_get(conn, args.mode) #print(repr(args)) cmds = { @@ -79,13 +65,14 @@ def dpctl_do(args: Any) -> int: 'get-mode-info': get_mode_info, 'set-mode': set_mode, 'bootloader': bootloader, + 'storage-info': sto_info, + 'storage-flush': sto_flush, + 'storage-get': sto_get, 'uart-cts-rts': uart_hw_flowctl, 'tempsensor': tempsensor, 'jtag-scan': jtag_scan, 'sump-overclock': sump_ovclk, - - 'storage': storage, } if args.subcmd is None: @@ -165,13 +152,12 @@ def main() -> int: bootloader = subcmds.add_parser("bootloader", help="Set the device in bootloader mode") # persistent storage commands - storage = subcmds.add_parser("storage", help="Persistent storage commands") - storagecmd = parser.add_subparsers(required=False, metavar="storage", - dest="storage", help="Persistent storage subcommand") - storagehdr = storagecmd.add_parser("info", help="Get persistent storage info") - storageflush = storagecmd.add_parser("flush", help="Flush persistent storage data to storage medium") - storageget = storagecmd.add_parser("get", help="Get data of a particular mode") - storageget.add_arguments('mode', default=None, nargs='?', + storagehdr = subcmds.add_parser("storage-info", help="Get persistent storage info") + + storageflush = subcmds.add_parser("storage-flush", help="Flush persistent storage data to storage medium") + + storageget = subcmds.add_parser("storage-get", help="Get data of a particular mode") + storageget.add_argument('mode', default=None, nargs='?', help="Mode to get data of. Defaults to the current mode, 'all' means all modes.") # mode 1 commands diff --git a/host/dpctl/commands.py b/host/dpctl/commands.py index fd89d1f..f1844cd 100644 --- a/host/dpctl/commands.py +++ b/host/dpctl/commands.py @@ -92,20 +92,31 @@ def storage_info(dev: DPDevice) -> int: return 0 except Exception as e: print("Could not get storage info: %s" % str(e)) + traceback.print_exc() return 1 def storage_flush(dev: DPDevice) -> int: try: - dev.storage_flush() + res = dev.storage_flush() + print("storage saved" if res else "no write needed") return 0 except Exception as e: print("Could not flush persistent storage: %s" % str(e)) return 1 -def storage_get(dev: DPDevice, mode: int) -> int: +def storage_get(dev: DPDevice, mode: str) -> int: try: + if mode == 'all': + for m in dev.mode_info.keys(): + res = dev.storage_get(mode) + print(repr(res)) # TODO + return 0 + elif mode is None: + mode = dev.current_mode + else: mode = int(mode,0) + res = dev.storage_get(mode) print(repr(res)) # TODO return 0 diff --git a/host/dpctl/protocol.py b/host/dpctl/protocol.py index 8419b0c..6d24d4e 100644 --- a/host/dpctl/protocol.py +++ b/host/dpctl/protocol.py @@ -28,7 +28,7 @@ class StorageInfoMode(NamedTuple): def from_bytes(b: bytes) -> StorageInfoMode: assert len(b) == 12 v, ds, oam, d = struct.unpack('> 28) & 15, d) + return StorageInfoMode(v, ds, oam & ((1<<28)-1), (oam >> 28) & 15, d) def list_from_bytes(b: bytes) -> List[StorageInfoMode]: nelem = len(b) // 12 @@ -56,7 +56,7 @@ class StorageInfo(NamedTuple): res = b[20:28] d2tab = struct.unpack(' got resp %d res %s" % (resp, repr(bs))) @@ -291,10 +291,11 @@ class DPDevice: return StorageInfo.from_bytes(pl) - def storage_flush(self): + def storage_flush(self) -> bool: self.write(b'\x0e') stat, pl = self.read_resp() - check_statpl(stat, pl, "flush storage", 0, 0) + check_statpl(stat, pl, "flush storage", 1, 1) + return pl[0] def storage_get(self, mode: int) -> bytes: cmd = bytearray(b'\x0d\x00') diff --git a/src/storage.c b/src/storage.c index ff1c11d..d3d2f2a 100644 --- a/src/storage.c +++ b/src/storage.c @@ -90,12 +90,13 @@ int storage_init(void) { struct mode_info storage_mode_get_info(int mode) { #define DEF_RETVAL ({ \ - if (mode < 16 && mode > 0 && header_valid) mode_bad |= 1< 0 && header_valid && header_tmp.nmodes != 0) mode_bad |= 1<= 16 || !header_valid || mode <= 0) return DEF_RETVAL; + if (mode >= 16 || !header_valid || mode <= 0 || header_tmp.nmodes == 0) + return DEF_RETVAL; for (size_t i = 0; i < header_tmp.nmodes; ++i) { struct mode_data md = header_tmp.mode_data_table[i]; @@ -147,7 +148,7 @@ struct mode_info storage_mode_get_info(int mode) { #undef DEF_RETVAL } void storage_mode_read(int mode, void* dst, size_t offset, size_t maxlen) { - if (mode >= 16 || !header_valid || mode <= 0) return; + if (mode >= 16 || !header_valid || mode <= 0 || header_tmp.nmodes == 0) return; for (size_t i = 0; i < header_tmp.nmodes; ++i) { struct mode_data md = header_tmp.mode_data_table[i]; diff --git a/src/storage_save.c b/src/storage_save.c index 45956bb..3f6ee70 100644 --- a/src/storage_save.c +++ b/src/storage_save.c @@ -104,7 +104,7 @@ static void st_safe_memcpy(void* dst, const void* src, size_t size) { } } -static void STORAGE_RAM_FUNC(storage_serialize_xip)(size_t page, +static void storage_serialize_xip(size_t page, size_t pagestart, size_t pageend, void* dest) { if (page == 0) { st_safe_memcpy((uint8_t*)dest + pageend - pagestart, @@ -123,32 +123,30 @@ static void STORAGE_RAM_FUNC(storage_serialize_xip)(size_t page, } } -static void STORAGE_RAM_FUNC(storage_write_data)(void) { +static void storage_write_data(void) { size_t npages = storage_allocate_new(); if (npages == 0) { storage_init(); return; // TODO: error, somehow } - storage_extra_ram_temp_t ramtmp = storage_extra_ram_enable(); - void* base = storage_extra_ram_get_base(); + static uint8_t base[STORAGE_ERASEWRITE_ALIGN]; // TODO FIXME: HUGE RAM HOG! size_t current_page = STORAGE_SIZE - STORAGE_ERASEWRITE_ALIGN, current_page_end = STORAGE_SIZE - sizeof(struct storage_header); for (size_t page = 0; page < npages; ++page) { storage_serialize_xip(page, current_page, current_page_end, base); - storage_erasewrite(current_page, base, STORAGE_ERASEWRITE_ALIGN); + if (!storage_erasewrite(current_page, base, STORAGE_ERASEWRITE_ALIGN)) { + storage_init(); + return; // TODO: error, somehow + } current_page_end = current_page; current_page -= STORAGE_ERASEWRITE_ALIGN; } - storage_extra_ram_disable(ramtmp); - - // also TODO: - // * call storage_flush_data on vnd cfg command - // * vnd cfg command to read storage data + // TODO: // * save on a timer event? // * try to save when unplugging??? }