1 extern "C" 2 { 3 #include <libpdbg.h> 4 } 5 6 #include "attributes_info.H" 7 8 #include "extensions/phal/common_utils.hpp" 9 #include "extensions/phal/phal_error.hpp" 10 #include "util.hpp" 11 12 #include <fmt/format.h> 13 #include <libekb.H> 14 15 #include <ext_interface.hpp> 16 #include <phosphor-logging/log.hpp> 17 #include <registration.hpp> 18 19 namespace openpower 20 { 21 namespace phal 22 { 23 24 using namespace phosphor::logging; 25 26 /** 27 * @brief Select BOOT SEEPROM and Measurement SEEPROM(PRIMARY/BACKUP) on POWER 28 * processor position 0/1 depending on boot count before kicking off 29 * the boot. 30 * 31 * @return void 32 */ 33 void selectBootSeeprom() 34 { 35 struct pdbg_target* procTarget; 36 ATTR_BACKUP_SEEPROM_SELECT_Enum bkpSeePromSelect; 37 ATTR_BACKUP_MEASUREMENT_SEEPROM_SELECT_Enum bkpMeaSeePromSelect; 38 39 pdbg_for_each_class_target("proc", procTarget) 40 { 41 if (!isPrimaryProc(procTarget)) 42 { 43 continue; 44 } 45 46 // Choose seeprom side to boot from based on boot count 47 if (getBootCount() > 0) 48 { 49 log<level::INFO>("Setting SBE seeprom side to 0", 50 entry("SBE_SIDE_SELECT=%d", 51 ENUM_ATTR_BACKUP_SEEPROM_SELECT_PRIMARY)); 52 53 bkpSeePromSelect = ENUM_ATTR_BACKUP_SEEPROM_SELECT_PRIMARY; 54 bkpMeaSeePromSelect = 55 ENUM_ATTR_BACKUP_MEASUREMENT_SEEPROM_SELECT_PRIMARY; 56 } 57 else 58 { 59 log<level::INFO>("Setting SBE seeprom side to 1", 60 entry("SBE_SIDE_SELECT=%d", 61 ENUM_ATTR_BACKUP_SEEPROM_SELECT_SECONDARY)); 62 bkpSeePromSelect = ENUM_ATTR_BACKUP_SEEPROM_SELECT_SECONDARY; 63 bkpMeaSeePromSelect = 64 ENUM_ATTR_BACKUP_MEASUREMENT_SEEPROM_SELECT_SECONDARY; 65 } 66 67 // Set the Attribute as per bootcount policy for boot seeprom 68 if (DT_SET_PROP(ATTR_BACKUP_SEEPROM_SELECT, procTarget, 69 bkpSeePromSelect)) 70 { 71 log<level::ERR>( 72 "Attribute [ATTR_BACKUP_SEEPROM_SELECT] set failed"); 73 throw std::runtime_error( 74 "Attribute [ATTR_BACKUP_SEEPROM_SELECT] set failed"); 75 } 76 77 // Set the Attribute as per bootcount policy for measurement seeprom 78 if (DT_SET_PROP(ATTR_BACKUP_MEASUREMENT_SEEPROM_SELECT, procTarget, 79 bkpMeaSeePromSelect)) 80 { 81 log<level::ERR>( 82 "Attribute [ATTR_BACKUP_MEASUREMENT_SEEPROM_SELECT] set " 83 "failed"); 84 throw std::runtime_error( 85 "Attribute [ATTR_BACKUP_MEASUREMENT_SEEPROM_SELECT] set " 86 "failed"); 87 } 88 } 89 } 90 91 /** 92 * @brief Read the HW Level from VPD and set CLK NE termination site 93 * Note any failure in this function will result startHost failure. 94 */ 95 void setClkNETerminationSite() 96 { 97 // Get Motherborad VINI Recored "HW" keyword 98 constexpr auto objPath = 99 "/xyz/openbmc_project/inventory/system/chassis/motherboard"; 100 constexpr auto kwdVpdInf = "com.ibm.ipzvpd.VINI"; 101 constexpr auto hwKwd = "HW"; 102 103 auto bus = sdbusplus::bus::new_default(); 104 105 std::string service = util::getService(bus, objPath, kwdVpdInf); 106 107 auto properties = bus.new_method_call( 108 service.c_str(), objPath, "org.freedesktop.DBus.Properties", "Get"); 109 properties.append(kwdVpdInf); 110 properties.append(hwKwd); 111 112 // Store "HW" Keyword data. 113 std::variant<std::vector<uint8_t>> val; 114 try 115 { 116 auto result = bus.call(properties); 117 result.read(val); 118 } 119 catch (const sdbusplus::exception::exception& e) 120 { 121 log<level::ERR>("Get HW Keyword read from VINI Failed"); 122 throw std::runtime_error("Get HW Keyword read from VINI Failed"); 123 } 124 125 auto hwData = std::get<std::vector<uint8_t>>(val); 126 127 //"HW" Keyword size is 2 as per VPD spec. 128 constexpr auto hwKwdSize = 2; 129 if (hwKwdSize != hwData.size()) 130 { 131 log<level::ERR>( 132 fmt::format("Incorrect VINI records HW Keyword data size({})", 133 hwData.size()) 134 .c_str()); 135 throw std::runtime_error("Incorrect VINI records HW Keyword data size"); 136 } 137 138 log<level::DEBUG>(fmt::format("VINI Records HW[0]:{} HW[1]:{}", 139 hwData.at(0), hwData.at(1)) 140 .c_str()); 141 142 // VINI Record "HW" keyword's Byte 0's MSB bit indicates 143 // proc or planar type need to choose. 144 constexpr uint8_t SYS_CLK_NE_TERMINATION_ON_MASK = 0x80; 145 146 ATTR_SYS_CLK_NE_TERMINATION_SITE_Type clockTerm = 147 ENUM_ATTR_SYS_CLK_NE_TERMINATION_SITE_PLANAR; 148 149 if (SYS_CLK_NE_TERMINATION_ON_MASK & hwData.at(0)) 150 { 151 clockTerm = ENUM_ATTR_SYS_CLK_NE_TERMINATION_SITE_PROC; 152 } 153 154 // update all the processor attributes 155 struct pdbg_target* procTarget; 156 pdbg_for_each_class_target("proc", procTarget) 157 { 158 159 if (DT_SET_PROP(ATTR_SYS_CLK_NE_TERMINATION_SITE, procTarget, 160 clockTerm)) 161 { 162 log<level::ERR>( 163 "Attribute ATTR_SYS_CLK_NE_TERMINATION_SITE set failed"); 164 throw std::runtime_error( 165 "Attribute ATTR_SYS_CLK_NE_TERMINATION_SITE set failed"); 166 } 167 } 168 } 169 170 /** 171 * @brief Starts the self boot engine on POWER processor position 0 172 * to kick off a boot. 173 * @return void 174 */ 175 void startHost(enum ipl_type iplType = IPL_TYPE_NORMAL) 176 { 177 try 178 { 179 phal_init(); 180 ipl_set_type(iplType); 181 } 182 catch (const std::exception& ex) 183 { 184 log<level::ERR>("Exception raised during init PHAL", 185 entry("EXCEPTION=%s", ex.what())); 186 openpower::pel::detail::processBootError(false); 187 throw std::runtime_error("PHAL initialization failed"); 188 } 189 190 // To clear trace if success 191 openpower::pel::detail::processBootError(true); 192 193 setClkNETerminationSite(); 194 195 // callback method will be called upon failure which will create the PEL 196 int rc = ipl_run_major(0); 197 if (rc > 0) 198 { 199 log<level::ERR>("step 0 failed to start the host"); 200 throw std::runtime_error("Failed to execute host start boot step"); 201 } 202 } 203 204 /** 205 * @brief Starts the reboot with type memory preserving reboot. 206 * @return void 207 */ 208 void startHostMpReboot() 209 { 210 // set ipl type as mpipl 211 startHost(IPL_TYPE_MPIPL); 212 } 213 214 /** 215 * @brief Starts the normal boot type. 216 * @return void 217 */ 218 void startHostNormal() 219 { 220 // Run select seeprom before poweron 221 try 222 { 223 selectBootSeeprom(); 224 225 // To clear trace as it is success 226 openpower::pel::detail::processBootError(true); 227 } 228 catch (const std::exception& ex) 229 { 230 // create PEL in failure 231 openpower::pel::detail::processBootError(false); 232 log<level::ERR>("SEEPROM selection failed", entry("ERR=%s", ex.what())); 233 throw ex; 234 } 235 236 startHost(); 237 } 238 239 REGISTER_PROCEDURE("startHost", startHostNormal) 240 REGISTER_PROCEDURE("startHostMpReboot", startHostMpReboot) 241 242 } // namespace phal 243 } // namespace openpower 244