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 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 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 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::TocEntryError &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 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