summaryrefslogtreecommitdiffstats
path: root/mboxd_pnor_partition_table.cpp
blob: e58b0192ed992a423f87d27e174378b6bfc2c27f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// SPDX-License-Identifier: Apache-2.0
// Copyright (C) 2018 IBM Corp.
#include "mboxd_pnor_partition_table.h"
#include "pnor_partition_table.hpp"
#include "common.h"
#include "mbox.h"
#include "mboxd_flash.h"
#include "pnor_partition_table.hpp"
#include "config.h"
#include "xyz/openbmc_project/Common/error.hpp"
#include <phosphor-logging/elog-errors.hpp>
#include <experimental/filesystem>

int init_vpnor(struct mbox_context *context)
{
    if (context && !context->vpnor)
    {
        int rc;

        strncpy(context->paths.ro_loc, PARTITION_FILES_RO_LOC, PATH_MAX);
        context->paths.ro_loc[PATH_MAX - 1] = '\0';
        strncpy(context->paths.rw_loc, PARTITION_FILES_RW_LOC, PATH_MAX);
        context->paths.rw_loc[PATH_MAX - 1] = '\0';
        strncpy(context->paths.prsv_loc, PARTITION_FILES_PRSV_LOC, PATH_MAX);
        context->paths.prsv_loc[PATH_MAX - 1] = '\0';
        strncpy(context->paths.patch_loc, PARTITION_FILES_PATCH_LOC, PATH_MAX);
        context->paths.prsv_loc[PATH_MAX - 1] = '\0';

        rc = vpnor_create_partition_table_from_path(context,
                                                    PARTITION_FILES_RO_LOC);
        if (rc < 0)
            return rc;
    }

    return 0;
}

int vpnor_create_partition_table_from_path(struct mbox_context *context,
                                           const char *path)
{
    namespace err = sdbusplus::xyz::openbmc_project::Common::Error;
    namespace fs = std::experimental::filesystem;
    namespace vpnor = openpower::virtual_pnor;

    if (context && !context->vpnor)
    {
        fs::path dir(path);
        try
        {
            context->vpnor = new vpnor_partition_table;
            context->vpnor->table =
                new openpower::virtual_pnor::partition::Table(
                    std::move(dir), 1 << context->erase_size_shift,
                    context->flash_size);
        }
        catch (vpnor::TocEntryError &e)
        {
            MSG_ERR("%s\n", e.what());
            phosphor::logging::commit<err::InternalFailure>();
            return -MBOX_R_SYSTEM_ERROR;
        }
    }

    return 0;
}

int vpnor_copy_bootloader_partition(const struct mbox_context *context)
{
    // The hostboot bootloader has certain size/offset assumptions, so
    // we need a special partition table here.
    // It assumes the PNOR is 64M, the TOC size is 32K, the erase block is
    // 4K, the page size is 4K.
    // It also assumes the TOC is at the 'end of pnor - toc size - 1 page size'
    // offset, and first looks for the TOC here, before proceeding to move up
    // page by page looking for the TOC. So it is optimal to place the TOC at
    // this offset.
    constexpr size_t eraseSize = 0x1000;
    constexpr size_t pageSize = 0x1000;
    constexpr size_t pnorSize = 0x4000000;
    constexpr size_t tocMaxSize = 0x8000;
    constexpr size_t tocStart = pnorSize - tocMaxSize - pageSize;
    constexpr auto blPartitionName = "HBB";

    namespace err = sdbusplus::xyz::openbmc_project::Common::Error;
    namespace fs = std::experimental::filesystem;
    namespace vpnor = openpower::virtual_pnor;

    try
    {
        openpower::virtual_pnor::partition::Table blTable(
            fs::path{PARTITION_FILES_RO_LOC}, eraseSize, pnorSize);

        vpnor_partition_table vtbl{};
        vtbl.table = &blTable;
        struct mbox_context local
        {
        };
        local.vpnor = &vtbl;
        local.block_size_shift = log_2(eraseSize);
        memcpy(&local.paths, &context->paths, sizeof(local.paths));

        size_t tocOffset = 0;

        // Copy TOC
        copy_flash(&local, tocOffset,
                   static_cast<uint8_t *>(context->mem) + tocStart,
                   blTable.capacity());
        const pnor_partition &partition = blTable.partition(blPartitionName);
        size_t hbbOffset = partition.data.base * eraseSize;
        uint32_t hbbSize = partition.data.actual;
        // Copy HBB
        copy_flash(&local, hbbOffset,
                   static_cast<uint8_t *>(context->mem) + hbbOffset, hbbSize);
    }
    catch (err::InternalFailure &e)
    {
        phosphor::logging::commit<err::InternalFailure>();
        return -MBOX_R_SYSTEM_ERROR;
    }
    catch (vpnor::TocEntryError &e)
    {
        MSG_ERR("%s\n", e.what());
        phosphor::logging::commit<err::InternalFailure>();
        return -MBOX_R_SYSTEM_ERROR;
    }

    return 0;
}

void destroy_vpnor(struct mbox_context *context)
{
    if (context && context->vpnor)
    {
        delete context->vpnor->table;
        delete context->vpnor;
        context->vpnor = nullptr;
    }
}
OpenPOWER on IntegriCloud