Browse Source

[efi] Install the HII config access protocol on a child of the SNP handle

In edk2, there are several drivers that associate HII forms (and
corresponding config access protocol instances) with each individual
network device.  (In this context, "network device" means the EFI
handle on which the SNP protocol is installed, and on which the device
path ending with the MAC() node is installed also.)  Such edk2 drivers
are, for example: Ip4Dxe, HttpBootDxe, VlanConfigDxe.

In UEFI, any given handle can carry at most one instance of a specific
protocol (see e.g. the specification of the InstallProtocolInterface()
boot service).  This implies that the class of drivers mentioned above
can't install their EFI_HII_CONFIG_ACCESS_PROTOCOL instances on the
SNP handle directly -- they would conflict with each other.
Accordingly, each of those edk2 drivers creates a "private" child
handle under the SNP handle, and installs its config access protocol
(and corresponding HII package list) on its child handle.

The device path for the child handle is traditionally derived by
appending a Hardware Vendor Device Path node after the MAC() node.
The VenHw() nodes in question consist of a GUID (by definition), and
no trailing data (by choice).  The purpose of these VenHw() nodes is
only that all the child nodes can be uniquely identified by device
path.

At the moment iPXE does not follow this pattern.  It doesn't run into
a conflict when it installs its EFI_HII_CONFIG_ACCESS_PROTOCOL
directly on the SNP handle, but that's only because iPXE is the sole
driver not following the pattern.  This behavior seems risky (one
might call it a "latent bug"); better align iPXE with the edk2 custom.

Cc: Michael Brown <mcb30@ipxe.org>
Cc: Gary Lin <glin@suse.com>
Cc: Ladi Prosek <lprosek@redhat.com>
Ref: http://thread.gmane.org/gmane.comp.bios.edk2.devel/13494/focus=13532
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Ladi Prosek <lprosek@redhat.com>
Modified-by: Michael Brown <mcb30@ipxe.org>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Laszlo Ersek 8 years ago
parent
commit
d6817943d1
2 changed files with 75 additions and 4 deletions
  1. 4
    0
      src/include/ipxe/efi/efi_snp.h
  2. 71
    4
      src/interface/efi/efi_snp_hii.c

+ 4
- 0
src/include/ipxe/efi/efi_snp.h View File

57
 	EFI_HII_CONFIG_ACCESS_PROTOCOL hii;
57
 	EFI_HII_CONFIG_ACCESS_PROTOCOL hii;
58
 	/** HII package list */
58
 	/** HII package list */
59
 	EFI_HII_PACKAGE_LIST_HEADER *package_list;
59
 	EFI_HII_PACKAGE_LIST_HEADER *package_list;
60
+	/** EFI child handle for HII association */
61
+	EFI_HANDLE hii_child_handle;
62
+	/** Device path of HII child handle */
63
+	EFI_DEVICE_PATH_PROTOCOL *hii_child_path;
60
 	/** HII handle */
64
 	/** HII handle */
61
 	EFI_HII_HANDLE hii_handle;
65
 	EFI_HII_HANDLE hii_handle;
62
 	/** Device name */
66
 	/** Device name */

+ 71
- 4
src/interface/efi/efi_snp_hii.c View File

63
 #include <ipxe/efi/efi_hii.h>
63
 #include <ipxe/efi/efi_hii.h>
64
 #include <ipxe/efi/efi_snp.h>
64
 #include <ipxe/efi/efi_snp.h>
65
 #include <ipxe/efi/efi_strings.h>
65
 #include <ipxe/efi/efi_strings.h>
66
+#include <ipxe/efi/efi_utils.h>
66
 #include <config/branding.h>
67
 #include <config/branding.h>
67
 
68
 
68
 /** EFI platform setup formset GUID */
69
 /** EFI platform setup formset GUID */
653
  */
654
  */
654
 int efi_snp_hii_install ( struct efi_snp_device *snpdev ) {
655
 int efi_snp_hii_install ( struct efi_snp_device *snpdev ) {
655
 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
656
 	EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
657
+	VENDOR_DEVICE_PATH *vendor_path;
658
+	EFI_DEVICE_PATH_PROTOCOL *path_end;
659
+	size_t path_prefix_len;
656
 	int efirc;
660
 	int efirc;
657
 	int rc;
661
 	int rc;
658
 
662
 
674
 		goto err_build_package_list;
678
 		goto err_build_package_list;
675
 	}
679
 	}
