mirror of https://github.com/ipxe/ipxe.git
[efi] Provide component name protocol and device path protocol interfaces
Include a minimal component name protocol so that the driver name shows up as something other than "<UNKNOWN>" in the driver list, and a device path protocol so that the network interface shows up as a separate device in the device list, rather than being attached directly to the PCI device. Incidentally, the EFI component name protocol reaches new depths for signal-to-noise ratio in program code. A typical instance within the EFI development kit will use an additional 300 lines of code to provide slightly less functionality than GNU gettext achieves with three additional characters.pull/1/head
parent
8fd81349b3
commit
cced04ef3b
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -961,6 +1046,50 @@ static EFI_DRIVER_BINDING_PROTOCOL efi_snp_binding = {
|
|||
NULL
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
|
@ -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 );
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue