[infiniband] Do not use GRH for local paths
[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 /* Process all request fragments */
550 for ( pos = *progress = request ; *progress && **progress ;
551 pos = *progress + 1 ) {
552 if ( ( rc = efi_snp_hii_process ( snpdev, pos, progress,
553 results, &have_setting,
554 efi_snp_hii_fetch ) ) != 0 ) {
555 return EFIRC ( rc );
556 }
557 }
558
559 /* If we have no explicit request, return all settings */
560 if ( ! have_setting ) {
561 struct setting *setting;
562
563 for_each_table_entry ( setting, SETTINGS ) {
564 if ( ! efi_snp_hii_setting_applies ( snpdev, setting ) )
565 continue;
566 if ( ( rc = efi_snp_hii_fetch ( snpdev, setting->name,
567 NULL, results,
568 NULL ) ) != 0 ) {
569 return EFIRC ( rc );
570 }
571 }
572 }
573
574 DBGC ( snpdev, "SNPDEV %p ExtractConfig results \"%ls\"\n",
575 snpdev, *results );
576 return 0;
577 }
578
579 /**
580 * Store configuration
581 *
582 * @v hii HII configuration access protocol
583 * @v config Configuration to store
584 * @ret progress Progress made through configuration to store
585 * @ret efirc EFI status code
586 */
587 static EFI_STATUS EFIAPI
588 efi_snp_hii_route_config ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii,
589 EFI_STRING config, EFI_STRING *progress ) {
590 struct efi_snp_device *snpdev =
591 container_of ( hii, struct efi_snp_device, hii );
592 wchar_t *pos;
593 int rc;
594
595 DBGC ( snpdev, "SNPDEV %p RouteConfig \"%ls\"\n", snpdev, config );
596
597 /* Process all request fragments */
598 for ( pos = *progress = config ; *progress && **progress ;
599 pos = *progress + 1 ) {
600 if ( ( rc = efi_snp_hii_process ( snpdev, pos, progress,
601 NULL, NULL,
602 efi_snp_hii_store ) ) != 0 ) {
603 return EFIRC ( rc );
604 }
605 }
606
607 return 0;
608 }
609
610 /**
611 * Handle form actions
612 *
613 * @v hii HII configuration access protocol
614 * @v action Form browser action
615 * @v question_id Question ID
616 * @v type Type of value
617 * @v value Value
618 * @ret action_request Action requested by driver
619 * @ret efirc EFI status code
620 */
621 static EFI_STATUS EFIAPI
622 efi_snp_hii_callback ( const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii,
623 EFI_BROWSER_ACTION action __unused,
624 EFI_QUESTION_ID question_id __unused,
625 UINT8 type __unused, EFI_IFR_TYPE_VALUE *value __unused,
626 EFI_BROWSER_ACTION_REQUEST *action_request __unused ) {
627 struct efi_snp_device *snpdev =
628 container_of ( hii, struct efi_snp_device, hii );
629
630 DBGC ( snpdev, "SNPDEV %p Callback\n", snpdev );
631 return EFI_UNSUPPORTED;
632 }
633
634 /** HII configuration access protocol */
635 static EFI_HII_CONFIG_ACCESS_PROTOCOL efi_snp_device_hii = {
636 .ExtractConfig = efi_snp_hii_extract_config,
637 .RouteConfig = efi_snp_hii_route_config,
638 .Callback = efi_snp_hii_callback,
639 };
640
641 /**
642 * Install HII protocol and packages for SNP device
643 *
644 * @v snpdev SNP device
645 * @ret rc Return status code
646 */
647 int efi_snp_hii_install ( struct efi_snp_device *snpdev ) {
648 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
649 int efirc;
650 int rc;
651
652 /* Do nothing if HII database protocol is not supported */
653 if ( ! efihii ) {
654 rc = -ENOTSUP;
655 goto err_no_hii;
656 }
657
658 /* Initialise HII protocol */
659 memcpy ( &snpdev->hii, &efi_snp_device_hii, sizeof ( snpdev->hii ) );
660
661 /* Create HII package list */
662 snpdev->package_list = efi_snp_hii_package_list ( snpdev );
663 if ( ! snpdev->package_list ) {
664 DBGC ( snpdev, "SNPDEV %p could not create HII package list\n",
665 snpdev );
666 rc = -ENOMEM;
667 goto err_build_package_list;
668 }
669
670 /* Add HII packages */
671 if ( ( efirc = efihii->NewPackageList ( efihii, snpdev->package_list,
672 snpdev->handle,
673 &snpdev->hii_handle ) ) != 0 ) {
674 rc = -EEFI ( efirc );
675 DBGC ( snpdev, "SNPDEV %p could not add HII packages: %s\n",
676 snpdev, strerror ( rc ) );
677 goto err_new_package_list;
678 }
679
680 /* Install HII protocol */
681 if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
682 &snpdev->handle,
683 &efi_hii_config_access_protocol_guid, &snpdev->hii,
684 NULL ) ) != 0 ) {
685 rc = -EEFI ( efirc );
686 DBGC ( snpdev, "SNPDEV %p could not install HII protocol: %s\n",
687 snpdev, strerror ( rc ) );
688 goto err_install_protocol;
689 }
690
691 return 0;
692
693 bs->UninstallMultipleProtocolInterfaces (
694 snpdev->handle,
695 &efi_hii_config_access_protocol_guid, &snpdev->hii,
696 NULL );
697 err_install_protocol:
698 efihii->RemovePackageList ( efihii, snpdev->hii_handle );
699 err_new_package_list:
700 free ( snpdev->package_list );
701 snpdev->package_list = NULL;
702 err_build_package_list:
703 err_no_hii:
704 return rc;
705 }
706
707 /**
708 * Uninstall HII protocol and package for SNP device
709 *
710 * @v snpdev SNP device
711 */
712 void efi_snp_hii_uninstall ( struct efi_snp_device *snpdev ) {
713 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
714
715 /* Do nothing if HII database protocol is not supported */
716 if ( ! efihii )
717 return;
718
719 /* Uninstall protocols and remove package list */
720 bs->UninstallMultipleProtocolInterfaces (
721 snpdev->handle,
722 &efi_hii_config_access_protocol_guid, &snpdev->hii,
723 NULL );
724 efihii->RemovePackageList ( efihii, snpdev->hii_handle );
725 free ( snpdev->package_list );
726 snpdev->package_list = NULL;
727 }