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