[Cryptech-Commits] [sw/stm32] 03/03: Refactor flash code.

git at cryptech.is git at cryptech.is
Wed Feb 22 23:15:18 UTC 2017


This is an automated email from the git hooks/post-receive script.

paul at psgd.org pushed a commit to branch ksng
in repository sw/stm32.

commit 189df371631a2b7bef91803d449e47470ad6a7bf
Author: Paul Selkirk <paul at psgd.org>
AuthorDate: Wed Feb 22 14:11:12 2017 -0500

    Refactor flash code.
---
 projects/board-test/keystore-perf.c |   4 +-
 projects/board-test/spiflash-perf.c |  23 ++-
 projects/cli-test/mgmt-dfu.c        |   4 +-
 projects/cli-test/mgmt-fpga.c       |  10 +-
 projects/cli-test/mgmt-keystore.c   |   2 +-
 projects/cli-test/mgmt-show.c       |   2 +-
 projects/hsm/mgmt-fpga.c            |  12 +-
 spiflash_n25q128.c                  | 323 +++++++++++++++++-------------------
 spiflash_n25q128.h                  |  18 +-
 stm-flash.c                         |   2 +-
 stm-flash.h                         |   1 -
 stm-fpgacfg.c                       |  18 +-
 stm-fpgacfg.h                       |   6 +-
 stm-keystore.c                      |  40 ++---
 stm-keystore.h                      |   9 +-
 15 files changed, 238 insertions(+), 236 deletions(-)

