]> Git Repo - J-u-boot.git/blob - boot/expo_build_cb.c
x86: coreboot: Allow building an expo for editing CMOS config
[J-u-boot.git] / boot / expo_build_cb.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Building an expo from an FDT description
4  *
5  * Copyright 2022 Google LLC
6  * Written by Simon Glass <[email protected]>
7  */
8
9 #define LOG_CATEGORY    LOGC_EXPO
10
11 #include <cedit.h>
12 #include <ctype.h>
13 #include <errno.h>
14 #include <expo.h>
15 #include <log.h>
16 #include <malloc.h>
17 #include <vsprintf.h>
18 #include <asm/cb_sysinfo.h>
19
20 /**
21  * struct build_info - Information to use when building
22  */
23 struct build_info {
24         const struct cb_cmos_option_table *tab;
25         struct cedit_priv *priv;
26 };
27
28 /**
29  * convert_to_title() - Convert text to 'title' format and allocate a string
30  *
31  * Converts "this_is_a_test" to "This is a test" so it looks better
32  *
33  * @text: Text to convert
34  * Return: Allocated string, or NULL if out of memory
35  */
36 static char *convert_to_title(const char *text)
37 {
38         int len = strlen(text);
39         char *buf, *s;
40
41         buf = malloc(len + 1);
42         if (!buf)
43                 return NULL;
44
45         for (s = buf; *text; s++, text++) {
46                 if (s == buf)
47                         *s = toupper(*text);
48                 else if (*text == '_')
49                         *s = ' ';
50                 else
51                         *s = *text;
52         }
53         *s = '\0';
54
55         return buf;
56 }
57
58 /**
59  * menu_build() - Build a menu and add it to a scene
60  *
61  * See doc/developer/expo.rst for a description of the format
62  *
63  * @info: Build information
64  * @entry: CMOS entry to build a menu for
65  * @scn: Scene to add the menu to
66  * @objp: Returns the object pointer
67  * Returns: 0 if OK, -ENOMEM if out of memory, -EINVAL if there is a format
68  * error, -ENOENT if there is a references to a non-existent string
69  */
70 static int menu_build(struct build_info *info,
71                       const struct cb_cmos_entries *entry, struct scene *scn,
72                       struct scene_obj **objp)
73 {
74         struct scene_obj_menu *menu;
75         const void *ptr, *end;
76         uint menu_id;
77         char *title;
78         int ret, i;
79
80         ret = scene_menu(scn, entry->name, 0, &menu);
81         if (ret < 0)
82                 return log_msg_ret("men", ret);
83         menu_id = ret;
84
85         title = convert_to_title(entry->name);
86         if (!title)
87                 return log_msg_ret("con", -ENOMEM);
88
89         /* Set the title */
90         ret = scene_txt_str(scn, "title", 0, 0, title, NULL);
91         if (ret < 0)
92                 return log_msg_ret("tit", ret);
93         menu->title_id = ret;
94
95         end = (void *)info->tab + info->tab->size;
96         for (ptr = (void *)info->tab + info->tab->header_length, i = 0;
97              ptr < end; i++) {
98                 const struct cb_cmos_enums *enums = ptr;
99                 struct scene_menitem *item;
100                 uint label;
101
102                 ptr += enums->size;
103                 if (enums->tag != CB_TAG_OPTION_ENUM ||
104                     enums->config_id != entry->config_id)
105                         continue;
106
107                 ret = scene_txt_str(scn, enums->text, 0, 0, enums->text, NULL);
108                 if (ret < 0)
109                         return log_msg_ret("tit", ret);
110                 label = ret;
111
112                 ret = scene_menuitem(scn, menu_id, simple_xtoa(i), 0, 0, label,
113                                      0, 0, 0, &item);
114                 if (ret < 0)
115                         return log_msg_ret("mi", ret);
116                 item->value = enums->value;
117         }
118         *objp = &menu->obj;
119
120         return 0;
121 }
122
123 /**
124  * scene_build() - Build a scene and all its objects
125  *
126  * See doc/developer/expo.rst for a description of the format
127  *
128  * @info: Build information
129  * @scn: Scene to add the object to
130  * Returns: 0 if OK, -ENOMEM if out of memory, -EINVAL if there is a format
131  * error, -ENOENT if there is a references to a non-existent string
132  */
133 static int scene_build(struct build_info *info, struct expo *exp)
134 {
135         struct scene_obj_menu *menu;
136         const void *ptr, *end;
137         struct scene_obj *obj;
138         struct scene *scn;
139         uint label, menu_id;
140         int ret;
141
142         ret = scene_new(exp, "cmos", 0, &scn);
143         if (ret < 0)
144                 return log_msg_ret("scn", ret);
145
146         ret = scene_txt_str(scn, "title", 0, 0, "CMOS RAM settings", NULL);
147         if (ret < 0)
148                 return log_msg_ret("add", ret);
149         scn->title_id = ret;
150
151         ret = scene_txt_str(scn, "prompt", 0, 0,
152                             "UP and DOWN to choose, ENTER to select", NULL);
153         if (ret < 0)
154                 return log_msg_ret("add", ret);
155
156         end = (void *)info->tab + info->tab->size;
157         for (ptr = (void *)info->tab + info->tab->header_length; ptr < end;) {
158                 const struct cb_cmos_entries *entry;
159                 const struct cb_record *rec = ptr;
160
161                 entry = ptr;
162                 ptr += rec->size;
163                 if (rec->tag != CB_TAG_OPTION)
164                         continue;
165                 switch (entry->config) {
166                 case 'e':
167                         ret = menu_build(info, entry, scn, &obj);
168                         break;
169                 default:
170                         continue;
171                 }
172                 if (ret < 0)
173                         return log_msg_ret("add", ret);
174
175                 obj->start_bit = entry->bit;
176                 obj->bit_length = entry->length;
177         }
178
179         ret = scene_menu(scn, "save", EXPOID_SAVE, &menu);
180         if (ret < 0)
181                 return log_msg_ret("men", ret);
182         menu_id = ret;
183
184         ret = scene_txt_str(scn, "save", 0, 0, "Save and exit", NULL);
185         if (ret < 0)
186                 return log_msg_ret("sav", ret);
187         label = ret;
188         ret = scene_menuitem(scn, menu_id, "save", 0, 0, label,
189                              0, 0, 0, NULL);
190         if (ret < 0)
191                 return log_msg_ret("mi", ret);
192
193         ret = scene_menu(scn, "nosave", EXPOID_DISCARD, &menu);
194         if (ret < 0)
195                 return log_msg_ret("men", ret);
196         menu_id = ret;
197
198         ret = scene_txt_str(scn, "nosave", 0, 0, "Exit without saving", NULL);
199         if (ret < 0)
200                 return log_msg_ret("nos", ret);
201         label = ret;
202         ret = scene_menuitem(scn, menu_id, "exit", 0, 0, label,
203                              0, 0, 0, NULL);
204         if (ret < 0)
205                 return log_msg_ret("mi", ret);
206
207         return 0;
208 }
209
210 static int build_it(struct build_info *info, struct expo **expp)
211 {
212         struct expo *exp;
213         int ret;
214
215         ret = expo_new("coreboot", NULL, &exp);
216         if (ret)
217                 return log_msg_ret("exp", ret);
218         expo_set_dynamic_start(exp, EXPOID_BASE_ID);
219
220         ret = scene_build(info, exp);
221         if (ret < 0)
222                 return log_msg_ret("scn", ret);
223
224         *expp = exp;
225
226         return 0;
227 }
228
229 int cb_expo_build(struct expo **expp)
230 {
231         struct build_info info;
232         struct expo *exp;
233         int ret;
234
235         info.tab = lib_sysinfo.option_table;
236         if (!info.tab)
237                 return log_msg_ret("tab", -ENOENT);
238
239         ret = build_it(&info, &exp);
240         if (ret)
241                 return log_msg_ret("bui", ret);
242         *expp = exp;
243
244         return 0;
245 }
This page took 0.034846 seconds and 4 git commands to generate.