vpnor: implement init_flash_dev
The vpnor version needs to set the erase block size as 4K.
That's the size hostboot expects in the FFS structure.
This change also requires moving code from mboxd_flash.c to
mboxd_flash_physical.c, else there will be 3 symbols per flash function.
It should suffice to just have mboxd_flash_physical.c and
mboxd_flash_virtual.cpp.
Change-Id: I35442a0c1dbee7f66b278cbf094be78e870b6c86
Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
diff --git a/Makefile.am b/Makefile.am
index 4e59529..59146ba 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5,7 +5,6 @@
mboxd.c \
common.c \
mboxd_dbus.c \
- mboxd_flash.c \
mboxd_lpc.c \
mboxd_msg.c \
mboxd_windows.c \
@@ -42,21 +41,18 @@
test_copy_flash_SOURCES = \
test/copy_flash.c \
- mboxd_flash.c \
mboxd_flash_physical.c \
common.c mtd.c \
test/tmpf.c
test_erase_flash_SOURCES = \
test/erase_flash.c \
- mboxd_flash.c \
mboxd_flash_physical.c \
common.c \
test/tmpf.c
test_write_flash_SOURCES = \
test/write_flash.c \
- mboxd_flash.c \
mboxd_flash_physical.c \
common.c \
test/tmpf.c
@@ -65,7 +61,6 @@
mboxd_msg.c \
mboxd_windows.c \
mboxd_lpc.c \
- mboxd_flash.c \
common.c \
mboxd_flash_physical.c
@@ -153,7 +148,6 @@
mboxd_msg.c \
mboxd_windows.c \
mboxd_lpc.c \
- mboxd_flash.c \
mboxd_pnor_partition_table.cpp \
mboxd_flash_virtual.cpp \
pnor_partition.cpp \
@@ -166,7 +160,6 @@
test_write_flash_vpnor_SOURCES = \
$(TEST_MBOX_VPNOR_SRCS) \
- mboxd_flash.c \
mboxd_pnor_partition_table.cpp \
mboxd_flash_virtual.cpp \
mtd.c \
diff --git a/mboxd_flash.c b/mboxd_flash.c
deleted file mode 100644
index 4b6c1f7..0000000
--- a/mboxd_flash.c
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * Mailbox Daemon Flash Helpers
- *
- * Copyright 2016 IBM
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-#define _GNU_SOURCE
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <getopt.h>
-#include <limits.h>
-#include <poll.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <signal.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-#include <sys/timerfd.h>
-#include <sys/types.h>
-#include <time.h>
-#include <unistd.h>
-#include <inttypes.h>
-#include <mtd/mtd-abi.h>
-
-#include "mbox.h"
-#include "common.h"
-#include "mboxd_flash.h"
-
-int init_flash_dev(struct mbox_context *context)
-{
- char *filename = get_dev_mtd();
- int fd, rc = 0;
-
- if (!filename) {
- MSG_ERR("Couldn't find the PNOR /dev/mtd partition\n");
- return -1;
- }
-
- MSG_DBG("Opening %s\n", filename);
-
- /* Open Flash Device */
- fd = open(filename, O_RDWR);
- if (fd < 0) {
- MSG_ERR("Couldn't open %s with flags O_RDWR: %s\n",
- filename, strerror(errno));
- rc = -errno;
- goto out;
- }
- context->fds[MTD_FD].fd = fd;
-
- /* Read the Flash Info */
- if (ioctl(fd, MEMGETINFO, &context->mtd_info) == -1) {
- MSG_ERR("Couldn't get information about MTD: %s\n",
- strerror(errno));
- rc = -1;
- goto out;
- }
-
- if (context->flash_size == 0) {
- /*
- * PNOR images for current OpenPOWER systems are at most 64MB
- * despite the PNOR itself sometimes being as big as 128MB. To
- * ensure the image read from the PNOR is exposed in the LPC
- * address space at the location expected by the host firmware,
- * it is required that the image size be used for
- * context->flash_size, and not the size of the flash device.
- *
- * However, the test cases specify the flash size via special
- * test APIs (controlling flash behaviour) which don't have
- * access to the mbox context. Rather than requiring
- * error-prone assignments in every test case, we instead rely
- * on context->flash_size being set to the size reported by the
- * MEMINFO ioctl().
- *
- * As this case should never be hit in production (i.e. outside
- * the test environment), log an error. As a consequence, this
- * error is expected in the test case output.
- */
- MSG_ERR("Flash size MUST be supplied on the commandline. However, continuing by assuming flash is %u bytes\n",
- context->mtd_info.size);
- context->flash_size = context->mtd_info.size;
- }
-
- /* We know the erase size so we can allocate the flash_erased bytemap */
- context->erase_size_shift = log_2(context->mtd_info.erasesize);
- context->flash_bmap = calloc(context->flash_size >>
- context->erase_size_shift,
- sizeof(*context->flash_bmap));
- MSG_DBG("Flash erase size: 0x%.8x\n", context->mtd_info.erasesize);
-
-out:
- free(filename);
- return rc;
-}
-
-void free_flash_dev(struct mbox_context *context)
-{
- free(context->flash_bmap);
- close(context->fds[MTD_FD].fd);
-}
-
-/* Flash Functions */
-
-/*
- * flash_is_erased() - Check if an offset into flash is erased
- * @context: The mbox context pointer
- * @offset: The flash offset to check (bytes)
- *
- * Return: true if erased otherwise false
- */
-static inline bool flash_is_erased(struct mbox_context *context,
- uint32_t offset)
-{
- return context->flash_bmap[offset >> context->erase_size_shift]
- == FLASH_ERASED;
-}
-
-/*
- * set_flash_bytemap() - Set the flash erased bytemap
- * @context: The mbox context pointer
- * @offset: The flash offset to set (bytes)
- * @count: Number of bytes to set
- * @val: Value to set the bytemap to
- *
- * The flash bytemap only tracks the erased status at the erase block level so
- * this will update the erased state for an (or many) erase blocks
- *
- * Return: 0 if success otherwise negative error code
- */
-int set_flash_bytemap(struct mbox_context *context, uint32_t offset,
- uint32_t count, uint8_t val)
-{
- if ((offset + count) > context->flash_size) {
- return -MBOX_R_PARAM_ERROR;
- }
-
- MSG_DBG("Set flash bytemap @ 0x%.8x for 0x%.8x to %s\n",
- offset, count, val ? "ERASED" : "DIRTY");
- memset(context->flash_bmap + (offset >> context->erase_size_shift),
- val,
- align_up(count, 1 << context->erase_size_shift) >>
- context->erase_size_shift);
-
- return 0;
-}
-
-/*
- * erase_flash() - Erase the flash
- * @context: The mbox context pointer
- * @offset: The flash offset to erase (bytes)
- * @size: The number of bytes to erase
- *
- * Return: 0 on success otherwise negative error code
- */
-int erase_flash(struct mbox_context *context, uint32_t offset, uint32_t count)
-{
- const uint32_t erase_size = 1 << context->erase_size_shift;
- struct erase_info_user erase_info = { 0 };
- int rc;
-
- MSG_DBG("Erase flash @ 0x%.8x for 0x%.8x\n", offset, count);
-
- /*
- * We have an erased_bytemap for the flash so we want to avoid erasing
- * blocks which we already know to be erased. Look for runs of blocks
- * which aren't erased and erase the entire run at once to avoid how
- * often we have to call the erase ioctl. If the block is already
- * erased then there's nothing we need to do.
- */
- while (count) {
- if (!flash_is_erased(context, offset)) { /* Need to erase */
- if (!erase_info.length) { /* Start of not-erased run */
- erase_info.start = offset;
- }
- erase_info.length += erase_size;
- } else if (erase_info.length) { /* Already erased|end of run? */
- /* Erase the previous run which just ended */
- MSG_DBG("Erase flash @ 0x%.8x for 0x%.8x\n",
- erase_info.start, erase_info.length);
- rc = ioctl(context->fds[MTD_FD].fd, MEMERASE,
- &erase_info);
- if (rc < 0) {
- MSG_ERR("Couldn't erase flash at 0x%.8x\n",
- erase_info.start);
- return -MBOX_R_SYSTEM_ERROR;
- }
- /* Mark ERASED where we just erased */
- set_flash_bytemap(context, erase_info.start,
- erase_info.length, FLASH_ERASED);
- erase_info.start = 0;
- erase_info.length = 0;
- }
-
- offset += erase_size;
- count -= erase_size;
- }
-
- if (erase_info.length) {
- MSG_DBG("Erase flash @ 0x%.8x for 0x%.8x\n",
- erase_info.start, erase_info.length);
- rc = ioctl(context->fds[MTD_FD].fd, MEMERASE, &erase_info);
- if (rc < 0) {
- MSG_ERR("Couldn't erase flash at 0x%.8x\n",
- erase_info.start);
- return -MBOX_R_SYSTEM_ERROR;
- }
- /* Mark ERASED where we just erased */
- set_flash_bytemap(context, erase_info.start, erase_info.length,
- FLASH_ERASED);
- }
-
- return 0;
-}
diff --git a/mboxd_flash_physical.c b/mboxd_flash_physical.c
index 16f2363..55624d9 100644
--- a/mboxd_flash_physical.c
+++ b/mboxd_flash_physical.c
@@ -18,11 +18,27 @@
*/
#define _GNU_SOURCE
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <limits.h>
+#include <poll.h>
+#include <stdbool.h>
#include <stdint.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <syslog.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/timerfd.h>
#include <sys/types.h>
+#include <time.h>
#include <unistd.h>
+#include <inttypes.h>
#include <errno.h>
#include <mtd/mtd-abi.h>
@@ -30,6 +46,192 @@
#include "common.h"
#include "mboxd_flash.h"
+int init_flash_dev(struct mbox_context *context)
+{
+ char *filename = get_dev_mtd();
+ int fd, rc = 0;
+
+ if (!filename) {
+ MSG_ERR("Couldn't find the PNOR /dev/mtd partition\n");
+ return -1;
+ }
+
+ MSG_DBG("Opening %s\n", filename);
+
+ /* Open Flash Device */
+ fd = open(filename, O_RDWR);
+ if (fd < 0) {
+ MSG_ERR("Couldn't open %s with flags O_RDWR: %s\n",
+ filename, strerror(errno));
+ rc = -errno;
+ goto out;
+ }
+ context->fds[MTD_FD].fd = fd;
+
+ /* Read the Flash Info */
+ if (ioctl(fd, MEMGETINFO, &context->mtd_info) == -1) {
+ MSG_ERR("Couldn't get information about MTD: %s\n",
+ strerror(errno));
+ rc = -1;
+ goto out;
+ }
+
+ if (context->flash_size == 0) {
+ /*
+ * PNOR images for current OpenPOWER systems are at most 64MB
+ * despite the PNOR itself sometimes being as big as 128MB. To
+ * ensure the image read from the PNOR is exposed in the LPC
+ * address space at the location expected by the host firmware,
+ * it is required that the image size be used for
+ * context->flash_size, and not the size of the flash device.
+ *
+ * However, the test cases specify the flash size via special
+ * test APIs (controlling flash behaviour) which don't have
+ * access to the mbox context. Rather than requiring
+ * error-prone assignments in every test case, we instead rely
+ * on context->flash_size being set to the size reported by the
+ * MEMINFO ioctl().
+ *
+ * As this case should never be hit in production (i.e. outside
+ * the test environment), log an error. As a consequence, this
+ * error is expected in the test case output.
+ */
+ MSG_ERR("Flash size MUST be supplied on the commandline. However, continuing by assuming flash is %u bytes\n",
+ context->mtd_info.size);
+ context->flash_size = context->mtd_info.size;
+ }
+
+ /* We know the erase size so we can allocate the flash_erased bytemap */
+ context->erase_size_shift = log_2(context->mtd_info.erasesize);
+ context->flash_bmap = calloc(context->flash_size >>
+ context->erase_size_shift,
+ sizeof(*context->flash_bmap));
+ MSG_DBG("Flash erase size: 0x%.8x\n", context->mtd_info.erasesize);
+
+out:
+ free(filename);
+ return rc;
+}
+
+void free_flash_dev(struct mbox_context *context)
+{
+ free(context->flash_bmap);
+ close(context->fds[MTD_FD].fd);
+}
+
+/* Flash Functions */
+
+/*
+ * flash_is_erased() - Check if an offset into flash is erased
+ * @context: The mbox context pointer
+ * @offset: The flash offset to check (bytes)
+ *
+ * Return: true if erased otherwise false
+ */
+static inline bool flash_is_erased(struct mbox_context *context,
+ uint32_t offset)
+{
+ return context->flash_bmap[offset >> context->erase_size_shift]
+ == FLASH_ERASED;
+}
+
+/*
+ * set_flash_bytemap() - Set the flash erased bytemap
+ * @context: The mbox context pointer
+ * @offset: The flash offset to set (bytes)
+ * @count: Number of bytes to set
+ * @val: Value to set the bytemap to
+ *
+ * The flash bytemap only tracks the erased status at the erase block level so
+ * this will update the erased state for an (or many) erase blocks
+ *
+ * Return: 0 if success otherwise negative error code
+ */
+int set_flash_bytemap(struct mbox_context *context, uint32_t offset,
+ uint32_t count, uint8_t val)
+{
+ if ((offset + count) > context->flash_size) {
+ return -MBOX_R_PARAM_ERROR;
+ }
+
+ MSG_DBG("Set flash bytemap @ 0x%.8x for 0x%.8x to %s\n",
+ offset, count, val ? "ERASED" : "DIRTY");
+ memset(context->flash_bmap + (offset >> context->erase_size_shift),
+ val,
+ align_up(count, 1 << context->erase_size_shift) >>
+ context->erase_size_shift);
+
+ return 0;
+}
+
+/*
+ * erase_flash() - Erase the flash
+ * @context: The mbox context pointer
+ * @offset: The flash offset to erase (bytes)
+ * @size: The number of bytes to erase
+ *
+ * Return: 0 on success otherwise negative error code
+ */
+int erase_flash(struct mbox_context *context, uint32_t offset, uint32_t count)
+{
+ const uint32_t erase_size = 1 << context->erase_size_shift;
+ struct erase_info_user erase_info = { 0 };
+ int rc;
+
+ MSG_DBG("Erase flash @ 0x%.8x for 0x%.8x\n", offset, count);
+
+ /*
+ * We have an erased_bytemap for the flash so we want to avoid erasing
+ * blocks which we already know to be erased. Look for runs of blocks
+ * which aren't erased and erase the entire run at once to avoid how
+ * often we have to call the erase ioctl. If the block is already
+ * erased then there's nothing we need to do.
+ */
+ while (count) {
+ if (!flash_is_erased(context, offset)) { /* Need to erase */
+ if (!erase_info.length) { /* Start of not-erased run */
+ erase_info.start = offset;
+ }
+ erase_info.length += erase_size;
+ } else if (erase_info.length) { /* Already erased|end of run? */
+ /* Erase the previous run which just ended */
+ MSG_DBG("Erase flash @ 0x%.8x for 0x%.8x\n",
+ erase_info.start, erase_info.length);
+ rc = ioctl(context->fds[MTD_FD].fd, MEMERASE,
+ &erase_info);
+ if (rc < 0) {
+ MSG_ERR("Couldn't erase flash at 0x%.8x\n",
+ erase_info.start);
+ return -MBOX_R_SYSTEM_ERROR;
+ }
+ /* Mark ERASED where we just erased */
+ set_flash_bytemap(context, erase_info.start,
+ erase_info.length, FLASH_ERASED);
+ erase_info.start = 0;
+ erase_info.length = 0;
+ }
+
+ offset += erase_size;
+ count -= erase_size;
+ }
+
+ if (erase_info.length) {
+ MSG_DBG("Erase flash @ 0x%.8x for 0x%.8x\n",
+ erase_info.start, erase_info.length);
+ rc = ioctl(context->fds[MTD_FD].fd, MEMERASE, &erase_info);
+ if (rc < 0) {
+ MSG_ERR("Couldn't erase flash at 0x%.8x\n",
+ erase_info.start);
+ return -MBOX_R_SYSTEM_ERROR;
+ }
+ /* Mark ERASED where we just erased */
+ set_flash_bytemap(context, erase_info.start, erase_info.length,
+ FLASH_ERASED);
+ }
+
+ return 0;
+}
+
#define CHUNKSIZE (64 * 1024)
/*
diff --git a/mboxd_flash_virtual.cpp b/mboxd_flash_virtual.cpp
index 3c83f02..6e3af71 100644
--- a/mboxd_flash_virtual.cpp
+++ b/mboxd_flash_virtual.cpp
@@ -23,6 +23,7 @@
#include <syslog.h>
#include <sys/mman.h>
#include <unistd.h>
+#include <sys/ioctl.h>
extern "C" {
#include "common.h"
@@ -36,10 +37,87 @@
#include <phosphor-logging/log.hpp>
#include <phosphor-logging/elog-errors.hpp>
+#include <memory>
#include <string>
#include <exception>
#include <stdexcept>
+/** @brief unique_ptr functor to release a char* reference. */
+struct StringDeleter
+{
+ void operator()(char* ptr) const
+ {
+ free(ptr);
+ }
+};
+using StringPtr = std::unique_ptr<char, StringDeleter>;
+
+int init_flash_dev(struct mbox_context *context)
+{
+ StringPtr filename(get_dev_mtd());
+ int fd = 0;
+ int rc = 0;
+
+ if (!filename)
+ {
+ MSG_ERR("Couldn't find the flash /dev/mtd partition\n");
+ return -1;
+ }
+
+ MSG_DBG("Opening %s\n", filename.get());
+
+ fd = open(filename.get(), O_RDWR);
+ if (fd < 0)
+ {
+ MSG_ERR("Couldn't open %s with flags O_RDWR: %s\n",
+ filename.get(), strerror(errno));
+ return -errno;
+ }
+
+ // Read the Flash Info
+ if (ioctl(fd, MEMGETINFO, &context->mtd_info) == -1)
+ {
+ MSG_ERR("Couldn't get information about MTD: %s\n",
+ strerror(errno));
+ close(fd);
+ return -errno;
+ }
+
+ if (context->flash_size == 0)
+ {
+ // See comment in mboxd_flash_physical.c on why
+ // this is needed.
+ context->flash_size = context->mtd_info.size;
+ }
+
+ // Hostboot requires a 4K block-size to be used in the FFS flash structure
+ context->mtd_info.erasesize = 4096;
+ context->erase_size_shift = log_2(context->mtd_info.erasesize);
+ context->flash_bmap = NULL;
+ context->fds[MTD_FD].fd = -1;
+
+ close(fd);
+ return rc;
+}
+
+void free_flash_dev(struct mbox_context *context)
+{
+ // No-op
+}
+
+int set_flash_bytemap(struct mbox_context *context, uint32_t offset,
+ uint32_t count, uint8_t val)
+{
+ // No-op
+ return 0;
+}
+
+int erase_flash(struct mbox_context *context, uint32_t offset, uint32_t count)
+{
+ // No-op
+ return 0;
+}
+
/*
* copy_flash() - Copy data from the virtual pnor into a provided buffer
* @context: The mbox context pointer