extern "C" { #include } #include "attributes_info.H" #include "extensions/phal/common_utils.hpp" #include "extensions/phal/create_pel.hpp" #include "extensions/phal/phal_error.hpp" #include "util.hpp" #include #include #include #include #include namespace openpower { namespace phal { using namespace phosphor::logging; /** * @brief Select BOOT SEEPROM and Measurement SEEPROM(PRIMARY/BACKUP) on POWER * processor position 0/1 depending on boot count before kicking off * the boot. * * @return void */ void selectBootSeeprom() { struct pdbg_target* procTarget; ATTR_BACKUP_SEEPROM_SELECT_Enum bkpSeePromSelect; ATTR_BACKUP_MEASUREMENT_SEEPROM_SELECT_Enum bkpMeaSeePromSelect; pdbg_for_each_class_target("proc", procTarget) { if (!isPrimaryProc(procTarget)) { continue; } // Choose seeprom side to boot from based on boot count if (getBootCount() > 0) { log("Setting SBE seeprom side to 0", entry("SBE_SIDE_SELECT=%d", ENUM_ATTR_BACKUP_SEEPROM_SELECT_PRIMARY)); bkpSeePromSelect = ENUM_ATTR_BACKUP_SEEPROM_SELECT_PRIMARY; bkpMeaSeePromSelect = ENUM_ATTR_BACKUP_MEASUREMENT_SEEPROM_SELECT_PRIMARY; } else { log("Setting SBE seeprom side to 1", entry("SBE_SIDE_SELECT=%d", ENUM_ATTR_BACKUP_SEEPROM_SELECT_SECONDARY)); bkpSeePromSelect = ENUM_ATTR_BACKUP_SEEPROM_SELECT_SECONDARY; bkpMeaSeePromSelect = ENUM_ATTR_BACKUP_MEASUREMENT_SEEPROM_SELECT_SECONDARY; } // Set the Attribute as per bootcount policy for boot seeprom if (DT_SET_PROP(ATTR_BACKUP_SEEPROM_SELECT, procTarget, bkpSeePromSelect)) { log( "Attribute [ATTR_BACKUP_SEEPROM_SELECT] set failed"); throw std::runtime_error( "Attribute [ATTR_BACKUP_SEEPROM_SELECT] set failed"); } // Set the Attribute as per bootcount policy for measurement seeprom if (DT_SET_PROP(ATTR_BACKUP_MEASUREMENT_SEEPROM_SELECT, procTarget, bkpMeaSeePromSelect)) { log( "Attribute [ATTR_BACKUP_MEASUREMENT_SEEPROM_SELECT] set " "failed"); throw std::runtime_error( "Attribute [ATTR_BACKUP_MEASUREMENT_SEEPROM_SELECT] set " "failed"); } } } /** * @brief Read the HW Level from VPD and set CLK NE termination site * Note any failure in this function will result startHost failure. */ void setClkNETerminationSite() { // Get Motherborad VINI Recored "HW" keyword constexpr auto objPath = "/xyz/openbmc_project/inventory/system/chassis/motherboard"; constexpr auto kwdVpdInf = "com.ibm.ipzvpd.VINI"; constexpr auto hwKwd = "HW"; auto bus = sdbusplus::bus::new_default(); std::string service = util::getService(bus, objPath, kwdVpdInf); auto properties = bus.new_method_call( service.c_str(), objPath, "org.freedesktop.DBus.Properties", "Get"); properties.append(kwdVpdInf); properties.append(hwKwd); // Store "HW" Keyword data. std::variant> val; try { auto result = bus.call(properties); result.read(val); } catch (const sdbusplus::exception::exception& e) { log("Get HW Keyword read from VINI Failed"); throw std::runtime_error("Get HW Keyword read from VINI Failed"); } auto hwData = std::get>(val); //"HW" Keyword size is 2 as per VPD spec. constexpr auto hwKwdSize = 2; if (hwKwdSize != hwData.size()) { log( fmt::format("Incorrect VINI records HW Keyword data size({})", hwData.size()) .c_str()); throw std::runtime_error("Incorrect VINI records HW Keyword data size"); } log(fmt::format("VINI Records HW[0]:{} HW[1]:{}", hwData.at(0), hwData.at(1)) .c_str()); // VINI Record "HW" keyword's Byte 0's MSB bit indicates // proc or planar type need to choose. constexpr uint8_t SYS_CLK_NE_TERMINATION_ON_MASK = 0x80; ATTR_SYS_CLK_NE_TERMINATION_SITE_Type clockTerm = ENUM_ATTR_SYS_CLK_NE_TERMINATION_SITE_PLANAR; if (SYS_CLK_NE_TERMINATION_ON_MASK & hwData.at(0)) { clockTerm = ENUM_ATTR_SYS_CLK_NE_TERMINATION_SITE_PROC; } // update all the processor attributes struct pdbg_target* procTarget; pdbg_for_each_class_target("proc", procTarget) { if (DT_SET_PROP(ATTR_SYS_CLK_NE_TERMINATION_SITE, procTarget, clockTerm)) { log( "Attribute ATTR_SYS_CLK_NE_TERMINATION_SITE set failed"); throw std::runtime_error( "Attribute ATTR_SYS_CLK_NE_TERMINATION_SITE set failed"); } } } /** * @brief Starts the self boot engine on POWER processor position 0 * to kick off a boot. * @return void */ void startHost(enum ipl_type iplType = IPL_TYPE_NORMAL) { try { phal_init(); ipl_set_type(iplType); if (iplType == IPL_TYPE_NORMAL) { // Update SEEPROM side only for NORMAL boot selectBootSeeprom(); } setClkNETerminationSite(); } catch (const std::exception& ex) { log("Exception raised during ipl initialisation", entry("EXCEPTION=%s", ex.what())); openpower::pel::createPEL("org.open_power.PHAL.Error.Boot"); openpower::pel::detail::processBootError(false); throw std::runtime_error("IPL initialization failed"); } // To clear trace if success openpower::pel::detail::processBootError(true); // callback method will be called upon failure which will create the PEL int rc = ipl_run_major(0); if (rc > 0) { log("step 0 failed to start the host"); throw std::runtime_error("Failed to execute host start boot step"); } } /** * @brief Starts the reboot with type memory preserving reboot. * @return void */ void startHostMpReboot() { // set ipl type as mpipl startHost(IPL_TYPE_MPIPL); } /** * @brief Starts the normal boot type. * @return void */ void startHostNormal() { startHost(IPL_TYPE_NORMAL); } REGISTER_PROCEDURE("startHost", startHostNormal) REGISTER_PROCEDURE("startHostMpReboot", startHostMpReboot) } // namespace phal } // namespace openpower