blob: e2125da1b20b9ad6da4fd6314923d1aadf75d515 [file] [log] [blame]
#include "mboxd_pnor_partition_table.h"
#include "common.h"
#include "mbox.h"
#include "mboxd_flash.h"
#include "pnor_partition_table.hpp"
#include "config.h"
#include <experimental/filesystem>
struct vpnor_partition_table
{
openpower::virtual_pnor::partition::Table* table = nullptr;
};
void init_vpnor(struct mbox_context *context)
{
if (context && !context->vpnor)
{
strcpy(context->paths.ro_loc, PARTITION_FILES_RO_LOC);
strcpy(context->paths.rw_loc, PARTITION_FILES_RW_LOC);
strcpy(context->paths.prsv_loc, PARTITION_FILES_PRSV_LOC);
strcpy(context->paths.patch_loc, PARTITION_FILES_PATCH_LOC);
context->vpnor = new vpnor_partition_table;
context->vpnor->table =
new openpower::virtual_pnor::partition::Table(
1 << context->erase_size_shift,
context->flash_size);
}
}
void vpnor_create_partition_table_from_path(struct mbox_context *context,
const char *path)
{
std::experimental::filesystem::path dir(path);
if (context && !context->vpnor)
{
context->vpnor = new vpnor_partition_table;
context->vpnor->table =
new openpower::virtual_pnor::partition::Table(
std::move(dir),
1 << context->erase_size_shift,
context->flash_size);
}
}
size_t vpnor_get_partition_table_size(const struct mbox_context *context)
{
return context && context->vpnor ?
context->vpnor->table->size() : 0;
}
const struct pnor_partition_table* vpnor_get_partition_table(
const struct mbox_context *context)
{
return context && context->vpnor ?
&(context->vpnor->table->getHostTable()) : nullptr;
}
const struct pnor_partition* vpnor_get_partition(
const struct mbox_context *context,
const size_t offset)
{
return context && context->vpnor ?
&(context->vpnor->table->partition(offset)) : nullptr;
}
void 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";
openpower::virtual_pnor::partition::Table blTable(eraseSize, pnorSize);
vpnor_partition_table vtbl{};
vtbl.table = &blTable;
struct mbox_context local{};
local.vpnor = &vtbl;
local.block_size_shift = log_2(eraseSize);
memcpy(&local.paths, &context->paths, sizeof(local.paths));
size_t tocOffset = 0;
uint32_t tocSize = blTable.size() * eraseSize;
// Copy TOC
copy_flash(&local, tocOffset,
static_cast<uint8_t*>(context->mem) + tocStart,
tocSize);
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);
}
void destroy_vpnor(struct mbox_context *context)
{
if(context && context->vpnor)
{
delete context->vpnor->table;
delete context->vpnor;
context->vpnor = nullptr;
}
}