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