summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/include/gpxe/efi/Protocol/ComponentName2.h174
-rw-r--r--src/interface/efi/efi_snp.c173
2 files changed, 325 insertions, 22 deletions
diff --git a/src/include/gpxe/efi/Protocol/ComponentName2.h b/src/include/gpxe/efi/Protocol/ComponentName2.h
new file mode 100644
index 00000000..0f010142
--- /dev/null
+++ b/src/include/gpxe/efi/Protocol/ComponentName2.h
@@ -0,0 +1,174 @@
+/** @file
+ UEFI Component Name 2 Protocol as defined in the UEFI 2.1 specification.
+ This protocol is used to retrieve user readable names of drivers
+ and controllers managed by UEFI Drivers.
+
+ Copyright (c) 2006 - 2008, Intel Corporation
+ All rights reserved. This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __EFI_COMPONENT_NAME2_H__
+#define __EFI_COMPONENT_NAME2_H__
+
+///
+/// Global ID for the Component Name Protocol
+///
+#define EFI_COMPONENT_NAME2_PROTOCOL_GUID \
+ {0x6a7a5cff, 0xe8d9, 0x4f70, { 0xba, 0xda, 0x75, 0xab, 0x30, 0x25, 0xce, 0x14 } }
+
+typedef struct _EFI_COMPONENT_NAME2_PROTOCOL EFI_COMPONENT_NAME2_PROTOCOL;
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of
+ the EFI Driver.
+
+ @param This A pointer to the
+ EFI_COMPONENT_NAME2_PROTOCOL instance.
+
+ @param Language A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller
+ is requesting, and it must match one of the
+ languages specified in SupportedLanguages.
+ The number of languages supported by a
+ driver is up to the driver writer. Language
+ is specified in RFC 3066 language code
+ format.
+
+ @param DriverName A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the
+ Driver specified by This and the
+ language specified by Language
+ was returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This
+ does not support the language
+ specified by Language.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_COMPONENT_NAME2_GET_DRIVER_NAME)(
+ IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of
+ the controller that is being managed by an EFI Driver.
+
+ @param This A pointer to the
+ EFI_COMPONENT_NAME2_PROTOCOL instance.
+
+ @param ControllerHandle The handle of a controller that the
+ driver specified by This is managing.
+ This handle specifies the controller
+ whose name is to be returned.
+
+ @param ChildHandle The handle of the child controller to
+ retrieve the name of. This is an
+ optional parameter that may be NULL.
+ It will be NULL for device drivers.
+ It will also be NULL for a bus
+ drivers that wish to retrieve the
+ name of the bus controller. It will
+ not be NULL for a bus driver that
+ wishes to retrieve the name of a
+ child controller.
+
+ @param Language A pointer to a Null-terminated ASCII
+ string array indicating the language.
+ This is the language of the driver
+ name that the caller is requesting,
+ and it must match one of the
+ languages specified in
+ SupportedLanguages. The number of
+ languages supported by a driver is up
+ to the driver writer. Language is
+ specified in RFC 3066 language code
+ format.
+
+ @param ControllerName A pointer to the Unicode string to
+ return. This Unicode string is the
+ name of the controller specified by
+ ControllerHandle and ChildHandle in
+ the language specified by Language
+ from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user
+ readable name in the language
+ specified by Language for the
+ driver specified by This was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it
+ is not a valid EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is
+ not currently managing the
+ controller specified by
+ ControllerHandle and
+ ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This
+ does not support the language
+ specified by Language.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)(
+ IN EFI_COMPONENT_NAME2_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+///
+/// This protocol is used to retrieve user readable names of drivers
+/// and controllers managed by UEFI Drivers.
+///
+struct _EFI_COMPONENT_NAME2_PROTOCOL {
+ EFI_COMPONENT_NAME2_GET_DRIVER_NAME GetDriverName;
+ EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME GetControllerName;
+
+ ///
+ /// A Null-terminated ASCII string array that contains one or more
+ /// supported language codes. This is the list of language codes that
+ /// this protocol supports. The number of languages supported by a
+ /// driver is up to the driver writer. SupportedLanguages is
+ /// specified in RFC 3066 format.
+ ///
+ CHAR8 *SupportedLanguages;
+};
+
+extern EFI_GUID gEfiComponentName2ProtocolGuid;
+
+#endif
diff --git a/src/interface/efi/efi_snp.c b/src/interface/efi/efi_snp.c
index 102130c8..9f92666b 100644
--- a/src/interface/efi/efi_snp.c
+++ b/src/interface/efi/efi_snp.c
@@ -29,6 +29,8 @@
#include <gpxe/efi/Protocol/DriverBinding.h>
#include <gpxe/efi/Protocol/PciIo.h>
#include <gpxe/efi/Protocol/SimpleNetwork.h>
+#include <gpxe/efi/Protocol/ComponentName2.h>
+#include <config/general.h>
/** @file
*
@@ -40,6 +42,8 @@
struct efi_snp_device {
/** The underlying gPXE network device */
struct net_device *netdev;
+ /** EFI device handle */
+ EFI_HANDLE handle;
/** The SNP structure itself */
EFI_SIMPLE_NETWORK_PROTOCOL snp;
/** The SNP "mode" (parameters) */
@@ -58,6 +62,14 @@ struct efi_snp_device {
unsigned int rx_count_interrupts;
/** Outstanding RX packet count (via WaitForPacket event) */
unsigned int rx_count_events;
+ /** Device name */
+ wchar_t name[ sizeof ( ( ( struct net_device * ) NULL )->name ) ];
+ /** The device path
+ *
+ * This field is variable in size and must appear at the end
+ * of the structure.
+ */
+ EFI_DEVICE_PATH_PROTOCOL path;
};
/** EFI simple network protocol GUID */
@@ -68,6 +80,14 @@ static EFI_GUID efi_simple_network_protocol_guid
static EFI_GUID efi_driver_binding_protocol_guid
= EFI_DRIVER_BINDING_PROTOCOL_GUID;
+/** EFI component name protocol GUID */
+static EFI_GUID efi_component_name2_protocol_guid
+ = EFI_COMPONENT_NAME2_PROTOCOL_GUID;
+
+/** EFI device path protocol GUID */
+static EFI_GUID efi_device_path_protocol_guid
+ = EFI_DEVICE_PATH_PROTOCOL_GUID;
+
/** EFI PCI I/O protocol GUID */
static EFI_GUID efi_pci_io_protocol_guid
= EFI_PCI_IO_PROTOCOL_GUID;
@@ -784,7 +804,7 @@ efi_snp_snpdev ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device ) {
EFI_SIMPLE_NETWORK_PROTOCOL *snp;
void *interface;
} u;
- struct efi_snp_device *snpdev;
+ struct efi_snp_device *snpdev = NULL;
EFI_STATUS efirc;
if ( ( efirc = bs->OpenProtocol ( device,
@@ -795,12 +815,16 @@ efi_snp_snpdev ( EFI_DRIVER_BINDING_PROTOCOL *driver, EFI_HANDLE device ) {
EFI_OPEN_PROTOCOL_GET_PROTOCOL))!=0){
DBGC ( driver, "SNPDRV %p device %p could not locate SNP: "
"%s\n", driver, device, efi_strerror ( efirc ) );
- return NULL;
+ goto err_no_snp;
}
snpdev = container_of ( u.snp, struct efi_snp_device, snp );
DBGCP ( driver, "SNPDRV %p device %p is SNPDEV %p\n",
driver, device, snpdev );
+
+ bs->CloseProtocol ( device, &efi_simple_network_protocol_guid,
+ driver->DriverBindingHandle, device );
+ err_no_snp:
return snpdev;
}
@@ -838,15 +862,41 @@ efi_snp_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver,
EFI_HANDLE device,
EFI_DEVICE_PATH_PROTOCOL *child ) {
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
+ EFI_DEVICE_PATH_PROTOCOL *path;
+ EFI_DEVICE_PATH_PROTOCOL *subpath;
+ MAC_ADDR_DEVICE_PATH *macpath;
struct efi_snp_device *snpdev;
struct net_device *netdev;
+ size_t subpath_len;
+ size_t path_prefix_len = 0;
+ unsigned int i;
EFI_STATUS efirc;
DBGCP ( driver, "SNPDRV %p DRIVER_START %p (%p)\n",
driver, device, child );
+ /* Determine device path prefix length */
+ if ( ( efirc = bs->OpenProtocol ( device,
+ &efi_device_path_protocol_guid,
+ ( void * ) &path,
+ driver->DriverBindingHandle,
+ device,
+ EFI_OPEN_PROTOCOL_BY_DRIVER )) !=0 ){
+ DBGCP ( driver, "SNPDRV %p device %p has no device path\n",
+ driver, device );
+ goto err_no_device_path;
+ }
+ subpath = path;
+ while ( subpath->Type != END_DEVICE_PATH_TYPE ) {
+ subpath_len = ( ( subpath->Length[1] << 8 ) |
+ subpath->Length[0] );
+ path_prefix_len += subpath_len;
+ subpath = ( ( ( void * ) subpath ) + subpath_len );
+ }
+
/* Allocate the SNP device */
- snpdev = zalloc ( sizeof ( *snpdev ) );
+ snpdev = zalloc ( sizeof ( *snpdev ) + path_prefix_len +
+ sizeof ( *macpath ) );
if ( ! snpdev ) {
efirc = EFI_OUT_OF_RESOURCES;
goto err_alloc_snp;
@@ -886,22 +936,50 @@ efi_snp_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver,
snpdev->mode.State = EfiSimpleNetworkStopped;
efi_snp_set_mode ( snpdev );
+ /* Populate the device name */
+ for ( i = 0 ; i < sizeof ( netdev->name ) ; i++ ) {
+ /* Damn Unicode names */
+ assert ( i < ( sizeof ( snpdev->name ) /
+ sizeof ( snpdev->name[0] ) ) );
+ snpdev->name[i] = netdev->name[i];
+ }
+
+ /* Populate the device path */
+ memcpy ( &snpdev->path, path, path_prefix_len );
+ macpath = ( ( ( void * ) &snpdev->path ) + path_prefix_len );
+ subpath = ( ( void * ) ( macpath + 1 ) );
+ memset ( macpath, 0, sizeof ( *macpath ) );
+ macpath->Header.Type = MESSAGING_DEVICE_PATH;
+ macpath->Header.SubType = MSG_MAC_ADDR_DP;
+ macpath->Header.Length[0] = sizeof ( *macpath );
+ memcpy ( &macpath->MacAddress, netdev->ll_addr,
+ sizeof ( macpath->MacAddress ) );
+ macpath->IfType = ntohs ( netdev->ll_protocol->ll_proto );
+ memset ( subpath, 0, sizeof ( *subpath ) );
+ subpath->Type = END_DEVICE_PATH_TYPE;
+ subpath->SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
+ subpath->Length[0] = sizeof ( *subpath );
+
/* Install the SNP */
- if ( ( efirc = bs->InstallProtocolInterface ( &device,
- &efi_simple_network_protocol_guid,
- EFI_NATIVE_INTERFACE, &snpdev->snp ) ) != 0 ) {
- DBGC ( snpdev, "SNPDEV %p could not install protocol: %s\n",
- snpdev, efi_strerror ( efirc ) );
+ if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
+ &snpdev->handle,
+ &efi_simple_network_protocol_guid, &snpdev->snp,
+ &efi_device_path_protocol_guid, &snpdev->path,
+ NULL ) ) != 0 ) {
+ DBGC ( snpdev, "SNPDEV %p could not install protocols: "
+ "%s\n", snpdev, efi_strerror ( efirc ) );
goto err_install_protocol_interface;
}
- DBGC ( snpdev, "SNPDEV %p installed for %s on device %p\n",
- snpdev, netdev->name, device );
+ DBGC ( snpdev, "SNPDEV %p installed for %s as device %p\n",
+ snpdev, netdev->name, snpdev->handle );
return 0;
- bs->UninstallProtocolInterface ( device,
- &efi_simple_network_protocol_guid,
- &snpdev->snp );
+ bs->UninstallMultipleProtocolInterfaces (
+ snpdev->handle,
+ &efi_simple_network_protocol_guid, &snpdev->snp,
+ &efi_device_path_protocol_guid, &snpdev->path,
+ NULL );
err_install_protocol_interface:
bs->CloseEvent ( snpdev->snp.WaitForPacket );
err_create_event:
@@ -910,6 +988,9 @@ efi_snp_driver_start ( EFI_DRIVER_BINDING_PROTOCOL *driver,
err_no_netdev:
free ( snpdev );
err_alloc_snp:
+ bs->CloseProtocol ( device, &efi_device_path_protocol_guid,
+ driver->DriverBindingHandle, device );
+ err_no_device_path:
return efirc;
}
@@ -942,12 +1023,16 @@ efi_snp_driver_stop ( EFI_DRIVER_BINDING_PROTOCOL *driver,
}
/* Uninstall the SNP */
- bs->UninstallProtocolInterface ( device,
- &efi_simple_network_protocol_guid,
- &snpdev->snp );
+ bs->UninstallMultipleProtocolInterfaces (
+ snpdev->handle,
+ &efi_simple_network_protocol_guid, &snpdev->snp,
+ &efi_device_path_protocol_guid, &snpdev->path,
+ NULL );
bs->CloseEvent ( snpdev->snp.WaitForPacket );
netdev_put ( snpdev->netdev );
free ( snpdev );
+ bs->CloseProtocol ( device, &efi_device_path_protocol_guid,
+ driver->DriverBindingHandle, device );
return 0;
}
@@ -962,6 +1047,50 @@ static EFI_DRIVER_BINDING_PROTOCOL efi_snp_binding = {
};
/**
+ * Look up driver name
+ *
+ * @v wtf Component name protocol
+ * @v language Language to use
+ * @v driver_name Driver name to fill in
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_get_driver_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused,
+ CHAR8 *language __unused, CHAR16 **driver_name ) {
+
+ *driver_name = L"" PRODUCT_SHORT_NAME " Driver";
+ return 0;
+}
+
+/**
+ * Look up controller name
+ *
+ * @v wtf Component name protocol
+ * @v device Device
+ * @v child Child device, or NULL
+ * @v language Language to use
+ * @v driver_name Device name to fill in
+ * @ret efirc EFI status code
+ */
+static EFI_STATUS EFIAPI
+efi_snp_get_controller_name ( EFI_COMPONENT_NAME2_PROTOCOL *wtf __unused,
+ EFI_HANDLE device __unused,
+ EFI_HANDLE child __unused,
+ CHAR8 *language __unused,
+ CHAR16 **controller_name __unused ) {
+
+ /* Just let EFI use the default Device Path Name */
+ return EFI_UNSUPPORTED;
+}
+
+/** EFI SNP component name protocol */
+static EFI_COMPONENT_NAME2_PROTOCOL efi_snp_name = {
+ efi_snp_get_driver_name,
+ efi_snp_get_controller_name,
+ "en"
+};
+
+/**
* Install EFI SNP driver
*
* @ret rc Return status code
@@ -972,12 +1101,12 @@ int efi_snp_install ( void ) {
EFI_STATUS efirc;
driver->ImageHandle = efi_image_handle;
- if ( ( efirc = bs->InstallProtocolInterface (
- &driver->DriverBindingHandle,
- &efi_driver_binding_protocol_guid,
- EFI_NATIVE_INTERFACE,
- driver ) ) != 0 ) {
- DBGC ( driver, "SNPDRV %p could not install driver binding: "
+ if ( ( efirc = bs->InstallMultipleProtocolInterfaces (
+ &driver->DriverBindingHandle,
+ &efi_driver_binding_protocol_guid, driver,
+ &efi_component_name2_protocol_guid, &efi_snp_name,
+ NULL ) ) != 0 ) {
+ DBGC ( driver, "SNPDRV %p could not install protocols: "
"%s\n", driver, efi_strerror ( efirc ) );
return EFIRC_TO_RC ( efirc );
}