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