]> git.ozlabs.org Git - petitboot/blob - discover/platform-arm64.c
lib/efi: Add EFI_DEFALT_ATTRIBUTES macro
[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 = EFI_DEFALT_ATTRIBUTES;
74
75         param_list_for_each(pl, param) {
76                 if (!param->modified)
77                         continue;
78
79                 efi_data.data = param->value;
80                 efi_data.data_size = strlen(param->value) + 1;
81                 efi_set_variable(efi_vars_guid, param->name, &efi_data);
82         }
83 }
84
85 static void get_active_consoles(struct config *config)
86 {
87         config->n_consoles = 0;
88         config->consoles = talloc_array(config, char *, 3);
89         if (!config->consoles)
90                 return;
91
92         config->consoles[0] = talloc_asprintf(config,
93                                         "/dev/hvc0 [IPMI / Serial]");
94         config->consoles[1] = talloc_asprintf(config,
95                                         "/dev/ttyAMA0 [Serial]");
96         config->consoles[2] = talloc_asprintf(config,
97                                         "/dev/tty1 [VGA]");
98         config->n_consoles = 3;
99 }
100
101 static int load_config(struct platform *p, struct config *config)
102 {
103         struct param_list *pl = to_platform_arm64(p)->params;
104
105         parse_nvram(pl);
106         config_populate_all(config, pl);
107         get_active_consoles(config);
108
109         return 0;
110 }
111
112 static char *stdout_cleaner(struct process_stdout *out)
113 {
114         char *p;
115         const char *const end = out->buf + out->len;
116
117         for (p = out->buf; *p && p < end; p++) {
118                 if (*p == '\n' || *p == '\r') {
119                         *p = 0;
120                 } else if (!isprint(*p)) {
121                         *p = '.';
122                 } else if (*p == '\t') {
123                         *p = ' ';
124                 }
125         }
126         return out->buf;
127 }
128
129 static int get_sysinfo(struct platform *p, struct system_info *sysinfo)
130 {
131         struct platform_arm64 *platform = to_platform_arm64(p);
132         struct process_stdout *out1, *out2;
133
134         /* Use dmidecode to get sysinfo type and identifier. */
135
136         process_get_stdout(NULL, &out1, pb_system_apps.dmidecode,
137                 "--string=system-manufacturer",
138                 NULL);
139         process_get_stdout(NULL, &out2, pb_system_apps.dmidecode,
140                 "--string=system-product-name",
141                 NULL);
142
143         if (out1 || out2)
144                 sysinfo->type = talloc_asprintf(sysinfo, "%s %s",
145                         out1 ? stdout_cleaner(out1) : "Unknown",
146                         out2 ? stdout_cleaner(out2) : "Unknown");
147         talloc_free(out1);
148         talloc_free(out2);
149
150         process_get_stdout(NULL, &out1, pb_system_apps.dmidecode,
151                 "--string=system-uuid",
152                 NULL);
153
154         if (out1)
155                 sysinfo->identifier = talloc_asprintf(sysinfo, "%s",
156                         stdout_cleaner(out1));
157         talloc_free(out1);
158
159         sysinfo->bmc_mac = talloc_zero_size(sysinfo, HWADDR_SIZE);
160
161         if (platform->ipmi) {
162                 ipmi_get_bmc_mac(platform->ipmi, sysinfo->bmc_mac);
163                 ipmi_get_bmc_versions(platform->ipmi, sysinfo);
164         }
165
166         pb_debug_fn("type:       '%s'\n", sysinfo->type);
167         pb_debug_fn("identifier: '%s'\n", sysinfo->identifier);
168         pb_debug_fn("bmc_mac:    '%s'\n", sysinfo->bmc_mac);
169
170         return 0;
171 }
172
173 static void params_update_all(struct param_list *pl,
174         const struct config *config, const struct config *defaults)
175 {
176         char *tmp = NULL;
177         const char *val;
178
179         if (config->autoboot_enabled == defaults->autoboot_enabled)
180                 val = "";
181         else
182                 val = config->autoboot_enabled ? "true" : "false";
183
184         param_list_set_non_empty(pl, "auto-boot?", val, true);
185
186         if (config->autoboot_timeout_sec == defaults->autoboot_timeout_sec)
187                 val = "";
188         else
189                 val = tmp = talloc_asprintf(pl, "%d",
190                         config->autoboot_timeout_sec);
191
192         param_list_set_non_empty(pl, "petitboot,timeout", val, true);
193         if (tmp)
194                 talloc_free(tmp);
195
196         val = config->lang ?: "";
197         param_list_set_non_empty(pl, "petitboot,language", val, true);
198
199         if (config->allow_writes == defaults->allow_writes)
200                 val = "";
201         else
202                 val = config->allow_writes ? "true" : "false";
203         param_list_set_non_empty(pl, "petitboot,write?", val, true);
204
205         if (!config->manual_console) {
206                 val = config->boot_console ?: "";
207                 param_list_set_non_empty(pl, "petitboot,console", val, true);
208         }
209
210         val = config->http_proxy ?: "";
211         param_list_set_non_empty(pl, "petitboot,http_proxy", val, true);
212         val = config->https_proxy ?: "";
213         param_list_set_non_empty(pl, "petitboot,https_proxy", val, true);
214
215         params_update_network_values(pl, "petitboot,network", config);
216         params_update_bootdev_values(pl, "petitboot,bootdevs", config);
217 }
218
219 static int save_config(struct platform *p, struct config *config)
220 {
221         struct param_list *pl = to_platform_arm64(p)->params;
222         struct config *defaults;
223
224         defaults = talloc_zero(NULL, struct config);
225         config_set_defaults(defaults);
226
227         params_update_all(pl, config, defaults);
228         talloc_free(defaults);
229
230         write_nvram(pl);
231         
232         return 0;
233 }
234
235 static bool probe(struct platform *p, void *ctx)
236 {
237         static const char *efivars = "/sys/firmware/efi/efivars";
238         struct platform_arm64 *platform;
239         struct statfs buf;
240
241         if (access(efivars, R_OK | W_OK)) {
242                 pb_debug_fn("Can't access %s\n", efivars);
243                 return false;
244         }
245
246         memset(&buf, '\0', sizeof(buf));
247         if (statfs(efivars, &buf)) {
248                 pb_debug_fn("statfs failed: %s: %s\n", efivars,
249                         strerror(errno));
250                 return false;
251         }
252
253         if (buf.f_type != EFIVARFS_MAGIC) {
254                 pb_debug_fn("Bad magic = 0x%lx\n", (unsigned long)buf.f_type);
255                 return false;
256         }
257
258         platform = talloc_zero(ctx, struct platform_arm64);
259         platform->params = talloc_zero(platform, struct param_list);
260         param_list_init(platform->params, common_known_params());
261
262         p->platform_data = platform;
263
264         return true;
265 }
266
267 static struct platform platform_arm64 = {
268         .name                   = "arm64",
269         .dhcp_arch_id           = 0x000d,
270         .probe                  = probe,
271         .load_config            = load_config,
272         .save_config            = save_config,
273         .get_sysinfo            = get_sysinfo,
274 };
275
276 register_platform(platform_arm64);