summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-phosphor/fru
diff options
context:
space:
mode:
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-phosphor/fru')
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru.bb30
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/CMakeLists.txt7
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/SetBaseboardFru.service9
-rwxr-xr-xmeta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/checkFru.sh44
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/mkfru.cpp219
5 files changed, 309 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru.bb b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru.bb
new file mode 100644
index 000000000..53cec437d
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru.bb
@@ -0,0 +1,30 @@
+SUMMARY = "Default Fru"
+DESCRIPTION = "Builds a default FRU file at runtime based on board ID"
+
+inherit systemd
+inherit cmake
+
+SYSTEMD_SERVICE_${PN} = "SetBaseboardFru.service"
+
+S = "${WORKDIR}"
+SRC_URI = "file://checkFru.sh \
+ file://SetBaseboardFru.service \
+ file://mkfru.cpp \
+ file://CMakeLists.txt \
+ "
+
+LICENSE = "Apache-2.0"
+LIC_FILES_CHKSUM = "\
+ file://${INTELBASE}/COPYING.apache-2.0;md5=34400b68072d710fecd0a2940a0d1658 \
+ file://mkfru.cpp;beginline=2;endline=14;md5=c451359f18a13ee69602afce1588c01a \
+ "
+
+RDEPENDS_${PN} = "bash"
+
+do_install_append() {
+ install -d ${D}${bindir}
+ install -m 0755 ${S}/checkFru.sh ${D}/${bindir}/checkFru.sh
+
+ install -d ${D}${base_libdir}/systemd/system
+ install -m 0644 ${S}/SetBaseboardFru.service ${D}${base_libdir}/systemd/system
+}
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/CMakeLists.txt b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/CMakeLists.txt
new file mode 100644
index 000000000..a8e633644
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.10 FATAL_ERROR)
+project(mkfru CXX)
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+add_executable(mkfru mkfru.cpp)
+install(TARGETS mkfru DESTINATION bin)
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/SetBaseboardFru.service b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/SetBaseboardFru.service
new file mode 100644
index 000000000..d8c2a75ac
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/SetBaseboardFru.service
@@ -0,0 +1,9 @@
+[Unit]
+Description=Check for FRU presence
+
+[Service]
+ExecStart=/usr/bin/checkFru.sh
+Type=oneshot
+
+[Install]
+WantedBy=basic.target
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/checkFru.sh b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/checkFru.sh
new file mode 100755
index 000000000..908e4b51e
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/checkFru.sh
@@ -0,0 +1,44 @@
+#!/bin/bash
+
+# this script checks the gpio id and loads the correct baseboard fru
+FRUPATH="/etc/fru"
+fruFile="$FRUPATH/baseboard.fru.bin"
+if [ -f $fruFile ]; then
+ exit 0
+fi
+
+read_id() {
+ local idx=0
+ local result=0
+ local value=0
+ for ((idx=0; idx<6; idx++))
+ do
+ typeset -i value=$(gpioget $(gpiofind "FM_BMC_BOARD_SKU_ID${idx}_N"))
+ value=$((value << idx))
+ result=$((result | value))
+ done
+ echo $result
+}
+
+BOARD_ID=$(read_id)
+if grep -q 'CPU part\s*: 0xb76' /proc/cpuinfo; then
+ # AST2500
+ case $BOARD_ID in
+ 12) NAME="D50TNP1SB";;
+ 40) NAME="CooperCity";;
+ 45) NAME="WilsonCity";;
+ 60) NAME="M50CYP2SB2U";;
+ 62) NAME="WilsonPoint";;
+ *) NAME="S2600WFT";;
+ esac
+fi
+
+if [ -z "$NAME" ]; then
+ NAME="Unknown"
+fi
+
+cd /tmp
+mkdir -p $FRUPATH
+mkfru $NAME
+mv $NAME.fru.bin $fruFile
+
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/mkfru.cpp b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/mkfru.cpp
new file mode 100644
index 000000000..afadbd324
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/fru/default-fru/mkfru.cpp
@@ -0,0 +1,219 @@
+/*
+// Copyright (c) 2019 Intel Corporation
+//
+// 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.
+//
+// Abstract: default FRU generation
+//
+*/
+
+#include <fstream>
+#include <iostream>
+#include <iterator>
+#include <numeric>
+#include <string>
+#include <vector>
+
+constexpr uint8_t fillChar = '.';
+constexpr uint8_t eof = 0xc1;
+const std::string intel = "Intel Corporation";
+
+// round up to nearest block size (power of 2)
+constexpr size_t blockRound(size_t len, size_t blk)
+{
+ return ((len) + (((blk) - ((len) & ((blk)-1))) & ((blk)-1)));
+}
+
+uint8_t mklen(uint8_t len)
+{
+ return static_cast<uint8_t>((0x3 << 6) | len);
+}
+
+struct FruEntry
+{
+ static constexpr size_t fruBlockSize = 8; // type, length, checksum
+ static constexpr size_t fixedBytes = 3; // type, length, checksum
+ FruEntry() = delete;
+ FruEntry(const std::vector<uint8_t>& contents)
+ {
+ constexpr size_t verOffset = 0;
+ constexpr size_t lenOffset = 1;
+ value.resize(blockRound(fixedBytes + contents.size(), fruBlockSize));
+ value[verOffset] = 1;
+ value[lenOffset] = blocks();
+ std::copy(contents.begin(), contents.end(), value.begin() + 2);
+ addChecksum();
+ }
+
+ void addChecksum()
+ {
+ int sum = std::accumulate(value.begin(), value.end(), 0);
+ value.back() = static_cast<uint8_t>(256 - sum & 0xff);
+ }
+
+ uint8_t blocks() const
+ {
+ return static_cast<uint8_t>(value.size() / 8);
+ }
+
+ std::vector<uint8_t> value;
+};
+
+size_t fillDots(std::vector<uint8_t>::iterator start, size_t count)
+{
+ *start++ = mklen(count); // prefix with (0xc0 | count)
+ auto end = start + count++;
+ std::fill(start, end, '.');
+ return count;
+}
+
+size_t fillStr(std::vector<uint8_t>::iterator start, const std::string& str)
+{
+ size_t count = str.size();
+ *start++ = mklen(count++); // prefix with (0xc0 | count)
+ std::copy(str.begin(), str.end(), start);
+ return count;
+}
+
+std::vector<uint8_t> genChassisContents()
+{
+ constexpr size_t pnSize = 18;
+ constexpr size_t snSize = 18;
+ constexpr size_t amSize = 31;
+ constexpr size_t headerSize = 1;
+ constexpr size_t contentSize = headerSize + 1 + pnSize + 1 + snSize + 1 +
+ amSize + 1 + amSize + sizeof(eof);
+ std::vector<uint8_t> data(contentSize);
+ size_t offset = 0;
+ // chassis type (main server chassis)
+ data[offset++] = 0x17;
+ // chassis part number
+ offset += fillDots(data.begin() + offset, pnSize);
+ // chassis serial number
+ offset += fillDots(data.begin() + offset, snSize);
+ // info am1
+ offset += fillDots(data.begin() + offset, amSize);
+ // info am2
+ offset += fillDots(data.begin() + offset, amSize);
+ data[offset] = eof;
+
+ return data;
+}
+
+std::vector<uint8_t> genBoardContents(const std::string& name)
+{
+ constexpr size_t headerSize = 4;
+ constexpr size_t snSize = 12;
+ constexpr size_t pnSize = 10;
+ const std::string version = "FRU Ver 0.01";
+ size_t contentSize = headerSize + 1 + name.size() + 1 + intel.size() + 1 +
+ snSize + 1 + pnSize + 1 + version.size() + sizeof(eof);
+ std::vector<uint8_t> data(contentSize);
+ size_t offset = 0;
+ // chassis type (main server chassis)
+ data[offset++] = 0; // language code
+ data[offset++] = 0; // mfg date/time
+ data[offset++] = 0; // mfg date/time
+ data[offset++] = 0; // mfg date/time
+ // manufacturer name
+ offset += fillStr(data.begin() + offset, intel);
+ // product name
+ offset += fillStr(data.begin() + offset, name);
+ // board sn
+ offset += fillDots(data.begin() + offset, snSize);
+ // board pn
+ offset += fillDots(data.begin() + offset, pnSize);
+ // fru version string
+ offset += fillStr(data.begin() + offset, version);
+ data[offset] = eof;
+
+ return data;
+}
+
+std::vector<uint8_t> genProductContents(const std::string& name)
+{
+ constexpr size_t headerSize = 1;
+ constexpr size_t pnSize = 10;
+ constexpr size_t pvSize = 20;
+ constexpr size_t snSize = 12;
+ constexpr size_t atSize = 20;
+ constexpr size_t idSize = 0;
+ const std::string version = "FRU Ver 0.01";
+ size_t contentSize = headerSize + 1 + intel.size() + 1 + name.size() + 1 +
+ pnSize + 1 + pvSize + 1 + snSize + 1 + atSize + 1 +
+ idSize + sizeof(eof);
+ std::vector<uint8_t> data(contentSize);
+ size_t offset = 0;
+ // chassis type (main server chassis)
+ data[offset++] = 0; // language code
+ // manufacturer name
+ offset += fillStr(data.begin() + offset, intel);
+ // product name
+ offset += fillStr(data.begin() + offset, name);
+ // product part number
+ offset += fillDots(data.begin() + offset, pnSize);
+ // product version
+ offset += fillDots(data.begin() + offset, pvSize);
+ // product serial number
+ offset += fillDots(data.begin() + offset, snSize);
+ // product asset tag
+ offset += fillDots(data.begin() + offset, atSize);
+ // empty fru file id
+ offset += fillDots(data.begin() + offset, idSize);
+ data[offset] = eof;
+
+ return data;
+}
+
+int createFru(const std::string& name)
+{
+ std::vector<uint8_t> internal{1, 0, 0, 0, 0, 0, 0, 1}; // fixed data
+ FruEntry chassis(genChassisContents());
+ FruEntry board(genBoardContents(name));
+ FruEntry product(genProductContents(name));
+ uint8_t offset = 1; // room for header's offset
+ FruEntry header({
+ offset += 1, // internal size
+ offset += chassis.blocks(),
+ offset += board.blocks(),
+ });
+ std::string filename = name + ".fru.bin";
+ std::ofstream output(filename);
+ std::ostream_iterator<uint8_t> outputIter(output);
+ std::copy(header.value.begin(), header.value.end(), outputIter);
+ std::copy(internal.begin(), internal.end(), outputIter);
+ std::copy(chassis.value.begin(), chassis.value.end(), outputIter);
+ std::copy(board.value.begin(), board.value.end(), outputIter);
+ std::copy(product.value.begin(), product.value.end(), outputIter);
+ constexpr size_t minFruSize = 0x1ff;
+ size_t fruSize = header.value.size() + internal.size() +
+ chassis.value.size() + board.value.size() +
+ product.value.size();
+ if (fruSize < minFruSize)
+ {
+ std::vector<uint8_t> padding(minFruSize - fruSize);
+ std::copy(padding.begin(), padding.end(), outputIter);
+ }
+ output.close();
+ return 0;
+}
+
+int main(int argc, const char* argv[])
+{
+ if (argc != 2)
+ {
+ std::cerr << "Usage: " << argv[0] << " <'Product Name'>\n";
+ return 1;
+ }
+ return createFru(argv[1]);
+}