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