util/crossgcc: Update DESTDIR variable use
[coreboot2.git] / src / drivers / option / cfr.c
blobe833d7bdba088b5ef829fe6849b14f65aec7fe0b
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include <assert.h>
4 #include <boot/coreboot_tables.h>
5 #include <commonlib/coreboot_tables.h>
6 #include <console/console.h>
7 #include <crc_byte.h>
8 #include <drivers/option/cfr_frontend.h>
9 #include <inttypes.h>
10 #include <string.h>
11 #include <types.h>
13 static uint32_t cfr_record_size(const char *startp, const char *endp)
15 const uintptr_t start = (uintptr_t)startp;
16 const uintptr_t end = (uintptr_t)endp;
18 if (start > end || end - start > UINT32_MAX) {
20 * Should never be reached unless something went really
21 * wrong. Record size can never be negative, and things
22 * would break long before record length exceeds 4 GiB.
24 die("%s: bad record size (start = %" PRIxPTR ", end = %" PRIxPTR ")",
25 __func__, start, end);
27 return (uint32_t)(end - start);
30 static uint32_t write_cfr_varchar(char *current, const char *string, uint32_t tag)
32 ASSERT(string);
33 if (!string)
34 return 0;
36 struct lb_cfr_varbinary *cfr_str = (struct lb_cfr_varbinary *)current;
37 cfr_str->tag = tag;
38 cfr_str->data_length = strlen(string) + 1;
39 char *data = current + sizeof(*cfr_str);
40 memcpy(data, string, cfr_str->data_length);
42 /* Make sure that every TAG/SIZE field is always aligned to LB_ENTRY_ALIGN */
43 cfr_str->size = ALIGN_UP(sizeof(*cfr_str) + cfr_str->data_length, LB_ENTRY_ALIGN);
45 return cfr_str->size;
48 static uint32_t sm_write_string_default_value(char *current, const char *string)
50 return write_cfr_varchar(current, string ? string : "", CFR_TAG_VARCHAR_DEF_VALUE);
53 static uint32_t sm_write_opt_name(char *current, const char *string)
55 return write_cfr_varchar(current, string, CFR_TAG_VARCHAR_OPT_NAME);
58 static uint32_t sm_write_ui_name(char *current, const char *string)
60 return write_cfr_varchar(current, string, CFR_TAG_VARCHAR_UI_NAME);
63 static uint32_t sm_write_ui_helptext(char *current, const char *string)
65 /* UI Helptext is optional, return if nothing to display */
66 if (!string || !strlen(string))
67 return 0;
69 return write_cfr_varchar(current, string, CFR_TAG_VARCHAR_UI_HELPTEXT);
72 static uint32_t sm_write_enum_value(char *current, const struct sm_enum_value *e)
74 struct lb_cfr_enum_value *enum_val = (struct lb_cfr_enum_value *)current;
75 enum_val->tag = CFR_TAG_ENUM_VALUE;
76 enum_val->value = e->value;
77 enum_val->size = sizeof(*enum_val);
79 current += enum_val->size;
80 current += sm_write_ui_name(current, e->ui_name);
82 enum_val->size = cfr_record_size((char *)enum_val, current);
83 return enum_val->size;
86 static uint32_t write_numeric_option(char *current, uint32_t tag, const uint64_t object_id,
87 const char *opt_name, const char *ui_name, const char *ui_helptext,
88 uint32_t flags, uint32_t default_value, const struct sm_enum_value *values,
89 const uint64_t dep_id)
91 struct lb_cfr_numeric_option *option = (struct lb_cfr_numeric_option *)current;
92 size_t len;
94 option->tag = tag;
95 option->object_id = object_id;
96 option->dependency_id = dep_id;
97 option->flags = flags;
98 if (option->flags & (CFR_OPTFLAG_INACTIVE | CFR_OPTFLAG_VOLATILE))
99 option->flags |= CFR_OPTFLAG_READONLY;
100 option->default_value = default_value;
101 option->size = sizeof(*option);
103 current += option->size;
104 len = sm_write_opt_name(current, opt_name);
105 if (!len)
106 return 0;
107 current += len;
108 len = sm_write_ui_name(current, ui_name);
109 if (!len)
110 return 0;
111 current += len;
112 current += sm_write_ui_helptext(current, ui_helptext);
114 if (option->tag == CFR_TAG_OPTION_ENUM && values) {
115 for (const struct sm_enum_value *e = values; e->ui_name; e++) {
116 current += sm_write_enum_value(current, e);
120 option->size = cfr_record_size((char *)option, current);
121 return option->size;
124 static uint32_t sm_write_opt_enum(char *current, const struct sm_obj_enum *sm_enum,
125 const uint64_t object_id, const uint64_t dep_id)
128 return write_numeric_option(current, CFR_TAG_OPTION_ENUM, object_id,
129 sm_enum->opt_name, sm_enum->ui_name, sm_enum->ui_helptext,
130 sm_enum->flags, sm_enum->default_value, sm_enum->values,
131 dep_id);
134 static uint32_t sm_write_opt_number(char *current, const struct sm_obj_number *sm_number,
135 const uint64_t object_id, const uint64_t dep_id)
138 return write_numeric_option(current, CFR_TAG_OPTION_NUMBER, object_id,
139 sm_number->opt_name, sm_number->ui_name, sm_number->ui_helptext,
140 sm_number->flags, sm_number->default_value, NULL, dep_id);
143 static uint32_t sm_write_opt_bool(char *current, const struct sm_obj_bool *sm_bool,
144 const uint64_t object_id, const uint64_t dep_id)
147 return write_numeric_option(current, CFR_TAG_OPTION_BOOL, object_id,
148 sm_bool->opt_name, sm_bool->ui_name, sm_bool->ui_helptext,
149 sm_bool->flags, sm_bool->default_value, NULL, dep_id);
152 static uint32_t sm_write_opt_varchar(char *current, const struct sm_obj_varchar *sm_varchar,
153 const uint64_t object_id, const uint64_t dep_id)
156 struct lb_cfr_varchar_option *option = (struct lb_cfr_varchar_option *)current;
157 size_t len;
159 option->tag = CFR_TAG_OPTION_VARCHAR;
160 option->object_id = object_id;
161 option->dependency_id = dep_id;
162 option->flags = sm_varchar->flags;
163 if (option->flags & (CFR_OPTFLAG_INACTIVE | CFR_OPTFLAG_VOLATILE))
164 option->flags |= CFR_OPTFLAG_READONLY;
165 option->size = sizeof(*option);
167 current += option->size;
168 current += sm_write_string_default_value(current, sm_varchar->default_value);
169 len = sm_write_opt_name(current, sm_varchar->opt_name);
170 if (!len)
171 return 0;
172 current += len;
173 len = sm_write_ui_name(current, sm_varchar->ui_name);
174 if (!len)
175 return 0;
176 current += len;
177 current += sm_write_ui_helptext(current, sm_varchar->ui_helptext);
179 option->size = cfr_record_size((char *)option, current);
180 return option->size;
183 static uint32_t sm_write_opt_comment(char *current, const struct sm_obj_comment *sm_comment,
184 const uint32_t object_id, const uint32_t dep_id)
186 struct lb_cfr_option_comment *comment = (struct lb_cfr_option_comment *)current;
187 size_t len;
189 comment->tag = CFR_TAG_OPTION_COMMENT;
190 comment->object_id = object_id;
191 comment->dependency_id = dep_id;
192 comment->flags = sm_comment->flags;
193 if (comment->flags & (CFR_OPTFLAG_INACTIVE | CFR_OPTFLAG_VOLATILE))
194 comment->flags |= CFR_OPTFLAG_READONLY;
195 comment->size = sizeof(*comment);
197 current += comment->size;
198 len = sm_write_ui_name(current, sm_comment->ui_name);
199 if (!len)
200 return 0;
201 current += len;
202 current += sm_write_ui_helptext(current, sm_comment->ui_helptext);
204 comment->size = cfr_record_size((char *)comment, current);
205 return comment->size;
208 static uint64_t sm_gen_obj_id(void *ptr)
210 uintptr_t id = (uintptr_t)ptr;
211 /* Convert pointer to unique ID */
212 return id ^ 0xffffcafecafecafe;
215 static uint32_t sm_write_object(char *current, const struct sm_object *sm_obj);
217 static uint32_t sm_write_form(char *current, struct sm_obj_form *sm_form,
218 const uint64_t object_id, const uint64_t dep_id)
220 struct lb_cfr_option_form *form = (struct lb_cfr_option_form *)current;
221 size_t len;
222 size_t i = 0;
224 form->tag = CFR_TAG_OPTION_FORM;
225 form->object_id = object_id;
226 form->dependency_id = dep_id;
227 form->flags = sm_form->flags;
228 if (form->flags & (CFR_OPTFLAG_INACTIVE | CFR_OPTFLAG_VOLATILE))
229 form->flags |= CFR_OPTFLAG_READONLY;
230 form->size = sizeof(*form);
232 current += form->size;
233 len = sm_write_ui_name(current, sm_form->ui_name);
234 if (!len)
235 return 0;
236 current += len;
238 while (sm_form->obj_list[i])
239 current += sm_write_object(current, sm_form->obj_list[i++]);
241 form->size = cfr_record_size((char *)form, current);
242 return form->size;
245 static uint32_t sm_write_object(char *current, const struct sm_object *sm_obj)
247 uint64_t dep_id, obj_id;
248 struct sm_object sm_obj_copy;
249 assert(sm_obj);
251 /* Assign uniqueue ID */
252 obj_id = sm_gen_obj_id((void *)sm_obj);
254 /* Set dependency ID */
255 dep_id = 0;
256 if (sm_obj->dep) {
257 assert(sm_obj->dep->kind == SM_OBJ_BOOL);
258 if (sm_obj->dep->kind == SM_OBJ_BOOL)
259 dep_id = sm_gen_obj_id((void *)sm_obj->dep);
262 /* Invoke callback to update fields */
263 if (sm_obj->ctor) {
264 memcpy(&sm_obj_copy, sm_obj, sizeof(*sm_obj));
265 sm_obj->ctor(sm_obj, &sm_obj_copy);
267 assert(sm_obj->kind == sm_obj_copy.kind);
268 sm_obj = (const struct sm_object *)&sm_obj_copy;
271 switch (sm_obj->kind) {
272 case SM_OBJ_NONE:
273 return 0;
274 case SM_OBJ_ENUM:
275 return sm_write_opt_enum(current, &sm_obj->sm_enum, obj_id,
276 dep_id);
277 case SM_OBJ_NUMBER:
278 return sm_write_opt_number(current, &sm_obj->sm_number, obj_id,
279 dep_id);
280 case SM_OBJ_BOOL:
281 return sm_write_opt_bool(current, &sm_obj->sm_bool, obj_id,
282 dep_id);
283 case SM_OBJ_VARCHAR:
284 return sm_write_opt_varchar(current, &sm_obj->sm_varchar, obj_id,
285 dep_id);
286 case SM_OBJ_COMMENT:
287 return sm_write_opt_comment(current, &sm_obj->sm_comment, obj_id,
288 dep_id);
289 case SM_OBJ_FORM:
290 return sm_write_form(current, (struct sm_obj_form *)&sm_obj->sm_form, obj_id, dep_id);
291 default:
292 BUG();
293 printk(BIOS_ERR, "Unknown setup menu object kind %u, ignoring\n", sm_obj->kind);
294 return 0;
298 void cfr_write_setup_menu(struct lb_cfr *cfr_root, struct sm_obj_form *sm_root[])
300 void *current = cfr_root;
301 struct sm_obj_form *obj;
302 size_t i = 0;
304 ASSERT(cfr_root);
305 if (!cfr_root)
306 return;
308 cfr_root->tag = LB_TAG_CFR_ROOT;
309 cfr_root->size = sizeof(*cfr_root);
311 current += cfr_root->size;
312 while (sm_root && sm_root[i])
313 current += sm_write_form(current, sm_root[i++], 0, 0);
316 * Add generic forms.
318 for (obj = &_cfr_forms[0]; obj != &_ecfr_forms[0]; obj++)
319 current += sm_write_form(current, obj, 0, 0);
321 cfr_root->size = cfr_record_size((char *)cfr_root, current);
323 cfr_root->checksum = CRC(cfr_root + 1, cfr_root->size - sizeof(*cfr_root), crc32_byte);
325 printk(BIOS_DEBUG, "CFR: Written %u bytes of CFR structures at %p, with CRC32 0x%08x\n",
326 cfr_root->size, cfr_root, cfr_root->checksum);