1 #include "config.h" 2 3 #include "systemintfcmds.hpp" 4 5 #include "host-cmd-manager.hpp" 6 #include "host-interface.hpp" 7 8 #include <ipmid-host/cmd.hpp> 9 #include <ipmid/api.hpp> 10 #include <nlohmann/json.hpp> 11 12 #include <cstring> 13 #include <fstream> 14 15 void register_netfn_app_functions() __attribute__((constructor)); 16 17 using namespace sdbusplus::server::xyz::openbmc_project::control; 18 19 // For accessing Host command manager 20 using cmdManagerPtr = std::unique_ptr<phosphor::host::command::Manager>; 21 extern cmdManagerPtr& ipmid_get_host_cmd_manager(); 22 23 //------------------------------------------------------------------- 24 // Called by Host post response from Get_Message_Flags 25 //------------------------------------------------------------------- 26 ipmi::RspType<uint16_t, // id 27 uint8_t, // type 28 uint24_t, // manuf_id 29 uint32_t, // timestamp 30 uint8_t, // netfun 31 uint8_t, // cmd 32 std::array<uint8_t, 4> // data 33 > 34 ipmiAppReadEventBuffer(ipmi::Context::ptr& ctx) 35 { 36 // require this to be limited to system interface 37 if (ctx->channel != ipmi::channelSystemIface) 38 { 39 return ipmi::responseInvalidCommand(); 40 } 41 42 constexpr uint16_t selOemId = 0x5555; 43 constexpr uint8_t selRecordTypeOem = 0xc0; 44 45 // read manufacturer ID from dev_id file 46 static uint24_t manufId{}; 47 if (!manufId) 48 { 49 const char* filename = "/usr/share/ipmi-providers/dev_id.json"; 50 std::ifstream devIdFile(filename); 51 if (devIdFile.is_open()) 52 { 53 auto data = nlohmann::json::parse(devIdFile, nullptr, false); 54 if (!data.is_discarded()) 55 { 56 manufId = data.value("manuf_id", 0); 57 } 58 } 59 } 60 61 constexpr uint32_t timestamp{0}; 62 63 // per IPMI spec NetFuntion for OEM 64 constexpr uint8_t netfun = 0x3a; 65 66 // Read from the Command Manager queue. What gets returned is a 67 // pair of <command, data> that can be directly used here 68 const auto& [cmd, data0] = ipmid_get_host_cmd_manager()->getNextCommand(); 69 constexpr uint8_t dataUnused = 0xff; 70 71 return ipmi::responseSuccess( 72 selOemId, selRecordTypeOem, manufId, timestamp, netfun, cmd, 73 std::to_array<uint8_t>({data0, dataUnused, dataUnused, dataUnused})); 74 } 75 76 //--------------------------------------------------------------------- 77 // Called by Host on seeing a SMS_ATN bit set. Return a hardcoded 78 // value of 0x0 to indicate Event Message Buffer is not supported 79 //------------------------------------------------------------------- 80 ipmi::RspType<uint8_t> ipmiAppGetMessageFlags() 81 { 82 // From IPMI spec V2.0 for Get Message Flags Command : 83 // bit:[1] from LSB : 1b = Event Message Buffer Full. 84 // Return as 0 if Event Message Buffer is not supported, 85 // or when the Event Message buffer is disabled. 86 // This path is used to communicate messages to the host 87 // from within the phosphor::host::command::Manager 88 constexpr uint8_t setEventMsgBufferNotSupported = 0x0; 89 return ipmi::responseSuccess(setEventMsgBufferNotSupported); 90 } 91 92 ipmi::RspType<bool, // Receive Message Queue Interrupt Enabled 93 bool, // Event Message Buffer Full Interrupt Enabled 94 bool, // Event Message Buffer Enabled 95 bool, // System Event Logging Enabled 96 uint1_t, // Reserved 97 bool, // OEM 0 enabled 98 bool, // OEM 1 enabled 99 bool // OEM 2 enabled 100 > 101 ipmiAppGetBMCGlobalEnable() 102 { 103 return ipmi::responseSuccess(true, false, false, true, 0, false, false, 104 false); 105 } 106 107 ipmi::RspType<> ipmiAppSetBMCGlobalEnable( 108 ipmi::Context::ptr ctx, bool receiveMessageQueueInterruptEnabled, 109 bool eventMessageBufferFullInterruptEnabled, bool eventMessageBufferEnabled, 110 bool systemEventLogEnable, uint1_t reserved, bool OEM0Enabled, 111 bool OEM1Enabled, bool OEM2Enabled) 112 { 113 ipmi::ChannelInfo chInfo; 114 115 if (ipmi::getChannelInfo(ctx->channel, chInfo) != ipmi::ccSuccess) 116 { 117 phosphor::logging::log<phosphor::logging::level::ERR>( 118 "Failed to get Channel Info", 119 phosphor::logging::entry("CHANNEL=%d", ctx->channel)); 120 return ipmi::responseUnspecifiedError(); 121 } 122 123 if (chInfo.mediumType != 124 static_cast<uint8_t>(ipmi::EChannelMediumType::systemInterface)) 125 { 126 phosphor::logging::log<phosphor::logging::level::ERR>( 127 "Error - supported only in system interface"); 128 return ipmi::responseCommandNotAvailable(); 129 } 130 131 // Recv Message Queue and SEL are enabled by default. 132 // Event Message buffer are disabled by default (not supported). 133 // Any request that try to change the mask will be rejected 134 if (!receiveMessageQueueInterruptEnabled || !systemEventLogEnable || 135 eventMessageBufferFullInterruptEnabled || eventMessageBufferEnabled || 136 OEM0Enabled || OEM1Enabled || OEM2Enabled || reserved) 137 { 138 return ipmi::responseInvalidFieldRequest(); 139 } 140 141 return ipmi::responseSuccess(); 142 } 143 144 namespace 145 { 146 // Static storage to keep the object alive during process life 147 std::unique_ptr<phosphor::host::command::Host> host 148 __attribute__((init_priority(101))); 149 std::unique_ptr<sdbusplus::server::manager_t> objManager 150 __attribute__((init_priority(101))); 151 } // namespace 152 153 void register_netfn_app_functions() 154 { 155 // <Read Event Message Buffer> 156 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 157 ipmi::app::cmdReadEventMessageBuffer, 158 ipmi::Privilege::Admin, ipmiAppReadEventBuffer); 159 160 // <Set BMC Global Enables> 161 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 162 ipmi::app::cmdSetBmcGlobalEnables, 163 ipmi::Privilege::Admin, ipmiAppSetBMCGlobalEnable); 164 165 // <Get BMC Global Enables> 166 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 167 ipmi::app::cmdGetBmcGlobalEnables, 168 ipmi::Privilege::User, ipmiAppGetBMCGlobalEnable); 169 170 // <Get Message Flags> 171 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 172 ipmi::app::cmdGetMessageFlags, ipmi::Privilege::Admin, 173 ipmiAppGetMessageFlags); 174 175 // Create new xyz.openbmc_project.host object on the bus 176 auto objPath = std::string{CONTROL_HOST_OBJ_MGR} + '/' + HOST_NAME + '0'; 177 178 std::unique_ptr<sdbusplus::asio::connection>& sdbusp = 179 ipmid_get_sdbus_plus_handler(); 180 181 // Add sdbusplus ObjectManager. 182 objManager = std::make_unique<sdbusplus::server::manager_t>( 183 *sdbusp, CONTROL_HOST_OBJ_MGR); 184 185 host = std::make_unique<phosphor::host::command::Host>(*sdbusp, 186 objPath.c_str()); 187 sdbusp->request_name(CONTROL_HOST_BUSNAME); 188 189 return; 190 } 191