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