Add qemu 2.4.0
[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
20 FILE_LICENCE ( GPL2_OR_LATER );
21
22 #include <stdlib.h>
23 #include <stddef.h>
24 #include <stdarg.h>
25 #include <string.h>
26 #include <ipxe/efi/efi.h>
27 #include <ipxe/efi/efi_strings.h>
28 #include <ipxe/efi/efi_hii.h>
29
30 /** Tiano GUID */
31 static const EFI_GUID tiano_guid = EFI_IFR_TIANO_GUID;
32
33 /**
34  * Add string to IFR builder
35  *
36  * @v ifr               IFR builder
37  * @v fmt               Format string
38  * @v ...               Arguments
39  * @ret string_id       String identifier, or zero on failure
40  */
41 unsigned int efi_ifr_string ( struct efi_ifr_builder *ifr, const char *fmt,
42                               ... ) {
43         EFI_HII_STRING_BLOCK *new_strings;
44         EFI_HII_SIBT_STRING_UCS2_BLOCK *ucs2;
45         size_t new_strings_len;
46         va_list args;
47         size_t len;
48         unsigned int string_id;
49
50         /* Do nothing if a previous allocation has failed */
51         if ( ifr->failed )
52                 return 0;
53
54         /* Calculate string length */
55         va_start ( args, fmt );
56         len = ( efi_vsnprintf ( NULL, 0, fmt, args ) + 1 /* wNUL */ );
57         va_end ( args );
58
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 ) {
65                 ifr->failed = 1;
66                 return 0;
67         }
68         ucs2 = ( ( ( void * ) new_strings ) + ifr->strings_len );
69         ifr->strings = new_strings;
70         ifr->strings_len = new_strings_len;
71
72         /* Fill in string */
73         ucs2->Header.BlockType = EFI_HII_SIBT_STRING_UCS2;
74         va_start ( args, fmt );
75         efi_vsnprintf ( ucs2->StringText, len, fmt, args );
76         va_end ( args );
77
78         /* Allocate string ID */
79         string_id = ++(ifr->string_id);
80
81         DBGC ( ifr, "IFR %p string %#04x is \"%ls\"\n",
82                ifr, string_id, ucs2->StringText );
83         return string_id;
84 }
85
86 /**
87  * Add IFR opcode to IFR builder
88  *
89  * @v ifr               IFR builder
90  * @v opcode            Opcode
91  * @v len               Opcode length
92  * @ret op              Opcode, or NULL
93  */
94 static void * efi_ifr_op ( struct efi_ifr_builder *ifr, unsigned int opcode,
95                            size_t len ) {
96         EFI_IFR_OP_HEADER *new_ops;
97         EFI_IFR_OP_HEADER *op;
98         size_t new_ops_len;
99
100         /* Do nothing if a previous allocation has failed */
101         if ( ifr->failed )
102                 return NULL;
103
104         /* Reallocate opcodes */
105         new_ops_len = ( ifr->ops_len + len );
106         new_ops = realloc ( ifr->ops, new_ops_len );
107         if ( ! new_ops ) {
108                 ifr->failed = 1;
109                 return NULL;
110         }
111         op = ( ( ( void * ) new_ops ) + ifr->ops_len );
112         ifr->ops = new_ops;
113         ifr->ops_len = new_ops_len;
114
115         /* Fill in opcode header */
116         op->OpCode = opcode;
117         op->Length = len;
118
119         return op;
120 }
121
122 /**
123  * Add end opcode to IFR builder
124  *
125  * @v ifr               IFR builder
126  */
127 void efi_ifr_end_op ( struct efi_ifr_builder *ifr ) {
128         size_t dispaddr = ifr->ops_len;
129         EFI_IFR_END *end;
130
131         /* Add opcode */
132         end = efi_ifr_op ( ifr, EFI_IFR_END_OP, sizeof ( *end ) );
133
134         DBGC ( ifr, "IFR %p end\n", ifr );
135         DBGC2_HDA ( ifr, dispaddr, end, sizeof ( *end ) );
136 }
137
138 /**
139  * Add false opcode to IFR builder
140  *
141  * @v ifr               IFR builder
142  */
143 void efi_ifr_false_op ( struct efi_ifr_builder *ifr ) {
144         size_t dispaddr = ifr->ops_len;
145         EFI_IFR_FALSE *false;
146
147         /* Add opcode */
148         false = efi_ifr_op ( ifr, EFI_IFR_FALSE_OP, sizeof ( *false ) );
149
150         DBGC ( ifr, "IFR %p false\n", ifr );
151         DBGC2_HDA ( ifr, dispaddr, false, sizeof ( *false ) );
152 }
153
154 /**
155  * Add form opcode to IFR builder
156  *
157  * @v ifr               IFR builder
158  * @v title_id          Title string identifier
159  * @ret form_id         Form identifier
160  */
161 unsigned int efi_ifr_form_op ( struct efi_ifr_builder *ifr,
162                                unsigned int title_id ) {
163         size_t dispaddr = ifr->ops_len;
164         EFI_IFR_FORM *form;
165
166         /* Add opcode */
167         form = efi_ifr_op ( ifr, EFI_IFR_FORM_OP, sizeof ( *form ) );
168         if ( ! form )
169                 return 0;
170         form->Header.Scope = 1;
171         form->FormId = ++(ifr->form_id);
172         form->FormTitle = title_id;
173
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 ) );
177         return form->FormId;
178 }
179
180 /**
181  * Add formset opcode to IFR builder
182  *
183  * @v ifr               IFR builder
184  * @v guid              GUID
185  * @v title_id          Title string identifier
186  * @v help_id           Help string identifier
187  * @v ...               Class GUIDs (terminated by NULL)
188  */
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;
195         size_t len;
196         va_list args;
197
198         /* Count number of class GUIDs */
199         va_start ( args, help_id );
200         while ( va_arg ( args, const EFI_GUID * ) != NULL )
201                 num_class_guids++;
202         va_end ( args );
203
204         /* Add opcode */
205         len = ( sizeof ( *formset ) +
206                 ( num_class_guids * sizeof ( *class_guid ) ) );
207         formset = efi_ifr_op ( ifr, EFI_IFR_FORM_SET_OP, len );
208         if ( ! formset )
209                 return;
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;
215
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 ) );
222         }
223         va_end ( args );
224
225         DBGC ( ifr, "IFR %p formset title %#04x help %#04x\n",
226                ifr, title_id, help_id );
227         DBGC2_HDA ( ifr, dispaddr, formset, len );
228 }
229
230 /**
231  * Add get opcode to IFR builder
232  *
233  * @v ifr               IFR builder
234  * @v varstore_id       Variable store identifier
235  * @v varstore_info     Variable string identifier or offset
236  * @v varstore_type     Variable type
237  */
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;
241         EFI_IFR_GET *get;
242
243         /* Add opcode */
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;
248
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 ) );
252 }
253
254 /**
255  * Add GUID class opcode to IFR builder
256  *
257  * @v ifr               IFR builder
258  * @v class             Class
259  */
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;
263
264         /* Add opcode */
265         guid_class = efi_ifr_op ( ifr, EFI_IFR_GUID_OP,
266                                   sizeof ( *guid_class ) );
267         if ( ! guid_class )
268                 return;
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;
272
273         DBGC ( ifr, "IFR %p GUID class %#02x\n", ifr, class );
274         DBGC2_HDA ( ifr, dispaddr, guid_class, sizeof ( *guid_class ) );
275 }
276
277 /**
278  * Add GUID subclass opcode to IFR builder
279  *
280  * @v ifr               IFR builder
281  * @v subclass          Subclass
282  */
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;
287
288         /* Add opcode */
289         guid_subclass = efi_ifr_op ( ifr, EFI_IFR_GUID_OP,
290                                      sizeof ( *guid_subclass ) );
291         if ( ! guid_subclass )
292                 return;
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;
297
298         DBGC ( ifr, "IFR %p GUID subclass %#02x\n", ifr, subclass );
299         DBGC2_HDA ( ifr, dispaddr, guid_subclass, sizeof ( *guid_subclass ) );
300 }
301
302 /**
303  * Add numeric opcode to IFR builder
304  *
305  * @v ifr               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
314  * @v step              Step
315  * @v flags             Flags
316  */
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;
325         unsigned int size;
326
327         /* Add opcode */
328         numeric = efi_ifr_op ( ifr, EFI_IFR_NUMERIC_OP, sizeof ( *numeric ) );
329         if ( ! numeric )
330                 return;
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 );
338         switch ( 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;
343                 break;
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;
348                 break;
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;
353                 break;
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;
358                 break;
359         }
360
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 ) );
365 }
366
367 /**
368  * Add string opcode to IFR builder
369  *
370  * @v ifr               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
379  * @v flags             Flags
380  */
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;
388
389         /* Add opcode */
390         string = efi_ifr_op ( ifr, EFI_IFR_STRING_OP, sizeof ( *string ) );
391         if ( ! string )
392                 return;
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;
402
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 ) );
407 }
408
409 /**
410  * Add suppress-if opcode to IFR builder
411  *
412  * @v ifr               IFR builder
413  */
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;
417
418         /* Add opcode */
419         suppress_if = efi_ifr_op ( ifr, EFI_IFR_SUPPRESS_IF_OP,
420                                    sizeof ( *suppress_if ) );
421         suppress_if->Header.Scope = 1;
422
423         DBGC ( ifr, "IFR %p suppress-if\n", ifr );
424         DBGC2_HDA ( ifr, dispaddr, suppress_if, sizeof ( *suppress_if ) );
425 }
426
427 /**
428  * Add text opcode to IFR builder
429  *
430  * @v ifr               IFR builder
431  * @v prompt_id         Prompt string identifier
432  * @v help_id           Help string identifier
433  * @v text_id           Text string identifier
434  */
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;
438         EFI_IFR_TEXT *text;
439
440         /* Add opcode */
441         text = efi_ifr_op ( ifr, EFI_IFR_TEXT_OP, sizeof ( *text ) );
442         if ( ! text )
443                 return;
444         text->Statement.Prompt = prompt_id;
445         text->Statement.Help = help_id;
446         text->TextTwo = text_id;
447
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 ) );
451 }
452
453 /**
454  * Add true opcode to IFR builder
455  *
456  * @v ifr               IFR builder
457  */
458 void efi_ifr_true_op ( struct efi_ifr_builder *ifr ) {
459         size_t dispaddr = ifr->ops_len;
460         EFI_IFR_TRUE *true;
461
462         /* Add opcode */
463         true = efi_ifr_op ( ifr, EFI_IFR_TRUE_OP, sizeof ( *true ) );
464
465         DBGC ( ifr, "IFR %p true\n", ifr );
466         DBGC2_HDA ( ifr, dispaddr, true, sizeof ( *true ) );
467 }
468
469 /**
470  * Add name/value store opcode to IFR builder
471  *
472  * @v ifr               IFR builder
473  * @v guid              GUID
474  * @ret varstore_id     Variable store identifier, or 0 on failure
475  */
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;
480
481         /* Add opcode */
482         varstore = efi_ifr_op ( ifr, EFI_IFR_VARSTORE_NAME_VALUE_OP,
483                                 sizeof ( *varstore ) );
484         if ( ! varstore )
485                 return 0;
486         varstore->VarStoreId = ++(ifr->varstore_id);
487         memcpy ( &varstore->Guid, guid, sizeof ( varstore->Guid ) );
488
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;
493 }
494
495 /**
496  * Free memory used by IFR builder
497  *
498  * @v ifr               IFR builder
499  */
500 void efi_ifr_free ( struct efi_ifr_builder *ifr ) {
501
502         free ( ifr->ops );
503         free ( ifr->strings );
504         memset ( ifr, 0, sizeof ( *ifr ) );
505 }
506
507 /**
508  * Construct package list from IFR builder
509  *
510  * @v ifr               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
515  *
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.)
519  */
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 ) {
524         struct {
525                 EFI_HII_PACKAGE_LIST_HEADER header;
526                 struct {
527                         EFI_HII_PACKAGE_HEADER header;
528                         uint8_t data[ifr->ops_len];
529                 } __attribute__ (( packed )) ops;
530                 struct {
531                         union {
532                                 EFI_HII_STRING_PACKAGE_HDR header;
533                                 uint8_t pad[offsetof(EFI_HII_STRING_PACKAGE_HDR,
534                                                      Language) +
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;
542
543         /* Fail if any previous allocation failed */
544         if ( ifr->failed )
545                 return NULL;
546
547         /* Allocate package list */
548         package = zalloc ( sizeof ( *package ) );
549         if ( ! package )
550                 return NULL;
551
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 );
574
575         return &package->header;
576 }
577