1 /* SPDX-License-Identifier: GPL-2.0-only */
4 #include <boot/coreboot_tables.h>
5 #include <commonlib/coreboot_tables.h>
6 #include <console/console.h>
8 #include <drivers/option/cfr_frontend.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
)
36 struct lb_cfr_varbinary
*cfr_str
= (struct lb_cfr_varbinary
*)current
;
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
);
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
))
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
;
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
);
108 len
= sm_write_ui_name(current
, ui_name
);
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
);
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
,
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
;
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
);
173 len
= sm_write_ui_name(current
, sm_varchar
->ui_name
);
177 current
+= sm_write_ui_helptext(current
, sm_varchar
->ui_helptext
);
179 option
->size
= cfr_record_size((char *)option
, current
);
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
;
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
);
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
;
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
);
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
);
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
;
251 /* Assign uniqueue ID */
252 obj_id
= sm_gen_obj_id((void *)sm_obj
);
254 /* Set dependency ID */
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 */
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
) {
275 return sm_write_opt_enum(current
, &sm_obj
->sm_enum
, obj_id
,
278 return sm_write_opt_number(current
, &sm_obj
->sm_number
, obj_id
,
281 return sm_write_opt_bool(current
, &sm_obj
->sm_bool
, obj_id
,
284 return sm_write_opt_varchar(current
, &sm_obj
->sm_varchar
, obj_id
,
287 return sm_write_opt_comment(current
, &sm_obj
->sm_comment
, obj_id
,
290 return sm_write_form(current
, (struct sm_obj_form
*)&sm_obj
->sm_form
, obj_id
, dep_id
);
293 printk(BIOS_ERR
, "Unknown setup menu object kind %u, ignoring\n", sm_obj
->kind
);
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
;
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);
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
);