2 * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 FILE_LICENCE ( GPL2_OR_LATER );
26 #include <ipxe/efi/efi.h>
27 #include <ipxe/efi/efi_strings.h>
28 #include <ipxe/efi/efi_hii.h>
31 static const EFI_GUID tiano_guid = EFI_IFR_TIANO_GUID;
34 * Add string to IFR builder
37 * @v fmt Format string
39 * @ret string_id String identifier, or zero on failure
41 unsigned int efi_ifr_string ( struct efi_ifr_builder *ifr, const char *fmt,
43 EFI_HII_STRING_BLOCK *new_strings;
44 EFI_HII_SIBT_STRING_UCS2_BLOCK *ucs2;
45 size_t new_strings_len;
48 unsigned int string_id;
50 /* Do nothing if a previous allocation has failed */
54 /* Calculate string length */
55 va_start ( args, fmt );
56 len = ( efi_vsnprintf ( NULL, 0, fmt, args ) + 1 /* wNUL */ );
59 /* Reallocate strings */
60 new_strings_len = ( ifr->strings_len +
61 offsetof ( typeof ( *ucs2 ), StringText ) +
62 ( len * sizeof ( ucs2->StringText[0] ) ) );
63 new_strings = realloc ( ifr->strings, new_strings_len );
64 if ( ! new_strings ) {
68 ucs2 = ( ( ( void * ) new_strings ) + ifr->strings_len );
69 ifr->strings = new_strings;
70 ifr->strings_len = new_strings_len;
73 ucs2->Header.BlockType = EFI_HII_SIBT_STRING_UCS2;
74 va_start ( args, fmt );
75 efi_vsnprintf ( ucs2->StringText, len, fmt, args );
78 /* Allocate string ID */
79 string_id = ++(ifr->string_id);
81 DBGC ( ifr, "IFR %p string %#04x is \"%ls\"\n",
82 ifr, string_id, ucs2->StringText );
87 * Add IFR opcode to IFR builder
91 * @v len Opcode length
92 * @ret op Opcode, or NULL
94 static void * efi_ifr_op ( struct efi_ifr_builder *ifr, unsigned int opcode,
96 EFI_IFR_OP_HEADER *new_ops;
97 EFI_IFR_OP_HEADER *op;
100 /* Do nothing if a previous allocation has failed */
104 /* Reallocate opcodes */
105 new_ops_len = ( ifr->ops_len + len );
106 new_ops = realloc ( ifr->ops, new_ops_len );
111 op = ( ( ( void * ) new_ops ) + ifr->ops_len );
113 ifr->ops_len = new_ops_len;
115 /* Fill in opcode header */
123 * Add end opcode to IFR builder
127 void efi_ifr_end_op ( struct efi_ifr_builder *ifr ) {
128 size_t dispaddr = ifr->ops_len;
132 end = efi_ifr_op ( ifr, EFI_IFR_END_OP, sizeof ( *end ) );
134 DBGC ( ifr, "IFR %p end\n", ifr );
135 DBGC2_HDA ( ifr, dispaddr, end, sizeof ( *end ) );
139 * Add false opcode to IFR builder
143 void efi_ifr_false_op ( struct efi_ifr_builder *ifr ) {
144 size_t dispaddr = ifr->ops_len;
145 EFI_IFR_FALSE *false;
148 false = efi_ifr_op ( ifr, EFI_IFR_FALSE_OP, sizeof ( *false ) );
150 DBGC ( ifr, "IFR %p false\n", ifr );
151 DBGC2_HDA ( ifr, dispaddr, false, sizeof ( *false ) );
155 * Add form opcode to IFR builder
158 * @v title_id Title string identifier
159 * @ret form_id Form identifier
161 unsigned int efi_ifr_form_op ( struct efi_ifr_builder *ifr,
162 unsigned int title_id ) {
163 size_t dispaddr = ifr->ops_len;
167 form = efi_ifr_op ( ifr, EFI_IFR_FORM_OP, sizeof ( *form ) );
170 form->Header.Scope = 1;
171 form->FormId = ++(ifr->form_id);
172 form->FormTitle = title_id;
174 DBGC ( ifr, "IFR %p name/value store %#04x title %#04x\n",
175 ifr, form->FormId, title_id );
176 DBGC2_HDA ( ifr, dispaddr, form, sizeof ( *form ) );
181 * Add formset opcode to IFR builder
185 * @v title_id Title string identifier
186 * @v help_id Help string identifier
187 * @v ... Class GUIDs (terminated by NULL)
189 void efi_ifr_form_set_op ( struct efi_ifr_builder *ifr, const EFI_GUID *guid,
190 unsigned int title_id, unsigned int help_id, ... ) {
191 size_t dispaddr = ifr->ops_len;
192 EFI_IFR_FORM_SET *formset;
193 EFI_GUID *class_guid;
194 unsigned int num_class_guids = 0;
198 /* Count number of class GUIDs */
199 va_start ( args, help_id );
200 while ( va_arg ( args, const EFI_GUID * ) != NULL )
205 len = ( sizeof ( *formset ) +
206 ( num_class_guids * sizeof ( *class_guid ) ) );
207 formset = efi_ifr_op ( ifr, EFI_IFR_FORM_SET_OP, len );
210 formset->Header.Scope = 1;
211 memcpy ( &formset->Guid, guid, sizeof ( formset->Guid ) );
212 formset->FormSetTitle = title_id;
213 formset->Help = help_id;
214 formset->Flags = num_class_guids;
216 /* Add class GUIDs */
217 class_guid = ( ( ( void * ) formset ) + sizeof ( *formset ) );
218 va_start ( args, help_id );
219 while ( num_class_guids-- ) {
220 memcpy ( class_guid++, va_arg ( args, const EFI_GUID * ),
221 sizeof ( *class_guid ) );
225 DBGC ( ifr, "IFR %p formset title %#04x help %#04x\n",
226 ifr, title_id, help_id );
227 DBGC2_HDA ( ifr, dispaddr, formset, len );
231 * Add get opcode to IFR builder
234 * @v varstore_id Variable store identifier
235 * @v varstore_info Variable string identifier or offset
236 * @v varstore_type Variable type
238 void efi_ifr_get_op ( struct efi_ifr_builder *ifr, unsigned int varstore_id,
239 unsigned int varstore_info, unsigned int varstore_type ) {
240 size_t dispaddr = ifr->ops_len;
244 get = efi_ifr_op ( ifr, EFI_IFR_GET_OP, sizeof ( *get ) );
245 get->VarStoreId = varstore_id;
246 get->VarStoreInfo.VarName = varstore_info;
247 get->VarStoreType = varstore_type;
249 DBGC ( ifr, "IFR %p get varstore %#04x:%#04x type %#02x\n",
250 ifr, varstore_id, varstore_info, varstore_type );
251 DBGC2_HDA ( ifr, dispaddr, get, sizeof ( *get ) );
255 * Add GUID class opcode to IFR builder
260 void efi_ifr_guid_class_op ( struct efi_ifr_builder *ifr, unsigned int class ) {
261 size_t dispaddr = ifr->ops_len;
262 EFI_IFR_GUID_CLASS *guid_class;
265 guid_class = efi_ifr_op ( ifr, EFI_IFR_GUID_OP,
266 sizeof ( *guid_class ) );
269 memcpy ( &guid_class->Guid, &tiano_guid, sizeof ( guid_class->Guid ) );
270 guid_class->ExtendOpCode = EFI_IFR_EXTEND_OP_CLASS;
271 guid_class->Class = class;
273 DBGC ( ifr, "IFR %p GUID class %#02x\n", ifr, class );
274 DBGC2_HDA ( ifr, dispaddr, guid_class, sizeof ( *guid_class ) );
278 * Add GUID subclass opcode to IFR builder
281 * @v subclass Subclass
283 void efi_ifr_guid_subclass_op ( struct efi_ifr_builder *ifr,
284 unsigned int subclass ) {
285 size_t dispaddr = ifr->ops_len;
286 EFI_IFR_GUID_SUBCLASS *guid_subclass;
289 guid_subclass = efi_ifr_op ( ifr, EFI_IFR_GUID_OP,
290 sizeof ( *guid_subclass ) );
291 if ( ! guid_subclass )
293 memcpy ( &guid_subclass->Guid, &tiano_guid,
294 sizeof ( guid_subclass->Guid ) );
295 guid_subclass->ExtendOpCode = EFI_IFR_EXTEND_OP_SUBCLASS;
296 guid_subclass->SubClass = subclass;
298 DBGC ( ifr, "IFR %p GUID subclass %#02x\n", ifr, subclass );
299 DBGC2_HDA ( ifr, dispaddr, guid_subclass, sizeof ( *guid_subclass ) );
303 * Add numeric opcode to IFR builder
306 * @v prompt_id Prompt string identifier
307 * @v help_id Help string identifier
308 * @v question_id Question identifier
309 * @v varstore_id Variable store identifier
310 * @v varstore_info Variable string identifier or offset
311 * @v vflags Variable flags
312 * @v min_value Minimum value
313 * @v max_value Maximum value
317 void efi_ifr_numeric_op ( struct efi_ifr_builder *ifr, unsigned int prompt_id,
318 unsigned int help_id, unsigned int question_id,
319 unsigned int varstore_id, unsigned int varstore_info,
320 unsigned int vflags, unsigned long min_value,
321 unsigned long max_value, unsigned int step,
322 unsigned int flags ) {
323 size_t dispaddr = ifr->ops_len;
324 EFI_IFR_NUMERIC *numeric;
328 numeric = efi_ifr_op ( ifr, EFI_IFR_NUMERIC_OP, sizeof ( *numeric ) );
331 numeric->Question.Header.Prompt = prompt_id;
332 numeric->Question.Header.Help = help_id;
333 numeric->Question.QuestionId = question_id;
334 numeric->Question.VarStoreId = varstore_id;
335 numeric->Question.VarStoreInfo.VarName = varstore_info;
336 numeric->Question.Flags = vflags;
337 size = ( flags & EFI_IFR_NUMERIC_SIZE );
339 case EFI_IFR_NUMERIC_SIZE_1 :
340 numeric->data.u8.MinValue = min_value;
341 numeric->data.u8.MaxValue = max_value;
342 numeric->data.u8.Step = step;
344 case EFI_IFR_NUMERIC_SIZE_2 :
345 numeric->data.u16.MinValue = min_value;
346 numeric->data.u16.MaxValue = max_value;
347 numeric->data.u16.Step = step;
349 case EFI_IFR_NUMERIC_SIZE_4 :
350 numeric->data.u32.MinValue = min_value;
351 numeric->data.u32.MaxValue = max_value;
352 numeric->data.u32.Step = step;
354 case EFI_IFR_NUMERIC_SIZE_8 :
355 numeric->data.u64.MinValue = min_value;
356 numeric->data.u64.MaxValue = max_value;
357 numeric->data.u64.Step = step;
361 DBGC ( ifr, "IFR %p numeric prompt %#04x help %#04x question %#04x "
362 "varstore %#04x:%#04x\n", ifr, prompt_id, help_id, question_id,
363 varstore_id, varstore_info );
364 DBGC2_HDA ( ifr, dispaddr, numeric, sizeof ( *numeric ) );
368 * Add string opcode to IFR builder
371 * @v prompt_id Prompt string identifier
372 * @v help_id Help string identifier
373 * @v question_id Question identifier
374 * @v varstore_id Variable store identifier
375 * @v varstore_info Variable string identifier or offset
376 * @v vflags Variable flags
377 * @v min_size Minimum size
378 * @v max_size Maximum size
381 void efi_ifr_string_op ( struct efi_ifr_builder *ifr, unsigned int prompt_id,
382 unsigned int help_id, unsigned int question_id,
383 unsigned int varstore_id, unsigned int varstore_info,
384 unsigned int vflags, unsigned int min_size,
385 unsigned int max_size, unsigned int flags ) {
386 size_t dispaddr = ifr->ops_len;
387 EFI_IFR_STRING *string;
390 string = efi_ifr_op ( ifr, EFI_IFR_STRING_OP, sizeof ( *string ) );
393 string->Question.Header.Prompt = prompt_id;
394 string->Question.Header.Help = help_id;
395 string->Question.QuestionId = question_id;
396 string->Question.VarStoreId = varstore_id;
397 string->Question.VarStoreInfo.VarName = varstore_info;
398 string->Question.Flags = vflags;
399 string->MinSize = min_size;
400 string->MaxSize = max_size;
401 string->Flags = flags;
403 DBGC ( ifr, "IFR %p string prompt %#04x help %#04x question %#04x "
404 "varstore %#04x:%#04x\n", ifr, prompt_id, help_id, question_id,
405 varstore_id, varstore_info );
406 DBGC2_HDA ( ifr, dispaddr, string, sizeof ( *string ) );
410 * Add suppress-if opcode to IFR builder
414 void efi_ifr_suppress_if_op ( struct efi_ifr_builder *ifr ) {
415 size_t dispaddr = ifr->ops_len;
416 EFI_IFR_SUPPRESS_IF *suppress_if;
419 suppress_if = efi_ifr_op ( ifr, EFI_IFR_SUPPRESS_IF_OP,
420 sizeof ( *suppress_if ) );
421 suppress_if->Header.Scope = 1;
423 DBGC ( ifr, "IFR %p suppress-if\n", ifr );
424 DBGC2_HDA ( ifr, dispaddr, suppress_if, sizeof ( *suppress_if ) );
428 * Add text opcode to IFR builder
431 * @v prompt_id Prompt string identifier
432 * @v help_id Help string identifier
433 * @v text_id Text string identifier
435 void efi_ifr_text_op ( struct efi_ifr_builder *ifr, unsigned int prompt_id,
436 unsigned int help_id, unsigned int text_id ) {
437 size_t dispaddr = ifr->ops_len;
441 text = efi_ifr_op ( ifr, EFI_IFR_TEXT_OP, sizeof ( *text ) );
444 text->Statement.Prompt = prompt_id;
445 text->Statement.Help = help_id;
446 text->TextTwo = text_id;
448 DBGC ( ifr, "IFR %p text prompt %#04x help %#04x text %#04x\n",
449 ifr, prompt_id, help_id, text_id );
450 DBGC2_HDA ( ifr, dispaddr, text, sizeof ( *text ) );
454 * Add true opcode to IFR builder
458 void efi_ifr_true_op ( struct efi_ifr_builder *ifr ) {
459 size_t dispaddr = ifr->ops_len;
463 true = efi_ifr_op ( ifr, EFI_IFR_TRUE_OP, sizeof ( *true ) );
465 DBGC ( ifr, "IFR %p true\n", ifr );
466 DBGC2_HDA ( ifr, dispaddr, true, sizeof ( *true ) );
470 * Add name/value store opcode to IFR builder
474 * @ret varstore_id Variable store identifier, or 0 on failure
476 unsigned int efi_ifr_varstore_name_value_op ( struct efi_ifr_builder *ifr,
477 const EFI_GUID *guid ) {
478 size_t dispaddr = ifr->ops_len;
479 EFI_IFR_VARSTORE_NAME_VALUE *varstore;
482 varstore = efi_ifr_op ( ifr, EFI_IFR_VARSTORE_NAME_VALUE_OP,
483 sizeof ( *varstore ) );
486 varstore->VarStoreId = ++(ifr->varstore_id);
487 memcpy ( &varstore->Guid, guid, sizeof ( varstore->Guid ) );
489 DBGC ( ifr, "IFR %p name/value store %#04x\n",
490 ifr, varstore->VarStoreId );
491 DBGC2_HDA ( ifr, dispaddr, varstore, sizeof ( *varstore ) );
492 return varstore->VarStoreId;
496 * Free memory used by IFR builder
500 void efi_ifr_free ( struct efi_ifr_builder *ifr ) {
503 free ( ifr->strings );
504 memset ( ifr, 0, sizeof ( *ifr ) );
508 * Construct package list from IFR builder
511 * @v guid Package GUID
512 * @v language Language
513 * @v language_id Language string ID
514 * @ret package Package list, or NULL
516 * The package list is allocated using malloc(), and must eventually
517 * be freed by the caller. (The caller must also call efi_ifr_free()
518 * to free the temporary storage used during construction.)
520 EFI_HII_PACKAGE_LIST_HEADER * efi_ifr_package ( struct efi_ifr_builder *ifr,
521 const EFI_GUID *guid,
522 const char *language,
523 unsigned int language_id ) {
525 EFI_HII_PACKAGE_LIST_HEADER header;
527 EFI_HII_PACKAGE_HEADER header;
528 uint8_t data[ifr->ops_len];
529 } __attribute__ (( packed )) ops;
532 EFI_HII_STRING_PACKAGE_HDR header;
533 uint8_t pad[offsetof(EFI_HII_STRING_PACKAGE_HDR,
535 strlen ( language ) + 1 /* NUL */ ];
536 } __attribute__ (( packed )) header;
537 uint8_t data[ifr->strings_len];
538 EFI_HII_STRING_BLOCK end;
539 } __attribute__ (( packed )) strings;
540 EFI_HII_PACKAGE_HEADER end;
541 } __attribute__ (( packed )) *package;
543 /* Fail if any previous allocation failed */
547 /* Allocate package list */
548 package = zalloc ( sizeof ( *package ) );
552 /* Populate package list */
553 package->header.PackageLength = sizeof ( *package );
554 memcpy ( &package->header.PackageListGuid, guid,
555 sizeof ( package->header.PackageListGuid ) );
556 package->ops.header.Length = sizeof ( package->ops );
557 package->ops.header.Type = EFI_HII_PACKAGE_FORMS;
558 memcpy ( package->ops.data, ifr->ops, sizeof ( package->ops.data ) );
559 package->strings.header.header.Header.Length =
560 sizeof ( package->strings );
561 package->strings.header.header.Header.Type =
562 EFI_HII_PACKAGE_STRINGS;
563 package->strings.header.header.HdrSize =
564 sizeof ( package->strings.header );
565 package->strings.header.header.StringInfoOffset =
566 sizeof ( package->strings.header );
567 package->strings.header.header.LanguageName = language_id;
568 strcpy ( package->strings.header.header.Language, language );
569 memcpy ( package->strings.data, ifr->strings,
570 sizeof ( package->strings.data ) );
571 package->strings.end.BlockType = EFI_HII_SIBT_END;
572 package->end.Type = EFI_HII_PACKAGE_END;
573 package->end.Length = sizeof ( package->end );
575 return &package->header;