get storage to work now
This commit is contained in:
parent
6a4eafb96e
commit
07db20ecb6
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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???
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue