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