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