]> git.ozlabs.org Git - petitboot/blob - discover/platform-arm64.c
discover/grub2: Allow to separate the --id argument using a space char
[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
26 #include "efi/efivar.h"
27 #include "file/file.h"
28 #include "log/log.h"
29 #include <process/process.h>
30 #include <system/system.h>
31 #include "talloc/talloc.h"
32 #include "types/types.h"
33
34 #include "ipmi.h"
35 #include "platform.h"
36
37 struct platform_arm64 {
38         const struct efi_mount *efi_mount;
39         struct param_list *params;
40         struct ipmi *ipmi;
41 };
42
43 static inline struct platform_arm64 *to_platform_arm64(struct platform *p)
44 {
45         return (struct platform_arm64 *)(p->platform_data);
46 }
47
48 static void read_efivars(const struct efi_mount *efi_mount,
49         struct param_list *pl)
50 {
51         const char** known;
52
53         if (!efi_mount)
54                 return;
55
56         param_list_for_each_known_param(pl, known) {
57                 struct efi_data *efi_data;
58
59                 if (efi_get_variable(NULL, efi_mount, *known, &efi_data))
60                         continue;
61
62                 param_list_set(pl, *known, efi_data->data, true);
63                 talloc_free(efi_data);
64         }
65 }
66
67 static void write_efivars(const struct efi_mount *efi_mount,
68         const struct param_list *pl)
69 {
70         struct efi_data efi_data;
71         struct param *param;
72
73         if (!efi_mount)
74                 return;
75
76         efi_data.attributes = EFI_DEFALT_ATTRIBUTES;
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_mount, 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         const struct efi_mount *efi_mount = to_platform_arm64(p)->efi_mount;
107         struct param_list *pl = to_platform_arm64(p)->params;
108
109         read_efivars(efi_mount, pl);
110         config_populate_all(config, pl);
111         get_active_consoles(config);
112
113         return 0;
114 }
115
116 static char *stdout_cleaner(struct process_stdout *out)
117 {
118         char *p;
119         const char *const end = out->buf + out->len;
120
121         for (p = out->buf; *p && p < end; p++) {
122                 if (*p == '\n' || *p == '\r') {
123                         *p = 0;
124                 } else if (!isprint(*p)) {
125                         *p = '.';
126                 } else if (*p == '\t') {
127                         *p = ' ';
128                 }
129         }
130         return out->buf;
131 }
132
133 static int get_sysinfo(struct platform *p, struct system_info *sysinfo)
134 {
135         struct platform_arm64 *platform = to_platform_arm64(p);
136         struct process_stdout *out1, *out2;
137
138         /* Use dmidecode to get sysinfo type and identifier. */
139
140         process_get_stdout(NULL, &out1, pb_system_apps.dmidecode,
141                 "--string=system-manufacturer",
142                 NULL);
143         process_get_stdout(NULL, &out2, pb_system_apps.dmidecode,
144                 "--string=system-product-name",
145                 NULL);
146
147         if (out1 || out2)
148                 sysinfo->type = talloc_asprintf(sysinfo, "%s %s",
149                         out1 ? stdout_cleaner(out1) : "Unknown",
150                         out2 ? stdout_cleaner(out2) : "Unknown");
151         talloc_free(out1);
152         talloc_free(out2);
153
154         process_get_stdout(NULL, &out1, pb_system_apps.dmidecode,
155                 "--string=system-uuid",
156                 NULL);
157
158         if (out1)
159                 sysinfo->identifier = talloc_asprintf(sysinfo, "%s",
160                         stdout_cleaner(out1));
161         talloc_free(out1);
162
163         sysinfo->bmc_mac = talloc_zero_size(sysinfo, HWADDR_SIZE);
164
165         if (platform->ipmi) {
166                 ipmi_get_bmc_mac(platform->ipmi, sysinfo->bmc_mac);
167                 ipmi_get_bmc_versions(platform->ipmi, sysinfo);
168         }
169
170         pb_debug_fn("type:       '%s'\n", sysinfo->type);
171         pb_debug_fn("identifier: '%s'\n", sysinfo->identifier);
172         pb_debug_fn("bmc_mac:    '%s'\n", sysinfo->bmc_mac);
173
174         return 0;
175 }
176
177 static void params_update_all(struct param_list *pl,
178         const struct config *config, const struct config *defaults)
179 {
180         char *tmp = NULL;
181         const char *val;
182
183         if (config->autoboot_enabled == defaults->autoboot_enabled)
184                 val = "";
185         else
186                 val = config->autoboot_enabled ? "true" : "false";
187
188         param_list_set_non_empty(pl, "auto-boot?", val, true);
189
190         if (config->autoboot_timeout_sec == defaults->autoboot_timeout_sec)
191                 val = "";
192         else
193                 val = tmp = talloc_asprintf(pl, "%d",
194                         config->autoboot_timeout_sec);
195
196         param_list_set_non_empty(pl, "petitboot,timeout", val, true);
197         if (tmp)
198                 talloc_free(tmp);
199
200         val = config->lang ?: "";
201         param_list_set_non_empty(pl, "petitboot,language", val, true);
202
203         if (config->allow_writes == defaults->allow_writes)
204                 val = "";
205         else
206                 val = config->allow_writes ? "true" : "false";
207         param_list_set_non_empty(pl, "petitboot,write?", val, true);
208
209         if (!config->manual_console) {
210                 val = config->boot_console ?: "";
211                 param_list_set_non_empty(pl, "petitboot,console", val, true);
212         }
213
214         val = config->http_proxy ?: "";
215         param_list_set_non_empty(pl, "petitboot,http_proxy", val, true);
216         val = config->https_proxy ?: "";
217         param_list_set_non_empty(pl, "petitboot,https_proxy", val, true);
218
219         params_update_network_values(pl, "petitboot,network", config);
220         params_update_bootdev_values(pl, "petitboot,bootdevs", config);
221 }
222
223 static int save_config(struct platform *p, struct config *config)
224 {
225         const struct efi_mount *efi_mount = to_platform_arm64(p)->efi_mount;
226         struct param_list *pl = to_platform_arm64(p)->params;
227         struct config *defaults;
228
229         defaults = talloc_zero(NULL, struct config);
230         config_set_defaults(defaults);
231
232         params_update_all(pl, config, defaults);
233         talloc_free(defaults);
234
235         write_efivars(efi_mount, pl);
236         
237         return 0;
238 }
239
240 static bool probe(struct platform *p, void *ctx)
241 {
242         static const struct efi_mount efi_mount = {
243                 .path = "/sys/firmware/efi/efivars",
244                 .guid = "fb78ab4b-bd43-41a0-99a2-4e74bef9169b",
245         };
246         struct platform_arm64 *platform;
247
248         platform = talloc_zero(ctx, struct platform_arm64);
249         platform->params = talloc_zero(platform, struct param_list);
250         param_list_init(platform->params, common_known_params());
251
252         if (efi_check_mount(&efi_mount))
253                 platform->efi_mount = &efi_mount;
254
255         p->platform_data = platform;
256
257         return true;
258 }
259
260 static struct platform platform_arm64 = {
261         .name                   = "arm64",
262         .dhcp_arch_id           = 0x000d,
263         .probe                  = probe,
264         .load_config            = load_config,
265         .save_config            = save_config,
266         .get_sysinfo            = get_sysinfo,
267 };
268
269 register_platform(platform_arm64);