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 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 FILE_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>
66 #include <ipxe/efi/efi_strings.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  */
90 static 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  */
103 static 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  */
129 static 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  */
249 static int efi_snp_hii_append ( struct efi_snp_device *snpdev __unused,
250  const char *key, const char *value,
251  wchar_t **results ) {
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  */
284 static 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 */
313  setting = find_setting ( key );
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  */
385 static 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 */
413  setting = find_setting ( key );
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  */
472 static 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  */
538 static 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 );
558  return EFI_INVALID_PARAMETER;
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  */
599 static 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  */
633 static 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 */
649  .RouteConfig = efi_snp_hii_route_config,
650  .Callback = efi_snp_hii_callback,
651 };
652 
653 /**
654  * Install HII protocol and packages for SNP device
655  *
656  * @v snpdev SNP device
657  * @ret rc Return status code
658  */
659 int efi_snp_hii_install ( struct efi_snp_device *snpdev ) {
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 )
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  */
797 int efi_snp_hii_uninstall ( struct efi_snp_device *snpdev ) {
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 ) &&
809  ( ( efirc = bs->UninstallMultipleProtocolInterfaces (
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 )
820  if ( ( ! efi_shutdown_in_progress ) &&
821  ( ( efirc = bs->UninstallMultipleProtocolInterfaces (
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 }
const char product_short_name[]
Product short name string.
Definition: version.c:77
EFI human interface infrastructure.
A process.
Definition: process.h:18
EFI_BOOT_SERVICES * BootServices
A pointer to the EFI Boot Services Table.
Definition: UefiSpec.h:2099
#define EINVAL
Invalid argument.
Definition: errno.h:429
#define EFI_UNSUPPORTED
Enumeration of EFI_STATUS.
Definition: UefiBaseType.h:118
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
const char * name
Definition: ath9k_hw.c:1986
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
uint64_t origin
Origin.
Definition: hyperv.h:20
#define EEFI(efirc)
Convert an EFI status code to an iPXE status code.
Definition: efi.h:175
static void efi_ifr_init(struct efi_ifr_builder *ifr)
Initialise IFR builder.
Definition: efi_hii.h:49
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
int nvo_applies(struct settings *settings __unused, const struct setting *setting)
Check applicability of NVO setting.
Definition: nvo.c:200
void efi_ifr_end_op(struct efi_ifr_builder *ifr)
Add end opcode to IFR builder.
Definition: efi_hii.c:133
unsigned long strtoul(const char *string, char **endp, int base)
Convert string to numeric value.
Definition: string.c:485
static void efi_snp_hii_random_guid(EFI_GUID *guid)
Generate a random GUID.
Definition: efi_snp_hii.c:114
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
static EFI_GUID efi_hii_ibm_ucm_compliant_formset_guid
EFI IBM UCM compliant formset GUID.
Definition: efi_snp_hii.c:78
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
128 bit buffer containing a unique identifier value.
Definition: Base.h:216
Error codes.
EFI_HII_DATABASE_REMOVE_PACK RemovePackageList
Definition: HiiDatabase.h:507
#define HARDWARE_DEVICE_PATH
Hardware Device Paths.
Definition: DevicePath.h:71
EFI strings.
uint32_t type
Operating system type.
Definition: ena.h:12
#define sprintf(buf, fmt,...)
Write a formatted string to a buffer.
Definition: stdio.h:37
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.
Definition: efi_snp_hii.c:249
#define DBGC(...)
Definition: compiler.h:505
FILE_SECBOOT(PERMITTED)
char name[40]
Name.
Definition: device.h:79
EFI_HII_ACCESS_EXTRACT_CONFIG ExtractConfig
EFI_INSTALL_MULTIPLE_PROTOCOL_INTERFACES InstallMultipleProtocolInterfaces
Definition: UefiSpec.h:2010
uint32_t string
Definition: multiboot.h:14
int strcasecmp(const char *first, const char *second)
Compare case-insensitive strings.
Definition: string.c:209
size_t efi_path_len(EFI_DEVICE_PATH_PROTOCOL *path)
Find length of device path (excluding terminator)
Definition: efi_path.c:174
Branding configuration.
This protocol can be used on any device handle to obtain generic path/location information concerning...
Definition: DevicePath.h:46
const char * description
Description.
Definition: settings.h:31
int efi_child_add(EFI_HANDLE parent, EFI_HANDLE child)
Add EFI device as child of another EFI device.
Definition: efi_utils.c:111
CHAR16 * EFI_STRING
EFI_HANDLE hii_child_handle
EFI child handle for HII association.
Definition: efi_snp.h:67
unsigned char UINT8
static const char * netdev_addr(struct net_device *netdev)
Get printable network device link-layer address.
Definition: netdevice.h:542
EFI_HII_CONFIG_ACCESS_PROTOCOL hii
HII configuration access protocol.
Definition: efi_snp.h:63
static struct settings * netdev_settings(struct net_device *netdev)
Get per-netdevice configuration settings block.
Definition: netdevice.h:587
EFI_HANDLE handle
EFI device handle.
Definition: efi_snp.h:37
size_t wcslen(const wchar_t *string)
Calculate length of wide-character string.
Definition: wchar.c:57
EFI_GUID efi_hii_config_access_protocol_guid
HII configuration access protocol GUID.
Definition: efi_guid.c:221
EFI utilities.
#define ENOTSUP
Operation not supported.
Definition: errno.h:590
static void efi_path_terminate(EFI_DEVICE_PATH_PROTOCOL *end)
Terminate device path.
Definition: efi_path.h:31
UINTN EFI_BROWSER_ACTION_REQUEST
Definition: FormBrowser2.h:50
This protocol provides a callable interface between the HII and drivers.
const char * name
Name.
Definition: settings.h:29
#define SETTINGS
Configuration setting table.
Definition: settings.h:54
struct net_device * netdev
The underlying iPXE network device.
Definition: efi_snp.h:33
unsigned long tmp
Definition: linux_pci.h:65
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
uint64_t tag
Setting tag, if applicable.
Definition: settings.h:44
void efi_child_del(EFI_HANDLE parent, EFI_HANDLE child)
Remove EFI device as child of another EFI device.
Definition: efi_utils.c:138
EFI_HII_HANDLE hii_handle
HII handle.
Definition: efi_snp.h:71
EFI_GUID Guid
Vendor-assigned GUID that defines the data that follows.
Definition: DevicePath.h:148
#define ENOMEM
Not enough space.
Definition: errno.h:535
A hardware device.
Definition: device.h:77
void * memcpy(void *dest, const void *src, size_t len) __nonnull
int efi_snp_hii_uninstall(struct efi_snp_device *snpdev)
Uninstall HII protocol and package for SNP device.
Definition: efi_snp_hii.c:797
Database manager for HII-related data structures.
Definition: HiiDatabase.h:505
static void efi_snp_hii_questions(struct efi_snp_device *snpdev, struct efi_ifr_builder *ifr, unsigned int varstore_id)
Generate EFI SNP questions.
Definition: efi_snp_hii.c:129
int efi_snp_hii_install(struct efi_snp_device *snpdev)
Install HII protocol and packages for SNP device.
Definition: efi_snp_hii.c:659
EFI_DEVICE_PATH_PROTOCOL Header
Definition: DevicePath.h:144
EFI_HII_PACKAGE_LIST_HEADER * package_list
HII package list.
Definition: efi_snp.h:65
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.
Definition: efi_snp_hii.c:472
#define PRODUCT_SETTING_URI
Definition: branding.h:171
#define container_of(ptr, type, field)
Get containing structure.
Definition: stddef.h:36
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.
Definition: efi_snp_hii.c:284
static EFI_STATUS EFIAPI efi_snp_hii_route_config(const EFI_HII_CONFIG_ACCESS_PROTOCOL *hii, EFI_STRING config, EFI_STRING *progress)
Store configuration.
Definition: efi_snp_hii.c:600
pseudo_bit_t value[0x00020]
Definition: arbel.h:13
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
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
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.
Definition: efi_snp_hii.c:385
#define HW_VENDOR_DP
Hardware Vendor Device Path SubType.
Definition: DevicePath.h:136
The Vendor Device Path allows the creation of vendor-defined Device Paths.
Definition: DevicePath.h:143
ring len
Length.
Definition: dwmac.h:231
static struct net_device * netdev
Definition: gdbudp.c:53
int efi_snprintf(wchar_t *wbuf, size_t wsize, const char *fmt,...)
Write a formatted string to a buffer.
Definition: efi_strings.c:107
static int efi_snp_hii_setting_applies(struct efi_snp_device *snpdev, struct setting *setting)
Check whether or not setting is applicable.
Definition: efi_snp_hii.c:103
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
#define EFI_HII_PLATFORM_SETUP_FORMSET_GUID
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
const char * driver_name
Driver name.
Definition: device.h:81
static EFI_GUID efi_hii_platform_setup_formset_guid
EFI platform setup formset GUID.
Definition: efi_snp_hii.c:74
EFI null interfaces.
unsigned int varstore_id
Current variable store identifier.
Definition: efi_hii.h:34
Configuration settings.
int storef_setting(struct settings *settings, const struct setting *setting, const char *value)
Store formatted value of setting.
Definition: settings.c:1320
Non-volatile stored options.
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:79
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:55
#define EFIAPI
void * zalloc(size_t size)
Allocate cleared memory.
Definition: malloc.c:662
EFI Boot Services Table.
Definition: UefiSpec.h:1931
void efi_nullify_hii(EFI_HII_CONFIG_ACCESS_PROTOCOL *hii)
Nullify HII configuration access protocol.
Definition: efi_null.c:344
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition: tables.h:386
A network device.
Definition: netdevice.h:353
EFI_UNINSTALL_MULTIPLE_PROTOCOL_INTERFACES UninstallMultipleProtocolInterfaces
Definition: UefiSpec.h:2011
long int random(void)
Generate a pseudo-random number between 0 and 2147483647L or 2147483562?
Definition: random.c:32
An SNP device.
Definition: efi_snp.h:29
#define ENODEV
No such device.
Definition: errno.h:510
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
size_t strlen(const char *src)
Get length of string.
Definition: string.c:244
A settings block.
Definition: settings.h:133
const char product_version[]
Product version string.
Definition: version.c:71
unsigned char uint8_t
Definition: stdint.h:10
EFI device paths.
static EFI_HII_PACKAGE_LIST_HEADER * efi_snp_hii_package_list(struct efi_snp_device *snpdev)
Build HII package list for SNP device.
Definition: efi_snp_hii.c:164
EFI_DEVICE_PATH_PROTOCOL * hii_child_path
Device path of HII child handle.
Definition: efi_snp.h:69
#define EFI_INVALID_PARAMETER
Enumeration of EFI_STATUS.
Definition: UefiBaseType.h:117
static EFI_HII_CONFIG_ACCESS_PROTOCOL efi_snp_device_hii
HII configuration access protocol.
Definition: efi_snp_hii.c:647
EFI_GUID efi_device_path_protocol_guid
Device path protocol GUID.
Definition: efi_guid.c:169
Version number.
EFI_FREE_POOL FreePool
Definition: UefiSpec.h:1950
void efi_ifr_free(struct efi_ifr_builder *ifr)
Free memory used by IFR builder.
Definition: efi_hii.c:506
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.
Definition: efi_snp_hii.c:539
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
EFI API.
A setting.
Definition: settings.h:24
uint64_t guid
GUID.
Definition: edd.h:31
#define EFI_HII_IBM_UCM_COMPLIANT_FORMSET_GUID
GUID indicating formset compliance for IBM Unified Configuration Manager.
Definition: efi_hii.h:17
struct device * dev
Underlying hardware device.
Definition: netdevice.h:365
Network device management.
static int setting_exists(struct settings *settings, const struct setting *setting)
Check existence of predefined setting.
Definition: settings.h:546
UINT8 Length[2]
Specific Device Path data.
Definition: DevicePath.h:59
unsigned int efi_ifr_string(struct efi_ifr_builder *ifr, const char *fmt,...)
Add string to IFR builder.
Definition: efi_hii.c:46
RETURN_STATUS EFI_STATUS
Function return status for EFI API.
Definition: UefiBaseType.h:32
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
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.
Definition: efi_snp_hii.c:634
u8 request[0]
List of IEs requested.
Definition: ieee80211.h:16
Device model.
EFI_HII_DATABASE_NEW_PACK NewPackageList
Definition: HiiDatabase.h:506
UINT8 Type
0x01 Hardware Device Path.
Definition: DevicePath.h:47
UINT16 EFI_QUESTION_ID
#define NVO_SETTINGS_NAME
Name of non-volatile options settings block.
Definition: nvo.h:47
#define EFI_NETWORK_DEVICE_CLASS
Definition: MdeModuleHii.h:102
EFI_SYSTEM_TABLE * efi_systab
iPXE EFI SNP interface
An EFI IFR builder.
Definition: efi_hii.h:22
const char product_name[]
Product name string.
Definition: version.c:74
The data portions of a loaded Boot Serves Driver, and the default data allocation type used by a Boot...
struct setting * find_setting(const char *name)
Find predefined setting.
Definition: settings.c:1467
struct settings * find_child_settings(struct settings *parent, const char *name)
Find child settings block.
Definition: settings.c:280
EFI_DEVICE_PATH_PROTOCOL * path
The device path.
Definition: efi_snp.h:79
The header found at the start of each package list.
int setting_cmp(const struct setting *a, const struct setting *b)
Compare two settings.
Definition: settings.c:1121
#define NULL
NULL pointer (VOID *)
Definition: Base.h:322
EFI_REQUEST_PROTOCOL(EFI_HII_DATABASE_PROTOCOL, &efihii)
String functions.
union @391 key
Sense key.
Definition: scsi.h:18
#define EFIRC(rc)
Convert an iPXE status code to an EFI status code.
Definition: efi.h:167
UINTN EFI_BROWSER_ACTION
String functions.
EFI_ALLOCATE_POOL AllocatePool
Definition: UefiSpec.h:1949
int efi_shutdown_in_progress
EFI shutdown is in progress.
Definition: efi_init.c:60
static EFI_HII_DATABASE_PROTOCOL * efihii
EFI HII database protocol.
Definition: efi_snp_hii.c:81