1 /**
2  * Copyright (C) 2020 IBM Corporation
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 "registration.hpp"
18 
19 extern "C"
20 {
21 #include <libpdbg.h>
22 #include <libpdbg_sbe.h>
23 }
24 
25 #include <sys/wait.h>
26 #include <unistd.h>
27 
28 #include <phosphor-logging/log.hpp>
29 
30 #include <format>
31 #include <system_error>
32 #include <vector>
33 
34 namespace openpower
35 {
36 namespace misc
37 {
38 
39 /**
40  * @brief Calls sbe_enter_mpipl on the SBE in the provided target.
41  * @return void
42  */
sbeEnterMpReboot(struct pdbg_target * tgt)43 void sbeEnterMpReboot(struct pdbg_target* tgt)
44 {
45     using namespace phosphor::logging;
46     int error = 0;
47     if ((error = sbe_mpipl_enter(tgt)) < 0)
48     {
49         log<level::ERR>("Failed to initiate memory preserving reboot");
50         // TODO Create a PEL in the future for this failure case.
51         throw std::system_error(error, std::generic_category(),
52                                 "Failed to initiate memory preserving reboot");
53     }
54 
55     log<level::INFO>(
56         std::format("Enter MPIPL completed on proc({})", pdbg_target_index(tgt))
57             .c_str());
58 }
59 
60 /**
61  * @brief initiate memory preserving reboot on each SBE.
62  * @return void
63  */
enterMpReboot()64 void enterMpReboot()
65 {
66     using namespace phosphor::logging;
67     struct pdbg_target* target;
68     std::vector<pid_t> pidList;
69     bool failed = false;
70     pdbg_targets_init(NULL);
71 
72     log<level::INFO>("Starting memory preserving reboot");
73     pdbg_for_each_class_target("pib", target)
74     {
75         if (pdbg_target_probe(target) != PDBG_TARGET_ENABLED)
76         {
77             continue;
78         }
79 
80         pid_t pid = fork();
81 
82         if (pid < 0)
83         {
84             log<level::ERR>("Fork failed while starting mp reboot");
85             failed = true;
86         }
87         else if (pid == 0)
88         {
89             sbeEnterMpReboot(target);
90             std::exit(EXIT_SUCCESS);
91         }
92         else
93         {
94             pidList.push_back(std::move(pid));
95         }
96     }
97 
98     for (auto& p : pidList)
99     {
100         int status = 0;
101         waitpid(p, &status, 0);
102         if (WEXITSTATUS(status))
103         {
104             log<level::ERR>("Memory preserving reboot failed");
105             failed = true;
106         }
107     }
108 
109     if (failed)
110     {
111         std::exit(EXIT_FAILURE);
112     }
113 }
114 
115 REGISTER_PROCEDURE("enterMpReboot", enterMpReboot)
116 
117 } // namespace misc
118 } // namespace openpower
119