676
 
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;
704
+	path_end->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
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,
710
+			&efi_device_path_protocol_guid, snpdev->hii_child_path,
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
+
677
 	/* Add HII packages */
718
 	/* Add HII packages */
678
 	if ( ( efirc = efihii->NewPackageList ( efihii, snpdev->package_list,
719
 	if ( ( efirc = efihii->NewPackageList ( efihii, snpdev->package_list,
679
-						snpdev->handle,
720
+						snpdev->hii_child_handle,
680
 						&snpdev->hii_handle ) ) != 0 ) {
721
 						&snpdev->hii_handle ) ) != 0 ) {
681
 		rc = -EEFI ( efirc );
722
 		rc = -EEFI ( efirc );
682
 		DBGC ( snpdev, "SNPDEV %p could not add HII packages: %s\n",
723
 		DBGC ( snpdev, "SNPDEV %p could not add HII packages: %s\n",
686
 
727
 
687
 	/* Install HII protocol */
728
 	/* Install HII protocol */
688
 	if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
729
 	if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
689
-			 &snpdev->handle,
730
+			 &snpdev->hii_child_handle,
690
 			 &efi_hii_config_access_protocol_guid, &snpdev->hii,
731
 			 &efi_hii_config_access_protocol_guid, &snpdev->hii,
691
 			 NULL ) ) != 0 ) {
732
 			 NULL ) ) != 0 ) {
692
 		rc = -EEFI ( efirc );
733
 		rc = -EEFI ( efirc );
695
 		goto err_install_protocol;
736
 		goto err_install_protocol;
696
 	}
737
 	}
697
 
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
+
698
 	return 0;
748
 	return 0;
699
 
749
 
750
+	efi_child_del ( snpdev->handle, snpdev->hii_child_handle );
751
+ err_efi_child_add:
700
 	bs->UninstallMultipleProtocolInterfaces (
752
 	bs->UninstallMultipleProtocolInterfaces (
701
-			snpdev->handle,
753
+			snpdev->hii_child_handle,
702
 			&efi_hii_config_access_protocol_guid, &snpdev->hii,
754
 			&efi_hii_config_access_protocol_guid, &snpdev->hii,
703
 			NULL );
755
 			NULL );
704
  err_install_protocol:
756
  err_install_protocol:
705
 	efihii->RemovePackageList ( efihii, snpdev->hii_handle );
757
 	efihii->RemovePackageList ( efihii, snpdev->hii_handle );
706
  err_new_package_list:
758
  err_new_package_list:
759
+	bs->UninstallMultipleProtocolInterfaces (
760
+			snpdev->hii_child_handle,
761
+			&efi_device_path_protocol_guid, snpdev->hii_child_path,
762
+			NULL );
763
+ err_hii_child_handle:
764
+	free ( snpdev->hii_child_path );
765
+	snpdev->hii_child_path = NULL;
766
+ err_alloc_child_path:
707
 	free ( snpdev->package_list );
767
 	free ( snpdev->package_list );
708
 	snpdev->package_list = NULL;
768
 	snpdev->package_list = NULL;
709
  err_build_package_list:
769
  err_build_package_list:
724
 		return;
784
 		return;
725
 
785
 
726
 	/* Uninstall protocols and remove package list */
786
 	/* Uninstall protocols and remove package list */
787
+	efi_child_del ( snpdev->handle, snpdev->hii_child_handle );
727
 	bs->UninstallMultipleProtocolInterfaces (
788
 	bs->UninstallMultipleProtocolInterfaces (
728
-			snpdev->handle,
789
+			snpdev->hii_child_handle,
729
 			&efi_hii_config_access_protocol_guid, &snpdev->hii,
790
 			&efi_hii_config_access_protocol_guid, &snpdev->hii,
730
 			NULL );
791
 			NULL );
731
 	efihii->RemovePackageList ( efihii, snpdev->hii_handle );
792
 	efihii->RemovePackageList ( efihii, snpdev->hii_handle );
793
+	bs->UninstallMultipleProtocolInterfaces (
794
+			snpdev->hii_child_handle,
795
+			&efi_device_path_protocol_guid, snpdev->hii_child_path,
796
+			NULL );
797
+	free ( snpdev->hii_child_path );
798
+	snpdev->hii_child_path = NULL;
732
 	free ( snpdev->package_list );
799
 	free ( snpdev->package_list );
733
 	snpdev->package_list = NULL;
800
 	snpdev->package_list = NULL;
734
 }
801
 }

Loading…
Cancel
Save