summaryrefslogtreecommitdiffstats
path: root/pnor_partition_table.cpp
diff options
context:
space:
mode:
authorDeepak Kodihalli <dkodihal@in.ibm.com>2017-04-28 04:44:38 -0500
committerDeepak Kodihalli <dkodihal@in.ibm.com>2017-06-27 08:40:30 -0500
commit393821dd663f54384ea5b12cf30ab7944ceae5a6 (patch)
treec338d1ad69b3962ae3fdfd2d606bfa1e0dcf8f0d /pnor_partition_table.cpp
parent90b92fe48ec72b6c15cce24d33ac983548368b98 (diff)
downloadphosphor-mboxd-393821dd663f54384ea5b12cf30ab7944ceae5a6.tar.gz
phosphor-mboxd-393821dd663f54384ea5b12cf30ab7944ceae5a6.zip
pnor : generate partition table
Implement a class that, upon construction, generates the virtual PNOR partition table. The virtual PNOR is typically a subset of the full PNOR image, by choosing partitions of interest. The generation is based on upon information read from the PNOR partition files and table of contents (toc) file. Provide an interface to the virtual PNOR partition table. Change-Id: I7a68e3833b8cf66e92eb6ca274f6a3c376ce0add Signed-off-by: Deepak Kodihalli <dkodihal@in.ibm.com>
Diffstat (limited to 'pnor_partition_table.cpp')
-rw-r--r--pnor_partition_table.cpp242
1 files changed, 242 insertions, 0 deletions
diff --git a/pnor_partition_table.cpp b/pnor_partition_table.cpp
new file mode 100644
index 0000000..17f5011
--- /dev/null
+++ b/pnor_partition_table.cpp
@@ -0,0 +1,242 @@
+#include "pnor_partition_table.hpp"
+#include "common.h"
+#include "config.h"
+#include <syslog.h>
+#include <endian.h>
+#include <regex>
+#include <fstream>
+#include <algorithm>
+
+namespace openpower
+{
+namespace virtual_pnor
+{
+
+namespace partition
+{
+namespace block
+{
+
+// The PNOR erase-block size is 4 KB
+constexpr size_t size = 4096;
+
+} // namespace block
+
+Table::Table():
+ Table(fs::path(PARTITION_FILES_LOC))
+{
+}
+
+Table::Table(fs::path&& directory):
+ szBlocks(0),
+ imgBlocks(0),
+ directory(std::move(directory)),
+ numParts(0)
+{
+ preparePartitions();
+ prepareHeader();
+ hostTbl = endianFixup(tbl);
+}
+
+void Table::prepareHeader()
+{
+ decltype(auto) table = getNativeTable();
+ table.data.magic = PARTITION_HEADER_MAGIC;
+ table.data.version = PARTITION_VERSION_1;
+ table.data.size = szBlocks;
+ table.data.entry_size = sizeof(pnor_partition);
+ table.data.entry_count = numParts;
+ table.data.block_size = block::size;
+ table.data.block_count = imgBlocks;
+ table.checksum = details::checksum(table.data);
+}
+
+inline void Table::allocateMemory(const fs::path& tocFile)
+{
+ size_t num = 0;
+ std::string line;
+ std::ifstream file(tocFile.c_str());
+
+ // Find number of lines in partition file - this will help
+ // determine the number of partitions and hence also how much
+ // memory to allocate for the partitions array.
+ // The actual number of partitions may turn out to be lesser than this,
+ // in case of errors.
+ while (std::getline(file, line))
+ {
+ // Check if line starts with "partition"
+ if (std::string::npos != line.find("partition", 0))
+ {
+ ++num;
+ }
+ }
+
+ size_t totalSizeBytes = sizeof(pnor_partition_table) +
+ (num * sizeof(pnor_partition));
+ size_t totalSizeAligned = align_up(totalSizeBytes, block::size);
+ szBlocks = totalSizeAligned / block::size;
+ imgBlocks = szBlocks;
+ tbl.resize(totalSizeAligned);
+}
+
+inline void Table::writeSizes(pnor_partition& part, size_t start, size_t end)
+{
+ size_t size = end - start;
+ part.data.base = imgBlocks;
+ size_t sizeInBlocks = align_up(size, block::size) / block::size;
+ imgBlocks += sizeInBlocks;
+ part.data.size = sizeInBlocks;
+ part.data.actual = size;
+}
+
+inline void Table::writeUserdata(pnor_partition& part, const std::string& data)
+{
+ if (std::string::npos != data.find("ECC"))
+ {
+ part.data.user.data[0] = PARTITION_ECC_PROTECTED;
+ }
+ auto perms = 0;
+ if (std::string::npos != data.find("READONLY"))
+ {
+ perms |= PARTITION_READONLY;
+ }
+ if (std::string::npos != data.find("PRESERVED"))
+ {
+ perms |= PARTITION_PRESERVED;
+ }
+ part.data.user.data[1] = perms;
+}
+
+inline void Table::writeDefaults(pnor_partition& part)
+{
+ part.data.pid = PARENT_PATITION_ID;
+ part.data.type = PARTITION_TYPE_DATA;
+ part.data.flags = 0; // flags unused
+}
+
+inline void Table::writeNameAndId(pnor_partition& part, std::string&& name,
+ const std::string& id)
+{
+ name.resize(PARTITION_NAME_MAX);
+ memcpy(part.data.name,
+ name.c_str(),
+ sizeof(part.data.name));
+ part.data.id = std::stoul(id);
+}
+
+void Table::preparePartitions()
+{
+ fs::path tocFile = directory;
+ tocFile /= PARTITION_TOC_FILE;
+ allocateMemory(tocFile);
+
+ std::ifstream file(tocFile.c_str());
+ static constexpr auto ID_MATCH = 1;
+ static constexpr auto NAME_MATCH = 2;
+ static constexpr auto START_ADDR_MATCH = 3;
+ static constexpr auto END_ADDR_MATCH = 4;
+ // Parse PNOR toc (table of contents) file, which has lines like :
+ // partition01=HBB,00010000,000a0000,ECC,PRESERVED, to indicate partitions
+ std::regex regex
+ {
+ "^partition([0-9]+)=([A-Za-z0-9_]+),"
+ "([0-9a-fA-F]+),([0-9a-fA-F]+)",
+ std::regex::extended
+ };
+ std::smatch match;
+ std::string line;
+
+ decltype(auto) table = getNativeTable();
+
+ while (std::getline(file, line))
+ {
+ if (std::regex_search(line, match, regex))
+ {
+ fs::path partitionFile = directory;
+ partitionFile /= match[NAME_MATCH].str();
+ if (!fs::exists(partitionFile))
+ {
+ MSG_ERR("Partition file %s does not exist",
+ partitionFile.c_str());
+ continue;
+ }
+
+ writeNameAndId(table.partitions[numParts],
+ match[NAME_MATCH].str(),
+ match[ID_MATCH].str());
+ writeDefaults(table.partitions[numParts]);
+ writeSizes(table.partitions[numParts],
+ std::stoul(match[START_ADDR_MATCH].str(), nullptr, 16),
+ std::stoul(match[END_ADDR_MATCH].str(), nullptr, 16));
+ writeUserdata(table.partitions[numParts], match.suffix().str());
+ table.partitions[numParts].checksum =
+ details::checksum(table.partitions[numParts].data);
+
+ ++numParts;
+ }
+ }
+}
+
+const pnor_partition& Table::partition(size_t offset) const
+{
+ const decltype(auto) table = getNativeTable();
+ size_t offt = offset / block::size;
+
+ for (decltype(numParts) i{}; i < numParts; ++i)
+ {
+ if ((offt >= table.partitions[i].data.base) &&
+ (offt < (table.partitions[i].data.base +
+ table.partitions[i].data.size)))
+ {
+ return table.partitions[i];
+ }
+ }
+
+ static pnor_partition p{};
+ return p;
+}
+
+} // namespace partition
+
+PartitionTable endianFixup(const PartitionTable& in)
+{
+ PartitionTable out;
+ out.resize(in.size());
+ auto src = reinterpret_cast<const pnor_partition_table*>(in.data());
+ auto dst = reinterpret_cast<pnor_partition_table*>(out.data());
+
+ dst->data.magic = htobe32(src->data.magic);
+ dst->data.version = htobe32(src->data.version);
+ dst->data.size = htobe32(src->data.size);
+ dst->data.entry_size = htobe32(src->data.entry_size);
+ dst->data.entry_count = htobe32(src->data.entry_count);
+ dst->data.block_size = htobe32(src->data.block_size);
+ dst->data.block_count = htobe32(src->data.block_count);
+ dst->checksum = htobe32(src->checksum);
+
+ for (decltype(src->data.entry_count) i{}; i < src->data.entry_count; ++i)
+ {
+ auto psrc = &src->partitions[i];
+ auto pdst = &dst->partitions[i];
+ strncpy(pdst->data.name, psrc->data.name, PARTITION_NAME_MAX);
+ // Just to be safe
+ pdst->data.name[PARTITION_NAME_MAX] = '\0';
+ pdst->data.base = htobe32(psrc->data.base);
+ pdst->data.size = htobe32(psrc->data.size);
+ pdst->data.pid = htobe32(psrc->data.pid);
+ pdst->data.id = htobe32(psrc->data.id);
+ pdst->data.type = htobe32(psrc->data.type);
+ pdst->data.flags = htobe32(psrc->data.flags);
+ pdst->data.actual = htobe32(psrc->data.actual);
+ for (size_t j = 0; j < PARTITION_USER_WORDS; ++j)
+ {
+ pdst->data.user.data[j] = htobe32(psrc->data.user.data[j]);
+ }
+ pdst->checksum = htobe32(psrc->checksum);
+ }
+
+ return out;
+}
+
+} // namespace virtual_pnor
+} // namespace openpower
OpenPOWER on IntegriCloud