153c21aaaSAndrew Jeffery // SPDX-License-Identifier: Apache-2.0
253c21aaaSAndrew Jeffery // Copyright (C) 2018 IBM Corp.
353c21aaaSAndrew Jeffery
453c21aaaSAndrew Jeffery #include <fcntl.h>
553c21aaaSAndrew Jeffery #include <stdint.h>
653c21aaaSAndrew Jeffery #include <stdlib.h>
753c21aaaSAndrew Jeffery #include <syslog.h>
853c21aaaSAndrew Jeffery #include <sys/mman.h>
953c21aaaSAndrew Jeffery #include <unistd.h>
1053c21aaaSAndrew Jeffery #include <sys/ioctl.h>
1153c21aaaSAndrew Jeffery #include <algorithm>
1253c21aaaSAndrew Jeffery
1353c21aaaSAndrew Jeffery extern "C" {
1453c21aaaSAndrew Jeffery #include "common.h"
1553c21aaaSAndrew Jeffery }
1653c21aaaSAndrew Jeffery
1753c21aaaSAndrew Jeffery #include "config.h"
1853c21aaaSAndrew Jeffery #include "mboxd_flash.h"
1953c21aaaSAndrew Jeffery #include "mboxd_pnor_partition_table.h"
2053c21aaaSAndrew Jeffery #include "pnor_partition.hpp"
2153c21aaaSAndrew Jeffery #include "pnor_partition_table.hpp"
2253c21aaaSAndrew Jeffery #include "xyz/openbmc_project/Common/error.hpp"
2353c21aaaSAndrew Jeffery #include <phosphor-logging/log.hpp>
2453c21aaaSAndrew Jeffery #include <phosphor-logging/elog-errors.hpp>
2553c21aaaSAndrew Jeffery
2653c21aaaSAndrew Jeffery #include <memory>
2753c21aaaSAndrew Jeffery #include <string>
2853c21aaaSAndrew Jeffery #include <exception>
2953c21aaaSAndrew Jeffery #include <stdexcept>
3053c21aaaSAndrew Jeffery
3153c21aaaSAndrew Jeffery namespace err = sdbusplus::xyz::openbmc_project::Common::Error;
3253c21aaaSAndrew Jeffery namespace fs = std::experimental::filesystem;
3353c21aaaSAndrew Jeffery namespace vpnor = openpower::virtual_pnor;
3453c21aaaSAndrew Jeffery
3553c21aaaSAndrew Jeffery /** @brief unique_ptr functor to release a char* reference. */
3653c21aaaSAndrew Jeffery struct StringDeleter
3753c21aaaSAndrew Jeffery {
operator ()StringDeleter3853c21aaaSAndrew Jeffery void operator()(char* ptr) const
3953c21aaaSAndrew Jeffery {
4053c21aaaSAndrew Jeffery free(ptr);
4153c21aaaSAndrew Jeffery }
4253c21aaaSAndrew Jeffery };
4353c21aaaSAndrew Jeffery using StringPtr = std::unique_ptr<char, StringDeleter>;
4453c21aaaSAndrew Jeffery
init_flash_dev(struct mbox_context * context)4553c21aaaSAndrew Jeffery int init_flash_dev(struct mbox_context* context)
4653c21aaaSAndrew Jeffery {
4753c21aaaSAndrew Jeffery StringPtr filename(get_dev_mtd());
4853c21aaaSAndrew Jeffery int fd = 0;
4953c21aaaSAndrew Jeffery int rc = 0;
5053c21aaaSAndrew Jeffery
5153c21aaaSAndrew Jeffery if (!filename)
5253c21aaaSAndrew Jeffery {
5353c21aaaSAndrew Jeffery MSG_ERR("Couldn't find the flash /dev/mtd partition\n");
5453c21aaaSAndrew Jeffery return -1;
5553c21aaaSAndrew Jeffery }
5653c21aaaSAndrew Jeffery
5753c21aaaSAndrew Jeffery MSG_DBG("Opening %s\n", filename.get());
5853c21aaaSAndrew Jeffery
5953c21aaaSAndrew Jeffery fd = open(filename.get(), O_RDWR);
6053c21aaaSAndrew Jeffery if (fd < 0)
6153c21aaaSAndrew Jeffery {
6253c21aaaSAndrew Jeffery MSG_ERR("Couldn't open %s with flags O_RDWR: %s\n", filename.get(),
6353c21aaaSAndrew Jeffery strerror(errno));
6453c21aaaSAndrew Jeffery return -errno;
6553c21aaaSAndrew Jeffery }
6653c21aaaSAndrew Jeffery
6753c21aaaSAndrew Jeffery // Read the Flash Info
6853c21aaaSAndrew Jeffery if (ioctl(fd, MEMGETINFO, &context->mtd_info) == -1)
6953c21aaaSAndrew Jeffery {
7053c21aaaSAndrew Jeffery MSG_ERR("Couldn't get information about MTD: %s\n", strerror(errno));
7153c21aaaSAndrew Jeffery close(fd);
7253c21aaaSAndrew Jeffery return -errno;
7353c21aaaSAndrew Jeffery }
7453c21aaaSAndrew Jeffery
7553c21aaaSAndrew Jeffery if (context->flash_size == 0)
7653c21aaaSAndrew Jeffery {
7753c21aaaSAndrew Jeffery // See comment in mboxd_flash_physical.c on why
7853c21aaaSAndrew Jeffery // this is needed.
7953c21aaaSAndrew Jeffery context->flash_size = context->mtd_info.size;
8053c21aaaSAndrew Jeffery }
8153c21aaaSAndrew Jeffery
8253c21aaaSAndrew Jeffery // Hostboot requires a 4K block-size to be used in the FFS flash structure
8353c21aaaSAndrew Jeffery context->mtd_info.erasesize = 4096;
8453c21aaaSAndrew Jeffery context->erase_size_shift = log_2(context->mtd_info.erasesize);
8553c21aaaSAndrew Jeffery context->flash_bmap = NULL;
8653c21aaaSAndrew Jeffery context->fds[MTD_FD].fd = -1;
8753c21aaaSAndrew Jeffery
8853c21aaaSAndrew Jeffery close(fd);
8953c21aaaSAndrew Jeffery return rc;
9053c21aaaSAndrew Jeffery }
9153c21aaaSAndrew Jeffery
free_flash_dev(struct mbox_context * context)9253c21aaaSAndrew Jeffery void free_flash_dev(struct mbox_context* context)
9353c21aaaSAndrew Jeffery {
9453c21aaaSAndrew Jeffery // No-op
9553c21aaaSAndrew Jeffery }
9653c21aaaSAndrew Jeffery
set_flash_bytemap(struct mbox_context * context,uint32_t offset,uint32_t count,uint8_t val)9753c21aaaSAndrew Jeffery int set_flash_bytemap(struct mbox_context* context, uint32_t offset,
9853c21aaaSAndrew Jeffery uint32_t count, uint8_t val)
9953c21aaaSAndrew Jeffery {
10053c21aaaSAndrew Jeffery // No-op
10153c21aaaSAndrew Jeffery return 0;
10253c21aaaSAndrew Jeffery }
10353c21aaaSAndrew Jeffery
erase_flash(struct mbox_context * context,uint32_t offset,uint32_t count)10453c21aaaSAndrew Jeffery int erase_flash(struct mbox_context* context, uint32_t offset, uint32_t count)
10553c21aaaSAndrew Jeffery {
10653c21aaaSAndrew Jeffery // No-op
10753c21aaaSAndrew Jeffery return 0;
10853c21aaaSAndrew Jeffery }
10953c21aaaSAndrew Jeffery
11053c21aaaSAndrew Jeffery /*
11153c21aaaSAndrew Jeffery * copy_flash() - Copy data from the virtual pnor into a provided buffer
11253c21aaaSAndrew Jeffery * @context: The mbox context pointer
11353c21aaaSAndrew Jeffery * @offset: The pnor offset to copy from (bytes)
11453c21aaaSAndrew Jeffery * @mem: The buffer to copy into (must be of atleast 'size' bytes)
11553c21aaaSAndrew Jeffery * @size: The number of bytes to copy
11653c21aaaSAndrew Jeffery * Return: Number of bytes copied on success, otherwise negative error
11753c21aaaSAndrew Jeffery * code. copy_flash will copy at most 'size' bytes, but it may
11853c21aaaSAndrew Jeffery * copy less.
11953c21aaaSAndrew Jeffery */
copy_flash(struct mbox_context * context,uint32_t offset,void * mem,uint32_t size)12053c21aaaSAndrew Jeffery int64_t copy_flash(struct mbox_context* context, uint32_t offset, void* mem,
12153c21aaaSAndrew Jeffery uint32_t size)
12253c21aaaSAndrew Jeffery {
12353c21aaaSAndrew Jeffery vpnor::partition::Table* table;
12453c21aaaSAndrew Jeffery int rc = size;
12553c21aaaSAndrew Jeffery
12653c21aaaSAndrew Jeffery if (!(context && context->vpnor && context->vpnor->table))
12753c21aaaSAndrew Jeffery {
12853c21aaaSAndrew Jeffery MSG_ERR("Trying to copy data with uninitialised context!\n");
12953c21aaaSAndrew Jeffery return -MBOX_R_SYSTEM_ERROR;
13053c21aaaSAndrew Jeffery }
13153c21aaaSAndrew Jeffery
13253c21aaaSAndrew Jeffery table = context->vpnor->table;
13353c21aaaSAndrew Jeffery
13453c21aaaSAndrew Jeffery MSG_DBG("Copy virtual pnor to %p for size 0x%.8x from offset 0x%.8x\n", mem,
13553c21aaaSAndrew Jeffery size, offset);
13653c21aaaSAndrew Jeffery
13753c21aaaSAndrew Jeffery /* The virtual PNOR partition table starts at offset 0 in the virtual
13853c21aaaSAndrew Jeffery * pnor image. Check if host asked for an offset that lies within the
13953c21aaaSAndrew Jeffery * partition table.
14053c21aaaSAndrew Jeffery */
14153c21aaaSAndrew Jeffery size_t sz = table->size();
14253c21aaaSAndrew Jeffery if (offset < sz)
14353c21aaaSAndrew Jeffery {
14453c21aaaSAndrew Jeffery const pnor_partition_table& toc = table->getHostTable();
14553c21aaaSAndrew Jeffery rc = std::min(sz - offset, static_cast<size_t>(size));
14653c21aaaSAndrew Jeffery memcpy(mem, ((uint8_t*)&toc) + offset, rc);
14753c21aaaSAndrew Jeffery return rc;
14853c21aaaSAndrew Jeffery }
14953c21aaaSAndrew Jeffery
15053c21aaaSAndrew Jeffery try
15153c21aaaSAndrew Jeffery {
15253c21aaaSAndrew Jeffery vpnor::Request req(context, offset);
15353c21aaaSAndrew Jeffery rc = req.read(mem, size);
15453c21aaaSAndrew Jeffery }
15553c21aaaSAndrew Jeffery catch (vpnor::UnmappedOffset& e)
15653c21aaaSAndrew Jeffery {
15753c21aaaSAndrew Jeffery /*
15853c21aaaSAndrew Jeffery * Hooo boy. Pretend that this is valid flash so we don't have
15953c21aaaSAndrew Jeffery * discontiguous regions presented to the host. Instead, fill a window
16053c21aaaSAndrew Jeffery * with 0xff so the 'flash' looks erased. Writes to such regions are
16153c21aaaSAndrew Jeffery * dropped on the floor, see the implementation of write_flash() below.
16253c21aaaSAndrew Jeffery */
16353c21aaaSAndrew Jeffery MSG_INFO("Host requested unmapped region of %" PRId32
16453c21aaaSAndrew Jeffery " bytes at offset 0x%" PRIx32 "\n",
16553c21aaaSAndrew Jeffery size, offset);
16653c21aaaSAndrew Jeffery uint32_t span = e.next - e.base;
16753c21aaaSAndrew Jeffery rc = std::min(size, span);
16853c21aaaSAndrew Jeffery memset(mem, 0xff, rc);
16953c21aaaSAndrew Jeffery }
17053c21aaaSAndrew Jeffery catch (std::exception& e)
17153c21aaaSAndrew Jeffery {
17253c21aaaSAndrew Jeffery MSG_ERR("%s\n", e.what());
17353c21aaaSAndrew Jeffery phosphor::logging::commit<err::InternalFailure>();
17453c21aaaSAndrew Jeffery rc = -MBOX_R_SYSTEM_ERROR;
17553c21aaaSAndrew Jeffery }
17653c21aaaSAndrew Jeffery return rc;
17753c21aaaSAndrew Jeffery }
17853c21aaaSAndrew Jeffery
17953c21aaaSAndrew Jeffery /*
18053c21aaaSAndrew Jeffery * write_flash() - Write to the virtual pnor from a provided buffer
18153c21aaaSAndrew Jeffery * @context: The mbox context pointer
18253c21aaaSAndrew Jeffery * @offset: The flash offset to write to (bytes)
18353c21aaaSAndrew Jeffery * @buf: The buffer to write from (must be of atleast size)
18453c21aaaSAndrew Jeffery * @size: The number of bytes to write
18553c21aaaSAndrew Jeffery *
18653c21aaaSAndrew Jeffery * Return: 0 on success otherwise negative error code
18753c21aaaSAndrew Jeffery */
18853c21aaaSAndrew Jeffery
write_flash(struct mbox_context * context,uint32_t offset,void * buf,uint32_t count)18953c21aaaSAndrew Jeffery int write_flash(struct mbox_context* context, uint32_t offset, void* buf,
19053c21aaaSAndrew Jeffery uint32_t count)
19153c21aaaSAndrew Jeffery {
19253c21aaaSAndrew Jeffery
19353c21aaaSAndrew Jeffery if (!(context && context->vpnor && context->vpnor->table))
19453c21aaaSAndrew Jeffery {
19553c21aaaSAndrew Jeffery MSG_ERR("Trying to write data with uninitialised context!\n");
19653c21aaaSAndrew Jeffery return -MBOX_R_SYSTEM_ERROR;
19753c21aaaSAndrew Jeffery }
19853c21aaaSAndrew Jeffery
19953c21aaaSAndrew Jeffery vpnor::partition::Table* table = context->vpnor->table;
20053c21aaaSAndrew Jeffery
20153c21aaaSAndrew Jeffery try
20253c21aaaSAndrew Jeffery {
20353c21aaaSAndrew Jeffery const struct pnor_partition& part = table->partition(offset);
20453c21aaaSAndrew Jeffery if (part.data.user.data[1] & PARTITION_READONLY)
20553c21aaaSAndrew Jeffery {
206*52a83196SAndrew Jeffery MSG_ERR("Unreachable: Host attempted to write to read-only "
207*52a83196SAndrew Jeffery "partition %s\n",
208*52a83196SAndrew Jeffery part.data.name);
20953c21aaaSAndrew Jeffery return -MBOX_R_WRITE_ERROR;
21053c21aaaSAndrew Jeffery }
21153c21aaaSAndrew Jeffery
21253c21aaaSAndrew Jeffery MSG_DBG("Write flash @ 0x%.8x for 0x%.8x from %p\n", offset, count,
21353c21aaaSAndrew Jeffery buf);
21453c21aaaSAndrew Jeffery vpnor::Request req(context, offset);
21553c21aaaSAndrew Jeffery req.write(buf, count);
21653c21aaaSAndrew Jeffery }
21753c21aaaSAndrew Jeffery catch (vpnor::UnmappedOffset& e)
21853c21aaaSAndrew Jeffery {
219*52a83196SAndrew Jeffery MSG_ERR("Unreachable: Host attempted to write %" PRIu32
220*52a83196SAndrew Jeffery " bytes to unmapped offset 0x%" PRIx32 "\n",
22153c21aaaSAndrew Jeffery count, offset);
222*52a83196SAndrew Jeffery return -MBOX_R_WRITE_ERROR;
22353c21aaaSAndrew Jeffery }
22453c21aaaSAndrew Jeffery catch (const vpnor::OutOfBoundsOffset& e)
22553c21aaaSAndrew Jeffery {
22653c21aaaSAndrew Jeffery MSG_ERR("%s\n", e.what());
22753c21aaaSAndrew Jeffery return -MBOX_R_PARAM_ERROR;
22853c21aaaSAndrew Jeffery }
22953c21aaaSAndrew Jeffery catch (const std::exception& e)
23053c21aaaSAndrew Jeffery {
23153c21aaaSAndrew Jeffery MSG_ERR("%s\n", e.what());
23253c21aaaSAndrew Jeffery phosphor::logging::commit<err::InternalFailure>();
23353c21aaaSAndrew Jeffery return -MBOX_R_SYSTEM_ERROR;
23453c21aaaSAndrew Jeffery }
23553c21aaaSAndrew Jeffery return 0;
23653c21aaaSAndrew Jeffery }
237