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 "vpnor/partition.hpp" 10 #include "vpnor/table.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 fs::permissions(dst, fs::perms::add_perms | fs::perms::owner_write); 95 96 return dst; 97 } 98 99 size_t Request::clamp(size_t len) 100 { 101 size_t maxAccess = offset + len; 102 size_t partSize = partition.data.size << backend->block_size_shift; 103 return std::min(maxAccess, partSize) - offset; 104 } 105 106 void Request::resize(const fs::path& path, size_t len) 107 { 108 size_t maxAccess = offset + len; 109 size_t fileSize = fs::file_size(path); 110 if (maxAccess < fileSize) 111 { 112 return; 113 } 114 MSG_DBG("Resizing %s to %zu bytes\n", path.c_str(), maxAccess); 115 int rc = truncate(path.c_str(), maxAccess); 116 if (rc == -1) 117 { 118 MSG_ERR("Failed to resize %s: %d\n", path.c_str(), errno); 119 throw std::system_error(errno, std::system_category()); 120 } 121 } 122 123 size_t Request::fulfil(const fs::path& path, int flags, void* buf, size_t len) 124 { 125 if (!(flags == O_RDONLY || flags == O_RDWR)) 126 { 127 std::stringstream err; 128 err << "Require O_RDONLY (0x" << std::hex << O_RDONLY << " or O_RDWR " 129 << std::hex << O_RDWR << " for flags, got: 0x" << std::hex << flags; 130 throw std::invalid_argument(err.str()); 131 } 132 133 int fd = ::open(path.c_str(), flags); 134 if (fd == -1) 135 { 136 MSG_ERR("Failed to open backing file at '%s': %d\n", path.c_str(), 137 errno); 138 throw std::system_error(errno, std::system_category()); 139 } 140 141 if (flags == O_RDONLY) 142 { 143 MSG_INFO("Fulfilling read request against %s at offset 0x%zx into %p " 144 "for %zu\n", 145 path.c_str(), offset, buf, len); 146 } 147 else 148 { 149 MSG_INFO("Fulfilling write request against %s at offset 0x%zx from %p " 150 "for %zu\n", 151 path.c_str(), offset, buf, len); 152 } 153 154 size_t fileSize = fs::file_size(path); 155 int mprot = PROT_READ | ((flags == O_RDWR) ? PROT_WRITE : 0); 156 auto map = mmap(NULL, fileSize, mprot, MAP_SHARED, fd, 0); 157 if (map == MAP_FAILED) 158 { 159 close(fd); 160 MSG_ERR("Failed to map backing file '%s' for %zd bytes: %d\n", 161 path.c_str(), fileSize, errno); 162 throw std::system_error(errno, std::system_category()); 163 } 164 165 // copy to the reserved memory area 166 if (flags == O_RDONLY) 167 { 168 memset(buf, 0xff, len); 169 memcpy(buf, (char*)map + offset, std::min(len, fileSize)); 170 } 171 else 172 { 173 memcpy((char*)map + offset, buf, len); 174 backend_set_bytemap(backend, base + offset, len, FLASH_DIRTY); 175 } 176 munmap(map, fileSize); 177 close(fd); 178 179 return len; 180 } 181 182 } // namespace virtual_pnor 183 } // namespace openpower 184