iPXE
efi_snp_hii.c
Go to the documentation of this file.
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
24FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25FILE_SECBOOT ( PERMITTED );
26
27/**
28 * @file
29 *
30 * EFI SNP HII protocol
31 *
32 * The HII protocols are some of the less-well designed parts of the
33 * entire EFI specification. This is a significant accomplishment.
34 *
35 * The face-slappingly ludicrous query string syntax seems to be
36 * motivated by the desire to allow a caller to query multiple drivers
37 * simultaneously via the single-instance HII_CONFIG_ROUTING_PROTOCOL,
38 * which is supposed to pass relevant subsets of the query string to
39 * the relevant drivers.
40 *
41 * Nobody uses the HII_CONFIG_ROUTING_PROTOCOL. Not even the EFI
42 * setup browser uses the HII_CONFIG_ROUTING_PROTOCOL. To the best of
43 * my knowledge, there has only ever been one implementation of the
44 * HII_CONFIG_ROUTING_PROTOCOL (as part of EDK2), and it just doesn't
45 * work. It's so badly broken that I can't even figure out what the
46 * code is _trying_ to do.
47 *
48 * Fundamentally, the problem seems to be that Javascript programmers
49 * should not be allowed to design APIs for C code.
50 */
51
52#include <string.h>
53#include <strings.h>
54#include <stdlib.h>
55#include <stdio.h>
56#include <wchar.h>
57#include <errno.h>
58#include <ipxe/settings.h>
59#include <ipxe/nvo.h>
60#include <ipxe/device.h>
61#include <ipxe/netdevice.h>
62#include <ipxe/version.h>
63#include <ipxe/efi/efi.h>
64#include <ipxe/efi/efi_hii.h>
65#include <ipxe/efi/efi_snp.h>
67#include <ipxe/efi/efi_path.h>
68#include <ipxe/efi/efi_utils.h>
69#include <ipxe/efi/efi_null.h>
70#include <config/branding.h>
71
72/** EFI platform setup formset GUID */
75
76/** EFI IBM UCM compliant formset GUID */
79
80/** EFI HII database protocol */
83
84/**
85 * Identify settings to be exposed via HII
86 *
87 * @v snpdev SNP device
88 * @ret settings Settings, or NULL
89 */
90static struct settings * efi_snp_hii_settings ( struct efi_snp_device *snpdev ){
91
92 return find_child_settings ( netdev_settings ( snpdev->netdev ),
94}
95
96/**
97 * Check whether or not setting is applicable
98 *
99 * @v snpdev SNP device
100 * @v setting Setting
101 * @ret applies Setting applies
102 */
103static int efi_snp_hii_setting_applies ( struct efi_snp_device *snpdev,
104 struct setting *setting ) {
105
106 return nvo_applies ( efi_snp_hii_settings ( snpdev ), setting );
107}
108
109/**
110 * Generate a random GUID
111 *
112 * @v guid GUID to fill in
113 */
115 uint8_t *byte = ( ( uint8_t * ) guid );
116 unsigned int i;
117
118 for ( i = 0 ; i < sizeof ( *guid ) ; i++ )
119 *(byte++) = random();
120}
121
122/**
123 * Generate EFI SNP questions
124 *
125 * @v snpdev SNP device
126 * @v ifr IFR builder
127 * @v varstore_id Variable store identifier
128 */
129static void efi_snp_hii_questions ( struct efi_snp_device *snpdev,
130 struct efi_ifr_builder *ifr,
131 unsigned int varstore_id ) {
132 struct setting *setting;
133 struct setting *previous = NULL;
134 unsigned int name_id;
135 unsigned int prompt_id;
136 unsigned int help_id;
137 unsigned int question_id;
138
139 /* Add all applicable settings */
141 if ( ! efi_snp_hii_setting_applies ( snpdev, setting ) )
142 continue;
143 if ( previous && ( setting_cmp ( setting, previous ) == 0 ) )
144 continue;
145 previous = setting;
146 name_id = efi_ifr_string ( ifr, "%s", setting->name );
147 prompt_id = efi_ifr_string ( ifr, "%s", setting->description );
148 help_id = efi_ifr_string ( ifr, PRODUCT_SETTING_URI,
149 setting->name );
150 question_id = setting->tag;
151 efi_ifr_string_op ( ifr, prompt_id, help_id,
152 question_id, varstore_id, name_id,
153 0, 0x00, 0xff, 0 );
154 }
155}
156
157/**
158 * Build HII package list for SNP device
159 *
160 * @v snpdev SNP device
161 * @ret package Package list, or NULL on error
162 */
165 struct net_device *netdev = snpdev->netdev;
166 struct device *dev = netdev->dev;
167 struct efi_ifr_builder ifr;
169 const char *name;
170 EFI_GUID package_guid;
171 EFI_GUID formset_guid;
172 EFI_GUID varstore_guid;
173 unsigned int title_id;
174 unsigned int varstore_id;
175
176 /* Initialise IFR builder */
177 efi_ifr_init ( &ifr );
178
179 /* Determine product name */
181
182 /* Generate GUIDs */
183 efi_snp_hii_random_guid ( &package_guid );
184 efi_snp_hii_random_guid ( &formset_guid );
185 efi_snp_hii_random_guid ( &varstore_guid );
186
187 /* Generate title string (used more than once) */
188 title_id = efi_ifr_string ( &ifr, "%s (%s)", name,
189 netdev_addr ( netdev ) );
190
191 /* Generate opcodes */
192 efi_ifr_form_set_op ( &ifr, &formset_guid, title_id,
193 efi_ifr_string ( &ifr, "Configure %s",
198 efi_ifr_guid_subclass_op ( &ifr, 0x03 );
199 varstore_id = efi_ifr_varstore_name_value_op ( &ifr, &varstore_guid );
200 efi_ifr_form_op ( &ifr, title_id );
201 efi_ifr_text_op ( &ifr,
202 efi_ifr_string ( &ifr, "Name" ),
203 efi_ifr_string ( &ifr, "Firmware product name" ),
204 efi_ifr_string ( &ifr, "%s", name ) );
205 efi_ifr_text_op ( &ifr,
206 efi_ifr_string ( &ifr, "Version" ),
207 efi_ifr_string ( &ifr, "Firmware version" ),
208 efi_ifr_string ( &ifr, "%s", product_version ) );
209 efi_ifr_text_op ( &ifr,
210 efi_ifr_string ( &ifr, "Driver" ),
211 efi_ifr_string ( &ifr, "Firmware driver" ),
212 efi_ifr_string ( &ifr, "%s", dev->driver_name ) );
213 efi_ifr_text_op ( &ifr,
214 efi_ifr_string ( &ifr, "Device" ),
215 efi_ifr_string ( &ifr, "Hardware device" ),
216 efi_ifr_string ( &ifr, "%s", dev->name ) );
217 efi_snp_hii_questions ( snpdev, &ifr, varstore_id );
218 efi_ifr_end_op ( &ifr );
219 efi_ifr_end_op ( &ifr );
220
221 /* Build package */
222 package = efi_ifr_package ( &ifr, &package_guid, "en-us",
223 efi_ifr_string ( &ifr, "English" ) );
224 if ( ! package ) {
225 DBGC ( snpdev, "SNPDEV %p could not build IFR package\n",
226 snpdev );
227 efi_ifr_free ( &ifr );
228 return NULL;
229 }
230
231 /* Free temporary storage */
232 efi_ifr_free ( &ifr );
233 return package;
234}
235
236/**
237 * Append response to result string
238 *
239 * @v snpdev SNP device
240 * @v key Key
241 * @v value Value
242 * @v results Result string
243 * @ret rc Return status code
244 *
245 * The result string is allocated dynamically using
246 * BootServices::AllocatePool(), and the caller is responsible for
247 * eventually calling BootServices::FreePool().
248 */
249static int efi_snp_hii_append ( struct efi_snp_device *snpdev __unused,
250 const char *key, const char *value,
251 wchar_t **results ) {
252 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
253 EFI_STATUS efirc;
254 size_t len;
255 void *new;
256
257 /* Allocate new string */
258 len = ( ( *results ? ( wcslen ( *results ) + 1 /* "&" */ ) : 0 ) +
259 strlen ( key ) + 1 /* "=" */ + strlen ( value ) + 1 /* NUL */ );
260 if ( ( efirc = bs->AllocatePool ( EfiBootServicesData,
261 ( len * sizeof ( wchar_t ) ),
262 &new ) ) != 0 )
263 return -EEFI ( efirc );
264
265 /* Populate string */
266 efi_snprintf ( new, len, "%ls%s%s=%s", ( *results ? *results : L"" ),
267 ( *results ? L"&" : L"" ), key, value );
268 bs->FreePool ( *results );
269 *results = new;
270
271 return 0;
272}
273
274/**
275 * Fetch HII setting
276 *
277 * @v snpdev SNP device
278 * @v key Key
279 * @v value Value
280 * @v results Result string
281 * @v have_setting Flag indicating detection of a setting
282 * @ret rc Return status code
283 */
284static int efi_snp_hii_fetch ( struct efi_snp_device *snpdev,
285 const char *key, const char *value,
286 wchar_t **results, int *have_setting ) {
287 struct settings *settings = efi_snp_hii_settings ( snpdev );
288 struct settings *origin;
289 struct setting *setting;
290 struct setting fetched;
291 int len;
292 char *buf;
293 char *encoded;
294 int i;
295 int rc;
296
297 /* Handle ConfigHdr components */
298 if ( ( strcasecmp ( key, "GUID" ) == 0 ) ||
299 ( strcasecmp ( key, "NAME" ) == 0 ) ||
300 ( strcasecmp ( key, "PATH" ) == 0 ) ) {
301 return efi_snp_hii_append ( snpdev, key, value, results );
302 }
303 if ( have_setting )
304 *have_setting = 1;
305
306 /* Do nothing more unless we have a settings block */
307 if ( ! settings ) {
308 rc = -ENOTSUP;
309 goto err_no_settings;
310 }
311
312 /* Identify setting */
314 if ( ! setting ) {
315 DBGC ( snpdev, "SNPDEV %p no such setting \"%s\"\n",
316 snpdev, key );
317 rc = -ENODEV;
318 goto err_find_setting;
319 }
320
321 /* Encode value */
322 if ( setting_exists ( settings, setting ) ) {
323
324 /* Calculate formatted length */
325 len = fetchf_setting ( settings, setting, &origin, &fetched,
326 NULL, 0 );
327 if ( len < 0 ) {
328 rc = len;
329 DBGC ( snpdev, "SNPDEV %p could not fetch %s: %s\n",
330 snpdev, setting->name, strerror ( rc ) );
331 goto err_fetchf_len;
332 }
333
334 /* Allocate buffer for formatted value and HII-encoded value */
335 buf = zalloc ( len + 1 /* NUL */ + ( len * 4 ) + 1 /* NUL */ );
336 if ( ! buf ) {
337 rc = -ENOMEM;
338 goto err_alloc;
339 }
340 encoded = ( buf + len + 1 /* NUL */ );
341
342 /* Format value */
343 fetchf_setting ( origin, &fetched, NULL, NULL, buf,
344 ( len + 1 /* NUL */ ) );
345 for ( i = 0 ; i < len ; i++ ) {
346 sprintf ( ( encoded + ( 4 * i ) ), "%04x",
347 *( ( uint8_t * ) buf + i ) );
348 }
349
350 } else {
351
352 /* Non-existent or inapplicable setting */
353 buf = NULL;
354 encoded = "";
355 }
356
357 /* Append results */
358 if ( ( rc = efi_snp_hii_append ( snpdev, key, encoded,
359 results ) ) != 0 ) {
360 goto err_append;
361 }
362
363 /* Success */
364 rc = 0;
365
366 err_append:
367 free ( buf );
368 err_alloc:
369 err_fetchf_len:
370 err_find_setting:
371 err_no_settings:
372 return rc;
373}
374
375/**
376 * Fetch HII setting
377 *
378 * @v snpdev SNP device
379 * @v key Key
380 * @v value Value
381 * @v results Result string (unused)
382 * @v have_setting Flag indicating detection of a setting (unused)
383 * @ret rc Return status code
384 */
385static int efi_snp_hii_store ( struct efi_snp_device *snpdev,
386 const char *key, const char *value,
387 wchar_t **results __unused,
388 int *have_setting __unused ) {
389 struct settings *settings = efi_snp_hii_settings ( snpdev );
390 struct setting *setting;
391 char *buf;
392 char tmp[5];
393 char *endp;
394 int len;
395 int i;
396 int rc;
397
398 /* Handle ConfigHdr components */
399 if ( ( strcasecmp ( key, "GUID" ) == 0 ) ||
400 ( strcasecmp ( key, "NAME" ) == 0 ) ||
401 ( strcasecmp ( key, "PATH" ) == 0 ) ) {
402 /* Nothing to do */
403 return 0;
404 }
405
406 /* Do nothing more unless we have a settings block */
407 if ( ! settings ) {
408 rc = -ENOTSUP;
409 goto err_no_settings;
410 }
411
412 /* Identify setting */
414 if ( ! setting ) {
415 DBGC ( snpdev, "SNPDEV %p no such setting \"%s\"\n",
416 snpdev, key );
417 rc = -ENODEV;
418 goto err_find_setting;
419 }
420
421 /* Allocate buffer */
422 len = ( strlen ( value ) / 4 );
423 buf = zalloc ( len + 1 /* NUL */ );
424 if ( ! buf ) {
425 rc = -ENOMEM;
426 goto err_alloc;
427 }
428
429 /* Decode value */
430 tmp[4] = '\0';
431 for ( i = 0 ; i < len ; i++ ) {
432 memcpy ( tmp, ( value + ( i * 4 ) ), 4 );
433 buf[i] = strtoul ( tmp, &endp, 16 );
434 if ( endp != &tmp[4] ) {
435 DBGC ( snpdev, "SNPDEV %p invalid character %s\n",
436 snpdev, tmp );
437 rc = -EINVAL;
438 goto err_inval;
439 }
440 }
441
442 /* Store value */
443 if ( ( rc = storef_setting ( settings, setting, buf ) ) != 0 ) {
444 DBGC ( snpdev, "SNPDEV %p could not store \"%s\" into %s: %s\n",
445 snpdev, buf, setting->name, strerror ( rc ) );
446 goto err_storef;
447 }
448
449 /* Success */
450 rc = 0;
451
452 err_storef:
453 err_inval:
454 free ( buf );
455 err_alloc:
456 err_find_setting:
457 err_no_settings:
458 return rc;
459}
460
461/**
462 * Process portion of HII configuration string
463 *
464 * @v snpdev SNP device
465 * @v string HII configuration string
466 * @v progress Progress through HII configuration string
467 * @v results Results string
468 * @v have_setting Flag indicating detection of a setting (unused)
469 * @v process Function used to process key=value pairs
470 * @ret rc Return status code
471 */
472static int efi_snp_hii_process ( struct efi_snp_device *snpdev,
473 wchar_t *string, wchar_t **progress,
474 wchar_t **results, int *have_setting,
475 int ( * process ) ( struct efi_snp_device *,
476 const char *key,
477 const char *value,
478 wchar_t **results,
479 int *have_setting ) ) {
480 wchar_t *wkey = string;
481 wchar_t *wend = string;
482 wchar_t *wvalue = NULL;
483 size_t key_len;
484 size_t value_len;
485 void *temp;
486 char *key;
487 char *value;
488 int rc;
489
490 /* Locate key, value (if any), and end */
491 while ( *wend ) {
492 if ( *wend == L'&' )
493 break;
494 if ( *(wend++) == L'=' )
495 wvalue = wend;
496 }
497
498 /* Allocate memory for key and value */
499 key_len = ( ( wvalue ? ( wvalue - 1 ) : wend ) - wkey );
500 value_len = ( wvalue ? ( wend - wvalue ) : 0 );
501 temp = zalloc ( key_len + 1 /* NUL */ + value_len + 1 /* NUL */ );
502 if ( ! temp )
503 return -ENOMEM;
504 key = temp;
505 value = ( temp + key_len + 1 /* NUL */ );
506
507 /* Copy key and value */
508 while ( key_len-- )
509 key[key_len] = wkey[key_len];
510 while ( value_len-- )
511 value[value_len] = wvalue[value_len];
512
513 /* Process key and value */
514 if ( ( rc = process ( snpdev, key, value, results,
515 have_setting ) ) != 0 ) {
516 goto err;
517 }
518
519 /* Update progress marker */
520 *progress = wend;
521
522 err:
523 /* Free temporary storage */
524 free ( temp );
525
526 return rc;
527}
528
529/**
530 * Fetch configuration
531 *
532 * @v hii HII configuration access protocol
533 * @v request Configuration to fetch
534 * @ret progress Progress made through configuration to fetch
535 * @ret results Query results
536 * @ret efirc EFI status code
537 */
538static EFI_STATUS EFIAPI
540 EFI_STRING request, EFI_STRING *progress,
541 EFI_STRING *results ) {
542 struct efi_snp_device *snpdev =
543 container_of ( hii, struct efi_snp_device, hii );
544 int have_setting = 0;
545 wchar_t *pos;
546 int rc;
547
548 DBGC ( snpdev, "SNPDEV %p ExtractConfig request \"%ls\"\n",
549 snpdev, request );
550
551 /* Initialise results */
552 *results = NULL;
553
554 /* Work around apparently broken UEFI specification */
555 if ( ! ( request && request[0] ) ) {
556 DBGC ( snpdev, "SNPDEV %p ExtractConfig ignoring malformed "
557 "request\n", snpdev );
559 }
560
561 /* Process all request fragments */
562 for ( pos = *progress = request ; *progress && **progress ;
563 pos = *progress + 1 ) {
564 if ( ( rc = efi_snp_hii_process ( snpdev, pos, progress,
565 results, &have_setting,
566 efi_snp_hii_fetch ) ) != 0 ) {
567 return EFIRC ( rc );
568 }
569 }
570
571 /* If we have no explicit request, return all settings */
572 if ( ! have_setting ) {
573 struct setting *setting;
574
576 if ( ! efi_snp_hii_setting_applies ( snpdev, setting ) )
577 continue;
578 if ( ( rc = efi_snp_hii_fetch ( snpdev, setting->name,
579 NULL, results,
580 NULL ) ) != 0 ) {
581 return EFIRC ( rc );
582 }
583 }
584 }
585
586 DBGC ( snpdev, "SNPDEV %p ExtractConfig results \"%ls\"\n",
587 snpdev, *results );
588 return 0;
589}
590
591/**
592 * Store configuration
593 *
594 * @v hii HII configuration access protocol
595 * @v config Configuration to store
596 * @ret progress Progress made through configuration to store
597 * @ret efirc EFI status code
598 */
599static EFI_STATUS EFIAPI
601 EFI_STRING config, EFI_STRING *progress ) {
602 struct efi_snp_device *snpdev =
603 container_of ( hii, struct efi_snp_device, hii );
604 wchar_t *pos;
605 int rc;
606
607 DBGC ( snpdev, "SNPDEV %p RouteConfig \"%ls\"\n", snpdev, config );
608
609 /* Process all request fragments */
610 for ( pos = *progress = config ; *progress && **progress ;
611 pos = *progress + 1 ) {
612 if ( ( rc = efi_snp_hii_process ( snpdev, pos, progress,
613 NULL, NULL,
614 efi_snp_hii_store ) ) != 0 ) {
615 return EFIRC ( rc );
616 }
617 }
618
619 return 0;
620}
621
622/**
623 * Handle form actions
624 *
625 * @v hii HII configuration access protocol
626 * @v action Form browser action
627 * @v question_id Question ID
628 * @v type Type of value
629 * @v value Value
630 * @ret action_request Action requested by driver
631 * @ret efirc EFI status code
632 */
633static EFI_STATUS EFIAPI
636 EFI_QUESTION_ID question_id __unused,
638 EFI_BROWSER_ACTION_REQUEST *action_request __unused ) {
639 struct efi_snp_device *snpdev =
640 container_of ( hii, struct efi_snp_device, hii );
641
642 DBGC ( snpdev, "SNPDEV %p Callback\n", snpdev );
643 return EFI_UNSUPPORTED;
644}
645
646/** HII configuration access protocol */
652
653/**
654 * Install HII protocol and packages for SNP device
655 *
656 * @v snpdev SNP device
657 * @ret rc Return status code
658 */
659int efi_snp_hii_install ( struct efi_snp_device *snpdev ) {
660 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
661 VENDOR_DEVICE_PATH *vendor_path;
662 EFI_DEVICE_PATH_PROTOCOL *path_end;
663 size_t path_prefix_len;
664 int leak = 0;
665 EFI_STATUS efirc;
666 int rc;
667
668 /* Do nothing if HII database protocol is not supported */
669 if ( ! efihii ) {
670 rc = -ENOTSUP;
671 goto err_no_hii;
672 }
673
674 /* Initialise HII protocol */
675 memcpy ( &snpdev->hii, &efi_snp_device_hii, sizeof ( snpdev->hii ) );
676
677 /* Create HII package list */
678 snpdev->package_list = efi_snp_hii_package_list ( snpdev );
679 if ( ! snpdev->package_list ) {
680 DBGC ( snpdev, "SNPDEV %p could not create HII package list\n",
681 snpdev );
682 rc = -ENOMEM;
683 goto err_build_package_list;
684 }
685
686 /* Allocate the new device path */
687 path_prefix_len = efi_path_len ( snpdev->path );
688 snpdev->hii_child_path = zalloc ( path_prefix_len +
689 sizeof ( *vendor_path ) +
690 sizeof ( *path_end ) );
691 if ( ! snpdev->hii_child_path ) {
692 DBGC ( snpdev,
693 "SNPDEV %p could not allocate HII child device path\n",
694 snpdev );
695 rc = -ENOMEM;
696 goto err_alloc_child_path;
697 }
698
699 /* Populate the device path */
700 memcpy ( snpdev->hii_child_path, snpdev->path, path_prefix_len );
701 vendor_path = ( ( ( void * ) snpdev->hii_child_path ) +
702 path_prefix_len );
703 vendor_path->Header.Type = HARDWARE_DEVICE_PATH;
704 vendor_path->Header.SubType = HW_VENDOR_DP;
705 vendor_path->Header.Length[0] = sizeof ( *vendor_path );
706 efi_snp_hii_random_guid ( &vendor_path->Guid );
707 path_end = ( ( void * ) ( vendor_path + 1 ) );
708 efi_path_terminate ( path_end );
709
710 /* Create device path and child handle for HII association */
711 if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
712 &snpdev->hii_child_handle,
714 NULL ) ) != 0 ) {
715 rc = -EEFI ( efirc );
716 DBGC ( snpdev, "SNPDEV %p could not create HII child handle: "
717 "%s\n", snpdev, strerror ( rc ) );
718 goto err_hii_child_handle;
719 }
720
721 /* Add HII packages */
722 if ( ( efirc = efihii->NewPackageList ( efihii, snpdev->package_list,
723 snpdev->hii_child_handle,
724 &snpdev->hii_handle ) ) != 0 ) {
725 rc = -EEFI ( efirc );
726 DBGC ( snpdev, "SNPDEV %p could not add HII packages: %s\n",
727 snpdev, strerror ( rc ) );
728 goto err_new_package_list;
729 }
730
731 /* Install HII protocol */
732 if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
733 &snpdev->hii_child_handle,
735 NULL ) ) != 0 ) {
736 rc = -EEFI ( efirc );
737 DBGC ( snpdev, "SNPDEV %p could not install HII protocol: %s\n",
738 snpdev, strerror ( rc ) );
739 goto err_install_protocol;
740 }
741
742 /* Add as child of handle with SNP instance */
743 if ( ( rc = efi_child_add ( snpdev->handle,
744 snpdev->hii_child_handle ) ) != 0 ) {
745 DBGC ( snpdev,
746 "SNPDEV %p could not adopt HII child handle: %s\n",
747 snpdev, strerror ( rc ) );
748 goto err_efi_child_add;
749 }
750
751 return 0;
752
753 efi_child_del ( snpdev->handle, snpdev->hii_child_handle );
754 err_efi_child_add:
755 if ( ( efirc = bs->UninstallMultipleProtocolInterfaces (
756 snpdev->hii_child_handle,
758 NULL ) ) != 0 ) {
759 DBGC ( snpdev, "SNPDEV %p could not uninstall HII protocol: "
760 "%s\n", snpdev, strerror ( -EEFI ( efirc ) ) );
761 leak = 1;
762 }
763 efi_nullify_hii ( &snpdev->hii );
764 err_install_protocol:
765 if ( ! leak )
766 efihii->RemovePackageList ( efihii, snpdev->hii_handle );
767 err_new_package_list:
768 if ( ( efirc = bs->UninstallMultipleProtocolInterfaces (
769 snpdev->hii_child_handle,
771 NULL ) ) != 0 ) {
772 DBGC ( snpdev, "SNPDEV %p could not uninstall HII path: %s\n",
773 snpdev, strerror ( -EEFI ( efirc ) ) );
774 leak = 1;
775 }
776 err_hii_child_handle:
777 if ( ! leak ) {
778 free ( snpdev->hii_child_path );
779 snpdev->hii_child_path = NULL;
780 }
781 err_alloc_child_path:
782 if ( ! leak ) {
783 free ( snpdev->package_list );
784 snpdev->package_list = NULL;
785 }
786 err_build_package_list:
787 err_no_hii:
788 return rc;
789}
790
791/**
792 * Uninstall HII protocol and package for SNP device
793 *
794 * @v snpdev SNP device
795 * @ret leak Uninstallation failed: leak memory
796 */
797int efi_snp_hii_uninstall ( struct efi_snp_device *snpdev ) {
798 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
799 int leak = efi_shutdown_in_progress;
800 EFI_STATUS efirc;
801
802 /* Do nothing if HII database protocol is not supported */
803 if ( ! efihii )
804 return 0;
805
806 /* Uninstall protocols and remove package list */
807 efi_child_del ( snpdev->handle, snpdev->hii_child_handle );
808 if ( ( ! efi_shutdown_in_progress ) &&
810 snpdev->hii_child_handle,
812 NULL ) ) != 0 ) ) {
813 DBGC ( snpdev, "SNPDEV %p could not uninstall HII protocol: "
814 "%s\n", snpdev, strerror ( -EEFI ( efirc ) ) );
815 leak = 1;
816 }
817 efi_nullify_hii ( &snpdev->hii );
818 if ( ! leak )
819 efihii->RemovePackageList ( efihii, snpdev->hii_handle );
820 if ( ( ! efi_shutdown_in_progress ) &&
822 snpdev->hii_child_handle,
824 NULL ) ) != 0 ) ) {
825 DBGC ( snpdev, "SNPDEV %p could not uninstall HII path: %s\n",
826 snpdev, strerror ( -EEFI ( efirc ) ) );
827 leak = 1;
828 }
829 if ( ! leak ) {
830 free ( snpdev->hii_child_path );
831 snpdev->hii_child_path = NULL;
832 free ( snpdev->package_list );
833 snpdev->package_list = NULL;
834 }
835
836 /* Report leakage, if applicable */
837 if ( leak && ( ! efi_shutdown_in_progress ) )
838 DBGC ( snpdev, "SNPDEV %p HII nullified and leaked\n", snpdev );
839 return leak;
840}
#define EFIAPI
unsigned char UINT8
1-byte unsigned value.
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
union @162305117151260234136356364136041353210355154177 key
Sense key.
Definition scsi.h:3
#define HARDWARE_DEVICE_PATH
Hardware Device Paths.
Definition DevicePath.h:71
#define HW_VENDOR_DP
Hardware Vendor Device Path SubType.
Definition DevicePath.h:136
UINTN EFI_BROWSER_ACTION_REQUEST
UINTN EFI_BROWSER_ACTION
struct _EFI_HII_CONFIG_ACCESS_PROTOCOL EFI_HII_CONFIG_ACCESS_PROTOCOL
struct _EFI_HII_DATABASE_PROTOCOL EFI_HII_DATABASE_PROTOCOL
Definition HiiDatabase.h:22
#define EFI_HII_PLATFORM_SETUP_FORMSET_GUID
#define EFI_NETWORK_DEVICE_CLASS
#define EFI_UNSUPPORTED
Enumeration of EFI_STATUS.
#define EFI_INVALID_PARAMETER
Enumeration of EFI_STATUS.
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
GUID EFI_GUID
128-bit buffer containing a unique identifier value.
CHAR16 * EFI_STRING
@ EfiBootServicesData
The data portions of a loaded Boot Serves Driver, and the default data allocation type used by a Boot...
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
pseudo_bit_t value[0x00020]
Definition arbel.h:2
unsigned char uint8_t
Definition stdint.h:10
const char * name
Definition ath9k_hw.c:1986
Branding configuration.
#define PRODUCT_SETTING_URI
Definition branding.h:171
Device model.
ring len
Length.
Definition dwmac.h:226
uint64_t guid
GUID.
Definition edd.h:1
EFI_GUID efi_device_path_protocol_guid
Device path protocol GUID.
Definition efi_guid.c:169
EFI_GUID efi_hii_config_access_protocol_guid
HII configuration access protocol GUID.
Definition efi_guid.c:221
unsigned int efi_ifr_form_op(struct efi_ifr_builder *ifr, unsigned int title_id)
Add form opcode to IFR builder.
Definition efi_hii.c:167
void efi_ifr_end_op(struct efi_ifr_builder *ifr)
Add end opcode to IFR builder.
Definition efi_hii.c:133
void efi_ifr_text_op(struct efi_ifr_builder *ifr, unsigned int prompt_id, unsigned int help_id, unsigned int text_id)
Add text opcode to IFR builder.
Definition efi_hii.c:441
unsigned int efi_ifr_string(struct efi_ifr_builder *ifr, const char *fmt,...)
Add string to IFR builder.
Definition efi_hii.c:46
void efi_ifr_guid_subclass_op(struct efi_ifr_builder *ifr, unsigned int subclass)
Add GUID subclass opcode to IFR builder.
Definition efi_hii.c:289
void efi_ifr_form_set_op(struct efi_ifr_builder *ifr, const EFI_GUID *guid, unsigned int title_id, unsigned int help_id,...)
Add formset opcode to IFR builder.
Definition efi_hii.c:195
void efi_ifr_free(struct efi_ifr_builder *ifr)
Free memory used by IFR builder.
Definition efi_hii.c:506
void efi_ifr_guid_class_op(struct efi_ifr_builder *ifr, unsigned int class)
Add GUID class opcode to IFR builder.
Definition efi_hii.c:266
void efi_ifr_string_op(struct efi_ifr_builder *ifr, unsigned int prompt_id, unsigned int help_id, unsigned int question_id, unsigned int varstore_id, unsigned int varstore_info, unsigned int vflags, unsigned int min_size, unsigned int max_size, unsigned int flags)
Add string opcode to IFR builder.
Definition efi_hii.c:387
unsigned int efi_ifr_varstore_name_value_op(struct efi_ifr_builder *ifr, const EFI_GUID *guid)
Add name/value store opcode to IFR builder.
Definition efi_hii.c:482
EFI human interface infrastructure.
#define EFI_HII_IBM_UCM_COMPLIANT_FORMSET_GUID
GUID indicating formset compliance for IBM Unified Configuration Manager.
Definition efi_hii.h:17
static void efi_ifr_init(struct efi_ifr_builder *ifr)
Initialise IFR builder.
Definition efi_hii.h:49
int efi_shutdown_in_progress
EFI shutdown is in progress.
Definition efi_init.c:60
void efi_nullify_hii(EFI_HII_CONFIG_ACCESS_PROTOCOL *hii)
Nullify HII configuration access protocol.
Definition efi_null.c:344
EFI null interfaces.
size_t efi_path_len(EFI_DEVICE_PATH_PROTOCOL *path)
Find length of device path (excluding terminator)
Definition efi_path.c:174
EFI device paths.
static void efi_path_terminate(EFI_DEVICE_PATH_PROTOCOL *end)
Terminate device path.
Definition efi_path.h:31
iPXE EFI SNP interface
static EFI_HII_PACKAGE_LIST_HEADER * efi_snp_hii_package_list(struct efi_snp_device *snpdev)
Build HII package list for SNP device.
static EFI_STATUS EFIAPI efi_snp_hii_route_config(const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii, EFI_STRING config, EFI_STRING *progress)
Store configuration.
static struct settings * efi_snp_hii_settings(struct efi_snp_device *snpdev)
Identify settings to be exposed via HII.
Definition efi_snp_hii.c:90
static void efi_snp_hii_random_guid(EFI_GUID *guid)
Generate a random GUID.
static int efi_snp_hii_setting_applies(struct efi_snp_device *snpdev, struct setting *setting)
Check whether or not setting is applicable.
static EFI_GUID efi_hii_platform_setup_formset_guid
EFI platform setup formset GUID.
Definition efi_snp_hii.c:74
static EFI_HII_DATABASE_PROTOCOL * efihii
EFI HII database protocol.
Definition efi_snp_hii.c:81
static EFI_GUID efi_hii_ibm_ucm_compliant_formset_guid
EFI IBM UCM compliant formset GUID.
Definition efi_snp_hii.c:78
static int efi_snp_hii_fetch(struct efi_snp_device *snpdev, const char *key, const char *value, wchar_t **results, int *have_setting)
Fetch HII setting.
static EFI_HII_CONFIG_ACCESS_PROTOCOL efi_snp_device_hii
HII configuration access protocol.
static EFI_STATUS EFIAPI efi_snp_hii_callback(const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii, EFI_BROWSER_ACTION action __unused, EFI_QUESTION_ID question_id __unused, UINT8 type __unused, EFI_IFR_TYPE_VALUE *value __unused, EFI_BROWSER_ACTION_REQUEST *action_request __unused)
Handle form actions.
int efi_snp_hii_install(struct efi_snp_device *snpdev)
Install HII protocol and packages for SNP device.
static EFI_STATUS EFIAPI efi_snp_hii_extract_config(const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii, EFI_STRING request, EFI_STRING *progress, EFI_STRING *results)
Fetch configuration.
static int efi_snp_hii_append(struct efi_snp_device *snpdev __unused, const char *key, const char *value, wchar_t **results)
Append response to result string.
static int efi_snp_hii_store(struct efi_snp_device *snpdev, const char *key, const char *value, wchar_t **results __unused, int *have_setting __unused)
Fetch HII setting.
static int efi_snp_hii_process(struct efi_snp_device *snpdev, wchar_t *string, wchar_t **progress, wchar_t **results, int *have_setting, int(*process)(struct efi_snp_device *, const char *key, const char *value, wchar_t **results, int *have_setting))
Process portion of HII configuration string.
int efi_snp_hii_uninstall(struct efi_snp_device *snpdev)
Uninstall HII protocol and package for SNP device.
static void efi_snp_hii_questions(struct efi_snp_device *snpdev, struct efi_ifr_builder *ifr, unsigned int varstore_id)
Generate EFI SNP questions.
int efi_snprintf(wchar_t *wbuf, size_t wsize, const char *fmt,...)
Write a formatted string to a buffer.
EFI strings.
void efi_child_del(EFI_HANDLE parent, EFI_HANDLE child)
Remove EFI device as child of another EFI device.
Definition efi_utils.c:138
int efi_child_add(EFI_HANDLE parent, EFI_HANDLE child)
Add EFI device as child of another EFI device.
Definition efi_utils.c:111
EFI utilities.
uint32_t type
Operating system type.
Definition ena.h:1
Error codes.
static struct net_device * netdev
Definition gdbudp.c:53
#define __unused
Declare a variable or data structure as unused.
Definition compiler.h:573
#define DBGC(...)
Definition compiler.h:505
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define EINVAL
Invalid argument.
Definition errno.h:429
#define ENOMEM
Not enough space.
Definition errno.h:535
#define ENOTSUP
Operation not supported.
Definition errno.h:590
#define ENODEV
No such device.
Definition errno.h:510
#define FILE_SECBOOT(_status)
Declare a file's UEFI Secure Boot permission status.
Definition compiler.h:926
u8 request[0]
List of IEs requested.
Definition ieee80211.h:2
EFI API.
#define EFI_REQUEST_PROTOCOL(_protocol, _ptr)
Declare an EFI protocol to be requested by iPXE.
Definition efi.h:122
#define EFIRC(rc)
Convert an iPXE status code to an EFI status code.
Definition efi.h:167
#define EEFI(efirc)
Convert an EFI status code to an iPXE status code.
Definition efi.h:175
EFI_SYSTEM_TABLE * efi_systab
uint64_t origin
Origin.
Definition hyperv.h:9
Configuration settings.
static int setting_exists(struct settings *settings, const struct setting *setting)
Check existence of predefined setting.
Definition settings.h:546
#define SETTINGS
Configuration setting table.
Definition settings.h:54
String functions.
void * memcpy(void *dest, const void *src, size_t len) __nonnull
String functions.
Version number.
unsigned long tmp
Definition linux_pci.h:65
void * zalloc(size_t size)
Allocate cleared memory.
Definition malloc.c:662
uint32_t string
Definition multiboot.h:2
Network device management.
static const char * netdev_addr(struct net_device *netdev)
Get printable network device link-layer address.
Definition netdevice.h:542
static struct settings * netdev_settings(struct net_device *netdev)
Get per-netdevice configuration settings block.
Definition netdevice.h:587
int nvo_applies(struct settings *settings __unused, const struct setting *setting)
Check applicability of NVO setting.
Definition nvo.c:200
Non-volatile stored options.
#define NVO_SETTINGS_NAME
Name of non-volatile options settings block.
Definition nvo.h:47
long int random(void)
Generate a pseudo-random number between 0 and 2147483647L or 2147483562?
Definition random.c:32
static void(* free)(struct refcnt *refcnt))
Definition refcnt.h:55
struct setting * find_setting(const char *name)
Find predefined setting.
Definition settings.c:1467
int setting_cmp(const struct setting *a, const struct setting *b)
Compare two settings.
Definition settings.c:1121
int fetchf_setting(struct settings *settings, const struct setting *setting, struct settings **origin, struct setting *fetched, char *buf, size_t len)
Fetch formatted value of setting.
Definition settings.c:1230
struct settings * find_child_settings(struct settings *parent, const char *name)
Find child settings block.
Definition settings.c:280
int storef_setting(struct settings *settings, const struct setting *setting, const char *value)
Store formatted value of setting.
Definition settings.c:1320
#define container_of(ptr, type, field)
Get containing structure.
Definition stddef.h:36
#define sprintf(buf, fmt,...)
Write a formatted string to a buffer.
Definition stdio.h:37
char * strerror(int errno)
Retrieve string representation of error number.
Definition strerror.c:79
unsigned long strtoul(const char *string, char **endp, int base)
Convert string to numeric value.
Definition string.c:485
int strcasecmp(const char *first, const char *second)
Compare case-insensitive strings.
Definition string.c:209
size_t strlen(const char *src)
Get length of string.
Definition string.c:244
EFI Boot Services Table.
Definition UefiSpec.h:1931
EFI_FREE_POOL FreePool
Definition UefiSpec.h:1950
EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES UninstallMultipleProtocolInterfaces
Definition UefiSpec.h:2011
EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES InstallMultipleProtocolInterfaces
Definition UefiSpec.h:2010
EFI_ALLOCATE_POOL AllocatePool
Definition UefiSpec.h:1949
This protocol can be used on any device handle to obtain generic path/location information concerning...
Definition DevicePath.h:46
UINT8 Type
0x01 Hardware Device Path.
Definition DevicePath.h:47
UINT8 Length[2]
Specific Device Path data.
Definition DevicePath.h:59
UINT8 SubType
Varies by Type 0xFF End Entire Device Path, or 0x01 End This Instance of a Device Path and start a ne...
Definition DevicePath.h:54
The header found at the start of each package list.
The Vendor Device Path allows the creation of vendor-defined Device Paths.
Definition DevicePath.h:143
EFI_DEVICE_PATH_PROTOCOL Header
Definition DevicePath.h:144
EFI_GUID Guid
Vendor-assigned GUID that defines the data that follows.
Definition DevicePath.h:148
A hardware device.
Definition device.h:77
const char * driver_name
Driver name.
Definition device.h:81
char name[40]
Name.
Definition device.h:79
An EFI IFR builder.
Definition efi_hii.h:22
unsigned int varstore_id
Current variable store identifier.
Definition efi_hii.h:34
An SNP device.
Definition efi_snp.h:29
EFI_HANDLE handle
EFI device handle.
Definition efi_snp.h:37
EFI_DEVICE_PATH_PROTOCOL * hii_child_path
Device path of HII child handle.
Definition efi_snp.h:69
EFI_HII_PACKAGE_LIST_HEADER * package_list
HII package list.
Definition efi_snp.h:65
EFI_DEVICE_PATH_PROTOCOL * path
The device path.
Definition efi_snp.h:79
struct net_device * netdev
The underlying iPXE network device.
Definition efi_snp.h:33
EFI_HII_CONFIG_ACCESS_PROTOCOL hii
HII configuration access protocol.
Definition efi_snp.h:63
EFI_HII_HANDLE hii_handle
HII handle.
Definition efi_snp.h:71
EFI_HANDLE hii_child_handle
EFI child handle for HII association.
Definition efi_snp.h:67
A network device.
Definition netdevice.h:353
A process.
Definition process.h:18
A setting.
Definition settings.h:24
const char * name
Name.
Definition settings.h:29
const char * description
Description.
Definition settings.h:31
uint64_t tag
Setting tag, if applicable.
Definition settings.h:44
A settings block.
Definition settings.h:133
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition tables.h:386
const char product_short_name[]
Product short name string.
Definition version.c:77
const char product_name[]
Product name string.
Definition version.c:74
const char product_version[]
Product version string.
Definition version.c:71
size_t wcslen(const wchar_t *string)
Calculate length of wide-character string.
Definition wchar.c:57