xref: /openbmc/fb-ipmi-oem/src/usb-dbg.cpp (revision 4ec80567)
1 /*
2  * Copyright (c)  2018-present Facebook. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <usb-dbg.hpp>
18 #include <commandutils.hpp>
19 
20 namespace ipmi
21 {
22 
23 ipmi_ret_t getNetworkData(uint8_t lan_param, char* data);
24 int8_t getFruData(std::string& serial, std::string& name);
25 
26 bool isMultiHostPlatform();
27 
28 /* Declare Host Selector interface and path */
29 namespace selector
30 {
31 const std::string path = "/xyz/openbmc_project/Chassis/Buttons/HostSelector";
32 const std::string interface =
33     "xyz.openbmc_project.Chassis.HostSelector.Selector";
34 const std::string propertyName = "Position";
35 } // namespace selector
36 
37 /* Declare storage functions used here */
38 namespace storage
39 {
40 int getSensorValue(std::string&, double&);
41 int getSensorUnit(std::string&, std::string&);
42 } // namespace storage
43 
44 size_t getSelectorPosition()
45 {
46     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
47     std::string service =
48         getService(*dbus, ipmi::selector::interface, ipmi::selector::path);
49     Value variant = getDbusProperty(*dbus, service, ipmi::selector::path,
50                                     ipmi::selector::interface,
51                                     ipmi::selector::propertyName);
52     size_t result = std::get<size_t>(variant);
53     return result;
54 }
55 
56 static int panelNum = (sizeof(panels) / sizeof(struct ctrl_panel)) - 1;
57 
58 /* Returns the FRU the hand-switch is switched to. If it is switched to BMC
59  * it returns FRU_ALL. Note, if in err, it returns FRU_ALL */
60 static size_t plat_get_fru_sel()
61 {
62     size_t position;
63     bool platform = isMultiHostPlatform();
64 
65     if (platform == true)
66     {
67         try
68         {
69             size_t hostPosition = getSelectorPosition();
70             position = hostPosition;
71             if (position == BMC_POSITION)
72             {
73                 return FRU_ALL;
74             }
75         }
76         catch (...)
77         {
78             std::cout << "Error reading host selector position" << std::endl;
79         }
80     }
81     else
82     {
83         // For Tiogapass it just return 1, can modify to support more platform
84         position = 1;
85     }
86     return position;
87 }
88 
89 // return 0 on seccuess
90 int frame::init(size_t size)
91 {
92     // Reset status
93     idx_head = idx_tail = 0;
94     lines = 0;
95     esc_sts = 0;
96     pages = 1;
97 
98     if (buf != NULL && max_size == size)
99     {
100         // reinit
101         return 0;
102     }
103 
104     if (buf != NULL && max_size != size)
105     {
106         delete[] buf;
107     }
108     // Initialize Configuration
109     title[0] = '\0';
110     buf = new char[size];
111     max_size = size;
112     max_page = size;
113     line_per_page = 7;
114     line_width = 16;
115     overwrite = 0;
116 
117     if (buf)
118         return 0;
119     else
120         return -1;
121 }
122 
123 // return 0 on seccuess
124 int frame::append(const char* string, int indent)
125 {
126     const size_t buf_size = 64;
127     char lbuf[buf_size];
128     char* ptr;
129     int ret;
130 
131     ret = parse(lbuf, buf_size, string, indent);
132 
133     if (ret < 0)
134         return ret;
135 
136     for (ptr = lbuf; *ptr != '\0'; ptr++)
137     {
138         if (isFull())
139         {
140             if (overwrite)
141             {
142                 if (buf[idx_head] == LINE_DELIMITER)
143                     lines--;
144                 idx_head = (idx_head + 1) % max_size;
145             }
146             else
147                 return -1;
148         }
149 
150         buf[idx_tail] = *ptr;
151         if (*ptr == LINE_DELIMITER)
152             lines++;
153 
154         idx_tail = (idx_tail + 1) % max_size;
155     }
156 
157     pages = (lines / line_per_page) + ((lines % line_per_page) ? 1 : 0);
158 
159     if (pages > max_page)
160         pages = max_page;
161 
162     return 0;
163 }
164 
165 // return 0 on seccuess
166 int frame::insert(const char* string, int indent)
167 {
168     const size_t buf_size = 128;
169     char lbuf[buf_size];
170     char* ptr;
171     int ret;
172     int i;
173 
174     ret = parse(lbuf, buf_size, string, indent);
175 
176     if (ret < 0)
177         return ret;
178 
179     for (i = strlen(lbuf) - 1; i >= 0; i--)
180     {
181         ptr = &lbuf[i];
182         if (isFull())
183         {
184             if (overwrite)
185             {
186                 idx_tail = (idx_tail + max_size - 1) % max_size;
187                 if (buf[idx_tail] == LINE_DELIMITER)
188                     lines--;
189             }
190             else
191                 return -1;
192         }
193 
194         idx_head = (idx_head + max_size - 1) % max_size;
195 
196         buf[idx_head] = *ptr;
197         if (*ptr == LINE_DELIMITER)
198             lines++;
199     }
200 
201     pages = (lines / line_per_page) + ((lines % line_per_page) ? 1 : 0);
202 
203     if (pages > max_page)
204         pages = max_page;
205 
206     return 0;
207 }
208 
209 // return page size
210 int frame::getPage(int page, char* page_buf, size_t page_buf_size)
211 {
212     int ret;
213     uint16_t line = 0;
214     uint16_t idx, len;
215 
216     if (buf == NULL)
217         return -1;
218 
219     // 1-based page
220     if (page > pages || page < 1)
221         return -1;
222 
223     if (page_buf == NULL || page_buf_size == 0)
224         return -1;
225 
226     ret = snprintf(page_buf, 17, "%-10s %02d/%02d", title, page, pages);
227     len = strlen(page_buf);
228     if (ret < 0)
229         return -1;
230 
231     line = 0;
232     idx = idx_head;
233     while (line < ((page - 1) * line_per_page) && idx != idx_tail)
234     {
235         if (buf[idx] == LINE_DELIMITER)
236             line++;
237         idx = (idx + 1) % max_size;
238     }
239 
240     while (line < ((page)*line_per_page) && idx != idx_tail)
241     {
242         if (buf[idx] == LINE_DELIMITER)
243         {
244             line++;
245         }
246         else
247         {
248             page_buf[len++] = buf[idx];
249             if (len == (page_buf_size - 1))
250             {
251                 break;
252             }
253         }
254         idx = (idx + 1) % max_size;
255     }
256 
257     return len;
258 }
259 
260 // return 1 for frame buffer full
261 int frame::isFull()
262 {
263     if (buf == NULL)
264         return -1;
265 
266     if ((idx_tail + 1) % max_size == idx_head)
267         return 1;
268     else
269         return 0;
270 }
271 
272 // return 1 for Escape Sequence
273 int frame::isEscSeq(char chr)
274 {
275     uint8_t curr_sts = esc_sts;
276 
277     if (esc_sts == 0 && (chr == 0x1b))
278         esc_sts = 1; // Escape Sequence
279     else if (esc_sts == 1 && (chr == 0x5b))
280         esc_sts = 2; // Control Sequence Introducer(CSI)
281     else if (esc_sts == 1 && (chr != 0x5b))
282         esc_sts = 0;
283     else if (esc_sts == 2 && (chr >= 0x40 && chr <= 0x7e))
284         esc_sts = 0;
285 
286     if (curr_sts || esc_sts)
287         return 1;
288     else
289         return 0;
290 }
291 
292 // return 0 on success
293 int frame::parse(char* lbuf, size_t buf_size, const char* input, int indent)
294 {
295     uint8_t pos, esc;
296     size_t i;
297     const char *in, *end;
298 
299     if (buf == NULL || input == NULL)
300         return -1;
301 
302     if (indent >= line_width || indent < 0)
303         return -1;
304 
305     in = input;
306     end = in + strlen(input);
307     pos = 0; // line position
308     esc = 0; // escape state
309     i = 0;   // buf index
310     while (in != end)
311     {
312         if (i >= buf_size)
313             break;
314 
315         if (pos < indent)
316         {
317             // fill indent
318             lbuf[i++] = ' ';
319             pos++;
320             continue;
321         }
322 
323         esc = isEscSeq(*in);
324 
325         if (!esc && pos == line_width)
326         {
327             lbuf[i++] = LINE_DELIMITER;
328             pos = 0;
329             continue;
330         }
331 
332         if (!esc)
333             pos++;
334 
335         // fill input data
336         lbuf[i++] = *(in++);
337     }
338 
339     // padding
340     while (pos <= line_width)
341     {
342         if (i >= buf_size)
343             break;
344         if (pos < line_width)
345             lbuf[i++] = ' ';
346         else
347             lbuf[i++] = LINE_DELIMITER;
348         pos++;
349     }
350 
351     // full
352     if (i >= buf_size)
353         return -1;
354 
355     lbuf[i++] = '\0';
356 
357     return 0;
358 }
359 
360 static int chk_cri_sel_update(uint8_t* cri_sel_up)
361 {
362     FILE* fp;
363     struct stat file_stat;
364     size_t pos = plat_get_fru_sel();
365     static uint8_t pre_pos = 0xff;
366 
367     fp = fopen("/mnt/data/cri_sel", "r");
368     if (fp)
369     {
370         if ((stat("/mnt/data/cri_sel", &file_stat) == 0) &&
371             (file_stat.st_mtime != frame_sel.mtime || pre_pos != pos))
372         {
373             *cri_sel_up = 1;
374         }
375         else
376         {
377             *cri_sel_up = 0;
378         }
379         fclose(fp);
380     }
381     else
382     {
383         if (frame_sel.buf == NULL || frame_sel.lines != 0 || pre_pos != pos)
384         {
385             *cri_sel_up = 1;
386         }
387         else
388         {
389             *cri_sel_up = 0;
390         }
391     }
392     pre_pos = pos;
393     return 0;
394 }
395 
396 int plat_udbg_get_frame_info(uint8_t* num)
397 {
398     *num = 3;
399     return 0;
400 }
401 
402 int plat_udbg_get_updated_frames(uint8_t* count, uint8_t* buffer)
403 {
404     uint8_t cri_sel_up = 0;
405     uint8_t info_page_up = 1;
406 
407     *count = 0;
408 
409     // info page update
410     if (info_page_up == 1)
411     {
412         buffer[*count] = 1;
413         *count += 1;
414     }
415 
416     // cri sel update
417     chk_cri_sel_update(&cri_sel_up);
418     if (cri_sel_up == 1)
419     {
420         buffer[*count] = 2;
421         *count += 1;
422     }
423 
424     // cri sensor update
425     buffer[*count] = 3;
426     *count += 1;
427 
428     return 0;
429 }
430 
431 int plat_udbg_get_post_desc(uint8_t index, uint8_t* next, uint8_t phase,
432                             uint8_t* end, uint8_t* length, uint8_t* buffer)
433 {
434     nlohmann::json postObj;
435     std::string postCode;
436 
437     /* Get post description data stored in json file */
438     std::ifstream file(JSON_POST_DATA_FILE);
439     if (file)
440     {
441         file >> postObj;
442         file.close();
443     }
444     else
445     {
446         phosphor::logging::log<phosphor::logging::level::ERR>(
447             "Post code description file not found",
448             phosphor::logging::entry("POST_CODE_FILE=%s", JSON_POST_DATA_FILE));
449         return -1;
450     }
451 
452     std::string phaseStr = "PhaseAny";
453     if (postObj.find(phaseStr) == postObj.end())
454     {
455         phaseStr = "Phase" + std::to_string(phase);
456     }
457 
458     if (postObj.find(phaseStr) == postObj.end())
459     {
460         phosphor::logging::log<phosphor::logging::level::ERR>(
461             "Post code phase not available",
462             phosphor::logging::entry("PHASE=%d", phase));
463         return -1;
464     }
465 
466     auto phaseObj = postObj[phaseStr];
467     int phaseSize = phaseObj.size();
468 
469     for (int i = 0; i < phaseSize; i++)
470     {
471         postCode = phaseObj[i][0];
472         if (index == stoul(postCode, nullptr, 16))
473         {
474             std::string postDesc = phaseObj[i][1];
475             *length = postDesc.size();
476             memcpy(buffer, postDesc.data(), *length);
477             buffer[*length] = '\0';
478 
479             if (phaseSize != i + 1)
480             {
481                 postCode = phaseObj[i + 1][0];
482                 *next = stoul(postCode, nullptr, 16);
483                 *end = 0;
484             }
485             else
486             {
487                 if (postObj.size() != phase)
488                 {
489                     std::string nextPhaseStr =
490                         "Phase" + std::to_string(phase + 1);
491                     postCode = postObj[nextPhaseStr][0][0];
492                     *next = stoul(postCode, nullptr, 16);
493                     *end = 0;
494                 }
495                 else
496                 {
497                     *next = 0xff;
498                     *end = 1;
499                 }
500             }
501 
502             return 0;
503         }
504     }
505 
506     phosphor::logging::log<phosphor::logging::level::ERR>(
507         "Post code description data not available",
508         phosphor::logging::entry("PHASE_CODE=%d_0x%x", phase, index));
509     return -1;
510 }
511 
512 int plat_udbg_get_gpio_desc(uint8_t index, uint8_t* next, uint8_t* level,
513                             uint8_t* def, uint8_t* length, uint8_t* buffer)
514 {
515     nlohmann::json gpioObj;
516     std::string gpioPin;
517 
518     /* Get gpio data stored in json file */
519     std::ifstream file(JSON_GPIO_DATA_FILE);
520     if (file)
521     {
522         file >> gpioObj;
523         file.close();
524     }
525     else
526     {
527         phosphor::logging::log<phosphor::logging::level::ERR>(
528             "GPIO pin description file not found",
529             phosphor::logging::entry("GPIO_PIN_DETAILS_FILE=%s",
530                                      JSON_GPIO_DATA_FILE));
531         return -1;
532     }
533 
534     if (gpioObj.find(DEBUG_GPIO_KEY) == gpioObj.end())
535     {
536         phosphor::logging::log<phosphor::logging::level::ERR>(
537             "GPIO pin details not available",
538             phosphor::logging::entry("GPIO_JSON_KEY=%d", DEBUG_GPIO_KEY));
539         return -1;
540     }
541 
542     auto obj = gpioObj[DEBUG_GPIO_KEY];
543     int objSize = obj.size();
544 
545     for (int i = 0; i < objSize; i++)
546     {
547         if (obj[i].size() != GPIO_ARRAY_SIZE)
548         {
549             phosphor::logging::log<phosphor::logging::level::ERR>(
550                 "Size of gpio array is incorrect",
551                 phosphor::logging::entry("EXPECTED_SIZE=%d", GPIO_ARRAY_SIZE));
552             return -1;
553         }
554 
555         gpioPin = obj[i][GPIO_PIN_INDEX];
556         if (index == stoul(gpioPin, nullptr, 16))
557         {
558             if (objSize != i + 1)
559             {
560                 gpioPin = obj[i + 1][GPIO_PIN_INDEX];
561                 *next = stoul(gpioPin, nullptr, 16);
562             }
563             else
564             {
565                 *next = 0xff;
566             }
567 
568             *level = obj[i][GPIO_LEVEL_INDEX];
569             *def = obj[i][GPIO_DEF_INDEX];
570             std::string gpioDesc = obj[i][GPIO_DESC_INDEX];
571             *length = gpioDesc.size();
572             memcpy(buffer, gpioDesc.data(), *length);
573             buffer[*length] = '\0';
574 
575             return 0;
576         }
577     }
578 
579     phosphor::logging::log<phosphor::logging::level::ERR>(
580         "GPIO pin description data not available",
581         phosphor::logging::entry("GPIO_PIN=0x%x", index));
582     return -1;
583 }
584 
585 static int udbg_get_cri_sel(uint8_t, uint8_t page, uint8_t* next,
586                             uint8_t* count, uint8_t* buffer)
587 {
588     int len;
589     int ret;
590     char line_buff[FRAME_PAGE_BUF_SIZE];
591     const char* ptr;
592     FILE* fp;
593     struct stat file_stat;
594     size_t pos = plat_get_fru_sel();
595     static uint8_t pre_pos = FRU_ALL;
596     bool pos_changed = pre_pos != pos;
597 
598     pre_pos = pos;
599 
600     /* Revisit this */
601     fp = fopen("/mnt/data/cri_sel", "r");
602     if (fp)
603     {
604         if ((stat("/mnt/data/cri_sel", &file_stat) == 0) &&
605             (file_stat.st_mtime != frame_sel.mtime || pos_changed))
606         {
607             // initialize and clear frame
608             frame_sel.init(FRAME_BUFF_SIZE);
609             frame_sel.overwrite = 1;
610             frame_sel.max_page = 20;
611             frame_sel.mtime = file_stat.st_mtime;
612             snprintf(frame_sel.title, 32, "Cri SEL");
613 
614             while (fgets(line_buff, FRAME_PAGE_BUF_SIZE, fp))
615             {
616                 // Remove newline
617                 line_buff[strlen(line_buff) - 1] = '\0';
618                 ptr = line_buff;
619                 // Find message
620                 ptr = strstr(ptr, "local0.err");
621                 if (ptr == NULL)
622                 {
623                     continue;
624                 }
625 
626                 if ((ptr = strrchr(ptr, ':')) == NULL)
627                 {
628                     continue;
629                 }
630                 len = strlen(ptr);
631                 if (len > 2)
632                 {
633                     // to skip log string ": "
634                     ptr += 2;
635                 }
636                 // Write new message
637                 frame_sel.insert(ptr, 0);
638             }
639         }
640         fclose(fp);
641     }
642     else
643     {
644         // Title only
645         frame_sel.init(FRAME_BUFF_SIZE);
646         snprintf(frame_sel.title, 32, "Cri SEL");
647         frame_sel.mtime = 0;
648     }
649 
650     if (page > frame_sel.pages)
651     {
652         return -1;
653     }
654 
655     ret = frame_sel.getPage(page, (char*)buffer, FRAME_PAGE_BUF_SIZE);
656     if (ret < 0)
657     {
658         *count = 0;
659         return -1;
660     }
661     *count = (uint8_t)ret;
662 
663     if (page < frame_sel.pages)
664         *next = page + 1;
665     else
666         *next = 0xFF; // Set the value of next to 0xFF to indicate this is the
667                       // last page
668 
669     return 0;
670 }
671 
672 static int udbg_get_cri_sensor(uint8_t, uint8_t page, uint8_t* next,
673                                uint8_t* count, uint8_t* buffer)
674 {
675     int ret;
676     double fvalue;
677     size_t pos = plat_get_fru_sel();
678 
679     if (page == 1)
680     {
681         // Only update frame data while getting page 1
682 
683         // initialize and clear frame
684         frame_snr.init(FRAME_BUFF_SIZE);
685         snprintf(frame_snr.title, 32, "CriSensor");
686 
687         nlohmann::json senObj;
688 
689         /* Get critical sensor names stored in json file */
690         std::ifstream file(JSON_SENSOR_NAMES_FILE);
691         if (file)
692         {
693             file >> senObj;
694             file.close();
695         }
696         else
697         {
698             phosphor::logging::log<phosphor::logging::level::ERR>(
699                 "Critical Sensor names file not found",
700                 phosphor::logging::entry("CRI_SENSOR_NAMES_FILE=%s",
701                                          JSON_SENSOR_NAMES_FILE));
702             return -1;
703         }
704 
705         /* Get sensors values for all critical sensors */
706         for (auto& j : senObj.items())
707         {
708             std::string senName = j.key();
709             auto val = j.value();
710 
711             if (senName[0] == '_')
712             {
713                 senName = std::to_string(pos) + senName;
714             }
715 
716             if (ipmi::storage::getSensorValue(senName, fvalue) == 0)
717             {
718                 std::stringstream ss;
719                 int prec = 0; // Default value
720 
721                 if (val.find("precision") != val.end())
722                     prec = val["precision"];
723 
724                 ss << std::fixed << std::setprecision(prec) << fvalue;
725 
726                 std::string senStr;
727                 if (val.find("short_name") != val.end())
728                     senStr = val["short_name"];
729                 else
730                     senStr = senName;
731 
732                 senStr += ss.str();
733 
734                 /* Get unit string for sensor and append in output */
735                 std::string unitStr;
736                 if (ipmi::storage::getSensorUnit(senName, unitStr) == 0)
737                     senStr += unitStr;
738 
739                 frame_snr.append(senStr.c_str(), 0);
740             }
741             else
742             {
743                 phosphor::logging::log<phosphor::logging::level::INFO>(
744                     "Critical sensor not found",
745                     phosphor::logging::entry("CRI_SENSOR_NAME=%s",
746                                              senName.c_str()));
747             }
748         }
749 
750     } // End of update frame
751 
752     if (page > frame_snr.pages)
753     {
754         return -1;
755     }
756 
757     ret = frame_snr.getPage(page, (char*)buffer, FRAME_PAGE_BUF_SIZE);
758     if (ret < 0)
759     {
760         *count = 0;
761         return -1;
762     }
763     *count = (uint8_t)ret;
764 
765     if (page < frame_snr.pages)
766         *next = page + 1;
767     else
768         *next = 0xFF; // Set the value of next to 0xFF to indicate this is the
769                       // last page
770 
771     return 0;
772 }
773 
774 static int getBiosVer(std::string& ver)
775 {
776     nlohmann::json appObj;
777 
778     std::ifstream file(JSON_APP_DATA_FILE);
779     if (file)
780     {
781         file >> appObj;
782         file.close();
783         if (appObj.find(KEY_SYSFW_VER) != appObj.end())
784         {
785             ver = appObj[KEY_SYSFW_VER].get<std::string>();
786             return 0;
787         }
788     }
789 
790     return -1;
791 }
792 
793 int sendBicCmd(uint8_t netFn, uint8_t cmd, uint8_t bicAddr,
794                std::vector<uint8_t>& cmdData, std::vector<uint8_t>& respData)
795 {
796     static constexpr uint8_t lun = 0;
797 
798     auto bus = getSdBus();
799 
800     auto method = bus->new_method_call("xyz.openbmc_project.Ipmi.Channel.Ipmb",
801                                        "/xyz/openbmc_project/Ipmi/Channel/Ipmb",
802                                        "org.openbmc.Ipmb", "sendRequest");
803     method.append(bicAddr, netFn, lun, cmd, cmdData);
804 
805     auto reply = bus->call(method);
806     if (reply.is_method_error())
807     {
808         phosphor::logging::log<phosphor::logging::level::ERR>(
809             "Error reading from BIC");
810         return -1;
811     }
812 
813     IpmbMethodType resp;
814     reply.read(resp);
815 
816     respData =
817         std::move(std::get<std::remove_reference_t<decltype(respData)>>(resp));
818 
819     return 0;
820 }
821 
822 int sendMeCmd(uint8_t netFn, uint8_t cmd, std::vector<uint8_t>& cmdData,
823               std::vector<uint8_t>& respData)
824 {
825     auto bus = getSdBus();
826 
827     if (DEBUG)
828     {
829         std::cout << "ME NetFn:cmd " << (int)netFn << ":" << (int)cmd << "\n";
830         std::cout << "ME req data: ";
831         for (auto d : cmdData)
832         {
833             std::cout << d << " ";
834         }
835         std::cout << "\n";
836     }
837 
838     auto method = bus->new_method_call("xyz.openbmc_project.Ipmi.Channel.Ipmb",
839                                        "/xyz/openbmc_project/Ipmi/Channel/Ipmb",
840                                        "org.openbmc.Ipmb", "sendRequest");
841     method.append(meAddress, netFn, lun, cmd, cmdData);
842 
843     auto reply = bus->call(method);
844     if (reply.is_method_error())
845     {
846         phosphor::logging::log<phosphor::logging::level::ERR>(
847             "Error reading from ME");
848         return -1;
849     }
850 
851     IpmbMethodType resp;
852     reply.read(resp);
853 
854     respData =
855         std::move(std::get<std::remove_reference_t<decltype(respData)>>(resp));
856 
857     if (DEBUG)
858     {
859         std::cout << "ME resp data: ";
860         for (auto d : respData)
861         {
862             std::cout << d << " ";
863         }
864         std::cout << "\n";
865     }
866 
867     return 0;
868 }
869 
870 static int getMeStatus(std::string& status, size_t pos)
871 {
872     uint8_t cmd = 0x01;   // Get Device id command
873     uint8_t netFn = 0x06; // Netfn for APP
874     std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
875     std::vector<uint8_t> cmdData;
876 
877     uint8_t meAddr = meAddress;
878     bool platform = isMultiHostPlatform();
879     if (platform == true)
880     {
881         meAddr = ((pos - 1) << 2);
882     }
883 
884     auto method = bus->new_method_call("xyz.openbmc_project.Ipmi.Channel.Ipmb",
885                                        "/xyz/openbmc_project/Ipmi/Channel/Ipmb",
886                                        "org.openbmc.Ipmb", "sendRequest");
887     method.append(meAddr, netFn, lun, cmd, cmdData);
888 
889     auto reply = bus->call(method);
890     if (reply.is_method_error())
891     {
892         std::cerr << "Error reading from ME\n";
893         return -1;
894     }
895 
896     IpmbMethodType resp;
897     reply.read(resp);
898 
899     std::vector<uint8_t> data;
900     data = std::get<5>(resp);
901 
902     if (DEBUG)
903     {
904         std::cout << "ME Get ID: ";
905         for (size_t d : data)
906         {
907             std::cout << d << " ";
908         }
909         std::cout << "\n";
910     }
911 
912     if (data[2] & 0x80)
913         status = "recovery mode";
914     else
915         status = "operation mode";
916 
917     return 0;
918 }
919 
920 static int udbg_get_info_page(uint8_t, uint8_t page, uint8_t* next,
921                               uint8_t* count, uint8_t* buffer)
922 {
923     char line_buff[1000];
924     [[maybe_unused]] char* pres_dev = line_buff;
925     [[maybe_unused]] size_t pos = plat_get_fru_sel();
926     int ret;
927     std::string serialName = "SerialNumber";
928     std::string partName = "PartNumber";
929     std::string verDel = "VERSION=";
930     std::string verPath = "/etc/os-release";
931     size_t hostPosition;
932 
933     if (page == 1)
934     {
935         // Only update frame data while getting page 1
936 
937         // initialize and clear frame
938         frame_info.init(FRAME_BUFF_SIZE);
939         snprintf(frame_info.title, 32, "SYS_Info");
940 
941         bool platform = isMultiHostPlatform();
942         if (platform == true)
943         {
944             hostPosition = getSelectorPosition();
945         }
946 
947         if (hostPosition == BMC_POSITION || hostInstances == "0")
948         {
949             frame_info.append("FRU:spb", 0);
950         }
951         else if (hostPosition != BMC_POSITION && hostPosition <= MAX_HOST_POS)
952         {
953             std::string data = "FRU:slot" + std::to_string(hostPosition);
954             frame_info.append(data.c_str(), 0);
955         }
956 
957         // FRU
958         std::string data;
959         frame_info.append("SN:", 0);
960         if (getFruData(data, serialName) != 0)
961         {
962             data = "Not Found";
963         }
964         frame_info.append(data.c_str(), 1);
965         frame_info.append("PN:", 0);
966         if (getFruData(data, partName) != 0)
967         {
968             data = "Not Found";
969         }
970         frame_info.append(data.c_str(), 1);
971 
972         // LAN
973         getNetworkData(3, line_buff);
974         frame_info.append("BMC_IP:", 0);
975         frame_info.append(line_buff, 1);
976         getNetworkData(59, line_buff);
977         frame_info.append("BMC_IPv6:", 0);
978         frame_info.append(line_buff, 1);
979 
980         // BMC ver
981         std::ifstream file(verPath);
982         if (file)
983         {
984             std::string line;
985             while (std::getline(file, line))
986             {
987                 if (line.find(verDel) != std::string::npos)
988                 {
989                     std::string bmcVer = line.substr(verDel.size());
990                     frame_info.append("BMC_FW_ver:", 0);
991                     frame_info.append(bmcVer.c_str(), 1);
992                     break;
993                 }
994             }
995         }
996 
997         if (hostPosition != BMC_POSITION)
998         {
999             // BIOS ver
1000             std::string biosVer;
1001             if (getBiosVer(biosVer) == 0)
1002             {
1003                 frame_info.append("BIOS_FW_ver:", 0);
1004                 frame_info.append(biosVer.c_str(), 1);
1005             }
1006             // ME status
1007             std::string meStatus;
1008             if (getMeStatus(meStatus, pos) != 0)
1009             {
1010                 phosphor::logging::log<phosphor::logging::level::WARNING>(
1011                     "Reading ME status failed");
1012                 meStatus = "unknown";
1013             }
1014             frame_info.append("ME_status:", 0);
1015             frame_info.append(meStatus.c_str(), 1);
1016         }
1017 
1018         /* TBD: Board ID needs implementation */
1019         // Board ID
1020 
1021         // Battery - Use Escape sequence
1022         frame_info.append("Battery:", 0);
1023         frame_info.append(ESC_BAT "     ", 1);
1024         // frame_info.append(&frame_info, esc_bat, 1);
1025 
1026         // MCU Version - Use Escape sequence
1027         frame_info.append("MCUbl_ver:", 0);
1028         frame_info.append(ESC_MCU_BL_VER, 1);
1029         frame_info.append("MCU_ver:", 0);
1030         frame_info.append(ESC_MCU_RUN_VER, 1);
1031 
1032         // TBD:
1033         // Sys config present device
1034 
1035     } // End of update frame
1036 
1037     if (page > frame_info.pages)
1038     {
1039         return -1;
1040     }
1041 
1042     ret = frame_info.getPage(page, (char*)buffer, FRAME_PAGE_BUF_SIZE);
1043     if (ret < 0)
1044     {
1045         *count = 0;
1046         return -1;
1047     }
1048     *count = (uint8_t)ret;
1049 
1050     if (page < frame_info.pages)
1051         *next = page + 1;
1052     else
1053         *next = 0xFF; // Set the value of next to 0xFF to indicate this is the
1054                       // last page
1055 
1056     return 0;
1057 }
1058 
1059 int plat_udbg_get_frame_data(uint8_t frame, uint8_t page, uint8_t* next,
1060                              uint8_t* count, uint8_t* buffer)
1061 {
1062     switch (frame)
1063     {
1064         case 1: // info_page
1065             return udbg_get_info_page(frame, page, next, count, buffer);
1066         case 2: // critical SEL
1067             return udbg_get_cri_sel(frame, page, next, count, buffer);
1068         case 3: // critical Sensor
1069             return udbg_get_cri_sensor(frame, page, next, count, buffer);
1070         default:
1071             return -1;
1072     }
1073 }
1074 
1075 static uint8_t panel_main(uint8_t item)
1076 {
1077     // Update item list when select item 0
1078     switch (item)
1079     {
1080         case 1:
1081             return panels[PANEL_BOOT_ORDER].select(0);
1082         case 2:
1083             return panels[PANEL_POWER_POLICY].select(0);
1084         default:
1085             return PANEL_MAIN;
1086     }
1087 }
1088 
1089 static uint8_t panel_boot_order(uint8_t)
1090 {
1091     /* To be implemented */
1092 #if 0
1093     int i;
1094     unsigned char buff[MAX_VALUE_LEN], pickup, len;
1095     size_t pos = plat_get_fru_sel();
1096     if (pos != FRU_ALL && pal_get_boot_order(pos, buff, buff, &len) == 0)
1097     {
1098         if (item > 0 && item < SIZE_BOOT_ORDER)
1099         {
1100             pickup = buff[item];
1101             while (item > 1)
1102             {
1103                 buff[item] = buff[item - 1];
1104                 item--;
1105             }
1106             buff[item] = pickup;
1107             buff[0] |= 0x80;
1108             pal_set_boot_order(pos, buff, buff, &len);
1109 
1110             // refresh items
1111             return panels[PANEL_BOOT_ORDER].select(0);
1112         }
1113 
1114         // '*': boot flags valid, BIOS has not yet read
1115         snprintf(panels[PANEL_BOOT_ORDER].item_str[0], 32, "Boot Order%c",
1116                  (buff[0] & 0x80) ? '*' : '\0');
1117 
1118         for (i = 1; i < SIZE_BOOT_ORDER; i++)
1119         {
1120             switch (buff[i])
1121             {
1122                 case 0x0:
1123                     snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1124                              " USB device");
1125                     break;
1126                 case 0x1:
1127                     snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1128                              " Network v4");
1129                     break;
1130                 case (0x1 | 0x8):
1131                     snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1132                              " Network v6");
1133                     break;
1134                 case 0x2:
1135                     snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1136                              " SATA HDD");
1137                     break;
1138                 case 0x3:
1139                     snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1140                              " SATA-CDROM");
1141                     break;
1142                 case 0x4:
1143                     snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1144                              " Other");
1145                     break;
1146                 default:
1147                     panels[PANEL_BOOT_ORDER].item_str[i][0] = '\0';
1148                     break;
1149             }
1150         }
1151 
1152         // remove empty items
1153         for (i--;
1154              (strlen(panels[PANEL_BOOT_ORDER].item_str[i]) == 0) && (i > 0);
1155              i--)
1156             ;
1157 
1158         panels[PANEL_BOOT_ORDER].item_num = i;
1159     }
1160     else
1161     {
1162         panels[PANEL_BOOT_ORDER].item_num = 0;
1163     }
1164 #endif
1165     return PANEL_BOOT_ORDER;
1166 }
1167 
1168 static uint8_t panel_power_policy(uint8_t)
1169 {
1170 /* To be cleaned */
1171 #if 0
1172     uint8_t buff[32] = {0};
1173     uint8_t res_len;
1174     size_t pos = plat_get_fru_sel();
1175     uint8_t policy;
1176     uint8_t pwr_policy_item_map[3] = {POWER_CFG_ON, POWER_CFG_LPS,
1177                                       POWER_CFG_OFF};
1178 
1179     if (pos != FRU_ALL)
1180     {
1181         if (item > 0 && item <= sizeof(pwr_policy_item_map))
1182         {
1183             policy = pwr_policy_item_map[item - 1];
1184             pal_set_power_restore_policy(pos, &policy, NULL);
1185         }
1186         pal_get_chassis_status(pos, NULL, buff, &res_len);
1187         policy = (((uint8_t)buff[0]) >> 5) & 0x7;
1188         snprintf(panels[PANEL_POWER_POLICY].item_str[1], 32, "%cPower On",
1189                  policy == POWER_CFG_ON ? '*' : ' ');
1190         snprintf(panels[PANEL_POWER_POLICY].item_str[2], 32, "%cLast State",
1191                  policy == POWER_CFG_LPS ? '*' : ' ');
1192         snprintf(panels[PANEL_POWER_POLICY].item_str[3], 32, "%cPower Off",
1193                  policy == POWER_CFG_OFF ? '*' : ' ');
1194         panels[PANEL_POWER_POLICY].item_num = 3;
1195     }
1196     else
1197     {
1198         panels[PANEL_POWER_POLICY].item_num = 0;
1199     }
1200 #endif
1201     return PANEL_POWER_POLICY;
1202 }
1203 
1204 int plat_udbg_control_panel(uint8_t panel, uint8_t operation, uint8_t item,
1205                             uint8_t* count, uint8_t* buffer)
1206 {
1207     if (panel > panelNum || panel < PANEL_MAIN)
1208         return IPMI_CC_PARM_OUT_OF_RANGE;
1209 
1210     // No more item; End of item list
1211     if (item > panels[panel].item_num)
1212         return IPMI_CC_PARM_OUT_OF_RANGE;
1213 
1214     switch (operation)
1215     {
1216         case 0: // Get Description
1217             break;
1218         case 1: // Select item
1219             panel = panels[panel].select(item);
1220             item = 0;
1221             break;
1222         case 2: // Back
1223             panel = panels[panel].parent;
1224             item = 0;
1225             break;
1226         default:
1227             return IPMI_CC_PARM_OUT_OF_RANGE;
1228     }
1229 
1230     buffer[0] = panel;
1231     buffer[1] = item;
1232     buffer[2] = strlen(panels[panel].item_str[item]);
1233     if (buffer[2] > 0 && (buffer[2] + 3) < FRAME_PAGE_BUF_SIZE)
1234     {
1235         memcpy(&buffer[3], panels[panel].item_str[item], buffer[2]);
1236     }
1237     *count = buffer[2] + 3;
1238     return IPMI_CC_OK;
1239 }
1240 
1241 } // end of namespace ipmi
1242