X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fkernel%2Fao_storage.c;h=43abc43c1ec9e24396aff9a0c5dcc13dce44e386;hb=d225adc3af9e5726d436cbbdbf8dcc5837e50804;hp=bee9293e8d1bb1dc7f2a76a9986433b6a5e81a0c;hpb=1085ec5d57e0ed5d132f2bbdac1a0b6a32c0ab4a;p=fw%2Faltos diff --git a/src/kernel/ao_storage.c b/src/kernel/ao_storage.c index bee9293e..43abc43c 100644 --- a/src/kernel/ao_storage.c +++ b/src/kernel/ao_storage.c @@ -19,9 +19,15 @@ #include #include +#define AO_STORAGE_DATA_SIZE 128 + +static uint8_t storage_data[AO_STORAGE_DATA_SIZE]; +static uint8_t storage_mutex; + uint8_t -ao_storage_read(ao_pos_t pos, __xdata void *buf, uint16_t len) __reentrant +ao_storage_read(ao_pos_t pos, void *v_buf, uint16_t len) { + uint8_t *buf = v_buf; uint16_t this_len; uint16_t this_off; @@ -50,8 +56,9 @@ ao_storage_read(ao_pos_t pos, __xdata void *buf, uint16_t len) __reentrant } uint8_t -ao_storage_write(ao_pos_t pos, __xdata void *buf, uint16_t len) __reentrant +ao_storage_write(ao_pos_t pos, void *v_buf, uint16_t len) { + uint8_t *buf = v_buf; uint16_t this_len; uint16_t this_off; @@ -79,30 +86,97 @@ ao_storage_write(ao_pos_t pos, __xdata void *buf, uint16_t len) __reentrant return 1; } -static __xdata uint8_t storage_data[8]; +uint8_t +ao_storage_is_erased(uint32_t pos) +{ + uint32_t read_pos; + uint32_t read_len; + uint32_t i; + uint8_t ret = 1; + + ao_storage_setup(); + ao_mutex_get(&storage_mutex); + read_pos = pos; + read_len = ao_storage_block; + while (read_len) { + uint32_t this_time = AO_STORAGE_DATA_SIZE; + if (this_time > read_len) + this_time = read_len; + if (!ao_storage_read(read_pos, storage_data, this_time)) { + ret = 0; + goto done; + } + for (i = 0; i < this_time; i++) + if (storage_data[i] != AO_STORAGE_ERASED_BYTE) { + ret = 0; + goto done; + } + read_pos += this_time; + read_len -= this_time; + } +done: + ao_mutex_put(&storage_mutex); + return ret; +} + +uint8_t +ao_storage_erase(uint32_t start_pos, uint32_t len) +{ + /* Round 'len' up to ao_storage_block units */ + len = ((len + ao_storage_block - 1) / ao_storage_block) * ao_storage_block; + + /* + * Start at the end of the area to erase so that the + * last block cleared is the first block; this will ensure + * that partially erased flight logs still appear in the list + * and can be re-erased. + */ + uint32_t pos = start_pos + len - ao_storage_block; + while (len) { + int tries; + +#define MAX_TRIES 4 /* needs to be at least 2 */ + for (tries = 0; tries < MAX_TRIES; tries++) { + if (ao_storage_is_erased(pos)) + break; + if (!ao_storage_device_erase(pos)) + return 0; + } + if (tries == MAX_TRIES) + return 0; + pos -= ao_storage_block; + len -= ao_storage_block; + } + return 1; +} static void -ao_storage_dump(void) __reentrant +ao_storage_dump(void) { - uint8_t i, j; + uint32_t block; + uint8_t i, j, k; - ao_cmd_hex(); + block = ao_cmd_hex(); if (ao_cmd_status != ao_cmd_success) return; - for (i = 0; ; i += 8) { - if (ao_storage_read(((uint32_t) (ao_cmd_lex_i) << 8) + i, - storage_data, - 8)) { - ao_cmd_put16((uint16_t) i); - for (j = 0; j < 8; j++) { - putchar(' '); - ao_cmd_put8(storage_data[j]); + ao_mutex_get(&storage_mutex); + for (i = 0; ; i += AO_STORAGE_DATA_SIZE) { + if (ao_storage_read((block << 8) + i, + storage_data, + AO_STORAGE_DATA_SIZE)) { + for (k = 0; k < AO_STORAGE_DATA_SIZE; k += 8) { + ao_cmd_put16((uint16_t) i + k); + for (j = 0; j < 8; j++) { + putchar(' '); + ao_cmd_put8(storage_data[k + j]); + } + putchar ('\n'); } - putchar ('\n'); } - if (i == 248) + if (i == 256 - AO_STORAGE_DATA_SIZE) break; } + ao_mutex_put(&storage_mutex); } #if HAS_STORAGE_DEBUG @@ -110,57 +184,222 @@ ao_storage_dump(void) __reentrant /* not enough space for this today */ static void -ao_storage_store(void) __reentrant +ao_storage_store(void) { uint16_t block; uint8_t i; uint16_t len; - static __xdata uint8_t b; + uint8_t b; uint32_t addr; - ao_cmd_hex(); - block = ao_cmd_lex_i; - ao_cmd_hex(); - i = ao_cmd_lex_i; + block = ao_cmd_hex(); + i = ao_cmd_hex(); addr = ((uint32_t) block << 8) | i; - ao_cmd_hex(); - len = ao_cmd_lex_i; + len = ao_cmd_hex(); if (ao_cmd_status != ao_cmd_success) return; while (len--) { - ao_cmd_hex(); + b = ao_cmd_hexbyte(); if (ao_cmd_status != ao_cmd_success) return; - b = ao_cmd_lex_i; ao_storage_write(addr, &b, 1); addr++; } } #endif -void -ao_storage_zap(void) __reentrant +static void +ao_storage_zap(void) { - ao_cmd_hex(); + uint32_t v = ao_cmd_hex(); if (ao_cmd_status != ao_cmd_success) return; - ao_storage_erase((uint32_t) ao_cmd_lex_i << 8); + ao_storage_erase((uint32_t) v << 8, ao_storage_block); } -void -ao_storage_zapall(void) __reentrant +static void +ao_storage_zapall(void) +{ + ao_cmd_white(); + if (!ao_match_word("DoIt")) + return; + ao_storage_erase(0, ao_storage_log_max); +} + +#if AO_STORAGE_TEST + +#define AO_STORAGE_TEST_SIZE 256 +static uint8_t storage_test[AO_STORAGE_TEST_SIZE]; + +static void +ao_storage_failure(uint32_t pos, char *format, ...) +{ + va_list a; + printf("TEST FAILURE AT %08x: ", pos); + va_start(a, format); + vprintf(format, a); + va_end(a); +} + +static uint8_t +ao_storage_check_block(uint32_t pos, uint8_t value) +{ + uint32_t offset; + uint32_t byte; + + for (offset = 0; offset < ao_storage_block; offset += sizeof (storage_test)) { + if (!ao_storage_read(pos + offset, storage_test, sizeof (storage_test))) { + ao_storage_failure(pos + offset, "read failed\n"); + return 0; + } + for (byte = 0; byte < sizeof (storage_test); byte++) + if (storage_test[byte] != value) { + ao_storage_failure(pos + offset + byte, + "want %02x got %02x\n", + value, storage_test[byte]); + return 0; + } + } + return 1; +} + +static uint8_t +ao_storage_fill_block(uint32_t pos, uint8_t value) +{ + uint32_t offset; + uint32_t byte; + + for (byte = 0; byte < sizeof (storage_test); byte++) + storage_test[byte] = value; + for (offset = 0; offset < ao_storage_block; offset += sizeof (storage_test)) { + if (!ao_storage_write(pos + offset, storage_test, sizeof (storage_test))) { + ao_storage_failure(pos + offset, "write failed\n"); + return 0; + } + } + return 1; +} + +static uint8_t +ao_storage_check_incr_block(uint32_t pos) +{ + uint32_t offset; + uint32_t byte; + + for (offset = 0; offset < ao_storage_block; offset += sizeof (storage_test)) { + if (!ao_storage_read(pos + offset, storage_test, sizeof (storage_test))) { + ao_storage_failure(pos + offset, "read failed\n"); + return 0; + } + for (byte = 0; byte < sizeof (storage_test); byte++) { + uint8_t value = offset + byte; + if (storage_test[byte] != value) { + ao_storage_failure(pos + offset + byte, + "want %02x got %02x\n", + value, storage_test[byte]); + return 0; + } + } + } + return 1; +} + +static uint8_t +ao_storage_fill_incr_block(uint32_t pos) +{ + uint32_t offset; + uint32_t byte; + + for (offset = 0; offset < ao_storage_block; offset += sizeof (storage_test)) { + for (byte = 0; byte < sizeof (storage_test); byte++) + storage_test[byte] = offset + byte; + if (!ao_storage_write(pos + offset, storage_test, sizeof (storage_test))) { + ao_storage_failure(pos + offset, "write failed\n"); + return 0; + } + } + return 1; +} + +static uint8_t +ao_storage_fill_check_block(uint32_t pos, uint8_t value) +{ + return ao_storage_fill_block(pos, value) && ao_storage_check_block(pos, value); +} + +static uint8_t +ao_storage_incr_check_block(uint32_t pos) +{ + return ao_storage_fill_incr_block(pos) && ao_storage_check_incr_block(pos); +} + +static uint8_t +ao_storage_test_block(uint32_t pos) +{ + ao_storage_erase(pos, ao_storage_block); + printf(" erase"); flush(); + if (!ao_storage_check_block(pos, 0xff)) + return 0; + printf(" zero"); flush(); + if (!ao_storage_fill_check_block(pos, 0x00)) + return 0; + ao_storage_erase(pos, ao_storage_block); + printf(" 0xaa"); flush(); + if (!ao_storage_fill_check_block(pos, 0xaa)) + return 0; + ao_storage_erase(pos, ao_storage_block); + printf(" 0x55"); flush(); + if (!ao_storage_fill_check_block(pos, 0x55)) + return 0; + ao_storage_erase(pos, ao_storage_block); + printf(" increment"); flush(); + if (!ao_storage_incr_check_block(pos)) + return 0; + ao_storage_erase(pos, ao_storage_block); + printf(" pass\n"); flush(); + return 1; +} + +static void +ao_storage_test(void) { uint32_t pos; ao_cmd_white(); if (!ao_match_word("DoIt")) return; - for (pos = 0; pos < ao_storage_log_max; pos += ao_storage_block) - ao_storage_erase(pos); + for (pos = 0; pos < ao_storage_log_max; pos += ao_storage_block) { + printf("Testing block 0x%08x:", pos); flush(); + if (!ao_storage_test_block(pos)) + break; + } + printf("Test complete\n"); } -void -ao_storage_info(void) __reentrant +static void +ao_storage_fill(void) +{ + uint32_t pos; + + ao_cmd_white(); + if (!ao_match_word("DoIt")) + return; + printf("erase "); flush(); + ao_storage_erase(0, ao_storage_log_max); + for (pos = 0; pos < sizeof (storage_test); pos++) + storage_test[pos] = (uint8_t) pos; + for (pos = 0; pos < ao_storage_log_max; pos += sizeof (storage_test)) { + if ((pos & 0xffff) == 0) { + printf("Fill 0x%x\n", pos); flush(); + } + ao_storage_write(pos, storage_test, sizeof (storage_test)); + } + printf("Fill complete\n"); +} +#endif /* AO_STORAGE_TEST */ + +static void +ao_storage_info(void) { ao_storage_setup(); printf("Storage size: %ld\n", (long) ao_storage_total); @@ -168,7 +407,7 @@ ao_storage_info(void) __reentrant ao_storage_device_info(); } -__code struct ao_cmds ao_storage_cmds[] = { +const struct ao_cmds ao_storage_cmds[] = { { ao_storage_info, "f\0Show storage" }, { ao_storage_dump, "e \0Dump flash" }, #if HAS_STORAGE_DEBUG @@ -176,6 +415,10 @@ __code struct ao_cmds ao_storage_cmds[] = { #endif { ao_storage_zap, "z \0Erase " }, { ao_storage_zapall,"Z \0Erase all. is doit with D&I" }, +#if AO_STORAGE_TEST + { ao_storage_test, "V \0Validate flash (destructive). is doit with D&I" }, + { ao_storage_fill, "F \0Fill flash with data. is doit with D&I" }, +#endif { 0, NULL }, };