summaryrefslogtreecommitdiffstats
path: root/src/usr/hdat/hdattpmdata.C
blob: 9337c7b9e5701aa0df2a79e10ae10d629e40cbad (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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/usr/hdat/hdattpmdata.C $                                  */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2017,2018                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#include <ctype.h>
#include "hdattpmdata.H"
#include <attributeenums.H>
#include "hdatutil.H"
#include <sys/mm.h>
#include <sys/mmio.h>
#include <sys/internode.h>
#include <vpd/mvpdenums.H>
#include <pnor/pnorif.H>
#include <util/align.H>
#include <algorithm>

#include <devicefw/userif.H>
#include <targeting/common/util.H>
#include <targeting/common/target.H>
#include <targeting/common/targetservice.H>
#include <targeting/common/utilFilter.H>
#include <targeting/common/entitypath.H>

namespace HDAT
{

extern trace_desc_t *g_trac_hdat;

HdatTpmData::HdatTpmData(errlHndl_t &o_errlHndl,
                         const HDAT::hdatMsAddr_t &i_msAddr):
    iv_msAddr(i_msAddr),
    iv_hdatTpmData(nullptr)
{
    assert(o_errlHndl == nullptr,"The error log handle passed must be nullptr");

    const uint64_t l_baseAddr = static_cast<uint64_t>(i_msAddr.hi) << 32
                                                                 | i_msAddr.lo;

    // get the top level target
    TARGETING::Target* sys = nullptr;
    TARGETING::targetService().getTopLevelTarget( sys );
    assert(sys != nullptr,
            "HdatTpmData::HdatTpmData: Bug! Could not obtain top level target");

    // get the node bit string to see what our node layout looks like
    auto l_nodeBits = sys->getAttr<TARGETING::ATTR_HB_EXISTING_IMAGE>();

    // count the bits to get the functional/present nodes
    iv_numNodes = __builtin_popcount(l_nodeBits);

    // Must be at least one. Add one in the zero case.
    iv_numNodes += !iv_numNodes;

    const auto maxLogicalSize = hdatTpmDataCalcInstanceSize() * iv_numNodes;
    const uint64_t l_size = ALIGN_PAGE(maxLogicalSize) + PAGESIZE;

    const uint64_t l_alignedAddr = ALIGN_PAGE_DOWN(l_baseAddr);

    auto l_virtAddr = reinterpret_cast<uint8_t*>(
        mm_block_map(reinterpret_cast<void*>(l_alignedAddr),l_size));
    if (l_virtAddr)
    {
        const auto l_offset = l_baseAddr - l_alignedAddr;

        iv_hdatTpmData = reinterpret_cast<hdatTpmData_t *>(l_virtAddr +
                                                                     l_offset);

        memset(iv_hdatTpmData, 0x0, maxLogicalSize);

        HDAT_DBG("Ctr iv_hdatTpmData addr 0x%.16llX virtual addr 0x%.16llX",
                                    reinterpret_cast<uint64_t>(iv_hdatTpmData),
                                    reinterpret_cast<uint64_t>(l_virtAddr));
    }
    else
    {
        /*@
         * @errortype
         * @moduleid          HDAT::MOD_TPMDATA_CONSTRUCTOR
         * @reasoncode        HDAT::RC_DEV_MAP_FAIL
         * @userdata1[00:31]  Address attempted to map upper
         * @userdata1[32:63]  Address attempted to map lower
         * @userdata2[00:31]  Size of mapped region upper
         * @userdata2[32:63]  Size of mapped region lower
         * @devdesc           Creation of mapped region failed
         * @custdesc          Firmware encountered an internal error
         */
        hdatBldErrLog(o_errlHndl,
            MOD_TPMDATA_CONSTRUCTOR,
            RC_DEV_MAP_FAIL,
            static_cast<uint32_t>(UINT64_HIGH(l_alignedAddr)),
            static_cast<uint32_t>(UINT64_LOW(l_alignedAddr)),
            static_cast<uint32_t>(UINT64_HIGH(l_size)),
            static_cast<uint32_t>(UINT64_LOW(l_size)),
            ERRORLOG::ERRL_SEV_UNRECOVERABLE,
            HDAT_VERSION1,
            false);
    }
}

HdatTpmData::~HdatTpmData()
{
    const uint64_t l_unmapAddr = ALIGN_PAGE_DOWN(
                                   reinterpret_cast<uint64_t>(iv_hdatTpmData));

    // if the constructor successfully mapped the region then
    // it must be unmapped
    if (iv_hdatTpmData)
    {
        auto rc = mm_block_unmap(reinterpret_cast<void*>(l_unmapAddr));
        if (rc)
        {
            errlHndl_t l_errl = nullptr;
            /*@
             * @errortype
             * @severity          ERRL_SEV_UNRECOVERABLE
             * @moduleid          HDAT::MOD_TPMDATA_DESTRUCTOR
             * @reasoncode        HDAT::RC_DEV_MAP_FAIL
             * @userdata1[00:31]  Address attempted to unmap upper
             * @userdata1[32:63]  Address attempted to unmap lower
             * @devdesc           Unmap of a mapped region failed
             * @custdesc          Firmware encountered an internal error
             */
            hdatBldErrLog(l_errl,
                MOD_TPMDATA_DESTRUCTOR,
                RC_DEV_MAP_FAIL,
                static_cast<uint32_t>(UINT64_HIGH(l_unmapAddr)),
                static_cast<uint32_t>(UINT64_LOW(l_unmapAddr)),
                0, 0,
                ERRORLOG::ERRL_SEV_UNRECOVERABLE,
                HDAT_VERSION1,
                true);
        }
        iv_hdatTpmData = nullptr;
    }
}

errlHndl_t HdatTpmData::hdatLoadTpmData(uint32_t &o_size, uint32_t &o_count)
{
    errlHndl_t l_errl = nullptr;

    o_count = 0;

    // calculate the size of each instance
    o_size = hdatTpmDataCalcInstanceSize();

    auto l_hdatTpmData = iv_hdatTpmData;

    for (uint32_t i_instance = 0; i_instance < iv_numNodes; i_instance++)
    {
        // Note: HdatTpmData constructor already cleared the memory to the tune
        // of o_size (hdatTpmDataCalcInstanceSize()) bytes

        // We add the first two fields for a reference to aid in debugging,
        // but the rest will be populated in FSP/OpenPower common code. Any
        // work here would just be duplicated later during the runtime istep.

        // add the format magic number
        iv_hdatTpmData->hdatHdr.hdatStructId = HDAT::HDAT_HDIF_STRUCT_ID;

        // add the eyecatcher
        memcpy(iv_hdatTpmData->hdatHdr.hdatStructName,
           g_hdatTpmDataEyeCatch,
           strlen(g_hdatTpmDataEyeCatch));

        // Account for this one instance of Node TPM Related Data.
        ++o_count;

        // Move to the next instance
        l_hdatTpmData = reinterpret_cast<hdatTpmData_t *>(
                        reinterpret_cast<uint8_t*>(l_hdatTpmData) + o_size);
    }

    return l_errl;
}

}
OpenPOWER on IntegriCloud