xref: /openbmc/phosphor-mboxd/vpnor/mboxd_pnor_partition_table.cpp (revision 30bcf84c932a579532e5f8417af549494e11b6e9)
1 // SPDX-License-Identifier: Apache-2.0
2 // Copyright (C) 2018 IBM Corp.
3 #include "mboxd_pnor_partition_table.h"
4 #include "pnor_partition_table.hpp"
5 #include "common.h"
6 #include "mbox.h"
7 #include "mboxd_flash.h"
8 #include "pnor_partition_table.hpp"
9 #include "config.h"
10 #include "xyz/openbmc_project/Common/error.hpp"
11 #include <phosphor-logging/elog-errors.hpp>
12 #include <experimental/filesystem>
13 
14 int init_vpnor(struct mbox_context *context)
15 {
16     if (context && !context->vpnor)
17     {
18         int rc;
19 
20         strncpy(context->paths.ro_loc, PARTITION_FILES_RO_LOC, PATH_MAX);
21         context->paths.ro_loc[PATH_MAX - 1] = '\0';
22         strncpy(context->paths.rw_loc, PARTITION_FILES_RW_LOC, PATH_MAX);
23         context->paths.rw_loc[PATH_MAX - 1] = '\0';
24         strncpy(context->paths.prsv_loc, PARTITION_FILES_PRSV_LOC, PATH_MAX);
25         context->paths.prsv_loc[PATH_MAX - 1] = '\0';
26         strncpy(context->paths.patch_loc, PARTITION_FILES_PATCH_LOC, PATH_MAX);
27         context->paths.prsv_loc[PATH_MAX - 1] = '\0';
28 
29         rc = init_vpnor_from_paths(context);
30         if (rc < 0)
31         {
32             return rc;
33         }
34     }
35 
36     return 0;
37 }
38 
39 int init_vpnor_from_paths(struct mbox_context *context)
40 {
41     namespace err = sdbusplus::xyz::openbmc_project::Common::Error;
42     namespace fs = std::experimental::filesystem;
43     namespace vpnor = openpower::virtual_pnor;
44 
45     if (context && !context->vpnor)
46     {
47         try
48         {
49             context->vpnor = new vpnor_partition_table;
50             context->vpnor->table =
51                 new openpower::virtual_pnor::partition::Table(context);
52         }
53         catch (vpnor::TocEntryError &e)
54         {
55             MSG_ERR("%s\n", e.what());
56             phosphor::logging::commit<err::InternalFailure>();
57             return -MBOX_R_SYSTEM_ERROR;
58         }
59     }
60 
61     return 0;
62 }
63 
64 int vpnor_copy_bootloader_partition(const struct mbox_context *context)
65 {
66     // The hostboot bootloader has certain size/offset assumptions, so
67     // we need a special partition table here.
68     // It assumes the PNOR is 64M, the TOC size is 32K, the erase block is
69     // 4K, the page size is 4K.
70     // It also assumes the TOC is at the 'end of pnor - toc size - 1 page size'
71     // offset, and first looks for the TOC here, before proceeding to move up
72     // page by page looking for the TOC. So it is optimal to place the TOC at
73     // this offset.
74     constexpr size_t eraseSize = 0x1000;
75     constexpr size_t pageSize = 0x1000;
76     constexpr size_t pnorSize = 0x4000000;
77     constexpr size_t tocMaxSize = 0x8000;
78     constexpr size_t tocStart = pnorSize - tocMaxSize - pageSize;
79     constexpr auto blPartitionName = "HBB";
80 
81     namespace err = sdbusplus::xyz::openbmc_project::Common::Error;
82     namespace fs = std::experimental::filesystem;
83     namespace vpnor = openpower::virtual_pnor;
84 
85     try
86     {
87         vpnor_partition_table vtbl{};
88         struct mbox_context local = *context;
89         local.vpnor = &vtbl;
90         local.block_size_shift = log_2(eraseSize);
91 
92         openpower::virtual_pnor::partition::Table blTable(&local);
93 
94         vtbl.table = &blTable;
95 
96         size_t tocOffset = 0;
97 
98         // Copy TOC
99         copy_flash(&local, tocOffset,
100                    static_cast<uint8_t *>(context->mem) + tocStart,
101                    blTable.capacity());
102         const pnor_partition &partition = blTable.partition(blPartitionName);
103         size_t hbbOffset = partition.data.base * eraseSize;
104         uint32_t hbbSize = partition.data.actual;
105         // Copy HBB
106         copy_flash(&local, hbbOffset,
107                    static_cast<uint8_t *>(context->mem) + hbbOffset, hbbSize);
108     }
109     catch (err::InternalFailure &e)
110     {
111         phosphor::logging::commit<err::InternalFailure>();
112         return -MBOX_R_SYSTEM_ERROR;
113     }
114     catch (vpnor::TocEntryError &e)
115     {
116         MSG_ERR("%s\n", e.what());
117         phosphor::logging::commit<err::InternalFailure>();
118         return -MBOX_R_SYSTEM_ERROR;
119     }
120 
121     return 0;
122 }
123 
124 void destroy_vpnor(struct mbox_context *context)
125 {
126     if (context && context->vpnor)
127     {
128         delete context->vpnor->table;
129         delete context->vpnor;
130         context->vpnor = nullptr;
131     }
132 }
133