| extern "C" { |
| #include <libpdbg.h> |
| } |
| |
| #include "phalerror/phal_error.hpp" |
| |
| #include <libekb.H> |
| #include <libipl.H> |
| |
| #include <ext_interface.hpp> |
| #include <phosphor-logging/log.hpp> |
| #include <registration.hpp> |
| |
| #include "attributes_info.H" |
| namespace openpower |
| { |
| namespace phal |
| { |
| |
| using namespace phosphor::logging; |
| |
| /** |
| * @brief Check if master processor or not |
| * |
| * @return True/False |
| */ |
| bool isMasterProc(struct pdbg_target* procTarget) |
| { |
| ATTR_PROC_MASTER_TYPE_Type type; |
| |
| // Get processor type (Master or Alt-master) |
| if (DT_GET_PROP(ATTR_PROC_MASTER_TYPE, procTarget, type)) |
| { |
| log<level::ERR>("Attribute [ATTR_PROC_MASTER_TYPE] get failed"); |
| throw std::runtime_error( |
| "Attribute [ATTR_PROC_MASTER_TYPE] get failed"); |
| } |
| |
| /* Attribute value 0 corresponds to master processor */ |
| if (type == 0) |
| { |
| return true; |
| } |
| else |
| { |
| return false; |
| } |
| } |
| |
| /** |
| * @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 (!isMasterProc(procTarget)) |
| { |
| continue; |
| } |
| |
| // Choose seeprom side to boot from based on boot count |
| if (getBootCount() > 0) |
| { |
| log<level::INFO>("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<level::INFO>("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<level::ERR>( |
| "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<level::ERR>( |
| "Attribute [ATTR_BACKUP_MEASUREMENT_SEEPROM_SELECT] set " |
| "failed"); |
| throw std::runtime_error( |
| "Attribute [ATTR_BACKUP_MEASUREMENT_SEEPROM_SELECT] 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) |
| { |
| // add callback methods for debug traces and for boot failures |
| openpower::pel::addBootErrorCallbacks(); |
| |
| if (!pdbg_targets_init(NULL)) |
| { |
| log<level::ERR>("pdbg_targets_init failed"); |
| openpower::pel::detail::processBootErrorCallback(false); |
| throw std::runtime_error("pdbg target initialization failed"); |
| } |
| // To clear trace if success |
| openpower::pel::detail::processBootErrorCallback(true); |
| |
| if (libekb_init()) |
| { |
| log<level::ERR>("libekb_init failed"); |
| openpower::pel::detail::processBootErrorCallback(false); |
| throw std::runtime_error("libekb initialization failed"); |
| } |
| // To clear trace if success |
| openpower::pel::detail::processBootErrorCallback(true); |
| |
| if (ipl_init(IPL_AUTOBOOT) != 0) |
| { |
| log<level::ERR>("ipl_init failed"); |
| openpower::pel::detail::processBootErrorCallback(false); |
| throw std::runtime_error("Boot initialization failed"); |
| } |
| |
| ipl_set_type(iplType); |
| |
| // To clear trace if success |
| openpower::pel::detail::processBootErrorCallback(true); |
| |
| // callback method will be called upon failure which will create the PEL |
| int rc = ipl_run_major(0); |
| if (rc > 0) |
| { |
| log<level::ERR>("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() |
| { |
| // Run select seeprom before poweron |
| try |
| { |
| selectBootSeeprom(); |
| |
| // To clear trace as it is success |
| openpower::pel::detail::processBootErrorCallback(true); |
| } |
| catch (const std::exception& ex) |
| { |
| // create PEL in failure |
| openpower::pel::detail::processBootErrorCallback(false); |
| log<level::ERR>("SEEPROM selection failed", entry("ERR=%s", ex.what())); |
| throw ex; |
| } |
| |
| startHost(); |
| } |
| |
| REGISTER_PROCEDURE("startHost", startHostNormal) |
| REGISTER_PROCEDURE("startHostMpReboot", startHostMpReboot) |
| |
| } // namespace phal |
| } // namespace openpower |