diff options
Diffstat (limited to 'vpnor/mboxd_pnor_partition_table.cpp')
-rw-r--r-- | vpnor/mboxd_pnor_partition_table.cpp | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/vpnor/mboxd_pnor_partition_table.cpp b/vpnor/mboxd_pnor_partition_table.cpp new file mode 100644 index 0000000..db53dc8 --- /dev/null +++ b/vpnor/mboxd_pnor_partition_table.cpp @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright (C) 2018 IBM Corp. +#include "mboxd_pnor_partition_table.h" +#include "pnor_partition_table.hpp" +#include "common.h" +#include "mbox.h" +#include "mboxd_flash.h" +#include "pnor_partition_table.hpp" +#include "config.h" +#include "xyz/openbmc_project/Common/error.hpp" +#include <phosphor-logging/elog-errors.hpp> +#include <experimental/filesystem> + +int init_vpnor(struct mbox_context *context) +{ + if (context && !context->vpnor) + { + int rc; + + strncpy(context->paths.ro_loc, PARTITION_FILES_RO_LOC, PATH_MAX); + context->paths.ro_loc[PATH_MAX - 1] = '\0'; + strncpy(context->paths.rw_loc, PARTITION_FILES_RW_LOC, PATH_MAX); + context->paths.rw_loc[PATH_MAX - 1] = '\0'; + strncpy(context->paths.prsv_loc, PARTITION_FILES_PRSV_LOC, PATH_MAX); + context->paths.prsv_loc[PATH_MAX - 1] = '\0'; + strncpy(context->paths.patch_loc, PARTITION_FILES_PATCH_LOC, PATH_MAX); + context->paths.prsv_loc[PATH_MAX - 1] = '\0'; + + rc = init_vpnor_from_paths(context); + if (rc < 0) + { + return rc; + } + } + + return 0; +} + +int init_vpnor_from_paths(struct mbox_context *context) +{ + namespace err = sdbusplus::xyz::openbmc_project::Common::Error; + namespace fs = std::experimental::filesystem; + namespace vpnor = openpower::virtual_pnor; + + if (context && !context->vpnor) + { + try + { + context->vpnor = new vpnor_partition_table; + context->vpnor->table = + new openpower::virtual_pnor::partition::Table(context); + } + catch (vpnor::TocEntryError &e) + { + MSG_ERR("%s\n", e.what()); + phosphor::logging::commit<err::InternalFailure>(); + return -MBOX_R_SYSTEM_ERROR; + } + } + + return 0; +} + +int vpnor_copy_bootloader_partition(const struct mbox_context *context) +{ + // The hostboot bootloader has certain size/offset assumptions, so + // we need a special partition table here. + // It assumes the PNOR is 64M, the TOC size is 32K, the erase block is + // 4K, the page size is 4K. + // It also assumes the TOC is at the 'end of pnor - toc size - 1 page size' + // offset, and first looks for the TOC here, before proceeding to move up + // page by page looking for the TOC. So it is optimal to place the TOC at + // this offset. + constexpr size_t eraseSize = 0x1000; + constexpr size_t pageSize = 0x1000; + constexpr size_t pnorSize = 0x4000000; + constexpr size_t tocMaxSize = 0x8000; + constexpr size_t tocStart = pnorSize - tocMaxSize - pageSize; + constexpr auto blPartitionName = "HBB"; + + namespace err = sdbusplus::xyz::openbmc_project::Common::Error; + namespace fs = std::experimental::filesystem; + namespace vpnor = openpower::virtual_pnor; + + try + { + vpnor_partition_table vtbl{}; + struct mbox_context local = *context; + local.vpnor = &vtbl; + local.block_size_shift = log_2(eraseSize); + + openpower::virtual_pnor::partition::Table blTable(&local); + + vtbl.table = &blTable; + + size_t tocOffset = 0; + + // Copy TOC + copy_flash(&local, tocOffset, + static_cast<uint8_t *>(context->mem) + tocStart, + blTable.capacity()); + const pnor_partition &partition = blTable.partition(blPartitionName); + size_t hbbOffset = partition.data.base * eraseSize; + uint32_t hbbSize = partition.data.actual; + // Copy HBB + copy_flash(&local, hbbOffset, + static_cast<uint8_t *>(context->mem) + hbbOffset, hbbSize); + } + catch (err::InternalFailure &e) + { + phosphor::logging::commit<err::InternalFailure>(); + return -MBOX_R_SYSTEM_ERROR; + } + catch (vpnor::TocEntryError &e) + { + MSG_ERR("%s\n", e.what()); + phosphor::logging::commit<err::InternalFailure>(); + return -MBOX_R_SYSTEM_ERROR; + } + + return 0; +} + +void destroy_vpnor(struct mbox_context *context) +{ + if (context && context->vpnor) + { + delete context->vpnor->table; + delete context->vpnor; + context->vpnor = nullptr; + } +} |