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