[efi] Generalise EFI entropy generation to non-x86 CPUs
[ipxe.git] / src / interface / efi / efi_snp_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 /**
27 * @file
28 *
29 * EFI SNP HII protocol
30 *
31 * The HII protocols are some of the less-well designed parts of the
32 * entire EFI specification. This is a significant accomplishment.
33 *
34 * The face-slappingly ludicrous query string syntax seems to be
35 * motivated by the desire to allow a caller to query multiple drivers
36 * simultaneously via the single-instance HII_CONFIG_ROUTING_PROTOCOL,
37 * which is supposed to pass relevant subsets of the query string to
38 * the relevant drivers.
39 *
40 * Nobody uses the HII_CONFIG_ROUTING_PROTOCOL. Not even the EFI
41 * setup browser uses the HII_CONFIG_ROUTING_PROTOCOL. To the best of
42 * my knowledge, there has only ever been one implementation of the
43 * HII_CONFIG_ROUTING_PROTOCOL (as part of EDK2), and it just doesn't
44 * work. It's so badly broken that I can't even figure out what the
45 * code is _trying_ to do.
46 *
47 * Fundamentally, the problem seems to be that Javascript programmers
48 * should not be allowed to design APIs for C code.
49 */
50
51 #include <string.h>
52 #include <strings.h>
53 #include <stdlib.h>
54 #include <stdio.h>
55 #include <wchar.h>
56 #include <errno.h>
57 #include <ipxe/settings.h>
58 #include <ipxe/nvo.h>
59 #include <ipxe/device.h>
60 #include <ipxe/netdevice.h>
61 #include <ipxe/version.h>
62 #include <ipxe/efi/efi.h>
63 #include <ipxe/efi/efi_hii.h>
64 #include <ipxe/efi/efi_snp.h>
65 #include <ipxe/efi/efi_strings.h>
66 #include <config/branding.h>
67
68 /** EFI platform setup formset GUID */
69 static EFI_GUID efi_hii_platform_setup_formset_guid
70 = EFI_HII_PLATFORM_SETUP_FORMSET_GUID;
71
72 /** EFI IBM UCM compliant formset GUID */
73 static EFI_GUID efi_hii_ibm_ucm_compliant_formset_guid
74 = EFI_HII_IBM_UCM_COMPLIANT_FORMSET_GUID;
75
76 /** EFI HII database protocol */
77 static EFI_HII_DATABASE_PROTOCOL *efihii;
78 EFI_REQUEST_PROTOCOL ( EFI_HII_DATABASE_PROTOCOL, &efihii );
79
80 /**
81 * Identify settings to be exposed via HII
82 *
83 * @v snpdev SNP device
84 * @ret settings Settings, or NULL
85 */
86 static struct settings * efi_snp_hii_settings ( struct efi_snp_device *snpdev ){
87
88 return find_child_settings ( netdev_settings ( snpdev->netdev ),
89 NVO_SETTINGS_NAME );
90 }
91
92 /**
93 * Check whether or not setting is applicable
94 *
95 * @v snpdev SNP device
96 * @v setting Setting
97 * @ret applies Setting applies
98 */
99 static int efi_snp_hii_setting_applies ( struct efi_snp_device *snpdev,
100 struct setting *setting ) {
101
102 return nvo_applies ( efi_snp_hii_settings ( snpdev ), setting );
103 }
104
105 /**
106 * Generate a random GUID
107 *
108 * @v guid GUID to fill in
109 */
110 static void efi_snp_hii_random_guid ( EFI_GUID *guid ) {
111 uint8_t *byte = ( ( uint8_t * ) guid );
112 unsigned int i;
113
114 for ( i = 0 ; i < sizeof ( *guid ) ; i++ )
115 *(byte++) = random();
116 }
117
118 /**
119 * Generate EFI SNP questions
120 *
121 * @v snpdev SNP device
122 * @v ifr IFR builder
123 * @v varstore_id Variable store identifier
124 */
125 static void efi_snp_hii_questions ( struct efi_snp_device *snpdev,
126 struct efi_ifr_builder *ifr,
127 unsigned int varstore_id ) {
128 struct setting *setting;
129 struct setting *previous = NULL;
130 unsigned int name_id;
131 unsigned int prompt_id;
132 unsigned int help_id;
133 unsigned int question_id;
134
135 /* Add all applicable settings */
136 for_each_table_entry ( setting, SETTINGS ) {
137 if ( ! efi_snp_hii_setting_applies ( snpdev, setting ) )
138 continue;
139 if ( previous && ( setting_cmp ( setting, previous ) == 0 ) )
140 continue;
141 previous = setting;
142 name_id = efi_ifr_string ( ifr, "%s", setting->name );
143 prompt_id = efi_ifr_string ( ifr, "%s", setting->description );
144 help_id = efi_ifr_string ( ifr, PRODUCT_SETTING_URI,
145 setting->name );
146 question_id = setting->tag;
147 efi_ifr_string_op ( ifr, prompt_id, help_id,
148 question_id, varstore_id, name_id,
149 0, 0x00, 0xff, 0 );
150 }
151 }
152
153 /**
154 * Build HII package list for SNP device
155 *
156 * @v snpdev SNP device
157 * @ret package Package list, or NULL on error
158 */
159 static EFI_HII_PACKAGE_LIST_HEADER *
160 efi_snp_hii_package_list ( struct efi_snp_device *snpdev ) {
161 struct net_device *netdev = snpdev->netdev;
162 struct device *dev = netdev->dev;
163 struct efi_ifr_builder ifr;
164 EFI_HII_PACKAGE_LIST_HEADER *package;
165 const char *name;
166 EFI_GUID package_guid;
167 EFI_GUID formset_guid;
168 EFI_GUID varstore_guid;
169 unsigned int title_id;
170 unsigned int varstore_id;
171
172 /* Initialise IFR builder */
173 efi_ifr_init ( &ifr );
174
175 /* Determine product name */
176 name = ( product_name[0] ? product_name : product_short_name );
177
178 /* Generate GUIDs */
179 efi_snp_hii_random_guid ( &package_guid );
180 efi_snp_hii_random_guid ( &formset_guid );
181 efi_snp_hii_random_guid ( &varstore_guid );
182
183 /* Generate title string (used more than once) */
184 title_id = efi_ifr_string ( &ifr, "%s (%s)", name,
185 netdev_addr ( netdev ) );
186
187 /* Generate opcodes */
188 efi_ifr_form_set_op ( &ifr, &formset_guid, title_id,
189 efi_ifr_string ( &ifr, "Configure %s",
190 product_short_name ),
191 &efi_hii_platform_setup_formset_guid,
192 &efi_hii_ibm_ucm_compliant_formset_guid, NULL );
193 efi_ifr_guid_class_op ( &ifr, EFI_NETWORK_DEVICE_CLASS );
194 efi_ifr_guid_subclass_op ( &ifr, 0x03 );
195 varstore_id = efi_ifr_varstore_name_value_op ( &ifr, &varstore_guid );
196 efi_ifr_form_op ( &ifr, title_id );
197 efi_ifr_text_op ( &ifr,
198 efi_ifr_string ( &ifr, "Name" ),
199 efi_ifr_string ( &ifr, "Firmware product name" ),
200 efi_ifr_string ( &ifr, "%s", name ) );
201 efi_ifr_text_op ( &ifr,
202 efi_ifr_string ( &ifr, "Version" ),
203 efi_ifr_string ( &ifr, "Firmware version" ),
204 efi_ifr_string ( &ifr, "%s", product_version ) );
205 efi_ifr_text_op ( &ifr,
206 efi_ifr_string ( &ifr, "Driver" ),
207 efi_ifr_string ( &ifr, "Firmware driver" ),
208 efi_ifr_string ( &ifr, "%s", dev->driver_name ) );
209 efi_ifr_text_op ( &ifr,
210 efi_ifr_string ( &ifr, "Device" ),
211 efi_ifr_string ( &ifr, "Hardware device" ),
212 efi_ifr_string ( &ifr, "%s", dev->name ) );
213 efi_snp_hii_questions ( snpdev, &ifr, varstore_id );
214 efi_ifr_end_op ( &ifr );
215 efi_ifr_end_op ( &ifr );
216
217 /* Build package */
218 package = efi_ifr_package ( &ifr, &package_guid, "en-us",
219 efi_ifr_string ( &ifr, "English" ) );
220 if ( ! package ) {
221 DBGC ( snpdev, "SNPDEV %p could not build IFR package\n",
222 snpdev );
223 efi_ifr_free ( &ifr );
224 return NULL;
225 }
226
227 /* Free temporary storage */
228 efi_ifr_free ( &ifr );
229 return package;
230 }
231
232 /**
233 * Append response to result string
234 *
235 * @v snpdev SNP device
236 * @v key Key
237 * @v value Value
238 * @v results Result string
239 * @ret rc Return status code
240 *
241 * The result string is allocated dynamically using
242 * BootServices::AllocatePool(), and the caller is responsible for
243 * eventually calling BootServices::FreePool().
244 */
245 static int efi_snp_hii_append ( struct efi_snp_device *snpdev __unused,
246 const char *key, const char *value,
247 wchar_t **results ) {
248 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
249 size_t len;
250 void *new;
251
252 /* Allocate new string */
253 len = ( ( *results ? ( wcslen ( *results ) + 1 /* "&" */ ) : 0 ) +
254 strlen ( key ) + 1 /* "=" */ + strlen ( value ) + 1 /* NUL */ );
255 bs->AllocatePool ( EfiBootServicesData, ( len * sizeof ( wchar_t ) ),
256 &new );
257 if ( ! new )
258 return -ENOMEM;
259
260 /* Populate string */
261 efi_snprintf ( new, len, "%ls%s%s=%s", ( *results ? *results : L"" ),
262 ( *results ? L"&" : L"" ), key, value );
263 bs->FreePool ( *results );
264 *results = new;
265
266 return 0;
267 }
268
269 /**
270 * Fetch HII setting
271 *
272 * @v snpdev SNP device
273 * @v key Key
274 * @v value Value
275 * @v results Result string
276 * @v have_setting Flag indicating detection of a setting
277 * @ret rc Return status code
278 */
279 static int efi_snp_hii_fetch ( struct efi_snp_device *snpdev,
280 const char *key, const char *value,
281 wchar_t **results, int *have_setting ) {
282 struct settings *settings = efi_snp_hii_settings ( snpdev );
283 struct settings *origin;
284 struct setting *setting;
285 struct setting fetched;
286 int len;
287 char *buf;
288 char *encoded;
289 int i;
290 int rc;
291
292 /* Handle ConfigHdr components */
293 if ( ( strcasecmp ( key, "GUID" ) == 0 ) ||
294 ( strcasecmp ( key, "NAME" ) == 0 ) ||
295 ( strcasecmp ( key, "PATH" ) == 0 ) ) {
296 return efi_snp_hii_append ( snpdev, key, value, results );
297 }
298 if ( have_setting )
299 *have_setting = 1;
300
301 /* Do nothing more unless we have a settings block */
302 if ( ! settings ) {
303 rc = -ENOTSUP;
304 goto err_no_settings;
305 }
306
307 /* Identify setting */
308 setting = find_setting ( key );
309 if ( ! setting ) {
310 DBGC ( snpdev, "SNPDEV %p no such setting \"%s\"\n",
311 snpdev, key );
312 rc = -ENODEV;
313 goto err_find_setting;
314 }
315
316 /* Encode value */
317 if ( setting_exists ( settings, setting ) ) {
318
319 /* Calculate formatted length */
320 len = fetchf_setting ( settings, setting, &origin, &fetched,
321 NULL, 0 );
322 if ( len < 0 ) {
323 rc = len;
324 DBGC ( snpdev, "SNPDEV %p could not fetch %s: %s\n",
325 snpdev, setting->name, strerror ( rc ) );
326 goto err_fetchf_len;
327 }
328
329 /* Allocate buffer for formatted value and HII-encoded value */
330 buf = zalloc ( len + 1 /* NUL */ + ( len * 4 ) + 1 /* NUL */ );
331 if ( ! buf ) {
332 rc = -ENOMEM;
333 goto err_alloc;
334 }
335 encoded = ( buf + len + 1 /* NUL */ );
336
337 /* Format value */
338 fetchf_setting ( origin, &fetched, NULL, NULL, buf,
339 ( len + 1 /* NUL */ ) );
340 for ( i = 0 ; i < len ; i++ ) {
341 sprintf ( ( encoded + ( 4 * i ) ), "%04x",
342 *( ( uint8_t * ) buf + i ) );
343 }
344
345 } else {
346
347 /* Non-existent or inapplicable setting */
348 buf = NULL;
349 encoded = "";
350 }
351
352 /* Append results */
353 if ( ( rc = efi_snp_hii_append ( snpdev, key, encoded,
354 results ) ) != 0 ) {
355 goto err_append;
356 }
357
358 /* Success */
359 rc = 0;
360
361 err_append:
362 free ( buf );
363 err_alloc:
364 err_fetchf_len:
365 err_find_setting:
366 err_no_settings:
367 return rc;
368 }
369
370 /**
371 * Fetch HII setting
372 *
373 * @v snpdev SNP device
374 * @v key Key
375 * @v value Value
376 * @v results Result string (unused)
377 * @v have_setting Flag indicating detection of a setting (unused)
378 * @ret rc Return status code
379 */
380 static int efi_snp_hii_store ( struct efi_snp_device *snpdev,
381 const char *key, const char *value,
382 wchar_t **results __unused,
383 int *have_setting __unused ) {
384 struct settings *settings = efi_snp_hii_settings ( snpdev );
385 struct setting *setting;
386 char *buf;
387 char tmp[5];
388 char *endp;
389 int len;
390 int i;
391 int rc;
392
393 /* Handle ConfigHdr components */
394 if ( ( strcasecmp ( key, "GUID" ) == 0 ) ||
395 ( strcasecmp ( key, "NAME" ) == 0 ) ||
396 ( strcasecmp ( key, "PATH" ) == 0 ) ) {
397 /* Nothing to do */
398 return 0;
399 }
400
401 /* Do nothing more unless we have a settings block */
402 if ( ! settings ) {
403 rc = -ENOTSUP;
404 goto err_no_settings;
405 }
406
407 /* Identify setting */
408 setting = find_setting ( key );
409 if ( ! setting ) {
410 DBGC ( snpdev, "SNPDEV %p no such setting \"%s\"\n",
411 snpdev, key );
412 rc = -ENODEV;
413 goto err_find_setting;
414 }
415
416 /* Allocate buffer */
417 len = ( strlen ( value ) / 4 );
418 buf = zalloc ( len + 1 /* NUL */ );
419 if ( ! buf ) {
420 rc = -ENOMEM;
421 goto err_alloc;
422 }
423
424 /* Decode value */
425 tmp[4] = '\0';
426 for ( i = 0 ; i < len ; i++ ) {
427 memcpy ( tmp, ( value + ( i * 4 ) ), 4 );
428 buf[i] = strtoul ( tmp, &endp, 16 );
429 if ( endp != &tmp[4] ) {
430 DBGC ( snpdev, "SNPDEV %p invalid character %s\n",
431 snpdev, tmp );
432 rc = -EINVAL;
433 goto err_inval;
434 }
435 }
436
437 /* Store value */
438 if ( ( rc = storef_setting ( settings, setting, buf ) ) != 0 ) {
439 DBGC ( snpdev, "SNPDEV %p could not store \"%s\" into %s: %s\n",
440 snpdev, buf, setting->name, strerror ( rc ) );
441 goto err_storef;
442 }
443
444 /* Success */
445 rc = 0;
446
447 err_storef:
448 err_inval:
449 free ( buf );
450 err_alloc:
451 err_find_setting:
452 err_no_settings:
453 return rc;
454 }
455
456 /**
457 * Process portion of HII configuration string
458 *
459 * @v snpdev SNP device
460 * @v string HII configuration string
461 * @v progress Progress through HII configuration string
462 * @v results Results string
463 * @v have_setting Flag indicating detection of a setting (unused)
464 * @v process Function used to process key=value pairs
465 * @ret rc Return status code
466 */
467 static int efi_snp_hii_process ( struct efi_snp_device *snpdev,
468 wchar_t *string, wchar_t **progress,
469 wchar_t **results, int *have_setting,
470 int ( * process ) ( struct efi_snp_device *,
471 const char *key,
472 const char *value,
473 wchar_t **results,
474 int *have_setting ) ) {
475 wchar_t *wkey = string;
476 wchar_t *wend = string;
477 wchar_t *wvalue = NULL;
478 size_t key_len;
479 size_t value_len;
480 void *temp;
481 char *key;
482 char *value;
483 int rc;
484
485 /* Locate key, value (if any), and end */
486 while ( *wend ) {
487 if ( *wend == L'&' )
488 break;
489 if ( *(wend++) == L'=' )
490 wvalue = wend;
491 }
492
493 /* Allocate memory for key and value */
494 key_len = ( ( wvalue ? ( wvalue - 1 ) : wend ) - wkey );
495 value_len = ( wvalue ? ( wend - wvalue ) : 0 );
496 temp = zalloc ( key_len + 1 /* NUL */ + value_len + 1 /* NUL */ );
497 if ( ! temp )
498 return -ENOMEM;
499 key = temp;
500 value = ( temp + key_len + 1 /* NUL */ );
501
502 /* Copy key and value */
503 while ( key_len-- )
504 key[key_len] = wkey[key_len];
505 while ( value_len-- )
506 value[value_len] = wvalue[value_len];
507
508 /* Process key and value */
509 if ( ( rc = process ( snpdev, key, value, results,
510 have_setting ) ) != 0 ) {
511 goto err;
512 }
513
514 /* Update progress marker */
515 *progress = wend;
516
517 err:
518 /* Free temporary storage */
519 free ( temp );
520
521 return rc;
522 }
523
524 /**
525 * Fetch configuration
526 *
527 * @v hii HII configuration access protocol
528 * @v request Configuration to fetch
529 * @ret progress Progress made through configuration to fetch
530 * @ret results Query results
531 * @ret efirc EFI status code
532 */
533 static EFI_STATUS EFIAPI
534 efi_snp_hii_extract_config ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii,
535 EFI_STRING request, EFI_STRING *progress,
536 EFI_STRING *results ) {
537 struct efi_snp_device *snpdev =
538 container_of ( hii, struct efi_snp_device, hii );
539 int have_setting = 0;
540 wchar_t *pos;
541 int rc;
542
543 DBGC ( snpdev, "SNPDEV %p ExtractConfig request \"%ls\"\n",
544 snpdev, request );
545
546 /* Initialise results */
547 *results = NULL;
548
549 /* Work around apparently broken UEFI specification */
550 if ( ! ( request && request[0] ) ) {
551 DBGC ( snpdev, "SNPDEV %p ExtractConfig ignoring malformed "
552 "request\n", snpdev );
553 return EFI_INVALID_PARAMETER;
554 }
555
556 /* Process all request fragments */
557 for ( pos = *progress = request ; *progress && **progress ;
558 pos = *progress + 1 ) {
559 if ( ( rc = efi_snp_hii_process ( snpdev, pos, progress,
560 results, &have_setting,
561 efi_snp_hii_fetch ) ) != 0 ) {
562 return EFIRC ( rc );
563 }
564 }
565
566 /* If we have no explicit request, return all settings */
567 if ( ! have_setting ) {
568 struct setting *setting;
569
570 for_each_table_entry ( setting, SETTINGS ) {
571 if ( ! efi_snp_hii_setting_applies ( snpdev, setting ) )
572 continue;
573 if ( ( rc = efi_snp_hii_fetch ( snpdev, setting->name,
574 NULL, results,
575 NULL ) ) != 0 ) {
576 return EFIRC ( rc );
577 }
578 }
579 }
580
581 DBGC ( snpdev, "SNPDEV %p ExtractConfig results \"%ls\"\n",
582 snpdev, *results );
583 return 0;
584 }
585
586 /**
587 * Store configuration
588 *
589 * @v hii HII configuration access protocol
590 * @v config Configuration to store
591 * @ret progress Progress made through configuration to store
592 * @ret efirc EFI status code
593 */
594 static EFI_STATUS EFIAPI
595 efi_snp_hii_route_config ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii,
596 EFI_STRING config, EFI_STRING *progress ) {
597 struct efi_snp_device *snpdev =
598 container_of ( hii, struct efi_snp_device, hii );
599 wchar_t *pos;
600 int rc;
601
602 DBGC ( snpdev, "SNPDEV %p RouteConfig \"%ls\"\n", snpdev, config );
603
604 /* Process all request fragments */
605 for ( pos = *progress = config ; *progress && **progress ;
606 pos = *progress + 1 ) {
607 if ( ( rc = efi_snp_hii_process ( snpdev, pos, progress,
608 NULL, NULL,
609 efi_snp_hii_store ) ) != 0 ) {
610 return EFIRC ( rc );
611 }
612 }
613
614 return 0;
615 }
616
617 /**
618 * Handle form actions
619 *
620 * @v hii HII configuration access protocol
621 * @v action Form browser action
622 * @v question_id Question ID
623 * @v type Type of value
624 * @v value Value
625 * @ret action_request Action requested by driver
626 * @ret efirc EFI status code
627 */
628 static EFI_STATUS EFIAPI
629 efi_snp_hii_callback ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii,
630 EFI_BROWSER_ACTION action __unused,
631 EFI_QUESTION_ID question_id __unused,
632 UINT8 type __unused, EFI_IFR_TYPE_VALUE *value __unused,
633 EFI_BROWSER_ACTION_REQUEST *action_request __unused ) {
634 struct efi_snp_device *snpdev =
635 container_of ( hii, struct efi_snp_device, hii );
636
637 DBGC ( snpdev, "SNPDEV %p Callback\n", snpdev );
638 return EFI_UNSUPPORTED;
639 }
640
641 /** HII configuration access protocol */
642 static EFI_HII_CONFIG_ACCESS_PROTOCOL efi_snp_device_hii = {
643 .ExtractConfig = efi_snp_hii_extract_config,
644 .RouteConfig = efi_snp_hii_route_config,
645 .Callback = efi_snp_hii_callback,
646 };
647
648 /**
649 * Install HII protocol and packages for SNP device
650 *
651 * @v snpdev SNP device
652 * @ret rc Return status code
653 */
654 int efi_snp_hii_install ( struct efi_snp_device *snpdev ) {
655 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
656 int efirc;
657 int rc;
658
659 /* Do nothing if HII database protocol is not supported */
660 if ( ! efihii ) {
661 rc = -ENOTSUP;
662 goto err_no_hii;
663 }
664
665 /* Initialise HII protocol */
666 memcpy ( &snpdev->hii, &efi_snp_device_hii, sizeof ( snpdev->hii ) );
667
668 /* Create HII package list */
669 snpdev->package_list = efi_snp_hii_package_list ( snpdev );
670 if ( ! snpdev->package_list ) {
671 DBGC ( snpdev, "SNPDEV %p could not create HII package list\n",
672 snpdev );
673 rc = -ENOMEM;
674 goto err_build_package_list;
675 }
676
677 /* Add HII packages */
678 if ( ( efirc = efihii->NewPackageList ( efihii, snpdev->package_list,
679 snpdev->handle,
680 &snpdev->hii_handle ) ) != 0 ) {
681 rc = -EEFI ( efirc );
682 DBGC ( snpdev, "SNPDEV %p could not add HII packages: %s\n",
683 snpdev, strerror ( rc ) );
684 goto err_new_package_list;
685 }
686
687 /* Install HII protocol */
688 if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
689 &snpdev->handle,
690 &efi_hii_config_access_protocol_guid, &snpdev->hii,
691 NULL ) ) != 0 ) {
692 rc = -EEFI ( efirc );
693 DBGC ( snpdev, "SNPDEV %p could not install HII protocol: %s\n",
694 snpdev, strerror ( rc ) );
695 goto err_install_protocol;
696 }
697
698 return 0;
699
700 bs->UninstallMultipleProtocolInterfaces (
701 snpdev->handle,
702 &efi_hii_config_access_protocol_guid, &snpdev->hii,
703 NULL );
704 err_install_protocol:
705 efihii->RemovePackageList ( efihii, snpdev->hii_handle );
706 err_new_package_list:
707 free ( snpdev->package_list );
708 snpdev->package_list = NULL;
709 err_build_package_list:
710 err_no_hii:
711 return rc;
712 }
713
714 /**
715 * Uninstall HII protocol and package for SNP device
716 *
717 * @v snpdev SNP device
718 */
719 void efi_snp_hii_uninstall ( struct efi_snp_device *snpdev ) {
720 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
721
722 /* Do nothing if HII database protocol is not supported */
723 if ( ! efihii )
724 return;
725
726 /* Uninstall protocols and remove package list */
727 bs->UninstallMultipleProtocolInterfaces (
728 snpdev->handle,
729 &efi_hii_config_access_protocol_guid, &snpdev->hii,
730 NULL );
731 efihii->RemovePackageList ( efihii, snpdev->hii_handle );
732 free ( snpdev->package_list );
733 snpdev->package_list = NULL;
734 }