These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / ipxe / 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