xref: /openbmc/phosphor-mboxd/vpnor/pnor_partition.cpp (revision 974507e3e35ae937d6a2d6315f8b06873715bf17)
153c21aaaSAndrew Jeffery // SPDX-License-Identifier: Apache-2.0
253c21aaaSAndrew Jeffery // Copyright (C) 2018 IBM Corp.
353c21aaaSAndrew Jeffery #include "pnor_partition.hpp"
453c21aaaSAndrew Jeffery #include "pnor_partition_table.hpp"
553c21aaaSAndrew Jeffery #include "config.h"
653c21aaaSAndrew Jeffery #include "mboxd_flash.h"
753c21aaaSAndrew Jeffery #include "mboxd_pnor_partition_table.h"
853c21aaaSAndrew Jeffery #include "xyz/openbmc_project/Common/error.hpp"
953c21aaaSAndrew Jeffery #include <phosphor-logging/log.hpp>
1053c21aaaSAndrew Jeffery #include <phosphor-logging/elog-errors.hpp>
1153c21aaaSAndrew Jeffery 
1253c21aaaSAndrew Jeffery #include <assert.h>
1353c21aaaSAndrew Jeffery #include <fcntl.h>
1453c21aaaSAndrew Jeffery #include <stdint.h>
1553c21aaaSAndrew Jeffery #include <stdlib.h>
1653c21aaaSAndrew Jeffery #include <syslog.h>
1753c21aaaSAndrew Jeffery #include <sys/types.h>
1853c21aaaSAndrew Jeffery #include <sys/ioctl.h>
1953c21aaaSAndrew Jeffery #include <sys/mman.h>
2053c21aaaSAndrew Jeffery #include <unistd.h>
2153c21aaaSAndrew Jeffery 
2253c21aaaSAndrew Jeffery #include "common.h"
2353c21aaaSAndrew Jeffery 
2453c21aaaSAndrew Jeffery #include <string>
2553c21aaaSAndrew Jeffery #include <exception>
2653c21aaaSAndrew Jeffery #include <stdexcept>
2753c21aaaSAndrew Jeffery #include <iostream>
2853c21aaaSAndrew Jeffery 
2953c21aaaSAndrew Jeffery namespace openpower
3053c21aaaSAndrew Jeffery {
3153c21aaaSAndrew Jeffery namespace virtual_pnor
3253c21aaaSAndrew Jeffery {
3353c21aaaSAndrew Jeffery 
3453c21aaaSAndrew Jeffery namespace fs = std::experimental::filesystem;
3553c21aaaSAndrew Jeffery 
getPartitionFilePath(int flags)3653c21aaaSAndrew Jeffery fs::path Request::getPartitionFilePath(int flags)
3753c21aaaSAndrew Jeffery {
3853c21aaaSAndrew Jeffery     // Check if partition exists in patch location
3953c21aaaSAndrew Jeffery     auto dst = fs::path(ctx->paths.patch_loc) / partition.data.name;
4053c21aaaSAndrew Jeffery     if (fs::is_regular_file(dst))
4153c21aaaSAndrew Jeffery     {
4253c21aaaSAndrew Jeffery         return dst;
4353c21aaaSAndrew Jeffery     }
4453c21aaaSAndrew Jeffery 
4553c21aaaSAndrew Jeffery     switch (partition.data.user.data[1] &
4653c21aaaSAndrew Jeffery             (PARTITION_PRESERVED | PARTITION_READONLY))
4753c21aaaSAndrew Jeffery     {
4853c21aaaSAndrew Jeffery         case PARTITION_PRESERVED:
4953c21aaaSAndrew Jeffery             dst = ctx->paths.prsv_loc;
5053c21aaaSAndrew Jeffery             break;
5153c21aaaSAndrew Jeffery 
5253c21aaaSAndrew Jeffery         case PARTITION_READONLY:
5353c21aaaSAndrew Jeffery             dst = ctx->paths.ro_loc;
5453c21aaaSAndrew Jeffery             break;
5553c21aaaSAndrew Jeffery 
5653c21aaaSAndrew Jeffery         default:
5753c21aaaSAndrew Jeffery             dst = ctx->paths.rw_loc;
5853c21aaaSAndrew Jeffery     }
5953c21aaaSAndrew Jeffery     dst /= partition.data.name;
6053c21aaaSAndrew Jeffery 
6153c21aaaSAndrew Jeffery     if (fs::exists(dst))
6253c21aaaSAndrew Jeffery     {
6353c21aaaSAndrew Jeffery         return dst;
6453c21aaaSAndrew Jeffery     }
6553c21aaaSAndrew Jeffery 
6653c21aaaSAndrew Jeffery     if (flags == O_RDONLY)
6753c21aaaSAndrew Jeffery     {
6853c21aaaSAndrew Jeffery         dst = fs::path(ctx->paths.ro_loc) / partition.data.name;
6953c21aaaSAndrew Jeffery         assert(fs::exists(dst));
7053c21aaaSAndrew Jeffery         return dst;
7153c21aaaSAndrew Jeffery     }
7253c21aaaSAndrew Jeffery 
7353c21aaaSAndrew Jeffery     assert(flags == O_RDWR);
7453c21aaaSAndrew Jeffery     auto src = fs::path(ctx->paths.ro_loc) / partition.data.name;
7553c21aaaSAndrew Jeffery     assert(fs::exists(src));
7653c21aaaSAndrew Jeffery 
7753c21aaaSAndrew Jeffery     MSG_DBG("RWRequest: Didn't find '%s' under '%s', copying from '%s'\n",
7853c21aaaSAndrew Jeffery             partition.data.name, dst.c_str(), src.c_str());
7953c21aaaSAndrew Jeffery 
8053c21aaaSAndrew Jeffery     dst = ctx->paths.rw_loc;
8153c21aaaSAndrew Jeffery     if (partition.data.user.data[1] & PARTITION_PRESERVED)
8253c21aaaSAndrew Jeffery     {
8353c21aaaSAndrew Jeffery         dst = ctx->paths.prsv_loc;
8453c21aaaSAndrew Jeffery     }
8553c21aaaSAndrew Jeffery 
8653c21aaaSAndrew Jeffery     dst /= partition.data.name;
8753c21aaaSAndrew Jeffery     fs::copy_file(src, dst);
8853c21aaaSAndrew Jeffery 
8953c21aaaSAndrew Jeffery     return dst;
9053c21aaaSAndrew Jeffery }
9153c21aaaSAndrew Jeffery 
clamp(size_t len)9253c21aaaSAndrew Jeffery size_t Request::clamp(size_t len)
9353c21aaaSAndrew Jeffery {
9453c21aaaSAndrew Jeffery     size_t maxAccess = offset + len;
9553c21aaaSAndrew Jeffery     size_t partSize = partition.data.size << ctx->block_size_shift;
9653c21aaaSAndrew Jeffery     return std::min(maxAccess, partSize) - offset;
9753c21aaaSAndrew Jeffery }
9853c21aaaSAndrew Jeffery 
resize(const fs::path & path,size_t len)9953c21aaaSAndrew Jeffery void Request::resize(const fs::path &path, size_t len)
10053c21aaaSAndrew Jeffery {
10153c21aaaSAndrew Jeffery     size_t maxAccess = offset + len;
10253c21aaaSAndrew Jeffery     size_t fileSize = fs::file_size(path);
10353c21aaaSAndrew Jeffery     if (maxAccess < fileSize)
10453c21aaaSAndrew Jeffery     {
10553c21aaaSAndrew Jeffery         return;
10653c21aaaSAndrew Jeffery     }
10753c21aaaSAndrew Jeffery     MSG_DBG("Resizing %s to %zu bytes\n", path.c_str(), maxAccess);
10853c21aaaSAndrew Jeffery     int rc = truncate(path.c_str(), maxAccess);
10953c21aaaSAndrew Jeffery     if (rc == -1)
11053c21aaaSAndrew Jeffery     {
11153c21aaaSAndrew Jeffery         MSG_ERR("Failed to resize %s: %d\n", path.c_str(), errno);
11253c21aaaSAndrew Jeffery         throw std::system_error(errno, std::system_category());
11353c21aaaSAndrew Jeffery     }
11453c21aaaSAndrew Jeffery }
11553c21aaaSAndrew Jeffery 
fulfil(const fs::path & path,int flags,void * buf,size_t len)11653c21aaaSAndrew Jeffery size_t Request::fulfil(const fs::path &path, int flags, void *buf, size_t len)
11753c21aaaSAndrew Jeffery {
11853c21aaaSAndrew Jeffery     if (!(flags == O_RDONLY || flags == O_RDWR))
11953c21aaaSAndrew Jeffery     {
12053c21aaaSAndrew Jeffery         std::stringstream err;
12153c21aaaSAndrew Jeffery         err << "Require O_RDONLY (0x" << std::hex << O_RDONLY << " or O_RDWR "
12253c21aaaSAndrew Jeffery             << std::hex << O_RDWR << " for flags, got: 0x" << std::hex << flags;
12353c21aaaSAndrew Jeffery         throw std::invalid_argument(err.str());
12453c21aaaSAndrew Jeffery     }
12553c21aaaSAndrew Jeffery 
12653c21aaaSAndrew Jeffery     int fd = ::open(path.c_str(), flags);
12753c21aaaSAndrew Jeffery     if (fd == -1)
12853c21aaaSAndrew Jeffery     {
129*974507e3SAndrew Jeffery         MSG_ERR("Failed to open backing file at '%s': %d\n", path.c_str(),
130*974507e3SAndrew Jeffery                 errno);
13153c21aaaSAndrew Jeffery         throw std::system_error(errno, std::system_category());
13253c21aaaSAndrew Jeffery     }
13353c21aaaSAndrew Jeffery 
13453c21aaaSAndrew Jeffery     size_t fileSize = fs::file_size(path);
13553c21aaaSAndrew Jeffery     int mprot = PROT_READ | ((flags == O_RDWR) ? PROT_WRITE : 0);
13653c21aaaSAndrew Jeffery     auto map = mmap(NULL, fileSize, mprot, MAP_SHARED, fd, 0);
13753c21aaaSAndrew Jeffery     if (map == MAP_FAILED)
13853c21aaaSAndrew Jeffery     {
13953c21aaaSAndrew Jeffery         close(fd);
14053c21aaaSAndrew Jeffery         MSG_ERR("Failed to map backing file '%s' for %zd bytes: %d\n",
14153c21aaaSAndrew Jeffery                 path.c_str(), fileSize, errno);
14253c21aaaSAndrew Jeffery         throw std::system_error(errno, std::system_category());
14353c21aaaSAndrew Jeffery     }
14453c21aaaSAndrew Jeffery 
14553c21aaaSAndrew Jeffery     // copy to the reserved memory area
14653c21aaaSAndrew Jeffery     if (flags == O_RDONLY)
14753c21aaaSAndrew Jeffery     {
14853c21aaaSAndrew Jeffery         memset(buf, 0xff, len);
14953c21aaaSAndrew Jeffery         memcpy(buf, (char *)map + offset, std::min(len, fileSize));
15053c21aaaSAndrew Jeffery     }
15153c21aaaSAndrew Jeffery     else
15253c21aaaSAndrew Jeffery     {
15353c21aaaSAndrew Jeffery         memcpy((char *)map + offset, buf, len);
15453c21aaaSAndrew Jeffery         set_flash_bytemap(ctx, base + offset, len, FLASH_DIRTY);
15553c21aaaSAndrew Jeffery     }
15653c21aaaSAndrew Jeffery     munmap(map, fileSize);
15753c21aaaSAndrew Jeffery     close(fd);
15853c21aaaSAndrew Jeffery 
15953c21aaaSAndrew Jeffery     return len;
16053c21aaaSAndrew Jeffery }
16153c21aaaSAndrew Jeffery 
16253c21aaaSAndrew Jeffery } // namespace virtual_pnor
16353c21aaaSAndrew Jeffery } // namespace openpower
164