153c21aaaSAndrew Jeffery // SPDX-License-Identifier: Apache-2.0
253c21aaaSAndrew Jeffery // Copyright (C) 2018 IBM Corp.
353c21aaaSAndrew Jeffery #include "mboxd_pnor_partition_table.h"
453c21aaaSAndrew Jeffery #include "pnor_partition_table.hpp"
553c21aaaSAndrew Jeffery #include "common.h"
653c21aaaSAndrew Jeffery #include "mbox.h"
753c21aaaSAndrew Jeffery #include "mboxd_flash.h"
853c21aaaSAndrew Jeffery #include "pnor_partition_table.hpp"
953c21aaaSAndrew Jeffery #include "config.h"
1053c21aaaSAndrew Jeffery #include "xyz/openbmc_project/Common/error.hpp"
1153c21aaaSAndrew Jeffery #include <phosphor-logging/elog-errors.hpp>
1253c21aaaSAndrew Jeffery #include <experimental/filesystem>
13943aba06SAndrew Jeffery #include "vpnor/mboxd_msg.hpp"
1453c21aaaSAndrew Jeffery 
init_vpnor(struct mbox_context * context)1553c21aaaSAndrew Jeffery int init_vpnor(struct mbox_context *context)
1653c21aaaSAndrew Jeffery {
1753c21aaaSAndrew Jeffery     if (context && !context->vpnor)
1853c21aaaSAndrew Jeffery     {
1953c21aaaSAndrew Jeffery         int rc;
2053c21aaaSAndrew Jeffery 
2153c21aaaSAndrew Jeffery         strncpy(context->paths.ro_loc, PARTITION_FILES_RO_LOC, PATH_MAX);
2253c21aaaSAndrew Jeffery         context->paths.ro_loc[PATH_MAX - 1] = '\0';
2353c21aaaSAndrew Jeffery         strncpy(context->paths.rw_loc, PARTITION_FILES_RW_LOC, PATH_MAX);
2453c21aaaSAndrew Jeffery         context->paths.rw_loc[PATH_MAX - 1] = '\0';
2553c21aaaSAndrew Jeffery         strncpy(context->paths.prsv_loc, PARTITION_FILES_PRSV_LOC, PATH_MAX);
2653c21aaaSAndrew Jeffery         context->paths.prsv_loc[PATH_MAX - 1] = '\0';
2753c21aaaSAndrew Jeffery         strncpy(context->paths.patch_loc, PARTITION_FILES_PATCH_LOC, PATH_MAX);
2853c21aaaSAndrew Jeffery         context->paths.prsv_loc[PATH_MAX - 1] = '\0';
2953c21aaaSAndrew Jeffery 
3053c21aaaSAndrew Jeffery         rc = init_vpnor_from_paths(context);
3153c21aaaSAndrew Jeffery         if (rc < 0)
3253c21aaaSAndrew Jeffery         {
3353c21aaaSAndrew Jeffery             return rc;
3453c21aaaSAndrew Jeffery         }
3553c21aaaSAndrew Jeffery     }
3653c21aaaSAndrew Jeffery 
3753c21aaaSAndrew Jeffery     return 0;
3853c21aaaSAndrew Jeffery }
3953c21aaaSAndrew Jeffery 
init_vpnor_from_paths(struct mbox_context * context)4053c21aaaSAndrew Jeffery int init_vpnor_from_paths(struct mbox_context *context)
4153c21aaaSAndrew Jeffery {
4253c21aaaSAndrew Jeffery     namespace err = sdbusplus::xyz::openbmc_project::Common::Error;
4353c21aaaSAndrew Jeffery     namespace fs = std::experimental::filesystem;
4453c21aaaSAndrew Jeffery     namespace vpnor = openpower::virtual_pnor;
4553c21aaaSAndrew Jeffery 
4653c21aaaSAndrew Jeffery     if (context && !context->vpnor)
4753c21aaaSAndrew Jeffery     {
48943aba06SAndrew Jeffery         context->handlers = vpnor_mbox_handlers;
49943aba06SAndrew Jeffery 
5053c21aaaSAndrew Jeffery         try
5153c21aaaSAndrew Jeffery         {
5253c21aaaSAndrew Jeffery             context->vpnor = new vpnor_partition_table;
5353c21aaaSAndrew Jeffery             context->vpnor->table =
5453c21aaaSAndrew Jeffery                 new openpower::virtual_pnor::partition::Table(context);
5553c21aaaSAndrew Jeffery         }
5653c21aaaSAndrew Jeffery         catch (vpnor::TocEntryError &e)
5753c21aaaSAndrew Jeffery         {
5853c21aaaSAndrew Jeffery             MSG_ERR("%s\n", e.what());
5953c21aaaSAndrew Jeffery             phosphor::logging::commit<err::InternalFailure>();
6053c21aaaSAndrew Jeffery             return -MBOX_R_SYSTEM_ERROR;
6153c21aaaSAndrew Jeffery         }
6253c21aaaSAndrew Jeffery     }
6353c21aaaSAndrew Jeffery 
6453c21aaaSAndrew Jeffery     return 0;
6553c21aaaSAndrew Jeffery }
6653c21aaaSAndrew Jeffery 
vpnor_copy_bootloader_partition(const struct mbox_context * context)6753c21aaaSAndrew Jeffery int vpnor_copy_bootloader_partition(const struct mbox_context *context)
6853c21aaaSAndrew Jeffery {
6953c21aaaSAndrew Jeffery     // The hostboot bootloader has certain size/offset assumptions, so
7053c21aaaSAndrew Jeffery     // we need a special partition table here.
7153c21aaaSAndrew Jeffery     // It assumes the PNOR is 64M, the TOC size is 32K, the erase block is
7253c21aaaSAndrew Jeffery     // 4K, the page size is 4K.
7353c21aaaSAndrew Jeffery     // It also assumes the TOC is at the 'end of pnor - toc size - 1 page size'
7453c21aaaSAndrew Jeffery     // offset, and first looks for the TOC here, before proceeding to move up
7553c21aaaSAndrew Jeffery     // page by page looking for the TOC. So it is optimal to place the TOC at
7653c21aaaSAndrew Jeffery     // this offset.
7753c21aaaSAndrew Jeffery     constexpr size_t eraseSize = 0x1000;
7853c21aaaSAndrew Jeffery     constexpr size_t pageSize = 0x1000;
7953c21aaaSAndrew Jeffery     constexpr size_t pnorSize = 0x4000000;
8053c21aaaSAndrew Jeffery     constexpr size_t tocMaxSize = 0x8000;
8153c21aaaSAndrew Jeffery     constexpr size_t tocStart = pnorSize - tocMaxSize - pageSize;
8253c21aaaSAndrew Jeffery     constexpr auto blPartitionName = "HBB";
8353c21aaaSAndrew Jeffery 
8453c21aaaSAndrew Jeffery     namespace err = sdbusplus::xyz::openbmc_project::Common::Error;
8553c21aaaSAndrew Jeffery     namespace fs = std::experimental::filesystem;
8653c21aaaSAndrew Jeffery     namespace vpnor = openpower::virtual_pnor;
8753c21aaaSAndrew Jeffery 
8853c21aaaSAndrew Jeffery     try
8953c21aaaSAndrew Jeffery     {
9053c21aaaSAndrew Jeffery         vpnor_partition_table vtbl{};
9153c21aaaSAndrew Jeffery         struct mbox_context local = *context;
9253c21aaaSAndrew Jeffery         local.vpnor = &vtbl;
9353c21aaaSAndrew Jeffery         local.block_size_shift = log_2(eraseSize);
9453c21aaaSAndrew Jeffery 
9553c21aaaSAndrew Jeffery         openpower::virtual_pnor::partition::Table blTable(&local);
9653c21aaaSAndrew Jeffery 
9753c21aaaSAndrew Jeffery         vtbl.table = &blTable;
9853c21aaaSAndrew Jeffery 
9953c21aaaSAndrew Jeffery         size_t tocOffset = 0;
10053c21aaaSAndrew Jeffery 
10153c21aaaSAndrew Jeffery         // Copy TOC
10253c21aaaSAndrew Jeffery         copy_flash(&local, tocOffset,
10353c21aaaSAndrew Jeffery                    static_cast<uint8_t *>(context->mem) + tocStart,
10453c21aaaSAndrew Jeffery                    blTable.capacity());
10553c21aaaSAndrew Jeffery         const pnor_partition &partition = blTable.partition(blPartitionName);
10653c21aaaSAndrew Jeffery         size_t hbbOffset = partition.data.base * eraseSize;
10753c21aaaSAndrew Jeffery         uint32_t hbbSize = partition.data.actual;
10853c21aaaSAndrew Jeffery         // Copy HBB
10953c21aaaSAndrew Jeffery         copy_flash(&local, hbbOffset,
11053c21aaaSAndrew Jeffery                    static_cast<uint8_t *>(context->mem) + hbbOffset, hbbSize);
11153c21aaaSAndrew Jeffery     }
11253c21aaaSAndrew Jeffery     catch (err::InternalFailure &e)
11353c21aaaSAndrew Jeffery     {
11453c21aaaSAndrew Jeffery         phosphor::logging::commit<err::InternalFailure>();
11553c21aaaSAndrew Jeffery         return -MBOX_R_SYSTEM_ERROR;
11653c21aaaSAndrew Jeffery     }
117*8fe809eeSAndrew Jeffery     catch (vpnor::ReasonedError &e)
11853c21aaaSAndrew Jeffery     {
11953c21aaaSAndrew Jeffery         MSG_ERR("%s\n", e.what());
12053c21aaaSAndrew Jeffery         phosphor::logging::commit<err::InternalFailure>();
12153c21aaaSAndrew Jeffery         return -MBOX_R_SYSTEM_ERROR;
12253c21aaaSAndrew Jeffery     }
12353c21aaaSAndrew Jeffery 
12453c21aaaSAndrew Jeffery     return 0;
12553c21aaaSAndrew Jeffery }
12653c21aaaSAndrew Jeffery 
destroy_vpnor(struct mbox_context * context)12753c21aaaSAndrew Jeffery void destroy_vpnor(struct mbox_context *context)
12853c21aaaSAndrew Jeffery {
12953c21aaaSAndrew Jeffery     if (context && context->vpnor)
13053c21aaaSAndrew Jeffery     {
13153c21aaaSAndrew Jeffery         delete context->vpnor->table;
13253c21aaaSAndrew Jeffery         delete context->vpnor;
13353c21aaaSAndrew Jeffery         context->vpnor = nullptr;
13453c21aaaSAndrew Jeffery     }
13553c21aaaSAndrew Jeffery }
136