1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright (C) 2018 IBM Corp. 3 extern "C" { 4 #include "mboxd.h" 5 } 6 7 #include "config.h" 8 9 #include "pnor_partition_table.hpp" 10 #include "vpnor/partition.hpp" 11 #include "xyz/openbmc_project/Common/error.hpp" 12 13 #include <assert.h> 14 #include <fcntl.h> 15 #include <stdint.h> 16 #include <stdlib.h> 17 #include <sys/ioctl.h> 18 #include <sys/mman.h> 19 #include <sys/types.h> 20 #include <syslog.h> 21 #include <unistd.h> 22 23 #include <exception> 24 #include <iostream> 25 #include <phosphor-logging/elog-errors.hpp> 26 #include <phosphor-logging/log.hpp> 27 #include <stdexcept> 28 #include <string> 29 30 #include "common.h" 31 #include "vpnor/backend.h" 32 33 namespace openpower 34 { 35 namespace virtual_pnor 36 { 37 38 namespace fs = std::experimental::filesystem; 39 40 fs::path Request::getPartitionFilePath(int flags) 41 { 42 struct vpnor_data* priv = (struct vpnor_data*)backend->priv; 43 44 // Check if partition exists in patch location 45 auto dst = fs::path(priv->paths.patch_loc) / partition.data.name; 46 if (fs::is_regular_file(dst)) 47 { 48 return dst; 49 } 50 51 switch (partition.data.user.data[1] & 52 (PARTITION_PRESERVED | PARTITION_READONLY)) 53 { 54 case PARTITION_PRESERVED: 55 dst = priv->paths.prsv_loc; 56 break; 57 58 case PARTITION_READONLY: 59 dst = priv->paths.ro_loc; 60 break; 61 62 default: 63 dst = priv->paths.rw_loc; 64 } 65 dst /= partition.data.name; 66 67 if (fs::exists(dst)) 68 { 69 return dst; 70 } 71 72 if (flags == O_RDONLY) 73 { 74 dst = fs::path(priv->paths.ro_loc) / partition.data.name; 75 assert(fs::exists(dst)); 76 return dst; 77 } 78 79 assert(flags == O_RDWR); 80 auto src = fs::path(priv->paths.ro_loc) / partition.data.name; 81 assert(fs::exists(src)); 82 83 MSG_DBG("RWRequest: Didn't find '%s' under '%s', copying from '%s'\n", 84 partition.data.name, dst.c_str(), src.c_str()); 85 86 dst = priv->paths.rw_loc; 87 if (partition.data.user.data[1] & PARTITION_PRESERVED) 88 { 89 dst = priv->paths.prsv_loc; 90 } 91 92 dst /= partition.data.name; 93 fs::copy_file(src, dst); 94 95 return dst; 96 } 97 98 size_t Request::clamp(size_t len) 99 { 100 size_t maxAccess = offset + len; 101 size_t partSize = partition.data.size << backend->block_size_shift; 102 return std::min(maxAccess, partSize) - offset; 103 } 104 105 void Request::resize(const fs::path& path, size_t len) 106 { 107 size_t maxAccess = offset + len; 108 size_t fileSize = fs::file_size(path); 109 if (maxAccess < fileSize) 110 { 111 return; 112 } 113 MSG_DBG("Resizing %s to %zu bytes\n", path.c_str(), maxAccess); 114 int rc = truncate(path.c_str(), maxAccess); 115 if (rc == -1) 116 { 117 MSG_ERR("Failed to resize %s: %d\n", path.c_str(), errno); 118 throw std::system_error(errno, std::system_category()); 119 } 120 } 121 122 size_t Request::fulfil(const fs::path& path, int flags, void* buf, size_t len) 123 { 124 if (!(flags == O_RDONLY || flags == O_RDWR)) 125 { 126 std::stringstream err; 127 err << "Require O_RDONLY (0x" << std::hex << O_RDONLY << " or O_RDWR " 128 << std::hex << O_RDWR << " for flags, got: 0x" << std::hex << flags; 129 throw std::invalid_argument(err.str()); 130 } 131 132 int fd = ::open(path.c_str(), flags); 133 if (fd == -1) 134 { 135 MSG_ERR("Failed to open backing file at '%s': %d\n", path.c_str(), 136 errno); 137 throw std::system_error(errno, std::system_category()); 138 } 139 140 if (flags == O_RDONLY) 141 { 142 MSG_INFO("Fulfilling read request against %s at offset 0x%zx into %p " 143 "for %zu\n", 144 path.c_str(), offset, buf, len); 145 } 146 else 147 { 148 MSG_INFO("Fulfilling write request against %s at offset 0x%zx from %p " 149 "for %zu\n", 150 path.c_str(), offset, buf, len); 151 } 152 153 size_t fileSize = fs::file_size(path); 154 int mprot = PROT_READ | ((flags == O_RDWR) ? PROT_WRITE : 0); 155 auto map = mmap(NULL, fileSize, mprot, MAP_SHARED, fd, 0); 156 if (map == MAP_FAILED) 157 { 158 close(fd); 159 MSG_ERR("Failed to map backing file '%s' for %zd bytes: %d\n", 160 path.c_str(), fileSize, errno); 161 throw std::system_error(errno, std::system_category()); 162 } 163 164 // copy to the reserved memory area 165 if (flags == O_RDONLY) 166 { 167 memset(buf, 0xff, len); 168 memcpy(buf, (char*)map + offset, std::min(len, fileSize)); 169 } 170 else 171 { 172 memcpy((char*)map + offset, buf, len); 173 backend_set_bytemap(backend, base + offset, len, FLASH_DIRTY); 174 } 175 munmap(map, fileSize); 176 close(fd); 177 178 return len; 179 } 180 181 } // namespace virtual_pnor 182 } // namespace openpower 183