blob: 23fc4cf1c48497c5cdbea08315161be04a6fdecf [file] [log] [blame]
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2018 IBM Corp.
extern "C" {
#include "flash.h"
}
#include "mboxd_pnor_partition_table.h"
#include "pnor_partition_table.hpp"
#include "common.h"
#include "mboxd.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 -EINVAL;
}
}
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
flash_copy(&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
flash_copy(&local, hbbOffset,
static_cast<uint8_t *>(context->mem) + hbbOffset, hbbSize);
}
catch (err::InternalFailure &e)
{
phosphor::logging::commit<err::InternalFailure>();
return -EIO;
}
catch (vpnor::ReasonedError &e)
{
MSG_ERR("%s\n", e.what());
phosphor::logging::commit<err::InternalFailure>();
return -EIO;
}
return 0;
}
void destroy_vpnor(struct mbox_context *context)
{
if (context && context->vpnor)
{
delete context->vpnor->table;
delete context->vpnor;
context->vpnor = nullptr;
}
}