get storage to work now

This commit is contained in:
Triss 2021-08-26 20:09:23 +02:00
parent 6a4eafb96e
commit 07db20ecb6
6 changed files with 46 additions and 100 deletions

View File

@ -16,13 +16,12 @@
#include <hardware/structs/xip_ctrl.h>
#include <hardware/flash.h>
#include <hardware/sync.h>
#include <pico/bootrom.h>
#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

View File

@ -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

View File

@ -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

View File

@ -28,7 +28,7 @@ class StorageInfoMode(NamedTuple):
def from_bytes(b: bytes) -> StorageInfoMode:
assert len(b) == 12
v, ds, oam, d = struct.unpack('<HHII', b)
return StorageInfoMode(v, ds, o & ((1<<28)-1), (o >> 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('<I', b[28:32])
mdat = StorageModeInfo.list_from_bytes(b[32:])
mdat = StorageInfoMode.list_from_bytes(b[32:256-32])
assert len(mdat) == nm
@ -189,11 +189,11 @@ class DPDevice:
if (plen & 0x80) != 0:
plen &= 0x7f
plen |= self.read(1) << 7
plen |= self.read(1)[0] << 7
if (plen & 0x4000) != 0:
plen &= 0x3fff
plen |= self.read(1) << 14
plen |= self.read(1)[0] << 14
bs = self.read(plen)
#print("==> 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')

View File

@ -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<<mode; \
if (mode < 16 && mode > 0 && header_valid && header_tmp.nmodes != 0) mode_bad |= 1<<mode; \
(struct mode_info){ .size = 0, .version = 0 }; \
}) \
if (mode >= 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];

View File

@ -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???
}