[infiniband] Do not use GRH for local paths
[ipxe.git] / src / interface / efi / efi_hii.c
1 /*
2 * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
3 *
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.
8 *
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.
13 *
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
17 * 02110-1301, USA.
18 *
19 * You can also choose to distribute this program under the terms of
20 * the Unmodified Binary Distribution Licence (as given in the file
21 * COPYING.UBDL), provided that you have satisfied its requirements.
22 */
23
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26 #include <stdlib.h>
27 #include <stddef.h>
28 #include <stdarg.h>
29 #include <string.h>
30 #include <ipxe/efi/efi.h>
31 #include <ipxe/efi/efi_strings.h>
32 #include <ipxe/efi/efi_hii.h>
33
34 /** Tiano GUID */
35 static const EFI_GUID tiano_guid = EFI_IFR_TIANO_GUID;
36
37 /**
38 * Add string to IFR builder
39 *
40 * @v ifr IFR builder
41 * @v fmt Format string
42 * @v ... Arguments
43 * @ret string_id String identifier, or zero on failure
44 */
45 unsigned int efi_ifr_string ( struct efi_ifr_builder *ifr, const char *fmt,
46 ... ) {
47 EFI_HII_STRING_BLOCK *new_strings;
48 EFI_HII_SIBT_STRING_UCS2_BLOCK *ucs2;
49 size_t new_strings_len;
50 va_list args;
51 size_t len;
52 unsigned int string_id;
53
54 /* Do nothing if a previous allocation has failed */
55 if ( ifr->failed )
56 return 0;
57
58 /* Calculate string length */
59 va_start ( args, fmt );
60 len = ( efi_vsnprintf ( NULL, 0, fmt, args ) + 1 /* wNUL */ );
61 va_end ( args );
62
63 /* Reallocate strings */
64 new_strings_len = ( ifr->strings_len +
65 offsetof ( typeof ( *ucs2 ), StringText ) +
66 ( len * sizeof ( ucs2->StringText[0] ) ) );
67 new_strings = realloc ( ifr->strings, new_strings_len );
68 if ( ! new_strings ) {
69 ifr->failed = 1;
70 return 0;
71 }
72 ucs2 = ( ( ( void * ) new_strings ) + ifr->strings_len );
73 ifr->strings = new_strings;
74 ifr->strings_len = new_strings_len;
75
76 /* Fill in string */
77 ucs2->Header.BlockType = EFI_HII_SIBT_STRING_UCS2;
78 va_start ( args, fmt );
79 efi_vsnprintf ( ucs2->StringText, len, fmt, args );
80 va_end ( args );
81
82 /* Allocate string ID */
83 string_id = ++(ifr->string_id);
84
85 DBGC ( ifr, "IFR %p string %#04x is \"%ls\"\n",
86 ifr, string_id, ucs2->StringText );
87 return string_id;
88 }
89
90 /**
91 * Add IFR opcode to IFR builder
92 *
93 * @v ifr IFR builder
94 * @v opcode Opcode
95 * @v len Opcode length
96 * @ret op Opcode, or NULL
97 */
98 static void * efi_ifr_op ( struct efi_ifr_builder *ifr, unsigned int opcode,
99 size_t len ) {
100 EFI_IFR_OP_HEADER *new_ops;
101 EFI_IFR_OP_HEADER *op;
102 size_t new_ops_len;
103
104 /* Do nothing if a previous allocation has failed */
105 if ( ifr->failed )
106 return NULL;
107
108 /* Reallocate opcodes */
109 new_ops_len = ( ifr->ops_len + len );
110 new_ops = realloc ( ifr->ops, new_ops_len );
111 if ( ! new_ops ) {
112 ifr->failed = 1;
113 return NULL;
114 }
115 op = ( ( ( void * ) new_ops ) + ifr->ops_len );
116 ifr->ops = new_ops;
117 ifr->ops_len = new_ops_len;
118
119 /* Fill in opcode header */
120 op->OpCode = opcode;
121 op->Length = len;
122
123 return op;
124 }
125
126 /**
127 * Add end opcode to IFR builder
128 *
129 * @v ifr IFR builder
130 */
131 void efi_ifr_end_op ( struct efi_ifr_builder *ifr ) {
132 size_t dispaddr = ifr->ops_len;
133 EFI_IFR_END *end;
134
135 /* Add opcode */
136 end = efi_ifr_op ( ifr, EFI_IFR_END_OP, sizeof ( *end ) );
137
138 DBGC ( ifr, "IFR %p end\n", ifr );
139 DBGC2_HDA ( ifr, dispaddr, end, sizeof ( *end ) );
140 }
141
142 /**
143 * Add false opcode to IFR builder
144 *
145 * @v ifr IFR builder
146 */
147 void efi_ifr_false_op ( struct efi_ifr_builder *ifr ) {
148 size_t dispaddr = ifr->ops_len;
149 EFI_IFR_FALSE *false;
150
151 /* Add opcode */
152 false = efi_ifr_op ( ifr, EFI_IFR_FALSE_OP, sizeof ( *false ) );
153
154 DBGC ( ifr, "IFR %p false\n", ifr );
155 DBGC2_HDA ( ifr, dispaddr, false, sizeof ( *false ) );
156 }
157
158 /**
159 * Add form opcode to IFR builder
160 *
161 * @v ifr IFR builder
162 * @v title_id Title string identifier
163 * @ret form_id Form identifier
164 */
165 unsigned int efi_ifr_form_op ( struct efi_ifr_builder *ifr,
166 unsigned int title_id ) {
167 size_t dispaddr = ifr->ops_len;
168 EFI_IFR_FORM *form;
169
170 /* Add opcode */
171 form = efi_ifr_op ( ifr, EFI_IFR_FORM_OP, sizeof ( *form ) );
172 if ( ! form )
173 return 0;
174 form->Header.Scope = 1;
175 form->FormId = ++(ifr->form_id);
176 form->FormTitle = title_id;
177
178 DBGC ( ifr, "IFR %p name/value store %#04x title %#04x\n",
179 ifr, form->FormId, title_id );
180 DBGC2_HDA ( ifr, dispaddr, form, sizeof ( *form ) );
181 return form->FormId;
182 }
183
184 /**
185 * Add formset opcode to IFR builder
186 *
187 * @v ifr IFR builder
188 * @v guid GUID
189 * @v title_id Title string identifier
190 * @v help_id Help string identifier
191 * @v ... Class GUIDs (terminated by NULL)
192 */
193 void efi_ifr_form_set_op ( struct efi_ifr_builder *ifr, const EFI_GUID *guid,
194 unsigned int title_id, unsigned int help_id, ... ) {
195 size_t dispaddr = ifr->ops_len;
196 EFI_IFR_FORM_SET *formset;
197 EFI_GUID *class_guid;
198 unsigned int num_class_guids = 0;
199 size_t len;
200 va_list args;
201
202 /* Count number of class GUIDs */
203 va_start ( args, help_id );
204 while ( va_arg ( args, const EFI_GUID * ) != NULL )
205 num_class_guids++;
206 va_end ( args );
207
208 /* Add opcode */
209 len = ( sizeof ( *formset ) +
210 ( num_class_guids * sizeof ( *class_guid ) ) );
211 formset = efi_ifr_op ( ifr, EFI_IFR_FORM_SET_OP, len );
212 if ( ! formset )
213 return;
214 formset->Header.Scope = 1;
215 memcpy ( &formset->Guid, guid, sizeof ( formset->Guid ) );
216 formset->FormSetTitle = title_id;
217 formset->Help = help_id;
218 formset->Flags = num_class_guids;
219
220 /* Add class GUIDs */
221 class_guid = ( ( ( void * ) formset ) + sizeof ( *formset ) );
222 va_start ( args, help_id );
223 while ( num_class_guids-- ) {
224 memcpy ( class_guid++, va_arg ( args, const EFI_GUID * ),
225 sizeof ( *class_guid ) );
226 }
227 va_end ( args );
228
229 DBGC ( ifr, "IFR %p formset title %#04x help %#04x\n",
230 ifr, title_id, help_id );
231 DBGC2_HDA ( ifr, dispaddr, formset, len );
232 }
233
234 /**
235 * Add get opcode to IFR builder
236 *
237 * @v ifr IFR builder
238 * @v varstore_id Variable store identifier
239 * @v varstore_info Variable string identifier or offset
240 * @v varstore_type Variable type
241 */
242 void efi_ifr_get_op ( struct efi_ifr_builder *ifr, unsigned int varstore_id,
243 unsigned int varstore_info, unsigned int varstore_type ) {
244 size_t dispaddr = ifr->ops_len;
245 EFI_IFR_GET *get;
246
247 /* Add opcode */
248 get = efi_ifr_op ( ifr, EFI_IFR_GET_OP, sizeof ( *get ) );
249 get->VarStoreId = varstore_id;
250 get->VarStoreInfo.VarName = varstore_info;
251 get->VarStoreType = varstore_type;
252
253 DBGC ( ifr, "IFR %p get varstore %#04x:%#04x type %#02x\n",
254 ifr, varstore_id, varstore_info, varstore_type );
255 DBGC2_HDA ( ifr, dispaddr, get, sizeof ( *get ) );
256 }
257
258 /**
259 * Add GUID class opcode to IFR builder
260 *
261 * @v ifr IFR builder
262 * @v class Class
263 */
264 void efi_ifr_guid_class_op ( struct efi_ifr_builder *ifr, unsigned int class ) {
265 size_t dispaddr = ifr->ops_len;
266 EFI_IFR_GUID_CLASS *guid_class;
267
268 /* Add opcode */
269 guid_class = efi_ifr_op ( ifr, EFI_IFR_GUID_OP,
270 sizeof ( *guid_class ) );
271 if ( ! guid_class )
272 return;
273 memcpy ( &guid_class->Guid, &tiano_guid, sizeof ( guid_class->Guid ) );
274 guid_class->ExtendOpCode = EFI_IFR_EXTEND_OP_CLASS;
275 guid_class->Class = class;
276
277 DBGC ( ifr, "IFR %p GUID class %#02x\n", ifr, class );
278 DBGC2_HDA ( ifr, dispaddr, guid_class, sizeof ( *guid_class ) );
279 }
280
281 /**
282 * Add GUID subclass opcode to IFR builder
283 *
284 * @v ifr IFR builder
285 * @v subclass Subclass
286 */
287 void efi_ifr_guid_subclass_op ( struct efi_ifr_builder *ifr,
288 unsigned int subclass ) {
289 size_t dispaddr = ifr->ops_len;
290 EFI_IFR_GUID_SUBCLASS *guid_subclass;
291
292 /* Add opcode */
293 guid_subclass = efi_ifr_op ( ifr, EFI_IFR_GUID_OP,
294 sizeof ( *guid_subclass ) );
295 if ( ! guid_subclass )
296 return;
297 memcpy ( &guid_subclass->Guid, &tiano_guid,
298 sizeof ( guid_subclass->Guid ) );
299 guid_subclass->ExtendOpCode = EFI_IFR_EXTEND_OP_SUBCLASS;
300 guid_subclass->SubClass = subclass;
301
302 DBGC ( ifr, "IFR %p GUID subclass %#02x\n", ifr, subclass );
303 DBGC2_HDA ( ifr, dispaddr, guid_subclass, sizeof ( *guid_subclass ) );
304 }
305
306 /**
307 * Add numeric opcode to IFR builder
308 *
309 * @v ifr IFR builder
310 * @v prompt_id Prompt string identifier
311 * @v help_id Help string identifier
312 * @v question_id Question identifier
313 * @v varstore_id Variable store identifier
314 * @v varstore_info Variable string identifier or offset
315 * @v vflags Variable flags
316 * @v min_value Minimum value
317 * @v max_value Maximum value
318 * @v step Step
319 * @v flags Flags
320 */
321 void efi_ifr_numeric_op ( struct efi_ifr_builder *ifr, unsigned int prompt_id,
322 unsigned int help_id, unsigned int question_id,
323 unsigned int varstore_id, unsigned int varstore_info,
324 unsigned int vflags, unsigned long min_value,
325 unsigned long max_value, unsigned int step,
326 unsigned int flags ) {
327 size_t dispaddr = ifr->ops_len;
328 EFI_IFR_NUMERIC *numeric;
329 unsigned int size;
330
331 /* Add opcode */
332 numeric = efi_ifr_op ( ifr, EFI_IFR_NUMERIC_OP, sizeof ( *numeric ) );
333 if ( ! numeric )
334 return;
335 numeric->Question.Header.Prompt = prompt_id;
336 numeric->Question.Header.Help = help_id;
337 numeric->Question.QuestionId = question_id;
338 numeric->Question.VarStoreId = varstore_id;
339 numeric->Question.VarStoreInfo.VarName = varstore_info;
340 numeric->Question.Flags = vflags;
341 size = ( flags & EFI_IFR_NUMERIC_SIZE );
342 switch ( size ) {
343 case EFI_IFR_NUMERIC_SIZE_1 :
344 numeric->data.u8.MinValue = min_value;
345 numeric->data.u8.MaxValue = max_value;
346 numeric->data.u8.Step = step;
347 break;
348 case EFI_IFR_NUMERIC_SIZE_2 :
349 numeric->data.u16.MinValue = min_value;
350 numeric->data.u16.MaxValue = max_value;
351 numeric->data.u16.Step = step;
352 break;
353 case EFI_IFR_NUMERIC_SIZE_4 :
354 numeric->data.u32.MinValue = min_value;
355 numeric->data.u32.MaxValue = max_value;
356 numeric->data.u32.Step = step;
357 break;
358 case EFI_IFR_NUMERIC_SIZE_8 :
359 numeric->data.u64.MinValue = min_value;
360 numeric->data.u64.MaxValue = max_value;
361 numeric->data.u64.Step = step;
362 break;
363 }
364
365 DBGC ( ifr, "IFR %p numeric prompt %#04x help %#04x question %#04x "
366 "varstore %#04x:%#04x\n", ifr, prompt_id, help_id, question_id,
367 varstore_id, varstore_info );
368 DBGC2_HDA ( ifr, dispaddr, numeric, sizeof ( *numeric ) );
369 }
370
371 /**
372 * Add string opcode to IFR builder
373 *
374 * @v ifr IFR builder
375 * @v prompt_id Prompt string identifier
376 * @v help_id Help string identifier
377 * @v question_id Question identifier
378 * @v varstore_id Variable store identifier
379 * @v varstore_info Variable string identifier or offset
380 * @v vflags Variable flags
381 * @v min_size Minimum size
382 * @v max_size Maximum size
383 * @v flags Flags
384 */
385 void efi_ifr_string_op ( struct efi_ifr_builder *ifr, unsigned int prompt_id,
386 unsigned int help_id, unsigned int question_id,
387 unsigned int varstore_id, unsigned int varstore_info,
388 unsigned int vflags, unsigned int min_size,
389 unsigned int max_size, unsigned int flags ) {
390 size_t dispaddr = ifr->ops_len;
391 EFI_IFR_STRING *string;
392
393 /* Add opcode */
394 string = efi_ifr_op ( ifr, EFI_IFR_STRING_OP, sizeof ( *string ) );
395 if ( ! string )
396 return;
397 string->Question.Header.Prompt = prompt_id;
398 string->Question.Header.Help = help_id;
399 string->Question.QuestionId = question_id;
400 string->Question.VarStoreId = varstore_id;
401 string->Question.VarStoreInfo.VarName = varstore_info;
402 string->Question.Flags = vflags;
403 string->MinSize = min_size;
404 string->MaxSize = max_size;
405 string->Flags = flags;
406
407 DBGC ( ifr, "IFR %p string prompt %#04x help %#04x question %#04x "
408 "varstore %#04x:%#04x\n", ifr, prompt_id, help_id, question_id,
409 varstore_id, varstore_info );
410 DBGC2_HDA ( ifr, dispaddr, string, sizeof ( *string ) );
411 }
412
413 /**
414 * Add suppress-if opcode to IFR builder
415 *
416 * @v ifr IFR builder
417 */
418 void efi_ifr_suppress_if_op ( struct efi_ifr_builder *ifr ) {
419 size_t dispaddr = ifr->ops_len;
420 EFI_IFR_SUPPRESS_IF *suppress_if;
421
422 /* Add opcode */
423 suppress_if = efi_ifr_op ( ifr, EFI_IFR_SUPPRESS_IF_OP,
424 sizeof ( *suppress_if ) );
425 suppress_if->Header.Scope = 1;
426
427 DBGC ( ifr, "IFR %p suppress-if\n", ifr );
428 DBGC2_HDA ( ifr, dispaddr, suppress_if, sizeof ( *suppress_if ) );
429 }
430
431 /**
432 * Add text opcode to IFR builder
433 *
434 * @v ifr IFR builder
435 * @v prompt_id Prompt string identifier
436 * @v help_id Help string identifier
437 * @v text_id Text string identifier
438 */
439 void efi_ifr_text_op ( struct efi_ifr_builder *ifr, unsigned int prompt_id,
440 unsigned int help_id, unsigned int text_id ) {
441 size_t dispaddr = ifr->ops_len;
442 EFI_IFR_TEXT *text;
443
444 /* Add opcode */
445 text = efi_ifr_op ( ifr, EFI_IFR_TEXT_OP, sizeof ( *text ) );
446 if ( ! text )
447 return;
448 text->Statement.Prompt = prompt_id;
449 text->Statement.Help = help_id;
450 text->TextTwo = text_id;
451
452 DBGC ( ifr, "IFR %p text prompt %#04x help %#04x text %#04x\n",
453 ifr, prompt_id, help_id, text_id );
454 DBGC2_HDA ( ifr, dispaddr, text, sizeof ( *text ) );
455 }
456
457 /**
458 * Add true opcode to IFR builder
459 *
460 * @v ifr IFR builder
461 */
462 void efi_ifr_true_op ( struct efi_ifr_builder *ifr ) {
463 size_t dispaddr = ifr->ops_len;
464 EFI_IFR_TRUE *true;
465
466 /* Add opcode */
467 true = efi_ifr_op ( ifr, EFI_IFR_TRUE_OP, sizeof ( *true ) );
468
469 DBGC ( ifr, "IFR %p true\n", ifr );
470 DBGC2_HDA ( ifr, dispaddr, true, sizeof ( *true ) );
471 }
472
473 /**
474 * Add name/value store opcode to IFR builder
475 *
476 * @v ifr IFR builder
477 * @v guid GUID
478 * @ret varstore_id Variable store identifier, or 0 on failure
479 */
480 unsigned int efi_ifr_varstore_name_value_op ( struct efi_ifr_builder *ifr,
481 const EFI_GUID *guid ) {
482 size_t dispaddr = ifr->ops_len;
483 EFI_IFR_VARSTORE_NAME_VALUE *varstore;
484
485 /* Add opcode */
486 varstore = efi_ifr_op ( ifr, EFI_IFR_VARSTORE_NAME_VALUE_OP,
487 sizeof ( *varstore ) );
488 if ( ! varstore )
489 return 0;
490 varstore->VarStoreId = ++(ifr->varstore_id);
491 memcpy ( &varstore->Guid, guid, sizeof ( varstore->Guid ) );
492
493 DBGC ( ifr, "IFR %p name/value store %#04x\n",
494 ifr, varstore->VarStoreId );
495 DBGC2_HDA ( ifr, dispaddr, varstore, sizeof ( *varstore ) );
496 return varstore->VarStoreId;
497 }
498
499 /**
500 * Free memory used by IFR builder
501 *
502 * @v ifr IFR builder
503 */
504 void efi_ifr_free ( struct efi_ifr_builder *ifr ) {
505
506 free ( ifr->ops );
507 free ( ifr->strings );
508 memset ( ifr, 0, sizeof ( *ifr ) );
509 }
510
511 /**
512 * Construct package list from IFR builder
513 *
514 * @v ifr IFR builder
515 * @v guid Package GUID
516 * @v language Language
517 * @v language_id Language string ID
518 * @ret package Package list, or NULL
519 *
520 * The package list is allocated using malloc(), and must eventually
521 * be freed by the caller. (The caller must also call efi_ifr_free()
522 * to free the temporary storage used during construction.)
523 */
524 EFI_HII_PACKAGE_LIST_HEADER * efi_ifr_package ( struct efi_ifr_builder *ifr,
525 const EFI_GUID *guid,
526 const char *language,
527 unsigned int language_id ) {
528 struct {
529 EFI_HII_PACKAGE_LIST_HEADER header;
530 struct {
531 EFI_HII_PACKAGE_HEADER header;
532 uint8_t data[ifr->ops_len];
533 } __attribute__ (( packed )) ops;
534 struct {
535 union {
536 EFI_HII_STRING_PACKAGE_HDR header;
537 uint8_t pad[offsetof(EFI_HII_STRING_PACKAGE_HDR,
538 Language) +
539 strlen ( language ) + 1 /* NUL */ ];
540 } __attribute__ (( packed )) header;
541 uint8_t data[ifr->strings_len];
542 EFI_HII_STRING_BLOCK end;
543 } __attribute__ (( packed )) strings;
544 EFI_HII_PACKAGE_HEADER end;
545 } __attribute__ (( packed )) *package;
546
547 /* Fail if any previous allocation failed */
548 if ( ifr->failed )
549 return NULL;
550
551 /* Allocate package list */
552 package = zalloc ( sizeof ( *package ) );
553 if ( ! package )
554 return NULL;
555
556 /* Populate package list */
557 package->header.PackageLength = sizeof ( *package );
558 memcpy ( &package->header.PackageListGuid, guid,
559 sizeof ( package->header.PackageListGuid ) );
560 package->ops.header.Length = sizeof ( package->ops );
561 package->ops.header.Type = EFI_HII_PACKAGE_FORMS;
562 memcpy ( package->ops.data, ifr->ops, sizeof ( package->ops.data ) );
563 package->strings.header.header.Header.Length =
564 sizeof ( package->strings );
565 package->strings.header.header.Header.Type =
566 EFI_HII_PACKAGE_STRINGS;
567 package->strings.header.header.HdrSize =
568 sizeof ( package->strings.header );
569 package->strings.header.header.StringInfoOffset =
570 sizeof ( package->strings.header );
571 package->strings.header.header.LanguageName = language_id;
572 strcpy ( package->strings.header.header.Language, language );
573 memcpy ( package->strings.data, ifr->strings,
574 sizeof ( package->strings.data ) );
575 package->strings.end.BlockType = EFI_HII_SIBT_END;
576 package->end.Type = EFI_HII_PACKAGE_END;
577 package->end.Length = sizeof ( package->end );
578
579 return &package->header;
580 }
581