diff options
| author | Ilya Smirnov <ismirno@us.ibm.com> | 2018-10-08 15:27:28 -0500 |
|---|---|---|
| committer | Daniel M. Crowell <dcrowell@us.ibm.com> | 2018-11-07 20:36:51 -0600 |
| commit | 22134d69a2016dd1ea6d9de858f4e68f732289ae (patch) | |
| tree | 3e6996dc775e869d6643e748f83d728187add2c3 /src/usr | |
| parent | beca51100d6ba74914391b2a0baec830f427ec99 (diff) | |
| download | blackbird-hostboot-22134d69a2016dd1ea6d9de858f4e68f732289ae.tar.gz blackbird-hostboot-22134d69a2016dd1ea6d9de858f4e68f732289ae.zip | |
SMF: Port NVRAM Reading Logic From Skiboot
As part of SMF secure memory distribution, we need to be able
to read the size of secure memory from NVRAM PNOR partition
(for OpenPOWER). The functionality to read (index into) NVRAM
already exists in skiboot. This commits ports the bare minimum
functionality required to read NVRAM from skiboot to hb.
Change-Id: I17b9014ec3df590bcd8745ae70e0f96e36580117
RTC: 192411
Reviewed-on: http://rchgit01.rchland.ibm.com/gerrit1/67414
Tested-by: Jenkins Server <pfd-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP Build CI <op-jenkins+hostboot@us.ibm.com>
Tested-by: Jenkins OP HW <op-hw-jenkins+hostboot@us.ibm.com>
Tested-by: FSP CI Jenkins <fsp-CI-jenkins+hostboot@us.ibm.com>
Reviewed-by: Dean Sanner <dsanner@us.ibm.com>
Reviewed-by: Roland Veloz <rveloz@us.ibm.com>
Reviewed-by: Nicholas E. Bofferding <bofferdn@us.ibm.com>
Reviewed-by: Daniel M. Crowell <dcrowell@us.ibm.com>
Diffstat (limited to 'src/usr')
| -rw-r--r-- | src/usr/makefile | 1 | ||||
| -rw-r--r-- | src/usr/nvram/import/nvram-format.C | 232 | ||||
| -rw-r--r-- | src/usr/nvram/makefile | 37 | ||||
| -rw-r--r-- | src/usr/nvram/nvram_interface.C | 119 | ||||
| -rw-r--r-- | src/usr/sbeio/common/sbe_attn.C | 2 |
5 files changed, 390 insertions, 1 deletions
diff --git a/src/usr/makefile b/src/usr/makefile index ca4f9d512..6d9ccd9c6 100644 --- a/src/usr/makefile +++ b/src/usr/makefile @@ -70,6 +70,7 @@ SUBDIRS += diag.d SUBDIRS += xz.d SUBDIRS += hwplibs.d SUBDIRS += $(if $(CONFIG_ENABLE_HDAT_IN_HOSTBOOT),hdat.d,) +SUBDIRS += $(if $(CONFIG_FSP_BUILD),,nvram.d) #errldisplay relies on some generated files from PRD. #Enforce that it goes after diff --git a/src/usr/nvram/import/nvram-format.C b/src/usr/nvram/import/nvram-format.C new file mode 100644 index 000000000..d57f9ab51 --- /dev/null +++ b/src/usr/nvram/import/nvram-format.C @@ -0,0 +1,232 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/nvram/import/nvram-format.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 <skiboot.h> +#include <nvram.h> + +struct chrp_nvram_hdr { + uint8_t sig; + uint8_t cksum; + be16 len; + char name[12]; +}; + +static struct chrp_nvram_hdr *skiboot_part_hdr; + +static uint8_t chrp_nv_cksum(struct chrp_nvram_hdr *hdr) +{ + struct chrp_nvram_hdr h_copy = *hdr; + uint8_t b_data, i_sum, c_sum; + uint8_t *p = (uint8_t *)&h_copy; + unsigned int nbytes = sizeof(h_copy); + + h_copy.cksum = 0; + for (c_sum = 0; nbytes; nbytes--) { + b_data = *(p++); + i_sum = c_sum + b_data; + if (i_sum < c_sum) + i_sum++; + c_sum = i_sum; + } + return c_sum; +} + +#define NVRAM_SIG_FW_PRIV 0x51 +#define NVRAM_SIG_SYSTEM 0x70 +#define NVRAM_NAME_COMMON "common" +#define NVRAM_NAME_FW_PRIV "ibm,skiboot" +#define NVRAM_SIZE_FW_PRIV 0x1000 + +static const char *find_next_key(const char *start, const char *end) +{ + /* + * Unused parts of the partition are set to NUL. If we hit two + * NULs in a row then we assume that we have hit the end of the + * partition. + */ + if (*start == 0) + return NULL; + + while (start < end) { + if (*start == 0) + return start + 1; + + start++; + } + + return NULL; +} + +/* + * Check that the nvram partition layout is sane and that it + * contains our required partitions. If not, we re-format the + * lot of it + */ +int nvram_check(void *nvram_image, const uint32_t nvram_size) +{ + unsigned int offset = 0; + bool found_common = false; + + skiboot_part_hdr = NULL; + + while (offset + sizeof(struct chrp_nvram_hdr) < nvram_size) { +#ifdef __HOSTBOOT_MODULE + struct chrp_nvram_hdr *h = reinterpret_cast<chrp_nvram_hdr*>( + reinterpret_cast<uint8_t*>(nvram_image) + + offset); +#else + struct chrp_nvram_hdr *h = nvram_image + offset; +#endif + + if (chrp_nv_cksum(h) != h->cksum) { + prerror("NVRAM: Partition at offset 0x%x" + " has bad checksum: 0x%02x vs 0x%02x\n", + offset, h->cksum, chrp_nv_cksum(h)); + goto failed; + } + if (be16_to_cpu(h->len) < 1) { + prerror("NVRAM: Partition at offset 0x%x" + " has incorrect 0 length\n", offset); + goto failed; + } + + if (h->sig == NVRAM_SIG_SYSTEM && + strcmp(h->name, NVRAM_NAME_COMMON) == 0) + found_common = true; + + if (h->sig == NVRAM_SIG_FW_PRIV && + strcmp(h->name, NVRAM_NAME_FW_PRIV) == 0) + skiboot_part_hdr = h; + + offset += be16_to_cpu(h->len) << 4; + if (offset > nvram_size) { + prerror("NVRAM: Partition at offset 0x%x" + " extends beyond end of nvram !\n", offset); + goto failed; + } + } + if (!found_common) { + prlog_once(PR_ERR, "NVRAM: Common partition not found !\n"); + goto failed; + } + + if (!skiboot_part_hdr) { + prlog_once(PR_ERR, "NVRAM: Skiboot private partition not found !\n"); + goto failed; + } else { + /* + * The OF NVRAM format requires config strings to be NUL + * terminated and unused memory to be set to zero. Well behaved + * software should ensure this is done for us, but we should + * always check. + */ + const char *last_byte = (const char *) skiboot_part_hdr + + be16_to_cpu(skiboot_part_hdr->len) * 16 - 1; + + if (*last_byte != 0) { + prerror("NVRAM: Skiboot private partition is not NUL terminated"); + goto failed; + } + } + + prlog(PR_INFO, "NVRAM: Layout appears sane\n"); + assert(skiboot_part_hdr); + return 0; + failed: + return -1; +} + +/* + * nvram_query() - Searches skiboot NVRAM partition for a key=value pair. + * + * Returns a pointer to a NUL terminated string that contains the value + * associated with the given key. + */ +const char *nvram_query(const char *key) +{ + const char *part_end, *start; + int key_len = strlen(key); + + assert(key); + + if (!nvram_has_loaded()) { + prlog(PR_DEBUG, + "NVRAM: Query for '%s' must wait for NVRAM to load\n", + key); + if (!nvram_wait_for_load()) { + prlog(PR_CRIT, "NVRAM: Failed to load\n"); + return NULL; + } + } + + /* + * The running OS can modify the NVRAM as it pleases so we need to be + * a little paranoid and check that it's ok before we try parse it. + * + * NB: nvram_validate() can update skiboot_part_hdr + */ + if (!nvram_validate()) + return NULL; + + assert(skiboot_part_hdr); + + part_end = (const char *) skiboot_part_hdr + + be16_to_cpu(skiboot_part_hdr->len) * 16 - 1; + + start = (const char *) skiboot_part_hdr + + sizeof(*skiboot_part_hdr); + + if (!key_len) { + prlog(PR_WARNING, "NVRAM: search key is empty!\n"); + return NULL; + } + + if (key_len > 32) + prlog(PR_WARNING, "NVRAM: search key '%s' is longer than 32 chars\n", key); + + while (start) { + int remaining = part_end - start; + + prlog(PR_TRACE, "NVRAM: '%s' (%lu)\n", + start, strlen(start)); + + if (key_len + 1 > remaining) + return NULL; + + if (!strncmp(key, start, key_len) && start[key_len] == '=') { + const char *value = &start[key_len + 1]; + + prlog(PR_DEBUG, "NVRAM: Searched for '%s' found '%s'\n", + key, value); + + return value; + } + + start = find_next_key(start, part_end); + } + + prlog(PR_DEBUG, "NVRAM: '%s' not found\n", key); + + return NULL; +} diff --git a/src/usr/nvram/makefile b/src/usr/nvram/makefile new file mode 100644 index 000000000..672e85529 --- /dev/null +++ b/src/usr/nvram/makefile @@ -0,0 +1,37 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/usr/nvram/makefile $ +# +# OpenPOWER HostBoot Project +# +# Contributors Listed Below - COPYRIGHT 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 +ROOTPATH = ../../.. + +MODULE = nvram + +EXTRAINCDIR += ${ROOTPATH}/src/include/usr +EXTRAINCDIR += ${ROOTPATH}/src/include/usr/nvram/import + +OBJS += nvram_interface.o +OBJS += nvram-format.o + +VPATH += import + +include ${ROOTPATH}/config.mk diff --git a/src/usr/nvram/nvram_interface.C b/src/usr/nvram/nvram_interface.C new file mode 100644 index 000000000..e4bb95796 --- /dev/null +++ b/src/usr/nvram/nvram_interface.C @@ -0,0 +1,119 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/usr/nvram/nvram_interface.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 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 <nvram/nvram_interface.H> +#include <nvram/import/nvram.h> +#include <nvram/nvram_reasoncodes.H> +#include <pnor/pnorif.H> + +static bool g_is_nvram_checked = false; + +namespace NVRAM_TRACE +{ + trace_desc_t * g_trac_nvram = nullptr; + // NVRAM won't be read too often in hostboot, so 1KB should be enough. + TRAC_INIT(&g_trac_nvram, NVRAM_COMP_NAME, KILOBYTE); +} + +namespace NVRAM +{ + +/* + * @brief Searches NVRAM partition for the i_key and puts the value in + * o_val. An error is returned if NVRAM can't be loaded or if + * it's formatted incorrectly. + */ +errlHndl_t nvramRead(const char* const i_key, const char*& o_val) +{ + errlHndl_t l_errl = nullptr; + + do { + + if(i_key == nullptr) + { + /*@ errorlog + * @errortype ERRL_SEV_UNRECOVERABLE + * @moduleid NVRAM::MOD_NVRAM_READ + * @reasoncode NVRAM::RC_NVRAM_READ_NULL_KEY + * @devdesc A nullptr was passed for i_key to nvramRead + * @custdesc Error occurred during system boot. + */ + l_errl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_UNRECOVERABLE, + NVRAM::MOD_NVRAM_READ, + NVRAM::RC_NVRAM_READ_NULL_KEY, + 0, + 0); + break; + } + + if(!g_is_nvram_checked) + { + PNOR::SectionInfo_t l_nvramSectionInfo; + l_errl = PNOR::getSectionInfo(PNOR::NVRAM, l_nvramSectionInfo); + if(l_errl) + { + break; + } + + // Skiboot function to check NVRAM for integrity. + // This function will also populate the inner skiboot_part_hdr + // pointer to point to the start of the NVRAM. nvram_query will + // then attempt to index into skiboot_part_hdr to find the K/V + // pairs. + int l_rc = nvram_check( + reinterpret_cast<uint8_t*>(l_nvramSectionInfo.vaddr), + l_nvramSectionInfo.size); + if(l_rc) + { + /*@ errorlog + * @errortype ERRL_SEV_INFORMATIONAL + * @moduleid NVRAM::MOD_NVRAM_READ + * @reasoncode NVRAM::RC_NVRAM_CHECK_FAILED + * @userdata1 rc from nvram_check + * @userdata2 NVRAM virtual address + * @devdesc nvram_check failed during an attempt to read the + * NVRAM PNOR partition. + * @custdesc Error occurred during system boot. + */ + l_errl = new ERRORLOG::ErrlEntry(ERRORLOG::ERRL_SEV_INFORMATIONAL, + NVRAM::MOD_NVRAM_READ, + NVRAM::RC_NVRAM_CHECK_FAILED, + l_rc, + l_nvramSectionInfo.vaddr); + l_errl->collectTrace(NVRAM_COMP_NAME); + l_errl->collectTrace(PNOR_COMP_NAME); + break; + } + + g_is_nvram_checked = true; + } + + o_val = nvram_query(i_key); + + }while(0); + + return l_errl; +} + +} // namespace NVRAM diff --git a/src/usr/sbeio/common/sbe_attn.C b/src/usr/sbeio/common/sbe_attn.C index fb146ed11..f09439344 100644 --- a/src/usr/sbeio/common/sbe_attn.C +++ b/src/usr/sbeio/common/sbe_attn.C @@ -199,4 +199,4 @@ namespace SBEIO return l_err; } -};
\ No newline at end of file +}; |

