]> git.ozlabs.org Git - petitboot/blob - discover/platform-arm64.c
discover/platforms: Fix param_list talloc failure
[petitboot] / discover / platform-arm64.c
1 /*
2  *  This program is free software; you can redistribute it and/or modify
3  *  it under the terms of the GNU General Public License as published by
4  *  the Free Software Foundation; version 2 of the License.
5  *
6  *  This program is distributed in the hope that it will be useful,
7  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
8  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
9  *  GNU General Public License for more details.
10  *
11  *  You should have received a copy of the GNU General Public License
12  *  along with this program; if not, write to the Free Software
13  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
14  *
15  *  Copyright (C) 2018 Huaxintong Semiconductor Technology Co.,Ltd. All rights
16  *  reserved.
17  *  Author: Ge Song <ge.song@hxt-semitech.com>
18  */
19
20 #include <ctype.h>
21 #include <errno.h>
22 #include <limits.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/statfs.h>
26
27 #include "efi/efivar.h"
28 #include "file/file.h"
29 #include "log/log.h"
30 #include <process/process.h>
31 #include <system/system.h>
32 #include "talloc/talloc.h"
33 #include "types/types.h"
34
35
36 #include "ipmi.h"
37 #include "platform.h"
38
39 static const char *efi_vars_guid = "fb78ab4b-bd43-41a0-99a2-4e74bef9169b";
40
41 struct platform_arm64 {
42         struct param_list *params;
43         struct ipmi *ipmi;
44 };
45
46 static inline struct platform_arm64 *to_platform_arm64(struct platform *p)
47 {
48         return (struct platform_arm64 *)(p->platform_data);
49 }
50
51 static void parse_nvram(struct param_list *pl)
52 {
53         const char** known;
54
55         param_list_for_each_known_param(pl, known) {
56                 struct efi_data *efi_data;
57
58                 if (efi_get_variable(NULL, efi_vars_guid, *known, &efi_data))
59                         continue;
60
61                 param_list_set(pl, *known, efi_data->data,
62                         true);
63
64                 talloc_free(efi_data);
65         }
66 }
67
68 static void write_nvram(const struct param_list *pl)
69 {
70         struct efi_data efi_data;
71         struct param *param;
72
73         efi_data.attributes =
74                 EFI_VARIABLE_NON_VOLATILE |
75                 EFI_VARIABLE_RUNTIME_ACCESS |
76                 EFI_VARIABLE_BOOTSERVICE_ACCESS;
77
78         param_list_for_each(pl, param) {
79                 if (!param->modified)
80                         continue;
81
82                 efi_data.data = param->value;
83                 efi_data.data_size = strlen(param->value) + 1;
84                 efi_set_variable(efi_vars_guid, param->name, &efi_data);
85         }
86 }
87
88 static void get_active_consoles(struct config *config)
89 {
90         config->n_consoles = 0;
91         config->consoles = talloc_array(config, char *, 3);
92         if (!config->consoles)
93                 return;
94
95         config->consoles[0] = talloc_asprintf(config,
96                                         "/dev/hvc0 [IPMI / Serial]");
97         config->consoles[1] = talloc_asprintf(config,
98                                         "/dev/ttyAMA0 [Serial]");
99         config->consoles[2] = talloc_asprintf(config,
100                                         "/dev/tty1 [VGA]");
101         config->n_consoles = 3;
102 }
103
104 static int load_config(struct platform *p, struct config *config)
105 {
106         struct param_list *pl = to_platform_arm64(p)->params;
107
108         parse_nvram(pl);
109         config_populate_all(config, pl);
110         get_active_consoles(config);
111
112         return 0;
113 }
114
115 static char *stdout_cleaner(struct process_stdout *out)
116 {
117         char *p;
118         const char *const end = out->buf + out->len;
119
120         for (p = out->buf; *p && p < end; p++) {
121                 if (*p == '\n' || *p == '\r') {
122                         *p = 0;
123                 } else if (!isprint(*p)) {
124                         *p = '.';
125                 } else if (*p == '\t') {
126                         *p = ' ';
127                 }
128         }
129         return out->buf;
130 }
131
132 static int get_sysinfo(struct platform *p, struct system_info *sysinfo)
133 {
134         struct platform_arm64 *platform = to_platform_arm64(p);
135         struct process_stdout *out1, *out2;
136
137         /* Use dmidecode to get sysinfo type and identifier. */
138
139         process_get_stdout(NULL, &out1, pb_system_apps.dmidecode,
140                 "--string=system-manufacturer",
141                 NULL);
142         process_get_stdout(NULL, &out2, pb_system_apps.dmidecode,
143                 "--string=system-product-name",
144                 NULL);
145
146         if (out1 || out2)
147                 sysinfo->type = talloc_asprintf(sysinfo, "%s %s",
148                         out1 ? stdout_cleaner(out1) : "Unknown",
149                         out2 ? stdout_cleaner(out2) : "Unknown");
150         talloc_free(out1);
151         talloc_free(out2);
152
153         process_get_stdout(NULL, &out1, pb_system_apps.dmidecode,
154                 "--string=system-uuid",
155                 NULL);
156
157         if (out1)
158                 sysinfo->identifier = talloc_asprintf(sysinfo, "%s",
159                         stdout_cleaner(out1));
160         talloc_free(out1);
161
162         sysinfo->bmc_mac = talloc_zero_size(sysinfo, HWADDR_SIZE);
163
164         if (platform->ipmi) {
165                 ipmi_get_bmc_mac(platform->ipmi, sysinfo->bmc_mac);
166                 ipmi_get_bmc_versions(platform->ipmi, sysinfo);
167         }
168
169         pb_debug_fn("type:       '%s'\n", sysinfo->type);
170         pb_debug_fn("identifier: '%s'\n", sysinfo->identifier);
171         pb_debug_fn("bmc_mac:    '%s'\n", sysinfo->bmc_mac);
172
173         return 0;
174 }
175
176 static void params_update_all(struct param_list *pl,
177         const struct config *config, const struct config *defaults)
178 {
179         char *tmp = NULL;
180         const char *val;
181
182         if (config->autoboot_enabled == defaults->autoboot_enabled)
183                 val = "";
184         else
185                 val = config->autoboot_enabled ? "true" : "false";
186
187         param_list_set_non_empty(pl, "auto-boot?", val, true);
188
189         if (config->autoboot_timeout_sec == defaults->autoboot_timeout_sec)
190                 val = "";
191         else
192                 val = tmp = talloc_asprintf(pl, "%d",
193                         config->autoboot_timeout_sec);
194
195         param_list_set_non_empty(pl, "petitboot,timeout", val, true);
196         if (tmp)
197                 talloc_free(tmp);
198
199         val = config->lang ?: "";
200         param_list_set_non_empty(pl, "petitboot,language", val, true);
201
202         if (config->allow_writes == defaults->allow_writes)
203                 val = "";
204         else
205                 val = config->allow_writes ? "true" : "false";
206         param_list_set_non_empty(pl, "petitboot,write?", val, true);
207
208         if (!config->manual_console) {
209                 val = config->boot_console ?: "";
210                 param_list_set_non_empty(pl, "petitboot,console", val, true);
211         }
212
213         val = config->http_proxy ?: "";
214         param_list_set_non_empty(pl, "petitboot,http_proxy", val, true);
215         val = config->https_proxy ?: "";
216         param_list_set_non_empty(pl, "petitboot,https_proxy", val, true);
217
218         params_update_network_values(pl, "petitboot,network", config);
219         params_update_bootdev_values(pl, "petitboot,bootdevs", config);
220 }
221
222 static int save_config(struct platform *p, struct config *config)
223 {
224         struct param_list *pl = to_platform_arm64(p)->params;
225         struct config *defaults;
226
227         defaults = talloc_zero(NULL, struct config);
228         config_set_defaults(defaults);
229
230         params_update_all(pl, config, defaults);
231         talloc_free(defaults);
232
233         write_nvram(pl);
234         
235         return 0;
236 }
237
238 static bool probe(struct platform *p, void *ctx)
239 {
240         static const char *efivars = "/sys/firmware/efi/efivars";
241         struct platform_arm64 *platform;
242         struct statfs buf;
243
244         if (access(efivars, R_OK | W_OK)) {
245                 pb_debug_fn("Can't access %s\n", efivars);
246                 return false;
247         }
248
249         memset(&buf, '\0', sizeof(buf));
250         if (statfs(efivars, &buf)) {
251                 pb_debug_fn("statfs failed: %s: %s\n", efivars,
252                         strerror(errno));
253                 return false;
254         }
255
256         if (buf.f_type != EFIVARFS_MAGIC) {
257                 pb_debug_fn("Bad magic = 0x%lx\n", (unsigned long)buf.f_type);
258                 return false;
259         }
260
261         platform = talloc_zero(ctx, struct platform_arm64);
262         platform->params = talloc_zero(platform, struct param_list);
263         param_list_init(platform->params, common_known_params());
264
265         p->platform_data = platform;
266
267         return true;
268 }
269
270 static struct platform platform_arm64 = {
271         .name                   = "arm64",
272         .dhcp_arch_id           = 0x000d,
273         .probe                  = probe,
274         .load_config            = load_config,
275         .save_config            = save_config,
276         .get_sysinfo            = get_sysinfo,
277 };
278
279 register_platform(platform_arm64);