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