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