aboutsummaryrefslogtreecommitdiff
path: root/ks_flash.c
diff options
context:
space:
mode:
Diffstat (limited to 'ks_flash.c')
-rw-r--r--ks_flash.c147
1 files changed, 84 insertions, 63 deletions
diff --git a/ks_flash.c b/ks_flash.c
index 1479ce7..00f9786 100644
--- a/ks_flash.c
+++ b/ks_flash.c
@@ -52,18 +52,9 @@
* General consideration:
*
* - bits can only be cleared, not set, unless one wants to erase the
- * (sub)sector. This has some odd knock on effects in terms of
+ * sector. This has some odd knock on effects in terms of
* things like values of enumerated constants used here.
*
- * - At the moment, all of the the low-level flash code deals with
- * sectors, not sub-sectors, so for the moment we only use the first
- * sub-sector of each sector. Fixing this should not involve any
- * major changes to the code, just redefinition of some constants
- * here once we figure out what effect this will have on the rest of
- * the code that shares the same low-level flash code. In either
- * case we're dealing with "blocks", where a block is a sector now
- * and will be a sub-sector later.
- *
* - This code assumes we're using ks_index.c, including its notion
* of a free list and its attempt at light-weight wear leveling.
*
@@ -163,21 +154,27 @@ typedef union {
} flash_block_t;
/*
- * In-memory index, cache, etc.
- *
- * Some or all of this probably ought to be allocated out of external
- * SDRAM, but try it as a plain static variable initially.
+ * In-memory cache.
+ */
+
+typedef struct {
+ unsigned blockno;
+ uint32_t lru;
+ flash_block_t block;
+} cache_block_t;
+
+/*
+ * In-memory database.
*
- * NUM_FLASH_BLOCKS should be KEYSTORE_NUM_SUBSECTORS, but all the
- * current flash code uses sectors rather than subsectors, so use
- * KEYSTORE_NUM_SECTORS until we have subsector erase code.
+ * The top-level structure is a static variable; the arrays are allocated at runtime
+ * using hal_allocate_static_memory() because they can get kind of large.
*/
#ifndef KS_FLASH_CACHE_SIZE
#define KS_FLASH_CACHE_SIZE 4
#endif
-#define NUM_FLASH_BLOCKS KEYSTORE_NUM_SECTORS
+#define NUM_FLASH_BLOCKS KEYSTORE_NUM_SUBSECTORS
typedef struct {
hal_ks_t ks; /* Must be first (C "subclassing") */
@@ -186,13 +183,7 @@ typedef struct {
hal_ks_pin_t so_pin;
hal_ks_pin_t user_pin;
uint32_t cache_lru;
- struct {
- unsigned blockno;
- uint32_t lru;
- flash_block_t block;
- } cache[KS_FLASH_CACHE_SIZE];
- uint16_t _index[NUM_FLASH_BLOCKS];
- hal_uuid_t _names[NUM_FLASH_BLOCKS];
+ cache_block_t *cache;
} db_t;
/*
@@ -234,7 +225,7 @@ static inline flash_block_t *cache_pick_lru(void)
uint32_t best_delta = 0;
int best_index = 0;
- for (int i = 0; i < sizeof(db.cache)/sizeof(*db.cache); i++) {
+ for (int i = 0; i < KS_FLASH_CACHE_SIZE; i++) {
if (db.cache[i].blockno == ~0)
return &db.cache[i].block;
@@ -257,7 +248,7 @@ static inline flash_block_t *cache_pick_lru(void)
static inline flash_block_t *cache_find_block(const unsigned blockno)
{
- for (int i = 0; i < sizeof(db.cache)/sizeof(*db.cache); i++)
+ for (int i = 0; i < KS_FLASH_CACHE_SIZE; i++)
if (db.cache[i].blockno == blockno)
return &db.cache[i].block;
return NULL;
@@ -269,7 +260,7 @@ static inline flash_block_t *cache_find_block(const unsigned blockno)
static inline void cache_mark_used(const flash_block_t * const block, const unsigned blockno)
{
- for (int i = 0; i < sizeof(db.cache)/sizeof(*db.cache); i++) {
+ for (int i = 0; i < KS_FLASH_CACHE_SIZE; i++) {
if (&db.cache[i].block == block) {
db.cache[i].blockno = blockno;
db.cache[i].lru = ++db.cache_lru;
@@ -313,49 +304,67 @@ static hal_crc32_t calculate_block_crc(const flash_block_t * const block)
}
/*
- * Calculate block offset. Once we have subsectors working this will
- * use subsector offsets, for the moment we have to use sector offsets.
+ * Calculate block offset.
*/
-#if 0
-#define BLOCK_OFFSET_SIZE KEYSTORE_SUBSECTOR_SIZE
-#else
-#define BLOCK_OFFSET_SIZE KEYSTORE_SECTOR_SIZE
-#endif
-
static uint32_t block_offset(const unsigned blockno)
{
- return blockno * BLOCK_OFFSET_SIZE;
+ return blockno * KEYSTORE_SUBSECTOR_SIZE;
}
/*
- * Read a flash block. In some cases we might be able to optimize by
- * reading just the first page, but NOR flash should be relatively
- * fast to read, and we need the whole block to check the CRC
- * anyway.
+ * Read a flash block.
+ *
+ * Sadly, flash on the Alpha is slow enough that it pays to
+ * check the first page before reading the rest of the block.
*/
-static hal_error_t block_read(const unsigned blockno, flash_block_t *block)
+static hal_error_t block_read(const unsigned blockno, flash_block_t *block, const int fast)
{
assert(block != NULL && blockno < NUM_FLASH_BLOCKS && sizeof(*block) == KEYSTORE_SUBSECTOR_SIZE);
/* Sigh, magic numeric return codes */
- if (keystore_read_data(block_offset(blockno), block->bytes, sizeof(*block)) != 1)
+ if (keystore_read_data(block_offset(blockno),
+ block->bytes,
+ KEYSTORE_PAGE_SIZE) != 1)
return HAL_ERROR_KEYSTORE_ACCESS;
- switch (block_get_type(block)) {
+ flash_block_type_t block_type = block_get_type(block);
+ hal_crc32_t crc = 0;
+
+ switch (block_type) {
case FLASH_KEYBLK:
case FLASH_PINBLK:
- return calculate_block_crc(block) == block->header.crc1 ? HAL_OK : HAL_ERROR_KEYSTORE_BAD_CRC;
+ crc = block->header.crc1;
+ break;
case FLASH_KEYOLD:
case FLASH_PINOLD:
- return calculate_block_crc(block) == block->header.crc2 ? HAL_OK : HAL_ERROR_KEYSTORE_BAD_CRC;
+ crc = block->header.crc2;
+ break;
case FLASH_ERASED:
case FLASH_ZEROED:
- return HAL_OK;
+ if (fast)
+ return HAL_OK;
+ else
+ break;
default:
return HAL_ERROR_KEYSTORE_BAD_BLOCK_TYPE;
}
+
+ /* Sigh, magic numeric return codes */
+ if (keystore_read_data(block_offset(blockno) + KEYSTORE_PAGE_SIZE,
+ block->bytes + KEYSTORE_PAGE_SIZE,
+ sizeof(*block) - KEYSTORE_PAGE_SIZE) != 1)
+ return HAL_ERROR_KEYSTORE_ACCESS;
+
+ switch (block_type) {
+ default:
+ if (calculate_block_crc(block) != crc)
+ return HAL_ERROR_KEYSTORE_BAD_CRC;
+ case FLASH_ERASED:
+ case FLASH_ZEROED:
+ return HAL_OK;
+ }
}
/*
@@ -375,7 +384,7 @@ static hal_error_t block_read_cached(const unsigned blockno, flash_block_t **blo
if ((*block = cache_pick_lru()) == NULL)
return HAL_ERROR_IMPOSSIBLE;
- return block_read(blockno, *block);
+ return block_read(blockno, *block, 1);
}
/*
@@ -442,7 +451,7 @@ static hal_error_t block_erase(const unsigned blockno)
assert(blockno < NUM_FLASH_BLOCKS);
/* Sigh, magic numeric return codes */
- if (keystore_erase_sectors(blockno, blockno) != 1)
+ if (keystore_erase_subsectors(blockno, blockno) != 1)
return HAL_ERROR_KEYSTORE_ACCESS;
return HAL_OK;
@@ -450,7 +459,7 @@ static hal_error_t block_erase(const unsigned blockno)
/*
* Erase a flash block if it hasn't already been erased.
- *
+ * We have to disable fast read for this to work properly.
* May not be necessary, trying to avoid unnecessary wear.
*/
@@ -462,7 +471,7 @@ static hal_error_t block_erase_maybe(const unsigned blockno)
if (block == NULL)
return HAL_ERROR_IMPOSSIBLE;
- err = block_read(blockno, block);
+ err = block_read(blockno, block, 0);
if (err == HAL_ERROR_KEYSTORE_BAD_BLOCK_TYPE ||
err == HAL_ERROR_KEYSTORE_BAD_CRC)
@@ -487,17 +496,27 @@ static hal_error_t block_erase_maybe(const unsigned blockno)
static hal_error_t ks_init(const hal_ks_driver_t * const driver)
{
/*
- * Initialize the in-memory database. In the long run this probably
- * needs to be using a block of SDRAM, which we would allocate here.
+ * Initialize the in-memory database.
*/
+ const size_t len = (sizeof(*db.ksi.index) * NUM_FLASH_BLOCKS +
+ sizeof(*db.ksi.names) * NUM_FLASH_BLOCKS +
+ sizeof(*db.cache) * KS_FLASH_CACHE_SIZE);
+
+ uint8_t *mem = hal_allocate_static_memory(len);
+
+ if (mem == NULL)
+ return HAL_ERROR_ALLOCATION_FAILURE;
+
memset(&db, 0, sizeof(db));
+ memset(mem, 0, len);
+
db.ksi.size = NUM_FLASH_BLOCKS;
- db.ksi.used = 0;
- db.ksi.index = db._index;
- db.ksi.names = db._names;
+ db.ksi.index = (void *) mem; mem += sizeof(*db.ksi.index) * NUM_FLASH_BLOCKS;
+ db.ksi.names = (void *) mem; mem += sizeof(*db.ksi.names) * NUM_FLASH_BLOCKS;
+ db.cache = (void *) mem;
- for (int i = 0; i < sizeof(db.cache)/sizeof(*db.cache); i++)
+ for (int i = 0; i < KS_FLASH_CACHE_SIZE; i++)
db.cache[i].blockno = ~0;
/*
@@ -525,7 +544,7 @@ static hal_error_t ks_init(const hal_ks_driver_t * const driver)
* we want the block to ends up near the end of the free list.
*/
- err = block_read(i, block);
+ err = block_read(i, block, 1);
if (err == HAL_ERROR_KEYSTORE_BAD_CRC || err == HAL_ERROR_KEYSTORE_BAD_BLOCK_TYPE)
block_types[i] = FLASH_UNKNOWN;
@@ -651,7 +670,7 @@ static hal_error_t ks_init(const hal_ks_driver_t * const driver)
hal_uuid_t name = db.ksi.names[i]; /* Paranoia */
- if ((err = block_read(i, block)) != HAL_OK)
+ if ((err = block_read(i, block, 1)) != HAL_OK)
return err;
block->header.block_type = restore_type;
@@ -685,10 +704,13 @@ static hal_error_t ks_init(const hal_ks_driver_t * const driver)
unsigned b;
memset(block, 0xFF, sizeof(*block));
- memset(&block->pin.so_pin, 0, sizeof(block->pin.so_pin));
- memset(&block->pin.user_pin, 0, sizeof(block->pin.user_pin));
+
+ db.wheel_pin = hal_last_gasp_pin;
+
block->header.block_type = FLASH_PINBLK;
- block->pin.wheel_pin = hal_last_gasp_pin;
+ block->pin.wheel_pin = db.wheel_pin;
+ block->pin.so_pin = db.so_pin;
+ block->pin.user_pin = db.user_pin;
if ((err = hal_ks_index_add(&db.ksi, &pin_uuid, &b)) != HAL_OK)
return err;
@@ -725,7 +747,6 @@ static hal_error_t ks_shutdown(const hal_ks_driver_t * const driver)
{
if (db.ks.driver != driver)
return HAL_ERROR_KEYSTORE_ACCESS;
- memset(&db, 0, sizeof(db));
return HAL_OK;
}