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 
getPartitionFilePath(int flags)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 
clamp(size_t len)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 
resize(const fs::path & path,size_t len)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 
fulfil(const fs::path & path,int flags,void * buf,size_t len)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", path.c_str(),
130                 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