diff --git a/projects/board-test/keystore-perf.c b/projects/board-test/keystore-perf.c
index 75b4e3f..09528a2 100644
--- a/projects/board-test/keystore-perf.c
+++ b/projects/board-test/keystore-perf.c
@@ -64,7 +64,7 @@ static void test_erase_sector(void)
     int err;
 
     for (i = 0; i < KEYSTORE_NUM_SECTORS; ++i) {
-        err = keystore_erase_sectors(i, i);
+        err = keystore_erase_sector(i);
         if (err != 1) {
             uart_send_string("ERROR: keystore_erase_sector returned ");
             uart_send_integer(err, 0);
@@ -83,7 +83,7 @@ static void test_erase_subsector(void)
     int err;
 
     for (i = 0; i < KEYSTORE_NUM_SUBSECTORS; ++i) {
-        err = keystore_erase_subsectors(i, i);
+        err = keystore_erase_subsector(i);
         if (err != 1) {
             uart_send_string("ERROR: keystore_erase_subsector returned ");
             uart_send_integer(err, 0);
diff --git a/projects/board-test/spiflash-perf.c b/projects/board-test/spiflash-perf.c
index 1abcd7b..53f29cb 100644
--- a/projects/board-test/spiflash-perf.c
+++ b/projects/board-test/spiflash-perf.c
@@ -23,7 +23,7 @@ extern struct spiflash_ctx keystore_ctx;
 static struct spiflash_ctx *ctx = &keystore_ctx;
 
 /*
- * 1. Read the entire flash by pages, ignoring data.
+ * 1a. Read the entire flash by pages, ignoring data.
  */
 static void test_read_page(void)
 {
@@ -43,6 +43,26 @@ static void test_read_page(void)
 }
 
 /*
+ * 1b. Read the entire flash by subsectors, ignoring data.
+ */
+static void test_read_subsector(void)
+{
+    uint8_t read_buf[N25Q128_SUBSECTOR_SIZE];
+    uint32_t i;
+    int err;
+
+    for (i = 0; i < N25Q128_NUM_SUBSECTORS; ++i) {
+        err = n25q128_read_subsector(ctx, i, read_buf);
+        if (err != 1) {
+            uart_send_string("ERROR: n25q128_read_subsector returned ");
+            uart_send_integer(err, 0);
+            uart_send_string("\r\n");
+            break;
+        }
+    }
+}
+
+/*
  * Read the flash data and verify it against a known pattern.
  * It turns out that verification doesn't slow us down in any measurable
  * way, because memcmp on 256 bytes is pretty inconsequential.
@@ -217,6 +237,7 @@ int main(void)
     uart_send_string("Starting...\r\n");
 
     time_check("read page       ", test_read_page(),       N25Q128_NUM_PAGES);
+    time_check("read subsector  ", test_read_subsector(),  N25Q128_NUM_SUBSECTORS);
     time_check("erase subsector ", test_erase_subsector(), N25Q128_NUM_SUBSECTORS);
     time_check("erase sector    ", test_erase_sector(),    N25Q128_NUM_SECTORS);
     time_check("erase bulk      ", test_erase_bulk(),      1);
diff --git a/projects/cli-test/mgmt-dfu.c b/projects/cli-test/mgmt-dfu.c
index 8f258ea..851c8ea 100644
--- a/projects/cli-test/mgmt-dfu.c
+++ b/projects/cli-test/mgmt-dfu.c
@@ -72,9 +72,7 @@ static int cmd_dfu_erase(struct cli_def *cli, const char *command, char *argv[],
 {
     int status;
 
-    cli_print(cli, "Erasing flash sectors %i to %i (address %p to %p) - expect the CLI to crash now",
-	      stm_flash_sector_num((uint32_t) dfu_firmware),
-	      stm_flash_sector_num((uint32_t) dfu_firmware_end),
+    cli_print(cli, "Erasing flash address %p to %p - expect the CLI to crash now",
 	      dfu_firmware,
 	      dfu_firmware_end);
 
diff --git a/projects/cli-test/mgmt-fpga.c b/projects/cli-test/mgmt-fpga.c
index 31a6e27..b1b0973 100644
--- a/projects/cli-test/mgmt-fpga.c
+++ b/projects/cli-test/mgmt-fpga.c
@@ -47,7 +47,13 @@ static volatile uint32_t dfu_offset = 0;
 
 
 
-static int _flash_write_callback(uint8_t *buf, size_t len) {
+static int _flash_write_callback(uint8_t *buf, size_t len)
+{
+    if ((dfu_offset % FPGACFG_SECTOR_SIZE) == 0)
+	/* first page in sector, need to erase sector */
+	if (fpgacfg_erase_sector(dfu_offset / FPGACFG_SECTOR_SIZE) != 1)
+	    return CLI_ERROR;
+
     int res = fpgacfg_write_data(dfu_offset, buf, BITSTREAM_UPLOAD_CHUNK_SIZE) == 1;
     dfu_offset += BITSTREAM_UPLOAD_CHUNK_SIZE;
     return res;
@@ -91,7 +97,7 @@ static int cmd_fpga_bitstream_erase(struct cli_def *cli, const char *command, ch
      *
      * This command could be made to accept an argument indicating the whole memory should be erased.
      */
-    if (! fpgacfg_erase_sectors(1)) {
+    if (fpgacfg_erase_sector(0) != 0) {
 	cli_print(cli, "Erasing first sector in FPGA config memory failed");
 	return CLI_ERROR;
     }
diff --git a/projects/cli-test/mgmt-keystore.c b/projects/cli-test/mgmt-keystore.c
index 457abc2..09d512e 100644
--- a/projects/cli-test/mgmt-keystore.c
+++ b/projects/cli-test/mgmt-keystore.c
@@ -334,7 +334,7 @@ static int cmd_keystore_erase(struct cli_def *cli, const char *command, char *ar
     }
 
     cli_print(cli, "OK, erasing keystore, this might take a while...");
-    if ((status = keystore_erase_sectors(0, KEYSTORE_NUM_SECTORS - 1)) != 1) {
+    if ((status = keystore_erase_bulk()) != 1) {
         cli_print(cli, "Failed erasing token keystore: %i", status);
 	return CLI_ERROR;
     }
diff --git a/projects/cli-test/mgmt-show.c b/projects/cli-test/mgmt-show.c
index 5cca8b7..f124830 100644
--- a/projects/cli-test/mgmt-show.c
+++ b/projects/cli-test/mgmt-show.c
@@ -132,7 +132,7 @@ static int cmd_show_keystore_data(struct cli_def *cli, const char *command, char
 	}
     } else {
 	cli_print(cli, "Erasing first sector since all the first 8 bytes are tombstones");
-	if ((i = keystore_erase_sectors(1, 1)) != 1) {
+	if ((i = keystore_erase_sector(0)) != 1) {
 	    cli_print(cli, "Failed erasing the first sector: %li", i);
 	    return CLI_ERROR;
 	}
diff --git a/projects/hsm/mgmt-fpga.c b/projects/hsm/mgmt-fpga.c
index d76315e..06f2a26 100644
--- a/projects/hsm/mgmt-fpga.c
+++ b/projects/hsm/mgmt-fpga.c
@@ -3,7 +3,7 @@
  * -----------
  * CLI code to manage the FPGA configuration etc.
  *
- * Copyright (c) 2016, NORDUnet A/S All rights reserved.
+ * Copyright (c) 2016-2017, NORDUnet A/S All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -55,7 +55,13 @@ extern hal_user_t user;
 static volatile uint32_t dfu_offset = 0;
 
 
-static int _flash_write_callback(uint8_t *buf, size_t len) {
+static int _flash_write_callback(uint8_t *buf, size_t len)
+{
+    if ((dfu_offset % FPGACFG_SECTOR_SIZE) == 0)
+	/* first page in sector, need to erase sector */
+	if (fpgacfg_erase_sector(dfu_offset / FPGACFG_SECTOR_SIZE) != 1)
+	    return CLI_ERROR;
+
     int res = fpgacfg_write_data(dfu_offset, buf, BITSTREAM_UPLOAD_CHUNK_SIZE) == 1;
     dfu_offset += BITSTREAM_UPLOAD_CHUNK_SIZE;
     return res;
@@ -104,7 +110,7 @@ static int cmd_fpga_bitstream_erase(struct cli_def *cli, const char *command, ch
      *
      * This command could be made to accept an argument indicating the whole memory should be erased.
      */
-    if (! fpgacfg_erase_sectors(1)) {
+    if (fpgacfg_erase_sector(0) != 0) {
 	cli_print(cli, "Erasing first sector in FPGA config memory failed");
 	return CLI_ERROR;
     }
diff --git a/spiflash_n25q128.c b/spiflash_n25q128.c
index 133ecb4..5c4a3b2 100644
--- a/spiflash_n25q128.c
+++ b/spiflash_n25q128.c
@@ -37,91 +37,129 @@
 
 #include "spiflash_n25q128.h"
 
-#define _n25q128_select(ctx)	HAL_GPIO_WritePin(ctx->cs_n_port, ctx->cs_n_pin, GPIO_PIN_RESET);
-#define _n25q128_deselect(ctx)	HAL_GPIO_WritePin(ctx->cs_n_port, ctx->cs_n_pin, GPIO_PIN_SET);
-
-
 #define N25Q128_NUM_BYTES	(N25Q128_PAGE_SIZE * N25Q128_NUM_PAGES)
 
 #if N25Q128_SECTOR_SIZE    * N25Q128_NUM_SECTORS    != N25Q128_NUM_BYTES || \
     N25Q128_SUBSECTOR_SIZE * N25Q128_NUM_SUBSECTORS != N25Q128_NUM_BYTES
-#error Inconsistant definitions for pages / sectors / subsectors
+#error Inconsistent definitions for pages / sectors / subsectors
 #endif
 
 
-static int _n25q128_get_wel_flag(struct spiflash_ctx *ctx);
-static int _wait_while_wip(struct spiflash_ctx *ctx, uint32_t timeout);
+static inline void _n25q128_select(struct spiflash_ctx *ctx)
+{
+    HAL_GPIO_WritePin(ctx->cs_n_port, ctx->cs_n_pin, GPIO_PIN_RESET);
+}
 
+static inline void _n25q128_deselect(struct spiflash_ctx *ctx)
+{
+    HAL_GPIO_WritePin(ctx->cs_n_port, ctx->cs_n_pin, GPIO_PIN_SET);
+}
 
-int n25q128_check_id(struct spiflash_ctx *ctx)
+/* Read a bit from the status register. */
+static inline int _n25q128_get_status_bit(struct spiflash_ctx *ctx, unsigned bitnum)
 {
     // tx, rx buffers
-    uint8_t spi_tx[4];
-    uint8_t spi_rx[4];
+    uint8_t spi_tx[2];
+    uint8_t spi_rx[2];
 
     // result
     HAL_StatusTypeDef ok;
 
-    // send READ ID command
-    spi_tx[0] = N25Q128_COMMAND_READ_ID;
+    //assert(bitnum < sizeof(uint8_t));
 
-    // select, send command & read response, deselect
+    // send READ STATUS command
+    spi_tx[0] = N25Q128_COMMAND_READ_STATUS;
+
+    // send command, read response, deselect
     _n25q128_select(ctx);
-    ok = HAL_SPI_TransmitReceive(ctx->hspi, spi_tx, spi_rx, 4, N25Q128_SPI_TIMEOUT);
+    ok = HAL_SPI_TransmitReceive(ctx->hspi, spi_tx, spi_rx, 2, N25Q128_SPI_TIMEOUT);
     _n25q128_deselect(ctx);
 
     // check
-    if (ok != HAL_OK) return 0;
-
-    // parse response (note, that the very first byte was received during the
-    // transfer of the command byte, so it contains garbage and should
-    // be ignored here)
-    if (spi_rx[1] != N25Q128_ID_MANUFACTURER) return 0;
-    if (spi_rx[2] != N25Q128_ID_DEVICE_TYPE) return 0;
-    if (spi_rx[3] != N25Q128_ID_DEVICE_CAPACITY) return 0;
+    if (ok != HAL_OK) return -1;
 
     // done
-    return 1;
+    return ((spi_rx[1] >> bitnum) & 1);
 }
 
+/* Read the Write Enable Latch bit in the status register. */
+static inline int _n25q128_get_wel_flag(struct spiflash_ctx *ctx)
+{
+    return _n25q128_get_status_bit(ctx, 1);
+}
+
+/* Read the Write In Progress bit in the status register. */
+static inline int _n25q128_get_wip_flag(struct spiflash_ctx *ctx)
+{
+    return _n25q128_get_status_bit(ctx, 0);
+}
 
-int n25q128_read_page(struct spiflash_ctx *ctx, uint32_t page_offset, uint8_t *page_buffer)
+/* Wait until the flash memory is done writing */
+static int _n25q128_wait_while_wip(struct spiflash_ctx *ctx, uint32_t timeout)
+{
+    uint32_t tick_end = HAL_GetTick() + timeout;
+    int i;
+
+    do {
+	i = _n25q128_get_wip_flag(ctx);
+	if (i < 0) return 0;
+	if (! i) return 1;
+    } while (HAL_GetTick() < tick_end);
+
+    return 0;
+}
+
+/* Send the Write Enable command */
+static int _n25q128_write_enable(struct spiflash_ctx *ctx)
 {
     // tx buffer
-    uint8_t spi_tx[4];
+    uint8_t spi_tx[1];
 
     // result
     HAL_StatusTypeDef ok;
 
-    // check offset
-    if (page_offset >= N25Q128_NUM_PAGES) return 0;
-
-    // calculate byte address
-    page_offset *= N25Q128_PAGE_SIZE;
-
-    // prepare READ command
-    spi_tx[0] = N25Q128_COMMAND_READ_PAGE;
-    spi_tx[1] = (uint8_t)(page_offset >> 16);
-    spi_tx[2] = (uint8_t)(page_offset >>  8);
-    spi_tx[3] = (uint8_t)(page_offset >>  0);
+    // enable writing
+    spi_tx[0] = N25Q128_COMMAND_WRITE_ENABLE;
 
-    // activate, send command
+    // activate, send command, deselect
     _n25q128_select(ctx);
-    ok = HAL_SPI_Transmit(ctx->hspi, spi_tx, 4, N25Q128_SPI_TIMEOUT);
+    ok = HAL_SPI_Transmit(ctx->hspi, spi_tx, 1, N25Q128_SPI_TIMEOUT);
+    _n25q128_deselect(ctx);
 
     // check
-    if (ok != HAL_OK) {
-	_n25q128_deselect(ctx);
-	return 0;
-    }
+    if (ok != HAL_OK) return -1;
 
-    // read response, deselect
-    ok = HAL_SPI_Receive(ctx->hspi, page_buffer, N25Q128_PAGE_SIZE, N25Q128_SPI_TIMEOUT);
+    // make sure, that write enable did the job
+    return _n25q128_get_wel_flag(ctx);
+}
+
+int n25q128_check_id(struct spiflash_ctx *ctx)
+{
+    // tx, rx buffers
+    uint8_t spi_tx[4];
+    uint8_t spi_rx[4];
+
+    // result
+    HAL_StatusTypeDef ok;
+
+    // send READ ID command
+    spi_tx[0] = N25Q128_COMMAND_READ_ID;
+
+    // select, send command & read response, deselect
+    _n25q128_select(ctx);
+    ok = HAL_SPI_TransmitReceive(ctx->hspi, spi_tx, spi_rx, 4, N25Q128_SPI_TIMEOUT);
     _n25q128_deselect(ctx);
 
     // check
     if (ok != HAL_OK) return 0;
 
+    // parse response (note, that the very first byte was received during the
+    // transfer of the command byte, so it contains garbage and should
+    // be ignored here)
+    if (spi_rx[1] != N25Q128_ID_MANUFACTURER) return 0;
+    if (spi_rx[2] != N25Q128_ID_DEVICE_TYPE) return 0;
+    if (spi_rx[3] != N25Q128_ID_DEVICE_CAPACITY) return 0;
+
     // done
     return 1;
 }
@@ -139,28 +177,16 @@ int n25q128_write_page(struct spiflash_ctx *ctx, uint32_t page_offset, const uin
     if (page_offset >= N25Q128_NUM_PAGES) return 0;
 
     // enable writing
-    spi_tx[0] = N25Q128_COMMAND_WRITE_ENABLE;
-
-    // activate, send command, deselect
-    _n25q128_select(ctx);
-    ok = HAL_SPI_Transmit(ctx->hspi, spi_tx, 1, N25Q128_SPI_TIMEOUT);
-    _n25q128_deselect(ctx);
-
-    // check
-    if (ok != HAL_OK) return 0;
-
-    // make sure, that write enable did the job
-    int wel = _n25q128_get_wel_flag(ctx);
-    if (wel != 1) return 0;
+    if (_n25q128_write_enable(ctx) != 1) return 0;
 
     // calculate byte address
-    page_offset *= N25Q128_PAGE_SIZE;
+    uint32_t byte_offset = page_offset * N25Q128_PAGE_SIZE;
 
     // prepare PROGRAM PAGE command
     spi_tx[0] = N25Q128_COMMAND_PAGE_PROGRAM;
-    spi_tx[1] = (uint8_t)(page_offset >> 16);
-    spi_tx[2] = (uint8_t)(page_offset >>  8);
-    spi_tx[3] = (uint8_t)(page_offset >>  0);
+    spi_tx[1] = (uint8_t)(byte_offset >> 16);
+    spi_tx[2] = (uint8_t)(byte_offset >>  8);
+    spi_tx[3] = (uint8_t)(byte_offset >>  0);
 
     // activate, send command
     _n25q128_select(ctx);
@@ -180,52 +206,13 @@ int n25q128_write_page(struct spiflash_ctx *ctx, uint32_t page_offset, const uin
     if (ok != HAL_OK) return 0;
 
     // wait until write finishes
-    if (! _wait_while_wip(ctx, 1000)) return 0;
+    if (! _n25q128_wait_while_wip(ctx, 1000)) return 0;
 
     // done
     return 1;
 }
 
 
-static int n25q128_get_wip_flag(struct spiflash_ctx *ctx)
-{
-    // tx, rx buffers
-    uint8_t spi_tx[2];
-    uint8_t spi_rx[2];
-
-    // result
-    HAL_StatusTypeDef ok;
-
-    // send READ STATUS command
-    spi_tx[0] = N25Q128_COMMAND_READ_STATUS;
-
-    // send command, read response, deselect
-    _n25q128_select(ctx);
-    ok = HAL_SPI_TransmitReceive(ctx->hspi, spi_tx, spi_rx, 2, N25Q128_SPI_TIMEOUT);
-    _n25q128_deselect(ctx);
-
-    // check
-    if (ok != HAL_OK) return -1;
-
-    // done
-    return (spi_rx[1] & 1);
-}
-
-/* Wait until the flash memory is done writing (wip = Write In Progress) */
-static int _wait_while_wip(struct spiflash_ctx *ctx, uint32_t timeout)
-{
-    uint32_t tick_end = HAL_GetTick() + timeout;
-    int i;
-
-    do {
-	i = n25q128_get_wip_flag(ctx);
-	if (i < 0) return 0;
-	if (! i) return 1;
-    } while (HAL_GetTick() < tick_end);
-
-    return 0;
-}
-
 static int n25q128_erase_something(struct spiflash_ctx *ctx, uint8_t command, uint32_t byte_offset)
 {
     // check offset
@@ -238,19 +225,7 @@ static int n25q128_erase_something(struct spiflash_ctx *ctx, uint8_t command, ui
     HAL_StatusTypeDef ok;
 
     // enable writing
-    spi_tx[0] = N25Q128_COMMAND_WRITE_ENABLE;
-
-    // select, send command, deselect
-    _n25q128_select(ctx);
-    ok = HAL_SPI_Transmit(ctx->hspi, spi_tx, 1, N25Q128_SPI_TIMEOUT);
-    _n25q128_deselect(ctx);
-
-    // check
-    if (ok != HAL_OK) return 0;
-
-    // make sure, that write enable did the job
-    int wel = _n25q128_get_wel_flag(ctx);
-    if (wel != 1) return 0;
+    if (_n25q128_write_enable(ctx) != 1) return 0;
 
     // send command (ERASE SECTOR or ERASE SUBSECTOR)
     spi_tx[0] = command;
@@ -268,7 +243,7 @@ static int n25q128_erase_something(struct spiflash_ctx *ctx, uint8_t command, ui
 
     // wait for erase to finish
 
-    if (! _wait_while_wip(ctx, 1000)) return 0;
+    if (! _n25q128_wait_while_wip(ctx, 1000)) return 0;
 
     // done
     return 1;
@@ -298,19 +273,7 @@ int n25q128_erase_bulk(struct spiflash_ctx *ctx)
     HAL_StatusTypeDef ok;
 
     // enable writing
-    spi_tx[0] = N25Q128_COMMAND_WRITE_ENABLE;
-
-    // select, send command, deselect
-    _n25q128_select(ctx);
-    ok = HAL_SPI_Transmit(ctx->hspi, spi_tx, 1, N25Q128_SPI_TIMEOUT);
-    _n25q128_deselect(ctx);
-
-    // check
-    if (ok != HAL_OK) return 0;
-
-    // make sure, that write enable did the job
-    int wel = _n25q128_get_wel_flag(ctx);
-    if (wel != 1) return 0;
+    if (_n25q128_write_enable(ctx) != 1) return 0;
 
     // send command
     spi_tx[0] = N25Q128_COMMAND_ERASE_BULK;
@@ -325,41 +288,13 @@ int n25q128_erase_bulk(struct spiflash_ctx *ctx)
 
     // wait for erase to finish
 
-    if (! _wait_while_wip(ctx, 60000)) return 0;
+    if (! _n25q128_wait_while_wip(ctx, 60000)) return 0;
 
     // done
     return 1;
 }
 
 
-/*
- * Read the Write Enable Latch bit in the status register.
- */
-static int _n25q128_get_wel_flag(struct spiflash_ctx *ctx)
-{
-    // tx, rx buffers
-    uint8_t spi_tx[2];
-    uint8_t spi_rx[2];
-
-    // result
-    HAL_StatusTypeDef ok;
-
-    // send READ STATUS command
-    spi_tx[0] = N25Q128_COMMAND_READ_STATUS;
-
-    // send command, read response, deselect
-    _n25q128_select(ctx);
-    ok = HAL_SPI_TransmitReceive(ctx->hspi, spi_tx, spi_rx, 2, N25Q128_SPI_TIMEOUT);
-    _n25q128_deselect(ctx);
-
-    // check
-    if (ok != HAL_OK) return -1;
-
-    // done
-    return ((spi_rx[1] >> 1) & 1);
-}
-
-
 /* This function writes of a number of pages to the flash memory.
  * The caller is responsible for ensuring that the pages have been erased.
  */
@@ -367,7 +302,24 @@ int n25q128_write_data(struct spiflash_ctx *ctx, uint32_t offset, const uint8_t
 {
     uint32_t page;
 
-    /* Ensure alignment */
+    /*
+     * The data sheet says:
+     * If the bits of the least significant address, which is the starting
+     * address, are not all zero, all data transmitted beyond the end of the
+     * current page is programmed from the starting address of the same page.
+     * If the number of bytes sent to the device exceed the maximum page size,
+     * previously latched data is discarded and only the last maximum
+     * page-size number of data bytes are guaranteed to be programmed
+     * correctly within the same page. If the number of bytes sent to the
+     * device is less than the maximum page size, they are correctly
+     * programmed at the specified addresses without any effect on the other
+     * bytes of the same page.
+     *
+     * This is sufficiently confusing that it makes sense to constrain the API
+     * to page alignment in address and length, because that's how we're using
+     * it anyway.
+     */
+
     if ((offset % N25Q128_PAGE_SIZE) != 0) return -1;
     if ((len % N25Q128_PAGE_SIZE) != 0) return -2;
 
@@ -377,10 +329,6 @@ int n25q128_write_data(struct spiflash_ctx *ctx, uint32_t offset, const uint8_t
 	}
 	buf += N25Q128_PAGE_SIZE;
 	offset += N25Q128_PAGE_SIZE;
-
-	/* XXX read back data and verify it, or maybe just verify ability to write
-	 * to memory by verifying the contents of one page after erase?
-	 */
     }
 
     return 1;
@@ -389,19 +337,50 @@ int n25q128_write_data(struct spiflash_ctx *ctx, uint32_t offset, const uint8_t
 /* This function reads zero or more pages from the SPI flash. */
 int n25q128_read_data(struct spiflash_ctx *ctx, uint32_t offset, uint8_t *buf, const uint32_t len)
 {
-    uint32_t page;
+    // tx buffer
+    uint8_t spi_tx[4];
 
-    /* Ensure alignment */
-    if ((offset % N25Q128_PAGE_SIZE) != 0) return -1;
-    if ((len % N25Q128_PAGE_SIZE) != 0) return -2;
+    // result
+    HAL_StatusTypeDef ok;
 
-    for (page = 0; page < len / N25Q128_PAGE_SIZE; page++) {
-	if (! n25q128_read_page(ctx, offset / N25Q128_PAGE_SIZE, buf)) {
-	    return -3;
-	}
-	buf += N25Q128_PAGE_SIZE;
-	offset += N25Q128_PAGE_SIZE;
+    /*
+     * The data sheet says:
+     * The addressed byte can be at any location, and the address
+     * automatically increments to the next address after each byte of data is
+     * shifted out; therefore, the entire memory can be read with a single
+     * command. The operation is terminated by driving S# [chip select] HIGH
+     * at any time during data output.
+     *
+     * We're only going to call this with page-aligned address and length, but
+     * we're not going to enforce it here.
+     */
+
+    // avoid overflow
+    if (offset + len > N25Q128_NUM_BYTES) return -3;
+
+    // prepare READ command
+    spi_tx[0] = N25Q128_COMMAND_READ;
+    spi_tx[1] = (uint8_t)(offset >> 16);
+    spi_tx[2] = (uint8_t)(offset >>  8);
+    spi_tx[3] = (uint8_t)(offset >>  0);
+
+    // activate, send command
+    _n25q128_select(ctx);
+    ok = HAL_SPI_Transmit(ctx->hspi, spi_tx, 4, N25Q128_SPI_TIMEOUT);
+
+    // check
+    if (ok != HAL_OK) {
+	_n25q128_deselect(ctx);
+	return 0;
     }
 
+    // read response, deselect
+    ok = HAL_SPI_Receive(ctx->hspi, buf, len, N25Q128_SPI_TIMEOUT);
+    _n25q128_deselect(ctx);
+
+    // check
+    if (ok != HAL_OK) return 0;
+
+    // done
     return 1;
 }
diff --git a/spiflash_n25q128.h b/spiflash_n25q128.h
index ff14c34..50243bd 100644
--- a/spiflash_n25q128.h
+++ b/spiflash_n25q128.h
@@ -6,7 +6,7 @@
  * The Alpha board has two of these SPI flash memorys, the FPGA config memory
  * and the keystore memory.
  *
- * Copyright (c) 2016, NORDUnet A/S All rights reserved.
+ * Copyright (c) 2016-2017, NORDUnet A/S All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -40,9 +40,9 @@
 
 #include "stm32f4xx_hal.h"
 
-#define N25Q128_COMMAND_READ_ID		0x9E
-#define N25Q128_COMMAND_READ_PAGE	0x03
+#define N25Q128_COMMAND_READ		0x03
 #define N25Q128_COMMAND_READ_STATUS	0x05
+#define N25Q128_COMMAND_READ_ID		0x9E
 #define N25Q128_COMMAND_WRITE_ENABLE	0x06
 #define N25Q128_COMMAND_ERASE_SECTOR	0xD8
 #define N25Q128_COMMAND_ERASE_SUBSECTOR	0x20
@@ -71,12 +71,16 @@ struct spiflash_ctx {
 };
 
 extern int n25q128_check_id(struct spiflash_ctx *ctx);
-extern int n25q128_read_page(struct spiflash_ctx *ctx, uint32_t page_offset, uint8_t *page_buffer);
+extern int n25q128_read_data(struct spiflash_ctx *ctx, uint32_t offset, uint8_t *buf, const uint32_t len);
 extern int n25q128_write_page(struct spiflash_ctx *ctx, uint32_t page_offset, const uint8_t *page_buffer);
-extern int n25q128_erase_sector(struct spiflash_ctx *ctx, uint32_t sector_offset);
+extern int n25q128_write_data(struct spiflash_ctx *ctx, uint32_t offset, const uint8_t *buf, const uint32_t len);
 extern int n25q128_erase_subsector(struct spiflash_ctx *ctx, uint32_t subsector_offset);
+extern int n25q128_erase_sector(struct spiflash_ctx *ctx, uint32_t sector_offset);
 extern int n25q128_erase_bulk(struct spiflash_ctx *ctx);
 
-extern int n25q128_write_data(struct spiflash_ctx *ctx, uint32_t offset, const uint8_t *buf, const uint32_t len);
-extern int n25q128_read_data(struct spiflash_ctx *ctx, uint32_t offset, uint8_t *buf, const uint32_t len);
+#define n25q128_read_page(ctx, page_offset, page_buffer) \
+    n25q128_read_data(ctx, page_offset * N25Q128_PAGE_SIZE, page_buffer, N25Q128_PAGE_SIZE)
+#define n25q128_read_subsector(ctx, subsector_offset, subsector_buffer) \
+    n25q128_read_data(ctx, subsector_offset * N25Q128_SUBSECTOR_SIZE, subsector_buffer, N25Q128_SUBSECTOR_SIZE)
+
 #endif /* __STM32_SPIFLASH_N25Q128_H */
diff --git a/stm-flash.c b/stm-flash.c
index fc79ea0..4456f44 100644
--- a/stm-flash.c
+++ b/stm-flash.c
@@ -70,7 +70,7 @@ uint32_t flash_sector_offsets[FLASH_NUM_SECTORS + 1] = {
     0x08200000  /* first address *after* flash */
 };
 
-int stm_flash_sector_num(const uint32_t offset)
+static int stm_flash_sector_num(const uint32_t offset)
 {
     int i;
 
diff --git a/stm-flash.h b/stm-flash.h
index a9cf7db..aecb87f 100644
--- a/stm-flash.h
+++ b/stm-flash.h
@@ -35,7 +35,6 @@
 #ifndef __STM32_FLASH_H
 #define __STM32_FLASH_H
 
-extern int stm_flash_sector_num(const uint32_t offset);
 extern int stm_flash_erase_sectors(const uint32_t start_offset, const uint32_t end_offset);
 extern int stm_flash_write32(const uint32_t offset, const uint32_t *buf, const uint32_t elements);
 
diff --git a/stm-fpgacfg.c b/stm-fpgacfg.c
index 16c490b..10abc57 100644
--- a/stm-fpgacfg.c
+++ b/stm-fpgacfg.c
@@ -4,7 +4,7 @@
  * Functions for accessing the FPGA config memory and controlling
  * the low-level status of the FPGA (reset registers/reboot etc.).
  *
- * Copyright (c) 2016, NORDUnet A/S All rights reserved.
+ * Copyright (c) 2016-2017, NORDUnet A/S All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -48,11 +48,6 @@ int fpgacfg_check_id()
 
 int fpgacfg_write_data(uint32_t offset, const uint8_t *buf, const uint32_t len)
 {
-    if ((offset % N25Q128_SECTOR_SIZE) == 0)
-	// first page in sector, need to erase sector
-	if (! n25q128_erase_sector(&fpgacfg_ctx, offset / N25Q128_SECTOR_SIZE))
-	    return -4;
-
     return n25q128_write_data(&fpgacfg_ctx, offset, buf, len);
 }
 
@@ -97,14 +92,7 @@ int fpgacfg_check_done(void)
     return (status == GPIO_PIN_SET);
 }
 
-int fpgacfg_erase_sectors(int num)
+int fpgacfg_erase_sector(uint32_t sector_offset)
 {
-    if (num > N25Q128_NUM_SECTORS || num < 0) num = N25Q128_NUM_SECTORS;
-    while (num) {
-	if (! n25q128_erase_sector(&fpgacfg_ctx, num - 1)) {
-            return -1;
-        }
-	num--;
-    }
-    return 1;
+    return n25q128_erase_sector(&fpgacfg_ctx, sector_offset);
 }
diff --git a/stm-fpgacfg.h b/stm-fpgacfg.h
index 0d5eeb9..9baebc4 100644
--- a/stm-fpgacfg.h
+++ b/stm-fpgacfg.h
@@ -4,7 +4,7 @@
  * Functions and defines for accessing the FPGA config memory and controlling
  * the low-level status of the FPGA (reset registers/reboot etc.).
  *
- * Copyright (c) 2016, NORDUnet A/S All rights reserved.
+ * Copyright (c) 2016-2017, NORDUnet A/S All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -39,6 +39,8 @@
 #include "stm32f4xx_hal.h"
 #include "spiflash_n25q128.h"
 
+#define FPGACFG_SECTOR_SIZE		N25Q128_SECTOR_SIZE
+
 /* Pins connected to the FPGA config memory (SPI flash) */
 #define PROM_FPGA_DIS_Pin              GPIO_PIN_14
 #define PROM_FPGA_DIS_GPIO_Port        GPIOI
@@ -87,7 +89,7 @@ extern SPI_HandleTypeDef hspi_fpgacfg;
 
 extern int fpgacfg_check_id(void);
 extern int fpgacfg_write_data(uint32_t offset, const uint8_t *buf, const uint32_t len);
-extern int fpgacfg_erase_sectors(int num);
+extern int fpgacfg_erase_sector(uint32_t sector_offset);
 extern void fpgacfg_access_control(enum fpgacfg_access_ctrl access);
 /* Reset the FPGA */
 extern void fpgacfg_reset_fpga(enum fpgacfg_reset reset);
diff --git a/stm-keystore.c b/stm-keystore.c
index 86fad91..b941489 100644
--- a/stm-keystore.c
+++ b/stm-keystore.c
@@ -3,7 +3,7 @@
  * ----------
  * Functions for accessing the keystore memory.
  *
- * Copyright (c) 2016, NORDUnet A/S All rights reserved.
+ * Copyright (c) 2016-2017, NORDUnet A/S All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -55,35 +55,31 @@ int keystore_write_data(uint32_t offset, const uint8_t *buf, const uint32_t len)
     return n25q128_write_data(&keystore_ctx, offset, buf, len);
 }
 
-static int keystore_erase_something(uint32_t start, uint32_t stop, uint32_t limit,
-				    int (*eraser)(struct spiflash_ctx *, uint32_t))
+int keystore_erase_subsector(uint32_t subsector_offset)
 {
-    uint32_t something;
-
-    if (start > limit) return -2;
-    if (stop > limit || stop < start) return -3;
-
-    for (something = start; something <= stop; something++) {
-	if (! eraser(&keystore_ctx, something)) {
-            return -1;
-        }
-    }
-    return 1;
+    return n25q128_erase_subsector(&keystore_ctx, subsector_offset);
 }
 
-int keystore_erase_sectors(uint32_t start, uint32_t stop)
+int keystore_erase_sector(uint32_t sector_offset)
 {
-    return keystore_erase_something(start, stop, N25Q128_NUM_SECTORS,
-				    n25q128_erase_sector);
+    return n25q128_erase_sector(&keystore_ctx, sector_offset);
 }
 
-int keystore_erase_subsectors(uint32_t start, uint32_t stop)
+int keystore_erase_bulk(void)
 {
-    return keystore_erase_something(start, stop, N25Q128_NUM_SUBSECTORS,
-				    n25q128_erase_subsector);
+    return n25q128_erase_bulk(&keystore_ctx);
 }
 
-int keystore_erase_bulk(void)
+/*
+ * Deprecated, will be removed when we fix libhal/ks_flash.c to use the
+ * new function. I love inter-dependent repos.
+ */
+
+int keystore_erase_subsectors(uint32_t start, uint32_t stop)
 {
-    return n25q128_erase_bulk(&keystore_ctx);
+    for (int i = start; i <= stop; ++i) {
+        if (keystore_erase_subsector(i) != 1)
+            return 0;
+    }
+    return 1;
 }
diff --git a/stm-keystore.h b/stm-keystore.h
index f27687a..419e12e 100644
--- a/stm-keystore.h
+++ b/stm-keystore.h
@@ -3,7 +3,7 @@
  * ---------
  * Functions and defines for accessing the keystore memory.
  *
- * Copyright (c) 2016, NORDUnet A/S All rights reserved.
+ * Copyright (c) 2016-2017, NORDUnet A/S All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are
@@ -60,8 +60,11 @@ extern SPI_HandleTypeDef hspi_keystore;
 extern int keystore_check_id(void);
 extern int keystore_read_data(uint32_t offset, uint8_t *buf, const uint32_t len);
 extern int keystore_write_data(uint32_t offset, const uint8_t *buf, const uint32_t len);
-extern int keystore_erase_sectors(uint32_t start, uint32_t stop);
-extern int keystore_erase_subsectors(uint32_t start, uint32_t stop);
+extern int keystore_erase_subsector(uint32_t subsector_offset);
+extern int keystore_erase_sector(uint32_t sector_offset);
 extern int keystore_erase_bulk(void);
 
+/* Deprecated, will be removed. */
+extern int keystore_erase_subsectors(uint32_t start, uint32_t stop);
+
 #endif /* __STM32_KEYSTORE_H */



More information about the Commits mailing list