NetworkPkg: Move Network library and drivers from MdeModulePkg to NetworkPkg

Signed-off-by: Liming Gao <liming.gao@intel.com>
Cc: Siyuan Fu <siyuan.fu@intel.com>
Cc: Jiaxin Wu <jiaxin.wu@intel.com>
Reviewed-by: Jiaxin Wu <jiaxin.wu@intel.com>
Reviewed-by: Siyuan Fu <siyuan.fu@intel.com>
This commit is contained in:
Liming Gao
2019-05-15 20:02:18 +08:00
parent c0fd7f734e
commit 4542f8b813
147 changed files with 24 additions and 24 deletions

View File

@@ -0,0 +1,354 @@
/** @file
This file contains the callback routines for undi3.1.
the callback routines for Undi3.1 have an extra parameter UniqueId which
stores the interface context for the NIC that snp is trying to talk.
Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Snp.h"
/**
Acquire or release a lock of the exclusive access to a critical section of the
code/data.
This is a callback routine supplied to UNDI3.1 at undi_start time.
New callbacks for 3.1: there won't be a virtual2physical callback for UNDI 3.1
because undi3.1 uses the MemMap call to map the required address by itself!
@param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to
store Undi interface context (Undi does not read or write
this variable).
@param Enable Non-zero indicates acquire; Zero indicates release.
**/
VOID
EFIAPI
SnpUndi32CallbackBlock (
IN UINT64 UniqueId,
IN UINT32 Enable
)
{
SNP_DRIVER *Snp;
Snp = (SNP_DRIVER *) (UINTN) UniqueId;
//
// tcpip was calling snp at tpl_notify and when we acquire a lock that was
// created at a lower level (TPL_CALLBACK) it gives an assert!
//
if (Enable != 0) {
EfiAcquireLock (&Snp->Lock);
} else {
EfiReleaseLock (&Snp->Lock);
}
}
/**
Delay MicroSeconds of micro seconds.
This is a callback routine supplied to UNDI at undi_start time.
@param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to
store Undi interface context (Undi does not read or write
this variable).
@param MicroSeconds Number of micro seconds to pause, ususlly multiple of 10.
**/
VOID
EFIAPI
SnpUndi32CallbackDelay (
IN UINT64 UniqueId,
IN UINT64 MicroSeconds
)
{
if (MicroSeconds != 0) {
gBS->Stall ((UINTN) MicroSeconds);
}
}
/**
IO routine for UNDI3.1.
This is a callback routine supplied to UNDI at undi_start time.
@param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this
to store Undi interface context (Undi does not read or
write this variable).
@param ReadOrWrite Indicates read or write, IO or Memory.
@param NumBytes Number of bytes to read or write.
@param MemOrPortAddr IO or memory address to read from or write to.
@param BufferPtr Memory location to read into or that contains the bytes
to write.
**/
VOID
EFIAPI
SnpUndi32CallbackMemio (
IN UINT64 UniqueId,
IN UINT8 ReadOrWrite,
IN UINT8 NumBytes,
IN UINT64 MemOrPortAddr,
IN OUT UINT64 BufferPtr
)
{
SNP_DRIVER *Snp;
EFI_PCI_IO_PROTOCOL_WIDTH Width;
Snp = (SNP_DRIVER *) (UINTN) UniqueId;
Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 0;
switch (NumBytes) {
case 2:
Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 1;
break;
case 4:
Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 2;
break;
case 8:
Width = (EFI_PCI_IO_PROTOCOL_WIDTH) 3;
break;
}
switch (ReadOrWrite) {
case PXE_IO_READ:
Snp->PciIo->Io.Read (
Snp->PciIo,
Width,
Snp->IoBarIndex, // BAR 1 (for 32bit regs), IO base address
MemOrPortAddr,
1, // count
(VOID *) (UINTN) BufferPtr
);
break;
case PXE_IO_WRITE:
Snp->PciIo->Io.Write (
Snp->PciIo,
Width,
Snp->IoBarIndex, // BAR 1 (for 32bit regs), IO base address
MemOrPortAddr,
1, // count
(VOID *) (UINTN) BufferPtr
);
break;
case PXE_MEM_READ:
Snp->PciIo->Mem.Read (
Snp->PciIo,
Width,
Snp->MemoryBarIndex, // BAR 0, Memory base address
MemOrPortAddr,
1, // count
(VOID *) (UINTN) BufferPtr
);
break;
case PXE_MEM_WRITE:
Snp->PciIo->Mem.Write (
Snp->PciIo,
Width,
Snp->MemoryBarIndex, // BAR 0, Memory base address
MemOrPortAddr,
1, // count
(VOID *) (UINTN) BufferPtr
);
break;
}
return ;
}
/**
Map a CPU address to a device address.
This is a callback routine supplied to UNDI at undi_start time.
@param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to
store Undi interface context (Undi does not read or write
this variable).
@param CpuAddr Virtual address to be mapped.
@param NumBytes Size of memory to be mapped.
@param Direction Direction of data flow for this memory's usage:
cpu->device, device->cpu or both ways.
@param DeviceAddrPtr Pointer to return the mapped device address.
**/
VOID
EFIAPI
SnpUndi32CallbackMap (
IN UINT64 UniqueId,
IN UINT64 CpuAddr,
IN UINT32 NumBytes,
IN UINT32 Direction,
IN OUT UINT64 DeviceAddrPtr
)
{
EFI_PHYSICAL_ADDRESS *DevAddrPtr;
EFI_PCI_IO_PROTOCOL_OPERATION DirectionFlag;
UINTN BuffSize;
SNP_DRIVER *Snp;
UINTN Index;
EFI_STATUS Status;
BuffSize = (UINTN) NumBytes;
Snp = (SNP_DRIVER *) (UINTN) UniqueId;
DevAddrPtr = (EFI_PHYSICAL_ADDRESS *) (UINTN) DeviceAddrPtr;
if (CpuAddr == 0) {
*DevAddrPtr = 0;
return ;
}
switch (Direction) {
case TO_AND_FROM_DEVICE:
DirectionFlag = EfiPciIoOperationBusMasterCommonBuffer;
break;
case FROM_DEVICE:
DirectionFlag = EfiPciIoOperationBusMasterWrite;
break;
case TO_DEVICE:
DirectionFlag = EfiPciIoOperationBusMasterRead;
break;
default:
*DevAddrPtr = 0;
//
// any non zero indicates error!
//
return ;
}
//
// find an unused map_list entry
//
for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {
if (Snp->MapList[Index].VirtualAddress == 0) {
break;
}
}
if (Index >= MAX_MAP_LENGTH) {
DEBUG ((EFI_D_INFO, "SNP maplist is FULL\n"));
*DevAddrPtr = 0;
return ;
}
Snp->MapList[Index].VirtualAddress = (EFI_PHYSICAL_ADDRESS) CpuAddr;
Status = Snp->PciIo->Map (
Snp->PciIo,
DirectionFlag,
(VOID *) (UINTN) CpuAddr,
&BuffSize,
DevAddrPtr,
&(Snp->MapList[Index].MapCookie)
);
if (Status != EFI_SUCCESS) {
*DevAddrPtr = 0;
Snp->MapList[Index].VirtualAddress = 0;
}
return ;
}
/**
Unmap an address that was previously mapped using map callback.
This is a callback routine supplied to UNDI at undi_start time.
@param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to
store. Undi interface context (Undi does not read or write
this variable).
@param CpuAddr Virtual address that was mapped.
@param NumBytes Size of memory mapped.
@param Direction Direction of data flow for this memory's usage:
cpu->device, device->cpu or both ways.
@param DeviceAddr The mapped device address.
**/
VOID
EFIAPI
SnpUndi32CallbackUnmap (
IN UINT64 UniqueId,
IN UINT64 CpuAddr,
IN UINT32 NumBytes,
IN UINT32 Direction,
IN UINT64 DeviceAddr
)
{
SNP_DRIVER *Snp;
UINT16 Index;
Snp = (SNP_DRIVER *) (UINTN) UniqueId;
for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {
if (Snp->MapList[Index].VirtualAddress == CpuAddr) {
break;
}
}
if (Index >= MAX_MAP_LENGTH) {
DEBUG ((EFI_D_ERROR, "SNP could not find a mapping, failed to unmap.\n"));
return ;
}
Snp->PciIo->Unmap (Snp->PciIo, Snp->MapList[Index].MapCookie);
Snp->MapList[Index].VirtualAddress = 0;
Snp->MapList[Index].MapCookie = NULL;
return ;
}
/**
Synchronize the virtual buffer contents with the mapped buffer contents.
This is a callback routine supplied to UNDI at undi_start time. The virtual
and mapped buffers need not correspond to the same physical memory (especially
if the virtual address is > 4GB). Depending on the direction for which the
buffer is mapped, undi will need to synchronize their contents whenever it
writes to/reads from the buffer using either the cpu address or the device
address.
EFI does not provide a sync call since virt=physical, we should just do the
synchronization ourselves here.
@param UniqueId This was supplied to UNDI at Undi_Start, SNP uses this to
store Undi interface context (Undi does not read or write
this variable).
@param CpuAddr Virtual address that was mapped.
@param NumBytes Size of memory mapped.
@param Direction Direction of data flow for this memory's usage:
cpu->device, device->cpu or both ways.
@param DeviceAddr The mapped device address.
**/
VOID
EFIAPI
SnpUndi32CallbackSync (
IN UINT64 UniqueId,
IN UINT64 CpuAddr,
IN UINT32 NumBytes,
IN UINT32 Direction,
IN UINT64 DeviceAddr
)
{
if ((CpuAddr == 0) || (DeviceAddr == 0) || (NumBytes == 0)) {
return ;
}
switch (Direction) {
case FROM_DEVICE:
CopyMem ((UINT8 *) (UINTN) CpuAddr, (UINT8 *) (UINTN) DeviceAddr, NumBytes);
break;
case TO_DEVICE:
CopyMem ((UINT8 *) (UINTN) DeviceAddr, (UINT8 *) (UINTN) CpuAddr, NumBytes);
break;
}
return ;
}

View File

@@ -0,0 +1,430 @@
/** @file
UEFI Component Name(2) protocol implementation for SnpDxe driver.
Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Snp.h"
//
// EFI Component Name Functions
//
/**
Retrieves a Unicode string that is the user readable name of the driver.
This function retrieves the user readable name of a driver in the form of a
Unicode string. If the driver specified by This has a user readable name in
the language specified by Language, then a pointer to the driver name is
returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
by This does not support the language specified by Language,
then EFI_UNSUPPORTED is returned.
@param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param Language[in] 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 4646 or ISO 639-2 language code format.
@param DriverName[out] 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.
**/
EFI_STATUS
EFIAPI
SimpleNetworkComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_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 a driver.
This function retrieves the user readable name of the controller specified by
ControllerHandle and ChildHandle in the form of a Unicode string. If the
driver specified by This has a user readable name in the language specified by
Language, then a pointer to the controller name is returned in ControllerName,
and EFI_SUCCESS is returned. If the driver specified by This is not currently
managing the controller specified by ControllerHandle and ChildHandle,
then EFI_UNSUPPORTED is returned. If the driver specified by This does not
support the language specified by Language, then EFI_UNSUPPORTED is returned.
@param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param ControllerHandle[in] 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[in] 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[in] 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 4646 or ISO 639-2 language code format.
@param ControllerName[out] 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 NULL.
@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.
**/
EFI_STATUS
EFIAPI
SimpleNetworkComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
);
//
// EFI Component Name Protocol
//
GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gSimpleNetworkComponentName = {
SimpleNetworkComponentNameGetDriverName,
SimpleNetworkComponentNameGetControllerName,
"eng"
};
//
// EFI Component Name 2 Protocol
//
GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gSimpleNetworkComponentName2 = {
(EFI_COMPONENT_NAME2_GET_DRIVER_NAME) SimpleNetworkComponentNameGetDriverName,
(EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) SimpleNetworkComponentNameGetControllerName,
"en"
};
GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mSimpleNetworkDriverNameTable[] = {
{
"eng;en",
L"Simple Network Protocol Driver"
},
{
NULL,
NULL
}
};
GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE *gSimpleNetworkControllerNameTable = NULL;
/**
Retrieves a Unicode string that is the user readable name of the driver.
This function retrieves the user readable name of a driver in the form of a
Unicode string. If the driver specified by This has a user readable name in
the language specified by Language, then a pointer to the driver name is
returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
by This does not support the language specified by Language,
then EFI_UNSUPPORTED is returned.
@param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param Language[in] 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 4646 or ISO 639-2 language code format.
@param DriverName[out] 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.
**/
EFI_STATUS
EFIAPI
SimpleNetworkComponentNameGetDriverName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN CHAR8 *Language,
OUT CHAR16 **DriverName
)
{
return LookupUnicodeString2 (
Language,
This->SupportedLanguages,
mSimpleNetworkDriverNameTable,
DriverName,
(BOOLEAN)(This == &gSimpleNetworkComponentName)
);
}
/**
Update the component name for the Snp child handle.
@param Snp[in] A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL.
@retval EFI_SUCCESS Update the ControllerNameTable of this instance successfully.
@retval EFI_INVALID_PARAMETER The input parameter is invalid.
**/
EFI_STATUS
UpdateName (
IN EFI_SIMPLE_NETWORK_PROTOCOL *Snp
)
{
EFI_STATUS Status;
CHAR16 HandleName[80];
UINTN OffSet;
UINTN Index;
if (Snp == NULL) {
return EFI_INVALID_PARAMETER;
}
OffSet = 0;
OffSet += UnicodeSPrint (
HandleName,
sizeof (HandleName),
L"SNP (MAC="
);
for (Index = 0; Index < Snp->Mode->HwAddressSize; Index++) {
OffSet += UnicodeSPrint (
HandleName + OffSet,
sizeof (HandleName) - OffSet * sizeof (CHAR16),
L"%02X-",
Snp->Mode->CurrentAddress.Addr[Index]
);
}
ASSERT (OffSet > 0);
//
// Remove the last '-'
//
OffSet--;
OffSet += UnicodeSPrint (
HandleName + OffSet,
sizeof (HandleName) - OffSet * sizeof (CHAR16),
L")"
);
if (gSimpleNetworkControllerNameTable != NULL) {
FreeUnicodeStringTable (gSimpleNetworkControllerNameTable);
gSimpleNetworkControllerNameTable = NULL;
}
Status = AddUnicodeString2 (
"eng",
gSimpleNetworkComponentName.SupportedLanguages,
&gSimpleNetworkControllerNameTable,
HandleName,
TRUE
);
if (EFI_ERROR (Status)) {
return Status;
}
return AddUnicodeString2 (
"en",
gSimpleNetworkComponentName2.SupportedLanguages,
&gSimpleNetworkControllerNameTable,
HandleName,
FALSE
);
}
/**
Retrieves a Unicode string that is the user readable name of the controller
that is being managed by a driver.
This function retrieves the user readable name of the controller specified by
ControllerHandle and ChildHandle in the form of a Unicode string. If the
driver specified by This has a user readable name in the language specified by
Language, then a pointer to the controller name is returned in ControllerName,
and EFI_SUCCESS is returned. If the driver specified by This is not currently
managing the controller specified by ControllerHandle and ChildHandle,
then EFI_UNSUPPORTED is returned. If the driver specified by This does not
support the language specified by Language, then EFI_UNSUPPORTED is returned.
Currently not implemented.
@param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
EFI_COMPONENT_NAME_PROTOCOL instance.
@param ControllerHandle[in] 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[in] 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[in] 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 4646 or ISO 639-2 language code format.
@param ControllerName[out] 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 NULL.
@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.
**/
EFI_STATUS
EFIAPI
SimpleNetworkComponentNameGetControllerName (
IN EFI_COMPONENT_NAME_PROTOCOL *This,
IN EFI_HANDLE ControllerHandle,
IN EFI_HANDLE ChildHandle OPTIONAL,
IN CHAR8 *Language,
OUT CHAR16 **ControllerName
)
{
EFI_STATUS Status;
EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
if (ChildHandle != NULL) {
return EFI_UNSUPPORTED;
}
//
// Make sure this driver is currently managing ControllHandle
//
Status = EfiTestManagedDevice (
ControllerHandle,
gSimpleNetworkDriverBinding.DriverBindingHandle,
&gEfiSimpleNetworkProtocolGuid
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Retrieve an instance of a produced protocol from ControllerHandle
//
Status = gBS->OpenProtocol (
ControllerHandle,
&gEfiSimpleNetworkProtocolGuid,
(VOID **)&Snp,
NULL,
NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Update the component name for this child handle.
//
Status = UpdateName (Snp);
if (EFI_ERROR (Status)) {
return Status;
}
return LookupUnicodeString2 (
Language,
This->SupportedLanguages,
gSimpleNetworkControllerNameTable,
ControllerName,
(BOOLEAN)(This == &gSimpleNetworkComponentName)
);
}

View File

@@ -0,0 +1,257 @@
/** @file
Implementation of reading the current interrupt status and recycled transmit
buffer status from a network interface.
Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Snp.h"
/**
Call undi to get the status of the interrupts, get the list of recycled transmit
buffers that completed transmitting. The recycled transmit buffer address will
be saved into Snp->RecycledTxBuf. This function will also update the MediaPresent
field of EFI_SIMPLE_NETWORK_MODE if UNDI support it.
@param[in] Snp Pointer to snp driver structure.
@param[out] InterruptStatusPtr A non null pointer to contain the interrupt
status.
@param[in] GetTransmittedBuf Set to TRUE to retrieve the recycled transmit
buffer address.
@retval EFI_SUCCESS The status of the network interface was retrieved.
@retval EFI_DEVICE_ERROR The command could not be sent to the network
interface.
**/
EFI_STATUS
PxeGetStatus (
IN SNP_DRIVER *Snp,
OUT UINT32 *InterruptStatusPtr,
IN BOOLEAN GetTransmittedBuf
)
{
PXE_DB_GET_STATUS *Db;
UINT16 InterruptFlags;
UINT32 Index;
UINT64 *Tmp;
Tmp = NULL;
Db = Snp->Db;
Snp->Cdb.OpCode = PXE_OPCODE_GET_STATUS;
Snp->Cdb.OpFlags = 0;
if (GetTransmittedBuf) {
Snp->Cdb.OpFlags |= PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS;
ZeroMem (Db->TxBuffer, sizeof (Db->TxBuffer));
}
if (InterruptStatusPtr != NULL) {
Snp->Cdb.OpFlags |= PXE_OPFLAGS_GET_INTERRUPT_STATUS;
}
if (Snp->MediaStatusSupported) {
Snp->Cdb.OpFlags |= PXE_OPFLAGS_GET_MEDIA_STATUS;
}
Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
Snp->Cdb.DBsize = (UINT16) sizeof (PXE_DB_GET_STATUS);
Snp->Cdb.DBaddr = (UINT64)(UINTN) Db;
Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
Snp->Cdb.IFnum = Snp->IfNum;
Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
//
// Issue UNDI command and check result.
//
DEBUG ((EFI_D_NET, "\nSnp->undi.get_status() "));
(*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
DEBUG (
(EFI_D_NET,
"\nSnp->undi.get_status() %xh:%xh\n",
Snp->Cdb.StatFlags,
Snp->Cdb.StatCode)
);
return EFI_DEVICE_ERROR;
}
//
// report the values back..
//
if (InterruptStatusPtr != NULL) {
InterruptFlags = (UINT16) (Snp->Cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_INTERRUPT_MASK);
*InterruptStatusPtr = 0;
if ((InterruptFlags & PXE_STATFLAGS_GET_STATUS_RECEIVE) == PXE_STATFLAGS_GET_STATUS_RECEIVE) {
*InterruptStatusPtr |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
}
if ((InterruptFlags & PXE_STATFLAGS_GET_STATUS_TRANSMIT) == PXE_STATFLAGS_GET_STATUS_TRANSMIT) {
*InterruptStatusPtr |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
}
if ((InterruptFlags & PXE_STATFLAGS_GET_STATUS_COMMAND) == PXE_STATFLAGS_GET_STATUS_COMMAND) {
*InterruptStatusPtr |= EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT;
}
if ((InterruptFlags & PXE_STATFLAGS_GET_STATUS_SOFTWARE) == PXE_STATFLAGS_GET_STATUS_SOFTWARE) {
*InterruptStatusPtr |= EFI_SIMPLE_NETWORK_COMMAND_INTERRUPT;
}
}
if (GetTransmittedBuf) {
if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN) == 0) {
//
// UNDI has written some transmitted buffer addresses into the DB. Store them into Snp->RecycledTxBuf.
//
for (Index = 0; Index < MAX_XMIT_BUFFERS; Index++) {
if (Db->TxBuffer[Index] != 0) {
if (Snp->RecycledTxBufCount == Snp->MaxRecycledTxBuf) {
//
// Snp->RecycledTxBuf is full, reallocate a new one.
//
if ((Snp->MaxRecycledTxBuf + SNP_TX_BUFFER_INCREASEMENT) >= SNP_MAX_TX_BUFFER_NUM) {
return EFI_DEVICE_ERROR;
}
Tmp = AllocatePool (sizeof (UINT64) * (Snp->MaxRecycledTxBuf + SNP_TX_BUFFER_INCREASEMENT));
if (Tmp == NULL) {
return EFI_DEVICE_ERROR;
}
CopyMem (Tmp, Snp->RecycledTxBuf, sizeof (UINT64) * Snp->RecycledTxBufCount);
FreePool (Snp->RecycledTxBuf);
Snp->RecycledTxBuf = Tmp;
Snp->MaxRecycledTxBuf += SNP_TX_BUFFER_INCREASEMENT;
}
Snp->RecycledTxBuf[Snp->RecycledTxBufCount] = Db->TxBuffer[Index];
Snp->RecycledTxBufCount++;
}
}
}
}
//
// Update MediaPresent field of EFI_SIMPLE_NETWORK_MODE if the UNDI support
// returning media status from GET_STATUS command
//
if (Snp->MediaStatusSupported) {
Snp->Snp.Mode->MediaPresent =
(BOOLEAN) (((Snp->Cdb.StatFlags & PXE_STATFLAGS_GET_STATUS_NO_MEDIA) != 0) ? FALSE : TRUE);
}
return EFI_SUCCESS;
}
/**
Reads the current interrupt status and recycled transmit buffer status from a
network interface.
This function gets the current interrupt and recycled transmit buffer status
from the network interface. The interrupt status is returned as a bit mask in
InterruptStatus. If InterruptStatus is NULL, the interrupt status will not be
read. If TxBuf is not NULL, a recycled transmit buffer address will be retrieved.
If a recycled transmit buffer address is returned in TxBuf, then the buffer has
been successfully transmitted, and the status for that buffer is cleared. If
the status of the network interface is successfully collected, EFI_SUCCESS
will be returned. If the driver has not been initialized, EFI_DEVICE_ERROR will
be returned.
@param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
@param InterruptStatus A pointer to the bit mask of the currently active
interrupts (see "Related Definitions"). If this is NULL,
the interrupt status will not be read from the device.
If this is not NULL, the interrupt status will be read
from the device. When the interrupt status is read, it
will also be cleared. Clearing the transmit interrupt does
not empty the recycled transmit buffer array.
@param TxBuf Recycled transmit buffer address. The network interface
will not transmit if its internal recycled transmit
buffer array is full. Reading the transmit buffer does
not clear the transmit interrupt. If this is NULL, then
the transmit buffer status will not be read. If there
are no transmit buffers to recycle and TxBuf is not NULL,
TxBuf will be set to NULL.
@retval EFI_SUCCESS The status of the network interface was retrieved.
@retval EFI_NOT_STARTED The network interface has not been started.
@retval EFI_INVALID_PARAMETER This parameter was NULL or did not point to a valid
EFI_SIMPLE_NETWORK_PROTOCOL structure.
@retval EFI_DEVICE_ERROR The command could not be sent to the network
interface.
**/
EFI_STATUS
EFIAPI
SnpUndi32GetStatus (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
OUT UINT32 *InterruptStatus, OPTIONAL
OUT VOID **TxBuf OPTIONAL
)
{
SNP_DRIVER *Snp;
EFI_TPL OldTpl;
EFI_STATUS Status;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
if (InterruptStatus == NULL && TxBuf == NULL) {
return EFI_INVALID_PARAMETER;
}
Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
if (Snp == NULL) {
return EFI_DEVICE_ERROR;
}
switch (Snp->Mode.State) {
case EfiSimpleNetworkInitialized:
break;
case EfiSimpleNetworkStopped:
Status = EFI_NOT_STARTED;
goto ON_EXIT;
default:
Status = EFI_DEVICE_ERROR;
goto ON_EXIT;
}
if (Snp->RecycledTxBufCount == 0 && TxBuf != NULL) {
Status = PxeGetStatus (Snp, InterruptStatus, TRUE);
} else {
Status = PxeGetStatus (Snp, InterruptStatus, FALSE);
}
if (TxBuf != NULL) {
//
// Get a recycled buf from Snp->RecycledTxBuf
//
if (Snp->RecycledTxBufCount == 0) {
*TxBuf = NULL;
} else {
Snp->RecycledTxBufCount--;
*TxBuf = (VOID *) (UINTN) Snp->RecycledTxBuf[Snp->RecycledTxBufCount];
}
}
ON_EXIT:
gBS->RestoreTPL (OldTpl);
return Status;
}

View File

@@ -0,0 +1,277 @@
/** @file
Implementation of initializing a network adapter.
Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Snp.h"
/**
Call UNDI to initialize the interface.
@param Snp Pointer to snp driver structure.
@param CableDetectFlag Do/don't detect the cable (depending on what
undi supports).
@retval EFI_SUCCESS UNDI is initialized successfully.
@retval EFI_DEVICE_ERROR UNDI could not be initialized.
@retval Other Other errors as indicated.
**/
EFI_STATUS
PxeInit (
SNP_DRIVER *Snp,
UINT16 CableDetectFlag
)
{
PXE_CPB_INITIALIZE *Cpb;
VOID *Addr;
EFI_STATUS Status;
Status = EFI_SUCCESS;
Cpb = Snp->Cpb;
if (Snp->TxRxBufferSize != 0) {
Status = Snp->PciIo->AllocateBuffer (
Snp->PciIo,
AllocateAnyPages,
EfiBootServicesData,
SNP_MEM_PAGES (Snp->TxRxBufferSize),
&Addr,
0
);
if (Status != EFI_SUCCESS) {
DEBUG (
(EFI_D_ERROR,
"\nSnp->PxeInit() AllocateBuffer %xh (%r)\n",
Status,
Status)
);
return Status;
}
ASSERT (Addr);
Snp->TxRxBuffer = Addr;
}
Cpb->MemoryAddr = (UINT64)(UINTN) Snp->TxRxBuffer;
Cpb->MemoryLength = Snp->TxRxBufferSize;
//
// let UNDI decide/detect these values
//
Cpb->LinkSpeed = 0;
Cpb->TxBufCnt = 0;
Cpb->TxBufSize = 0;
Cpb->RxBufCnt = 0;
Cpb->RxBufSize = 0;
Cpb->DuplexMode = PXE_DUPLEX_DEFAULT;
Cpb->LoopBackMode = LOOPBACK_NORMAL;
Snp->Cdb.OpCode = PXE_OPCODE_INITIALIZE;
Snp->Cdb.OpFlags = CableDetectFlag;
Snp->Cdb.CPBsize = (UINT16) sizeof (PXE_CPB_INITIALIZE);
Snp->Cdb.DBsize = (UINT16) sizeof (PXE_DB_INITIALIZE);
Snp->Cdb.CPBaddr = (UINT64)(UINTN) Snp->Cpb;
Snp->Cdb.DBaddr = (UINT64)(UINTN) Snp->Db;
Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
Snp->Cdb.IFnum = Snp->IfNum;
Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
DEBUG ((EFI_D_NET, "\nSnp->undi.initialize() "));
(*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
//
// There are two fields need to be checked here:
// First is the upper two bits (14 & 15) in the CDB.StatFlags field. Until these bits change to report
// PXE_STATFLAGS_COMMAND_COMPLETE or PXE_STATFLAGS_COMMAND_FAILED, the command has not been executed by the UNDI.
// Second is the CDB.StatCode field. After command execution completes, either successfully or not,
// the CDB.StatCode field contains the result of the command execution.
//
if ((((Snp->Cdb.StatFlags) & PXE_STATFLAGS_STATUS_MASK) == PXE_STATFLAGS_COMMAND_COMPLETE) &&
(Snp->Cdb.StatCode == PXE_STATCODE_SUCCESS)) {
//
// If cable detect feature is enabled in CDB.OpFlags, check the CDB.StatFlags to see if there is an
// active connection to this network device. If the no media StatFlag is set, the UNDI and network
// device are still initialized.
//
if (CableDetectFlag == PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) {
if(((Snp->Cdb.StatFlags) & PXE_STATFLAGS_INITIALIZED_NO_MEDIA) != PXE_STATFLAGS_INITIALIZED_NO_MEDIA) {
Snp->Mode.MediaPresent = TRUE;
} else {
Snp->Mode.MediaPresent = FALSE;
}
}
Snp->Mode.State = EfiSimpleNetworkInitialized;
Status = EFI_SUCCESS;
} else {
DEBUG (
(EFI_D_WARN,
"\nSnp->undi.initialize() %xh:%xh\n",
Snp->Cdb.StatFlags,
Snp->Cdb.StatCode)
);
if (Snp->TxRxBuffer != NULL) {
Snp->PciIo->FreeBuffer (
Snp->PciIo,
SNP_MEM_PAGES (Snp->TxRxBufferSize),
(VOID *) Snp->TxRxBuffer
);
}
Snp->TxRxBuffer = NULL;
Status = EFI_DEVICE_ERROR;
}
return Status;
}
/**
Resets a network adapter and allocates the transmit and receive buffers
required by the network interface; optionally, also requests allocation of
additional transmit and receive buffers.
This function allocates the transmit and receive buffers required by the network
interface. If this allocation fails, then EFI_OUT_OF_RESOURCES is returned.
If the allocation succeeds and the network interface is successfully initialized,
then EFI_SUCCESS will be returned.
@param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
@param ExtraRxBufferSize The size, in bytes, of the extra receive buffer space
that the driver should allocate for the network interface.
Some network interfaces will not be able to use the
extra buffer, and the caller will not know if it is
actually being used.
@param ExtraTxBufferSize The size, in bytes, of the extra transmit buffer space
that the driver should allocate for the network interface.
Some network interfaces will not be able to use the
extra buffer, and the caller will not know if it is
actually being used.
@retval EFI_SUCCESS The network interface was initialized.
@retval EFI_NOT_STARTED The network interface has not been started.
@retval EFI_OUT_OF_RESOURCES There was not enough memory for the transmit and
receive buffers.
@retval EFI_INVALID_PARAMETER This parameter was NULL or did not point to a valid
EFI_SIMPLE_NETWORK_PROTOCOL structure.
@retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
@retval EFI_UNSUPPORTED The increased buffer size feature is not supported.
**/
EFI_STATUS
EFIAPI
SnpUndi32Initialize (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
IN UINTN ExtraRxBufferSize OPTIONAL,
IN UINTN ExtraTxBufferSize OPTIONAL
)
{
EFI_STATUS EfiStatus;
SNP_DRIVER *Snp;
EFI_TPL OldTpl;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
if (Snp == NULL) {
EfiStatus = EFI_INVALID_PARAMETER;
goto ON_EXIT;
}
switch (Snp->Mode.State) {
case EfiSimpleNetworkStarted:
break;
case EfiSimpleNetworkStopped:
EfiStatus = EFI_NOT_STARTED;
goto ON_EXIT;
default:
EfiStatus = EFI_DEVICE_ERROR;
goto ON_EXIT;
}
EfiStatus = gBS->CreateEvent (
EVT_NOTIFY_WAIT,
TPL_NOTIFY,
&SnpWaitForPacketNotify,
Snp,
&Snp->Snp.WaitForPacket
);
if (EFI_ERROR (EfiStatus)) {
Snp->Snp.WaitForPacket = NULL;
EfiStatus = EFI_DEVICE_ERROR;
goto ON_EXIT;
}
//
//
//
Snp->Mode.MCastFilterCount = 0;
Snp->Mode.ReceiveFilterSetting = 0;
ZeroMem (Snp->Mode.MCastFilter, sizeof Snp->Mode.MCastFilter);
CopyMem (
&Snp->Mode.CurrentAddress,
&Snp->Mode.PermanentAddress,
sizeof (EFI_MAC_ADDRESS)
);
//
// Compute tx/rx buffer sizes based on UNDI init info and parameters.
//
Snp->TxRxBufferSize = (UINT32) (Snp->InitInfo.MemoryRequired + ExtraRxBufferSize + ExtraTxBufferSize);
//
// If UNDI support cable detect for INITIALIZE command, try it first.
//
if (Snp->CableDetectSupported) {
if (PxeInit (Snp, PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) == EFI_SUCCESS) {
goto ON_EXIT;
}
}
Snp->Mode.MediaPresent = FALSE;
EfiStatus = PxeInit (Snp, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE);
if (EFI_ERROR (EfiStatus)) {
gBS->CloseEvent (Snp->Snp.WaitForPacket);
goto ON_EXIT;
}
//
// Try to update the MediaPresent field of EFI_SIMPLE_NETWORK_MODE if the UNDI support it.
//
if (Snp->MediaStatusSupported) {
PxeGetStatus (Snp, NULL, FALSE);
}
ON_EXIT:
gBS->RestoreTPL (OldTpl);
return EfiStatus;
}

View File

@@ -0,0 +1,173 @@
/** @file
Implementation of converting an multicast IP address to multicast HW MAC
address.
Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Snp.h"
/**
Call undi to convert an multicast IP address to a MAC address.
@param Snp Pointer to snp driver structure.
@param IPv6 Flag to indicate if this is an ipv6 address.
@param IP Multicast IP address.
@param MAC Pointer to hold the return MAC address.
@retval EFI_SUCCESS The multicast IP address was mapped to the
multicast HW MAC address.
@retval EFI_INVALID_PARAMETER Invalid UNDI command.
@retval EFI_UNSUPPORTED Command is not supported by UNDI.
@retval EFI_DEVICE_ERROR Fail to execute UNDI command.
**/
EFI_STATUS
PxeIp2Mac (
IN SNP_DRIVER *Snp,
IN BOOLEAN IPv6,
IN EFI_IP_ADDRESS *IP,
IN OUT EFI_MAC_ADDRESS *MAC
)
{
PXE_CPB_MCAST_IP_TO_MAC *Cpb;
PXE_DB_MCAST_IP_TO_MAC *Db;
Cpb = Snp->Cpb;
Db = Snp->Db;
Snp->Cdb.OpCode = PXE_OPCODE_MCAST_IP_TO_MAC;
Snp->Cdb.OpFlags = (UINT16) (IPv6 ? PXE_OPFLAGS_MCAST_IPV6_TO_MAC : PXE_OPFLAGS_MCAST_IPV4_TO_MAC);
Snp->Cdb.CPBsize = (UINT16) sizeof (PXE_CPB_MCAST_IP_TO_MAC);
Snp->Cdb.DBsize = (UINT16) sizeof (PXE_DB_MCAST_IP_TO_MAC);
Snp->Cdb.CPBaddr = (UINT64)(UINTN) Cpb;
Snp->Cdb.DBaddr = (UINT64)(UINTN) Db;
Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
Snp->Cdb.IFnum = Snp->IfNum;
Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
CopyMem (&Cpb->IP, IP, sizeof (PXE_IP_ADDR));
//
// Issue UNDI command and check result.
//
DEBUG ((EFI_D_NET, "\nSnp->undi.mcast_ip_to_mac() "));
(*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
switch (Snp->Cdb.StatCode) {
case PXE_STATCODE_SUCCESS:
break;
case PXE_STATCODE_INVALID_CPB:
return EFI_INVALID_PARAMETER;
case PXE_STATCODE_UNSUPPORTED:
DEBUG (
(EFI_D_NET,
"\nSnp->undi.mcast_ip_to_mac() %xh:%xh\n",
Snp->Cdb.StatFlags,
Snp->Cdb.StatCode)
);
return EFI_UNSUPPORTED;
default:
//
// UNDI command failed. Return EFI_DEVICE_ERROR
// to caller.
//
DEBUG (
(EFI_D_NET,
"\nSnp->undi.mcast_ip_to_mac() %xh:%xh\n",
Snp->Cdb.StatFlags,
Snp->Cdb.StatCode)
);
return EFI_DEVICE_ERROR;
}
CopyMem (MAC, &Db->MAC, sizeof (PXE_MAC_ADDR));
return EFI_SUCCESS;
}
/**
Converts a multicast IP address to a multicast HW MAC address.
This function converts a multicast IP address to a multicast HW MAC address
for all packet transactions. If the mapping is accepted, then EFI_SUCCESS will
be returned.
@param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
@param IPv6 Set to TRUE if the multicast IP address is IPv6 [RFC 2460].
Set to FALSE if the multicast IP address is IPv4 [RFC 791].
@param IP The multicast IP address that is to be converted to a multicast
HW MAC address.
@param MAC The multicast HW MAC address that is to be generated from IP.
@retval EFI_SUCCESS The multicast IP address was mapped to the
multicast HW MAC address.
@retval EFI_NOT_STARTED The Simple Network Protocol interface has not
been started by calling Start().
@retval EFI_INVALID_PARAMETER IP is NULL.
@retval EFI_INVALID_PARAMETER MAC is NULL.
@retval EFI_INVALID_PARAMETER IP does not point to a valid IPv4 or IPv6
multicast address.
@retval EFI_DEVICE_ERROR The Simple Network Protocol interface has not
been initialized by calling Initialize().
@retval EFI_UNSUPPORTED IPv6 is TRUE and the implementation does not
support IPv6 multicast to MAC address conversion.
**/
EFI_STATUS
EFIAPI
SnpUndi32McastIpToMac (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
IN BOOLEAN IPv6,
IN EFI_IP_ADDRESS *IP,
OUT EFI_MAC_ADDRESS *MAC
)
{
SNP_DRIVER *Snp;
EFI_TPL OldTpl;
EFI_STATUS Status;
//
// Get pointer to SNP driver instance for *this.
//
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
if (IP == NULL || MAC == NULL) {
return EFI_INVALID_PARAMETER;
}
Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
switch (Snp->Mode.State) {
case EfiSimpleNetworkInitialized:
break;
case EfiSimpleNetworkStopped:
Status = EFI_NOT_STARTED;
goto ON_EXIT;
default:
Status = EFI_DEVICE_ERROR;
goto ON_EXIT;
}
Status = PxeIp2Mac (Snp, IPv6, IP, MAC);
ON_EXIT:
gBS->RestoreTPL (OldTpl);
return Status;
}

217
NetworkPkg/SnpDxe/Nvdata.c Normal file
View File

@@ -0,0 +1,217 @@
/** @file
Implementation of reading and writing operations on the NVRAM device
attached to a network interface.
Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Snp.h"
/**
This routine calls Undi to read the desired number of eeprom bytes.
@param Snp pointer to the snp driver structure
@param Offset eeprom register value relative to the base address
@param BufferSize number of bytes to read
@param Buffer pointer where to read into
@retval EFI_SUCCESS The NVRAM access was performed.
@retval EFI_INVALID_PARAMETER Invalid UNDI command.
@retval EFI_UNSUPPORTED Command is not supported by UNDI.
@retval EFI_DEVICE_ERROR Fail to execute UNDI command.
**/
EFI_STATUS
PxeNvDataRead (
IN SNP_DRIVER *Snp,
IN UINTN Offset,
IN UINTN BufferSize,
IN OUT VOID *Buffer
)
{
PXE_DB_NVDATA *Db;
Db = Snp->Db;
Snp->Cdb.OpCode = PXE_OPCODE_NVDATA;
Snp->Cdb.OpFlags = PXE_OPFLAGS_NVDATA_READ;
Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
Snp->Cdb.DBsize = (UINT16) sizeof (PXE_DB_NVDATA);
Snp->Cdb.DBaddr = (UINT64)(UINTN) Db;
Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
Snp->Cdb.IFnum = Snp->IfNum;
Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
//
// Issue UNDI command and check result.
//
DEBUG ((EFI_D_NET, "\nsnp->undi.nvdata () "));
(*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
switch (Snp->Cdb.StatCode) {
case PXE_STATCODE_SUCCESS:
break;
case PXE_STATCODE_UNSUPPORTED:
DEBUG (
(EFI_D_NET,
"\nsnp->undi.nvdata() %xh:%xh\n",
Snp->Cdb.StatFlags,
Snp->Cdb.StatCode)
);
return EFI_UNSUPPORTED;
default:
DEBUG (
(EFI_D_NET,
"\nsnp->undi.nvdata() %xh:%xh\n",
Snp->Cdb.StatFlags,
Snp->Cdb.StatCode)
);
return EFI_DEVICE_ERROR;
}
ASSERT (Offset < sizeof (Db->Data));
CopyMem (Buffer, &Db->Data.Byte[Offset], BufferSize);
return EFI_SUCCESS;
}
/**
Performs read and write operations on the NVRAM device attached to a network
interface.
This function performs read and write operations on the NVRAM device attached
to a network interface. If ReadWrite is TRUE, a read operation is performed.
If ReadWrite is FALSE, a write operation is performed. Offset specifies the
byte offset at which to start either operation. Offset must be a multiple of
NvRamAccessSize , and it must have a value between zero and NvRamSize.
BufferSize specifies the length of the read or write operation. BufferSize must
also be a multiple of NvRamAccessSize, and Offset + BufferSize must not exceed
NvRamSize.
If any of the above conditions is not met, then EFI_INVALID_PARAMETER will be
returned.
If all the conditions are met and the operation is "read," the NVRAM device
attached to the network interface will be read into Buffer and EFI_SUCCESS
will be returned. If this is a write operation, the contents of Buffer will be
used to update the contents of the NVRAM device attached to the network
interface and EFI_SUCCESS will be returned.
It does the basic checking on the input parameters and retrieves snp structure
and then calls the read_nvdata() call which does the actual reading
@param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
@param ReadWrite TRUE for read operations, FALSE for write operations.
@param Offset Byte offset in the NVRAM device at which to start the read or
write operation. This must be a multiple of NvRamAccessSize
and less than NvRamSize. (See EFI_SIMPLE_NETWORK_MODE)
@param BufferSize The number of bytes to read or write from the NVRAM device.
This must also be a multiple of NvramAccessSize.
@param Buffer A pointer to the data buffer.
@retval EFI_SUCCESS The NVRAM access was performed.
@retval EFI_NOT_STARTED The network interface has not been started.
@retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
* The This parameter is NULL
* The This parameter does not point to a valid
EFI_SIMPLE_NETWORK_PROTOCOL structure
* The Offset parameter is not a multiple of
EFI_SIMPLE_NETWORK_MODE.NvRamAccessSize
* The Offset parameter is not less than
EFI_SIMPLE_NETWORK_MODE.NvRamSize
* The BufferSize parameter is not a multiple of
EFI_SIMPLE_NETWORK_MODE.NvRamAccessSize
* The Buffer parameter is NULL
@retval EFI_DEVICE_ERROR The command could not be sent to the network
interface.
@retval EFI_UNSUPPORTED This function is not supported by the network
interface.
**/
EFI_STATUS
EFIAPI
SnpUndi32NvData (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
IN BOOLEAN ReadWrite,
IN UINTN Offset,
IN UINTN BufferSize,
IN OUT VOID *Buffer
)
{
SNP_DRIVER *Snp;
EFI_TPL OldTpl;
EFI_STATUS Status;
//
// Get pointer to SNP driver instance for *this.
//
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
//
// Return error if the SNP is not initialized.
//
switch (Snp->Mode.State) {
case EfiSimpleNetworkInitialized:
break;
case EfiSimpleNetworkStopped:
Status = EFI_NOT_STARTED;
goto ON_EXIT;
default:
Status = EFI_DEVICE_ERROR;
goto ON_EXIT;
}
//
// Return error if non-volatile memory variables are not valid.
//
if (Snp->Mode.NvRamSize == 0 || Snp->Mode.NvRamAccessSize == 0) {
Status = EFI_UNSUPPORTED;
goto ON_EXIT;
}
//
// Check for invalid parameter combinations.
//
if ((BufferSize == 0) ||
(Buffer == NULL) ||
(Offset >= Snp->Mode.NvRamSize) ||
(Offset + BufferSize > Snp->Mode.NvRamSize) ||
(BufferSize % Snp->Mode.NvRamAccessSize != 0) ||
(Offset % Snp->Mode.NvRamAccessSize != 0)
) {
Status = EFI_INVALID_PARAMETER;
goto ON_EXIT;
}
//
// check the implementation flags of undi if we can write the nvdata!
//
if (!ReadWrite) {
Status = EFI_UNSUPPORTED;
} else {
Status = PxeNvDataRead (Snp, Offset, BufferSize, Buffer);
}
ON_EXIT:
gBS->RestoreTPL (OldTpl);
return Status;
}

251
NetworkPkg/SnpDxe/Receive.c Normal file
View File

@@ -0,0 +1,251 @@
/** @file
Implementation of receiving a packet from a network interface.
Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Snp.h"
/**
Call UNDI to receive a packet and fills in the data in the input pointers.
@param Snp Pointer to snp driver structure
@param Buffer Pointer to the memory for the received data
@param BufferSize Pointer to the length of the buffer on entry and contains
the length of the received data on return
@param HeaderSize Pointer to the header portion of the data received.
@param SrcAddr Pointer to contain the source ethernet address on return
@param DestAddr Pointer to contain the destination ethernet address on
return
@param Protocol Pointer to contain the protocol type from the ethernet
header on return
@retval EFI_SUCCESS The received data was stored in Buffer, and
BufferSize has been updated to the number of
bytes received.
@retval EFI_DEVICE_ERROR Fail to execute UNDI command.
@retval EFI_NOT_READY No packets have been received on the network
interface.
@retval EFI_BUFFER_TOO_SMALL BufferSize is too small for the received
packets. BufferSize has been updated to the
required size.
**/
EFI_STATUS
PxeReceive (
SNP_DRIVER *Snp,
VOID *Buffer,
UINTN *BufferSize,
UINTN *HeaderSize,
EFI_MAC_ADDRESS *SrcAddr,
EFI_MAC_ADDRESS *DestAddr,
UINT16 *Protocol
)
{
PXE_CPB_RECEIVE *Cpb;
PXE_DB_RECEIVE *Db;
UINTN BuffSize;
Cpb = Snp->Cpb;
Db = Snp->Db;
BuffSize = *BufferSize;
Cpb->BufferAddr = (UINT64)(UINTN) Buffer;
Cpb->BufferLen = (UINT32) *BufferSize;
Cpb->reserved = 0;
Snp->Cdb.OpCode = PXE_OPCODE_RECEIVE;
Snp->Cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
Snp->Cdb.CPBsize = (UINT16) sizeof (PXE_CPB_RECEIVE);
Snp->Cdb.CPBaddr = (UINT64)(UINTN) Cpb;
Snp->Cdb.DBsize = (UINT16) sizeof (PXE_DB_RECEIVE);
Snp->Cdb.DBaddr = (UINT64)(UINTN) Db;
Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
Snp->Cdb.IFnum = Snp->IfNum;
Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
//
// Issue UNDI command and check result.
//
DEBUG ((EFI_D_NET, "\nsnp->undi.receive () "));
(*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
switch (Snp->Cdb.StatCode) {
case PXE_STATCODE_SUCCESS:
break;
case PXE_STATCODE_NO_DATA:
DEBUG (
(EFI_D_NET,
"\nsnp->undi.receive () %xh:%xh\n",
Snp->Cdb.StatFlags,
Snp->Cdb.StatCode)
);
return EFI_NOT_READY;
default:
DEBUG (
(EFI_D_ERROR,
"\nsnp->undi.receive() %xh:%xh\n",
Snp->Cdb.StatFlags,
Snp->Cdb.StatCode)
);
return EFI_DEVICE_ERROR;
}
*BufferSize = Db->FrameLen;
if (HeaderSize != NULL) {
*HeaderSize = Db->MediaHeaderLen;
}
if (SrcAddr != NULL) {
CopyMem (SrcAddr, &Db->SrcAddr, Snp->Mode.HwAddressSize);
}
if (DestAddr != NULL) {
CopyMem (DestAddr, &Db->DestAddr, Snp->Mode.HwAddressSize);
}
if (Protocol != NULL) {
//
// We need to do the byte swapping
//
*Protocol = (UINT16) PXE_SWAP_UINT16 (Db->Protocol);
}
//
// We have received a packet from network interface, which implies that the
// network cable should be present. While, some UNDI driver may not report
// correct media status during Snp->Initialize(). So, we need ensure
// MediaPresent in SNP mode data is set to correct value.
//
if (Snp->Mode.MediaPresentSupported && !Snp->Mode.MediaPresent) {
Snp->Mode.MediaPresent = TRUE;
}
return (*BufferSize <= BuffSize) ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;
}
/**
Receives a packet from a network interface.
This function retrieves one packet from the receive queue of a network interface.
If there are no packets on the receive queue, then EFI_NOT_READY will be
returned. If there is a packet on the receive queue, and the size of the packet
is smaller than BufferSize, then the contents of the packet will be placed in
Buffer, and BufferSize will be updated with the actual size of the packet.
In addition, if SrcAddr, DestAddr, and Protocol are not NULL, then these values
will be extracted from the media header and returned. EFI_SUCCESS will be
returned if a packet was successfully received.
If BufferSize is smaller than the received packet, then the size of the receive
packet will be placed in BufferSize and EFI_BUFFER_TOO_SMALL will be returned.
If the driver has not been initialized, EFI_DEVICE_ERROR will be returned.
@param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
@param HeaderSize The size, in bytes, of the media header received on the network
interface. If this parameter is NULL, then the media header size
will not be returned.
@param BufferSize On entry, the size, in bytes, of Buffer. On exit, the size, in
bytes, of the packet that was received on the network interface.
@param Buffer A pointer to the data buffer to receive both the media
header and the data.
@param SrcAddr The source HW MAC address. If this parameter is NULL, the HW
MAC source address will not be extracted from the media header.
@param DestAddr The destination HW MAC address. If this parameter is NULL,
the HW MAC destination address will not be extracted from
the media header.
@param Protocol The media header type. If this parameter is NULL, then the
protocol will not be extracted from the media header. See
RFC 1700 section "Ether Types" for examples.
@retval EFI_SUCCESS The received data was stored in Buffer, and
BufferSize has been updated to the number of
bytes received.
@retval EFI_NOT_STARTED The network interface has not been started.
@retval EFI_NOT_READY No packets have been received on the network interface.
@retval EFI_BUFFER_TOO_SMALL BufferSize is too small for the received packets.
BufferSize has been updated to the required size.
@retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
* The This parameter is NULL
* The This parameter does not point to a valid
EFI_SIMPLE_NETWORK_PROTOCOL structure.
* The BufferSize parameter is NULL
* The Buffer parameter is NULL
@retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
**/
EFI_STATUS
EFIAPI
SnpUndi32Receive (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
OUT UINTN *HeaderSize OPTIONAL,
IN OUT UINTN *BufferSize,
OUT VOID *Buffer,
OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
OUT EFI_MAC_ADDRESS *DestAddr OPTIONAL,
OUT UINT16 *Protocol OPTIONAL
)
{
SNP_DRIVER *Snp;
EFI_TPL OldTpl;
EFI_STATUS Status;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
switch (Snp->Mode.State) {
case EfiSimpleNetworkInitialized:
break;
case EfiSimpleNetworkStopped:
Status = EFI_NOT_STARTED;
goto ON_EXIT;
default:
Status = EFI_DEVICE_ERROR;
goto ON_EXIT;
}
if ((BufferSize == NULL) || (Buffer == NULL)) {
Status = EFI_INVALID_PARAMETER;
goto ON_EXIT;
}
if (Snp->Mode.ReceiveFilterSetting == 0) {
Status = EFI_DEVICE_ERROR;
goto ON_EXIT;
}
Status = PxeReceive (
Snp,
Buffer,
BufferSize,
HeaderSize,
SrcAddr,
DestAddr,
Protocol
);
ON_EXIT:
gBS->RestoreTPL (OldTpl);
return Status;
}

View File

@@ -0,0 +1,478 @@
/** @file
Implementation of managing the multicast receive filters of a network
interface.
Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Snp.h"
/**
Call undi to enable the receive filters.
@param Snp Pointer to snp driver structure.
@param EnableFlags Bit mask for enabling the receive filters.
@param MCastAddressCount Multicast address count for a new multicast address
list.
@param MCastAddressList List of new multicast addresses.
@retval EFI_SUCCESS The multicast receive filter list was updated.
@retval EFI_INVALID_PARAMETER Invalid UNDI command.
@retval EFI_UNSUPPORTED Command is not supported by UNDI.
@retval EFI_DEVICE_ERROR Fail to execute UNDI command.
**/
EFI_STATUS
PxeRecvFilterEnable (
SNP_DRIVER *Snp,
UINT32 EnableFlags,
UINTN MCastAddressCount,
EFI_MAC_ADDRESS *MCastAddressList
)
{
Snp->Cdb.OpCode = PXE_OPCODE_RECEIVE_FILTERS;
Snp->Cdb.OpFlags = PXE_OPFLAGS_RECEIVE_FILTER_ENABLE;
Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
Snp->Cdb.DBsize = PXE_DBSIZE_NOT_USED;
Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
Snp->Cdb.DBaddr = PXE_DBADDR_NOT_USED;
Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
Snp->Cdb.IFnum = Snp->IfNum;
Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) != 0) {
Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_UNICAST;
}
if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) {
Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
}
if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {
Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS;
}
if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {
Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
}
if ((EnableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
}
if (MCastAddressCount != 0) {
Snp->Cdb.CPBsize = (UINT16) (MCastAddressCount * sizeof (EFI_MAC_ADDRESS));
Snp->Cdb.CPBaddr = (UINT64)(UINTN)Snp->Cpb;
CopyMem (Snp->Cpb, MCastAddressList, Snp->Cdb.CPBsize);
}
//
// Issue UNDI command and check result.
//
DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters() "));
(*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
//
// UNDI command failed. Return UNDI status to caller.
//
DEBUG (
(EFI_D_ERROR,
"\nsnp->undi.receive_filters() %xh:%xh\n",
Snp->Cdb.StatFlags,
Snp->Cdb.StatCode)
);
switch (Snp->Cdb.StatCode) {
case PXE_STATCODE_INVALID_CDB:
case PXE_STATCODE_INVALID_CPB:
case PXE_STATCODE_INVALID_PARAMETER:
return EFI_INVALID_PARAMETER;
case PXE_STATCODE_UNSUPPORTED:
return EFI_UNSUPPORTED;
}
return EFI_DEVICE_ERROR;
}
return EFI_SUCCESS;
}
/**
Call undi to disable the receive filters.
@param Snp Pointer to snp driver structure
@param DisableFlags Bit mask for disabling the receive filters
@param ResetMCastList Boolean flag to reset/delete the multicast filter
list.
@retval EFI_SUCCESS The multicast receive filter list was updated.
@retval EFI_DEVICE_ERROR Fail to execute UNDI command.
**/
EFI_STATUS
PxeRecvFilterDisable (
SNP_DRIVER *Snp,
UINT32 DisableFlags,
BOOLEAN ResetMCastList
)
{
Snp->Cdb.OpCode = PXE_OPCODE_RECEIVE_FILTERS;
Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
Snp->Cdb.DBsize = PXE_DBSIZE_NOT_USED;
Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
Snp->Cdb.DBaddr = PXE_DBADDR_NOT_USED;
Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
Snp->Cdb.IFnum = Snp->IfNum;
Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
Snp->Cdb.OpFlags = (UINT16) ((DisableFlags != 0) ? PXE_OPFLAGS_RECEIVE_FILTER_DISABLE : PXE_OPFLAGS_NOT_USED);
if (ResetMCastList) {
Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST;
}
if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) != 0) {
Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_UNICAST;
}
if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) {
Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_BROADCAST;
}
if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {
Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_PROMISCUOUS;
}
if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {
Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST;
}
if ((DisableFlags & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
Snp->Cdb.OpFlags |= PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST;
}
//
// Issue UNDI command and check result.
//
DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters() "));
(*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
//
// UNDI command failed. Return UNDI status to caller.
//
DEBUG (
(EFI_D_ERROR,
"\nsnp->undi.receive_filters() %xh:%xh\n",
Snp->Cdb.StatFlags,
Snp->Cdb.StatCode)
);
return EFI_DEVICE_ERROR;
}
return EFI_SUCCESS;
}
/**
Call undi to read the receive filters.
@param Snp Pointer to snp driver structure.
@retval EFI_SUCCESS The receive filter was read.
@retval EFI_DEVICE_ERROR Fail to execute UNDI command.
**/
EFI_STATUS
PxeRecvFilterRead (
SNP_DRIVER *Snp
)
{
Snp->Cdb.OpCode = PXE_OPCODE_RECEIVE_FILTERS;
Snp->Cdb.OpFlags = PXE_OPFLAGS_RECEIVE_FILTER_READ;
Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
Snp->Cdb.DBsize = (UINT16) (Snp->Mode.MaxMCastFilterCount * sizeof (EFI_MAC_ADDRESS));
Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
if (Snp->Cdb.DBsize == 0) {
Snp->Cdb.DBaddr = (UINT64)(UINTN) NULL;
} else {
Snp->Cdb.DBaddr = (UINT64)(UINTN) Snp->Db;
ZeroMem (Snp->Db, Snp->Cdb.DBsize);
}
Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
Snp->Cdb.IFnum = Snp->IfNum;
Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
DEBUG ((EFI_D_NET, "\nsnp->undi.receive_filters() "));
(*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
//
// UNDI command failed. Return UNDI status to caller.
//
DEBUG (
(EFI_D_ERROR,
"\nsnp->undi.receive_filters() %xh:%xh\n",
Snp->Cdb.StatFlags,
Snp->Cdb.StatCode)
);
return EFI_DEVICE_ERROR;
}
//
// Convert UNDI32 StatFlags to EFI SNP filter flags.
//
Snp->Mode.ReceiveFilterSetting = 0;
if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_UNICAST) != 0) {
Snp->Mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;
}
if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_BROADCAST) != 0) {
Snp->Mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
}
if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_PROMISCUOUS) != 0) {
Snp->Mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
}
if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) {
Snp->Mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
}
if ((Snp->Cdb.StatFlags & PXE_STATFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {
Snp->Mode.ReceiveFilterSetting |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;
}
CopyMem (Snp->Mode.MCastFilter, Snp->Db, Snp->Cdb.DBsize);
//
// Count number of active entries in multicast filter list.
//
{
EFI_MAC_ADDRESS ZeroMacAddr;
SetMem (&ZeroMacAddr, sizeof ZeroMacAddr, 0);
for (Snp->Mode.MCastFilterCount = 0;
Snp->Mode.MCastFilterCount < Snp->Mode.MaxMCastFilterCount;
Snp->Mode.MCastFilterCount++
) {
if (CompareMem (
&Snp->Mode.MCastFilter[Snp->Mode.MCastFilterCount],
&ZeroMacAddr,
sizeof ZeroMacAddr
) == 0) {
break;
}
}
}
return EFI_SUCCESS;
}
/**
Manages the multicast receive filters of a network interface.
This function is used enable and disable the hardware and software receive
filters for the underlying network device.
The receive filter change is broken down into three steps:
* The filter mask bits that are set (ON) in the Enable parameter are added to
the current receive filter settings.
* The filter mask bits that are set (ON) in the Disable parameter are subtracted
from the updated receive filter settings.
* If the resulting receive filter setting is not supported by the hardware a
more liberal setting is selected.
If the same bits are set in the Enable and Disable parameters, then the bits
in the Disable parameter takes precedence.
If the ResetMCastFilter parameter is TRUE, then the multicast address list
filter is disabled (irregardless of what other multicast bits are set in the
Enable and Disable parameters). The SNP->Mode->MCastFilterCount field is set
to zero. The Snp->Mode->MCastFilter contents are undefined.
After enabling or disabling receive filter settings, software should verify
the new settings by checking the Snp->Mode->ReceiveFilterSettings,
Snp->Mode->MCastFilterCount and Snp->Mode->MCastFilter fields.
Note: Some network drivers and/or devices will automatically promote receive
filter settings if the requested setting can not be honored. For example, if
a request for four multicast addresses is made and the underlying hardware
only supports two multicast addresses the driver might set the promiscuous
or promiscuous multicast receive filters instead. The receiving software is
responsible for discarding any extra packets that get through the hardware
receive filters.
Note: Note: To disable all receive filter hardware, the network driver must
be Shutdown() and Stopped(). Calling ReceiveFilters() with Disable set to
Snp->Mode->ReceiveFilterSettings will make it so no more packets are
returned by the Receive() function, but the receive hardware may still be
moving packets into system memory before inspecting and discarding them.
Unexpected system errors, reboots and hangs can occur if an OS is loaded
and the network devices are not Shutdown() and Stopped().
If ResetMCastFilter is TRUE, then the multicast receive filter list on the
network interface will be reset to the default multicast receive filter list.
If ResetMCastFilter is FALSE, and this network interface allows the multicast
receive filter list to be modified, then the MCastFilterCnt and MCastFilter
are used to update the current multicast receive filter list. The modified
receive filter list settings can be found in the MCastFilter field of
EFI_SIMPLE_NETWORK_MODE. If the network interface does not allow the multicast
receive filter list to be modified, then EFI_INVALID_PARAMETER will be returned.
If the driver has not been initialized, EFI_DEVICE_ERROR will be returned.
If the receive filter mask and multicast receive filter list have been
successfully updated on the network interface, EFI_SUCCESS will be returned.
@param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
@param Enable A bit mask of receive filters to enable on the network
interface.
@param Disable A bit mask of receive filters to disable on the network
interface. For backward compatibility with EFI 1.1
platforms, the EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST bit
must be set when the ResetMCastFilter parameter is TRUE.
@param ResetMCastFilter Set to TRUE to reset the contents of the multicast
receive filters on the network interface to their
default values.
@param MCastFilterCnt Number of multicast HW MAC addresses in the new MCastFilter
list. This value must be less than or equal to the
MCastFilterCnt field of EFI_SIMPLE_NETWORK_MODE.
This field is optional if ResetMCastFilter is TRUE.
@param MCastFilter A pointer to a list of new multicast receive filter HW
MAC addresses. This list will replace any existing
multicast HW MAC address list. This field is optional
if ResetMCastFilter is TRUE.
@retval EFI_SUCCESS The multicast receive filter list was updated.
@retval EFI_NOT_STARTED The network interface has not been started.
@retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
* This is NULL
* There are bits set in Enable that are not set
in Snp->Mode->ReceiveFilterMask
* There are bits set in Disable that are not set
in Snp->Mode->ReceiveFilterMask
* Multicast is being enabled (the
EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST bit is
set in Enable, it is not set in Disable, and
ResetMCastFilter is FALSE) and MCastFilterCount
is zero
* Multicast is being enabled and MCastFilterCount
is greater than Snp->Mode->MaxMCastFilterCount
* Multicast is being enabled and MCastFilter is NULL
* Multicast is being enabled and one or more of
the addresses in the MCastFilter list are not
valid multicast MAC addresses
@retval EFI_DEVICE_ERROR One or more of the following conditions is TRUE:
* The network interface has been started but has
not been initialized
* An unexpected error was returned by the
underlying network driver or device
@retval EFI_UNSUPPORTED This function is not supported by the network
interface.
**/
EFI_STATUS
EFIAPI
SnpUndi32ReceiveFilters (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
IN UINT32 Enable,
IN UINT32 Disable,
IN BOOLEAN ResetMCastFilter,
IN UINTN MCastFilterCnt, OPTIONAL
IN EFI_MAC_ADDRESS *MCastFilter OPTIONAL
)
{
SNP_DRIVER *Snp;
EFI_STATUS Status;
EFI_TPL OldTpl;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
switch (Snp->Mode.State) {
case EfiSimpleNetworkInitialized:
break;
case EfiSimpleNetworkStopped:
Status = EFI_NOT_STARTED;
goto ON_EXIT;
default:
Status = EFI_DEVICE_ERROR;
goto ON_EXIT;
}
//
// check if we are asked to enable or disable something that the UNDI
// does not even support!
//
if (((Enable &~Snp->Mode.ReceiveFilterMask) != 0) ||
((Disable &~Snp->Mode.ReceiveFilterMask) != 0)) {
Status = EFI_INVALID_PARAMETER;
goto ON_EXIT;
}
if (ResetMCastFilter) {
Disable |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST & Snp->Mode.ReceiveFilterMask;
MCastFilterCnt = 0;
MCastFilter = NULL;
} else {
if (MCastFilterCnt != 0) {
if ((MCastFilterCnt > Snp->Mode.MaxMCastFilterCount) ||
(MCastFilter == NULL)) {
Status = EFI_INVALID_PARAMETER;
goto ON_EXIT;
}
}
}
if (Enable == 0 && Disable == 0 && !ResetMCastFilter && MCastFilterCnt == 0) {
Status = EFI_SUCCESS;
goto ON_EXIT;
}
if ((Enable & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0 && MCastFilterCnt == 0) {
Status = EFI_INVALID_PARAMETER;
goto ON_EXIT;
}
if ((Enable != 0) || (MCastFilterCnt != 0)) {
Status = PxeRecvFilterEnable (
Snp,
Enable,
MCastFilterCnt,
MCastFilter
);
if (EFI_ERROR (Status)) {
goto ON_EXIT;
}
}
if ((Disable != 0) || ResetMCastFilter) {
Status = PxeRecvFilterDisable (Snp, Disable, ResetMCastFilter);
if (EFI_ERROR (Status)) {
goto ON_EXIT;
}
}
Status = PxeRecvFilterRead (Snp);
ON_EXIT:
gBS->RestoreTPL (OldTpl);
return Status;
}

130
NetworkPkg/SnpDxe/Reset.c Normal file
View File

@@ -0,0 +1,130 @@
/** @file
Implementation of resetting a network adapter.
Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Snp.h"
/**
Call UNDI to reset the NIC.
@param Snp Pointer to the snp driver structure.
@return EFI_SUCCESSFUL The NIC was reset.
@retval EFI_DEVICE_ERROR The NIC cannot be reset.
**/
EFI_STATUS
PxeReset (
SNP_DRIVER *Snp
)
{
Snp->Cdb.OpCode = PXE_OPCODE_RESET;
Snp->Cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
Snp->Cdb.DBsize = PXE_DBSIZE_NOT_USED;
Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
Snp->Cdb.DBaddr = PXE_DBADDR_NOT_USED;
Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
Snp->Cdb.IFnum = Snp->IfNum;
Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
//
// Issue UNDI command and check result.
//
DEBUG ((EFI_D_NET, "\nsnp->undi.reset() "));
(*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
DEBUG (
(EFI_D_WARN,
"\nsnp->undi32.reset() %xh:%xh\n",
Snp->Cdb.StatFlags,
Snp->Cdb.StatCode)
);
//
// UNDI could not be reset. Return UNDI error.
//
return EFI_DEVICE_ERROR;
}
return EFI_SUCCESS;
}
/**
Resets a network adapter and reinitializes it with the parameters that were
provided in the previous call to Initialize().
This function resets a network adapter and reinitializes it with the parameters
that were provided in the previous call to Initialize(). The transmit and
receive queues are emptied and all pending interrupts are cleared.
Receive filters, the station address, the statistics, and the multicast-IP-to-HW
MAC addresses are not reset by this call. If the network interface was
successfully reset, then EFI_SUCCESS will be returned. If the driver has not
been initialized, EFI_DEVICE_ERROR will be returned.
@param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
@param ExtendedVerification Indicates that the driver may perform a more
exhaustive verification operation of the device
during reset.
@retval EFI_SUCCESS The network interface was reset.
@retval EFI_NOT_STARTED The network interface has not been started.
@retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
@retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
@retval EFI_UNSUPPORTED This function is not supported by the network interface.
**/
EFI_STATUS
EFIAPI
SnpUndi32Reset (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
IN BOOLEAN ExtendedVerification
)
{
SNP_DRIVER *Snp;
EFI_TPL OldTpl;
EFI_STATUS Status;
//
// Resolve Warning 4 unreferenced parameter problem
//
ExtendedVerification = 0;
DEBUG ((EFI_D_WARN, "ExtendedVerification = %d is not implemented!\n", ExtendedVerification));
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
switch (Snp->Mode.State) {
case EfiSimpleNetworkInitialized:
break;
case EfiSimpleNetworkStopped:
Status = EFI_NOT_STARTED;
goto ON_EXIT;
default:
Status = EFI_DEVICE_ERROR;
goto ON_EXIT;
}
Status = PxeReset (Snp);
ON_EXIT:
gBS->RestoreTPL (OldTpl);
return Status;
}

View File

@@ -0,0 +1,146 @@
/** @file
Implementation of shuting down a network adapter.
Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Snp.h"
/**
Call UNDI to shut down the interface.
@param Snp Pointer to snp driver structure.
@retval EFI_SUCCESS UNDI is shut down successfully.
@retval EFI_DEVICE_ERROR UNDI could not be shut down.
**/
EFI_STATUS
PxeShutdown (
IN SNP_DRIVER *Snp
)
{
Snp->Cdb.OpCode = PXE_OPCODE_SHUTDOWN;
Snp->Cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
Snp->Cdb.DBsize = PXE_DBSIZE_NOT_USED;
Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
Snp->Cdb.DBaddr = PXE_DBADDR_NOT_USED;
Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
Snp->Cdb.IFnum = Snp->IfNum;
Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
//
// Issue UNDI command and check result.
//
DEBUG ((EFI_D_NET, "\nsnp->undi.shutdown() "));
(*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
//
// UNDI could not be shutdown. Return UNDI error.
//
DEBUG ((EFI_D_WARN, "\nsnp->undi.shutdown() %xh:%xh\n", Snp->Cdb.StatFlags, Snp->Cdb.StatCode));
return EFI_DEVICE_ERROR;
}
//
// Free allocated memory.
//
if (Snp->TxRxBuffer != NULL) {
Snp->PciIo->FreeBuffer (
Snp->PciIo,
SNP_MEM_PAGES (Snp->TxRxBufferSize),
(VOID *) Snp->TxRxBuffer
);
}
Snp->TxRxBuffer = NULL;
Snp->TxRxBufferSize = 0;
return EFI_SUCCESS;
}
/**
Resets a network adapter and leaves it in a state that is safe for another
driver to initialize.
This function releases the memory buffers assigned in the Initialize() call.
Pending transmits and receives are lost, and interrupts are cleared and disabled.
After this call, only the Initialize() and Stop() calls may be used. If the
network interface was successfully shutdown, then EFI_SUCCESS will be returned.
If the driver has not been initialized, EFI_DEVICE_ERROR will be returned.
@param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
@retval EFI_SUCCESS The network interface was shutdown.
@retval EFI_NOT_STARTED The network interface has not been started.
@retval EFI_INVALID_PARAMETER This parameter was NULL or did not point to a valid
EFI_SIMPLE_NETWORK_PROTOCOL structure.
@retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
**/
EFI_STATUS
EFIAPI
SnpUndi32Shutdown (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This
)
{
SNP_DRIVER *Snp;
EFI_STATUS Status;
EFI_TPL OldTpl;
//
// Get pointer to SNP driver instance for *This.
//
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
//
// Return error if the SNP is not initialized.
//
switch (Snp->Mode.State) {
case EfiSimpleNetworkInitialized:
break;
case EfiSimpleNetworkStopped:
Status = EFI_NOT_STARTED;
goto ON_EXIT;
default:
Status = EFI_DEVICE_ERROR;
goto ON_EXIT;
}
Status = PxeShutdown (Snp);
Snp->Mode.State = EfiSimpleNetworkStarted;
Snp->Mode.ReceiveFilterSetting = 0;
Snp->Mode.MCastFilterCount = 0;
Snp->Mode.ReceiveFilterSetting = 0;
ZeroMem (Snp->Mode.MCastFilter, sizeof Snp->Mode.MCastFilter);
CopyMem (
&Snp->Mode.CurrentAddress,
&Snp->Mode.PermanentAddress,
sizeof (EFI_MAC_ADDRESS)
);
gBS->CloseEvent (Snp->Snp.WaitForPacket);
ON_EXIT:
gBS->RestoreTPL (OldTpl);
return Status;
}

862
NetworkPkg/SnpDxe/Snp.c Normal file
View File

@@ -0,0 +1,862 @@
/** @file
Implementation of driver entry point and driver binding protocol.
Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Snp.h"
/**
One notified function to stop UNDI device when gBS->ExitBootServices() called.
@param Event Pointer to this event
@param Context Event handler private data
**/
VOID
EFIAPI
SnpNotifyExitBootServices (
EFI_EVENT Event,
VOID *Context
)
{
SNP_DRIVER *Snp;
Snp = (SNP_DRIVER *)Context;
//
// Shutdown and stop UNDI driver
//
PxeShutdown (Snp);
PxeStop (Snp);
}
/**
Send command to UNDI. It does nothing currently.
@param Cdb command to be sent to UNDI.
@retval EFI_INVALID_PARAMETER The command is 0.
@retval EFI_UNSUPPORTED Default return status because it's not
supported currently.
**/
EFI_STATUS
EFIAPI
IssueHwUndiCommand (
UINT64 Cdb
)
{
DEBUG ((EFI_D_ERROR, "\nIssueHwUndiCommand() - This should not be called!"));
if (Cdb == 0) {
return EFI_INVALID_PARAMETER;
}
//
// %%TBD - For now, nothing is done.
//
return EFI_UNSUPPORTED;
}
/**
Compute 8-bit checksum of a buffer.
@param Buffer Pointer to buffer.
@param Length Length of buffer in bytes.
@return 8-bit checksum of all bytes in buffer, or zero if ptr is NULL or len
is zero.
**/
UINT8
Calc8BitCksum (
VOID *Buffer,
UINTN Length
)
{
UINT8 *Ptr;
UINT8 Cksum;
Ptr = Buffer;
Cksum = 0;
if (Ptr == NULL || Length == 0) {
return 0;
}
while (Length-- != 0) {
Cksum = (UINT8) (Cksum + *Ptr++);
}
return Cksum;
}
/**
Test to see if this driver supports ControllerHandle. This service
is called by the EFI boot service ConnectController(). In
order to make drivers as small as possible, there are a few calling
restrictions for this service. ConnectController() must
follow these calling restrictions. If any other agent wishes to call
Supported() it must also follow these calling restrictions.
@param This Protocol instance pointer.
@param ControllerHandle Handle of device to test.
@param RemainingDevicePath Optional parameter use to pick a specific child
device to start.
@retval EFI_SUCCESS This driver supports this device.
@retval EFI_ALREADY_STARTED This driver is already running on this device.
@retval other This driver does not support this device.
**/
EFI_STATUS
EFIAPI
SimpleNetworkDriverSupported (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_STATUS Status;
EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *NiiProtocol;
PXE_UNDI *Pxe;
Status = gBS->OpenProtocol (
Controller,
&gEfiDevicePathProtocolGuid,
NULL,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_TEST_PROTOCOL
);
if (EFI_ERROR (Status)) {
return Status;
}
Status = gBS->OpenProtocol (
Controller,
&gEfiNetworkInterfaceIdentifierProtocolGuid_31,
(VOID **) &NiiProtocol,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
if (Status == EFI_ALREADY_STARTED) {
DEBUG ((EFI_D_INFO, "Support(): Already Started. on handle %p\n", Controller));
}
return Status;
}
DEBUG ((EFI_D_INFO, "Support(): UNDI3.1 found on handle %p\n", Controller));
//
// check the version, we don't want to connect to the undi16
//
if (NiiProtocol->Type != EfiNetworkInterfaceUndi) {
Status = EFI_UNSUPPORTED;
goto Done;
}
//
// Check to see if !PXE structure is valid. Paragraph alignment of !PXE structure is required.
//
if ((NiiProtocol->Id & 0x0F) != 0) {
DEBUG ((EFI_D_NET, "\n!PXE structure is not paragraph aligned.\n"));
Status = EFI_UNSUPPORTED;
goto Done;
}
Pxe = (PXE_UNDI *) (UINTN) (NiiProtocol->Id);
//
// Verify !PXE revisions.
//
if (Pxe->hw.Signature != PXE_ROMID_SIGNATURE) {
DEBUG ((EFI_D_NET, "\n!PXE signature is not valid.\n"));
Status = EFI_UNSUPPORTED;
goto Done;
}
if (Pxe->hw.Rev < PXE_ROMID_REV) {
DEBUG ((EFI_D_NET, "\n!PXE.Rev is not supported.\n"));
Status = EFI_UNSUPPORTED;
goto Done;
}
if (Pxe->hw.MajorVer < PXE_ROMID_MAJORVER) {
DEBUG ((EFI_D_NET, "\n!PXE.MajorVer is not supported.\n"));
Status = EFI_UNSUPPORTED;
goto Done;
} else if (Pxe->hw.MajorVer == PXE_ROMID_MAJORVER && Pxe->hw.MinorVer < PXE_ROMID_MINORVER) {
DEBUG ((EFI_D_NET, "\n!PXE.MinorVer is not supported."));
Status = EFI_UNSUPPORTED;
goto Done;
}
//
// Do S/W UNDI specific checks.
//
if ((Pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) == 0) {
if (Pxe->sw.EntryPoint < Pxe->sw.Len) {
DEBUG ((EFI_D_NET, "\n!PXE S/W entry point is not valid."));
Status = EFI_UNSUPPORTED;
goto Done;
}
if (Pxe->sw.BusCnt == 0) {
DEBUG ((EFI_D_NET, "\n!PXE.BusCnt is zero."));
Status = EFI_UNSUPPORTED;
goto Done;
}
}
Status = EFI_SUCCESS;
DEBUG ((EFI_D_INFO, "Support(): supported on %p\n", Controller));
Done:
gBS->CloseProtocol (
Controller,
&gEfiNetworkInterfaceIdentifierProtocolGuid_31,
This->DriverBindingHandle,
Controller
);
return Status;
}
/**
Start this driver on ControllerHandle. This service is called by the
EFI boot service ConnectController(). In order to make
drivers as small as possible, there are a few calling restrictions for
this service. ConnectController() must follow these
calling restrictions. If any other agent wishes to call Start() it
must also follow these calling restrictions.
@param This Protocol instance pointer.
@param ControllerHandle Handle of device to bind driver to.
@param RemainingDevicePath Optional parameter use to pick a specific child
device to start.
@retval EFI_SUCCESS This driver is added to ControllerHandle
@retval EFI_DEVICE_ERROR This driver could not be started due to a device error
@retval other This driver does not support this device
**/
EFI_STATUS
EFIAPI
SimpleNetworkDriverStart (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
)
{
EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL *Nii;
EFI_DEVICE_PATH_PROTOCOL *NiiDevicePath;
EFI_STATUS Status;
PXE_UNDI *Pxe;
SNP_DRIVER *Snp;
VOID *Address;
EFI_HANDLE Handle;
UINT8 BarIndex;
PXE_STATFLAGS InitStatFlags;
EFI_PCI_IO_PROTOCOL *PciIo;
EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BarDesc;
BOOLEAN FoundIoBar;
BOOLEAN FoundMemoryBar;
DEBUG ((EFI_D_NET, "\nSnpNotifyNetworkInterfaceIdentifier() "));
Status = gBS->OpenProtocol (
Controller,
&gEfiDevicePathProtocolGuid,
(VOID **) &NiiDevicePath,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
return Status;
}
Status = gBS->LocateDevicePath (
&gEfiPciIoProtocolGuid,
&NiiDevicePath,
&Handle
);
if (EFI_ERROR (Status)) {
return Status;
}
Status = gBS->OpenProtocol (
Handle,
&gEfiPciIoProtocolGuid,
(VOID **) &PciIo,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Get the NII interface.
//
Status = gBS->OpenProtocol (
Controller,
&gEfiNetworkInterfaceIdentifierProtocolGuid_31,
(VOID **) &Nii,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_BY_DRIVER
);
if (EFI_ERROR (Status)) {
gBS->CloseProtocol (
Controller,
&gEfiDevicePathProtocolGuid,
This->DriverBindingHandle,
Controller
);
return Status;
}
DEBUG ((EFI_D_INFO, "Start(): UNDI3.1 found\n"));
Pxe = (PXE_UNDI *) (UINTN) (Nii->Id);
if (Calc8BitCksum (Pxe, Pxe->hw.Len) != 0) {
DEBUG ((EFI_D_NET, "\n!PXE checksum is not correct.\n"));
goto NiiError;
}
if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {
//
// We can get any packets.
//
} else if ((Pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {
//
// We need to be able to get broadcast packets for DHCP.
// If we do not have promiscuous support, we must at least have
// broadcast support or we cannot do DHCP!
//
} else {
DEBUG ((EFI_D_NET, "\nUNDI does not have promiscuous or broadcast support."));
goto NiiError;
}
//
// OK, we like this UNDI, and we know snp is not already there on this handle
// Allocate and initialize a new simple network protocol structure.
//
Status = PciIo->AllocateBuffer (
PciIo,
AllocateAnyPages,
EfiBootServicesData,
SNP_MEM_PAGES (sizeof (SNP_DRIVER)),
&Address,
0
);
if (Status != EFI_SUCCESS) {
DEBUG ((EFI_D_NET, "\nCould not allocate SNP_DRIVER structure.\n"));
goto NiiError;
}
Snp = (SNP_DRIVER *) (UINTN) Address;
ZeroMem (Snp, sizeof (SNP_DRIVER));
Snp->PciIo = PciIo;
Snp->Signature = SNP_DRIVER_SIGNATURE;
EfiInitializeLock (&Snp->Lock, TPL_NOTIFY);
Snp->Snp.Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;
Snp->Snp.Start = SnpUndi32Start;
Snp->Snp.Stop = SnpUndi32Stop;
Snp->Snp.Initialize = SnpUndi32Initialize;
Snp->Snp.Reset = SnpUndi32Reset;
Snp->Snp.Shutdown = SnpUndi32Shutdown;
Snp->Snp.ReceiveFilters = SnpUndi32ReceiveFilters;
Snp->Snp.StationAddress = SnpUndi32StationAddress;
Snp->Snp.Statistics = SnpUndi32Statistics;
Snp->Snp.MCastIpToMac = SnpUndi32McastIpToMac;
Snp->Snp.NvData = SnpUndi32NvData;
Snp->Snp.GetStatus = SnpUndi32GetStatus;
Snp->Snp.Transmit = SnpUndi32Transmit;
Snp->Snp.Receive = SnpUndi32Receive;
Snp->Snp.WaitForPacket = NULL;
Snp->Snp.Mode = &Snp->Mode;
Snp->TxRxBufferSize = 0;
Snp->TxRxBuffer = NULL;
Snp->RecycledTxBuf = AllocatePool (sizeof (UINT64) * SNP_TX_BUFFER_INCREASEMENT);
if (Snp->RecycledTxBuf == NULL) {
Status = EFI_OUT_OF_RESOURCES;
goto Error_DeleteSNP;
}
Snp->MaxRecycledTxBuf = SNP_TX_BUFFER_INCREASEMENT;
Snp->RecycledTxBufCount = 0;
if (Nii->Revision >= EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION) {
Snp->IfNum = Nii->IfNum;
} else {
Snp->IfNum = (UINT8) (Nii->IfNum & 0xFF);
}
if ((Pxe->hw.Implementation & PXE_ROMID_IMP_HW_UNDI) != 0) {
Snp->IsSwUndi = FALSE;
Snp->IssueUndi32Command = &IssueHwUndiCommand;
} else {
Snp->IsSwUndi = TRUE;
if ((Pxe->sw.Implementation & PXE_ROMID_IMP_SW_VIRT_ADDR) != 0) {
Snp->IssueUndi32Command = (ISSUE_UNDI32_COMMAND) (UINTN) Pxe->sw.EntryPoint;
} else {
Snp->IssueUndi32Command = (ISSUE_UNDI32_COMMAND) (UINTN) ((UINT8) (UINTN) Pxe + Pxe->sw.EntryPoint);
}
}
//
// Allocate a global CPB and DB buffer for this UNDI interface.
// we do this because:
//
// -UNDI 3.0 wants all the addresses passed to it (even the cpb and db) to be
// within 2GB limit, create them here and map them so that when undi calls
// v2p callback to check if the physical address is < 2gb, we will pass.
//
// -This is not a requirement for 3.1 or later UNDIs but the code looks
// simpler if we use the same cpb, db variables for both old and new undi
// interfaces from all the SNP interface calls (we don't map the buffers
// for the newer undi interfaces though)
// .
// -it is OK to allocate one global set of CPB, DB pair for each UNDI
// interface as EFI does not multi-task and so SNP will not be re-entered!
//
Status = PciIo->AllocateBuffer (
PciIo,
AllocateAnyPages,
EfiBootServicesData,
SNP_MEM_PAGES (4096),
&Address,
0
);
if (Status != EFI_SUCCESS) {
DEBUG ((EFI_D_NET, "\nCould not allocate CPB and DB structures.\n"));
goto Error_DeleteSNP;
}
Snp->Cpb = (VOID *) (UINTN) Address;
Snp->Db = (VOID *) ((UINTN) Address + 2048);
//
// Find the correct BAR to do IO.
//
// Enumerate through the PCI BARs for the device to determine which one is
// the IO BAR. Save the index of the BAR into the adapter info structure.
// for regular 32bit BARs, 0 is memory mapped, 1 is io mapped
//
Snp->MemoryBarIndex = 0;
Snp->IoBarIndex = 1;
FoundMemoryBar = FALSE;
FoundIoBar = FALSE;
for (BarIndex = 0; BarIndex < PCI_MAX_BAR; BarIndex++) {
Status = PciIo->GetBarAttributes (
PciIo,
BarIndex,
NULL,
(VOID**) &BarDesc
);
if (Status == EFI_UNSUPPORTED) {
continue;
} else if (EFI_ERROR (Status)) {
goto Error_DeleteSNP;
}
if ((!FoundMemoryBar) && (BarDesc->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM)) {
Snp->MemoryBarIndex = BarIndex;
FoundMemoryBar = TRUE;
} else if ((!FoundIoBar) && (BarDesc->ResType == ACPI_ADDRESS_SPACE_TYPE_IO)) {
Snp->IoBarIndex = BarIndex;
FoundIoBar = TRUE;
}
FreePool (BarDesc);
if (FoundMemoryBar && FoundIoBar) {
break;
}
}
Status = PxeStart (Snp);
if (Status != EFI_SUCCESS) {
goto Error_DeleteSNP;
}
Snp->Cdb.OpCode = PXE_OPCODE_GET_INIT_INFO;
Snp->Cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
Snp->Cdb.CPBaddr = PXE_DBADDR_NOT_USED;
Snp->Cdb.DBsize = (UINT16) sizeof (Snp->InitInfo);
Snp->Cdb.DBaddr = (UINT64)(UINTN) (&Snp->InitInfo);
Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
Snp->Cdb.IFnum = Snp->IfNum;
Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
DEBUG ((EFI_D_NET, "\nSnp->undi.get_init_info() "));
(*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
//
// Save the INIT Stat Code...
//
InitStatFlags = Snp->Cdb.StatFlags;
if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
DEBUG ((EFI_D_NET, "\nSnp->undi.init_info() %xh:%xh\n", Snp->Cdb.StatFlags, Snp->Cdb.StatCode));
PxeStop (Snp);
goto Error_DeleteSNP;
}
//
// Initialize simple network protocol mode structure
//
Snp->Mode.State = EfiSimpleNetworkStopped;
Snp->Mode.HwAddressSize = Snp->InitInfo.HWaddrLen;
Snp->Mode.MediaHeaderSize = Snp->InitInfo.MediaHeaderLen;
Snp->Mode.MaxPacketSize = Snp->InitInfo.FrameDataLen;
Snp->Mode.NvRamAccessSize = Snp->InitInfo.NvWidth;
Snp->Mode.NvRamSize = Snp->InitInfo.NvCount * Snp->Mode.NvRamAccessSize;
Snp->Mode.IfType = Snp->InitInfo.IFtype;
Snp->Mode.MaxMCastFilterCount = Snp->InitInfo.MCastFilterCnt;
Snp->Mode.MCastFilterCount = 0;
switch (InitStatFlags & PXE_STATFLAGS_CABLE_DETECT_MASK) {
case PXE_STATFLAGS_CABLE_DETECT_SUPPORTED:
Snp->CableDetectSupported = TRUE;
break;
case PXE_STATFLAGS_CABLE_DETECT_NOT_SUPPORTED:
default:
Snp->CableDetectSupported = FALSE;
}
switch (InitStatFlags & PXE_STATFLAGS_GET_STATUS_NO_MEDIA_MASK) {
case PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED:
Snp->MediaStatusSupported = TRUE;
break;
case PXE_STATFLAGS_GET_STATUS_NO_MEDIA_NOT_SUPPORTED:
default:
Snp->MediaStatusSupported = FALSE;
}
if (Snp->CableDetectSupported || Snp->MediaStatusSupported) {
Snp->Mode.MediaPresentSupported = TRUE;
}
if ((Pxe->hw.Implementation & PXE_ROMID_IMP_STATION_ADDR_SETTABLE) != 0) {
Snp->Mode.MacAddressChangeable = TRUE;
} else {
Snp->Mode.MacAddressChangeable = FALSE;
}
if ((Pxe->hw.Implementation & PXE_ROMID_IMP_MULTI_FRAME_SUPPORTED) != 0) {
Snp->Mode.MultipleTxSupported = TRUE;
} else {
Snp->Mode.MultipleTxSupported = FALSE;
}
Snp->Mode.ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST;
if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) != 0) {
Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
}
if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED) != 0) {
Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS;
}
if ((Pxe->hw.Implementation & PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED) != 0) {
Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST;
}
if ((Pxe->hw.Implementation & PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED) != 0) {
Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST;
}
if ((Pxe->hw.Implementation & PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED) != 0) {
Snp->Mode.ReceiveFilterMask |= EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
}
Snp->Mode.ReceiveFilterSetting = 0;
//
// need to get the station address to save in the mode structure. we need to
// initialize the UNDI first for this.
//
Snp->TxRxBufferSize = Snp->InitInfo.MemoryRequired;
Status = PxeInit (Snp, PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE);
if (EFI_ERROR (Status)) {
PxeStop (Snp);
goto Error_DeleteSNP;
}
Status = PxeGetStnAddr (Snp);
if (Status != EFI_SUCCESS) {
DEBUG ((EFI_D_ERROR, "\nSnp->undi.get_station_addr() failed.\n"));
PxeShutdown (Snp);
PxeStop (Snp);
goto Error_DeleteSNP;
}
Snp->Mode.MediaPresent = FALSE;
//
// We should not leave UNDI started and initialized here. this DriverStart()
// routine must only find and attach the SNP interface to UNDI layer that it
// finds on the given handle!
// The UNDI layer will be started when upper layers call Snp->start.
// How ever, this DriverStart() must fill up the snp mode structure which
// contains the MAC address of the NIC. For this reason we started and
// initialized UNDI here, now we are done, do a shutdown and stop of the
// UNDI interface!
//
PxeShutdown (Snp);
PxeStop (Snp);
//
// Create EXIT_BOOT_SERIVES Event
//
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_NOTIFY,
SnpNotifyExitBootServices,
Snp,
&gEfiEventExitBootServicesGuid,
&Snp->ExitBootServicesEvent
);
if (EFI_ERROR (Status)) {
goto Error_DeleteSNP;
}
//
// add SNP to the undi handle
//
Status = gBS->InstallProtocolInterface (
&Controller,
&gEfiSimpleNetworkProtocolGuid,
EFI_NATIVE_INTERFACE,
&(Snp->Snp)
);
if (!EFI_ERROR (Status)) {
return Status;
}
PciIo->FreeBuffer (
PciIo,
SNP_MEM_PAGES (4096),
Snp->Cpb
);
Error_DeleteSNP:
if (Snp->RecycledTxBuf != NULL) {
FreePool (Snp->RecycledTxBuf);
}
PciIo->FreeBuffer (
PciIo,
SNP_MEM_PAGES (sizeof (SNP_DRIVER)),
Snp
);
NiiError:
gBS->CloseProtocol (
Controller,
&gEfiNetworkInterfaceIdentifierProtocolGuid_31,
This->DriverBindingHandle,
Controller
);
gBS->CloseProtocol (
Controller,
&gEfiDevicePathProtocolGuid,
This->DriverBindingHandle,
Controller
);
//
// If we got here that means we are in error state.
//
if (!EFI_ERROR (Status)) {
Status = EFI_DEVICE_ERROR;
}
return Status;
}
/**
Stop this driver on ControllerHandle. This service is called by the
EFI boot service DisconnectController(). In order to
make drivers as small as possible, there are a few calling
restrictions for this service. DisconnectController()
must follow these calling restrictions. If any other agent wishes
to call Stop() it must also follow these calling restrictions.
@param This Protocol instance pointer.
@param ControllerHandle Handle of device to stop driver on
@param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
children is zero stop the entire bus driver.
@param ChildHandleBuffer List of Child Handles to Stop.
@retval EFI_SUCCESS This driver is removed ControllerHandle
@retval other This driver was not removed from this device
**/
EFI_STATUS
EFIAPI
SimpleNetworkDriverStop (
IN EFI_DRIVER_BINDING_PROTOCOL *This,
IN EFI_HANDLE Controller,
IN UINTN NumberOfChildren,
IN EFI_HANDLE *ChildHandleBuffer
)
{
EFI_STATUS Status;
EFI_SIMPLE_NETWORK_PROTOCOL *SnpProtocol;
SNP_DRIVER *Snp;
EFI_PCI_IO_PROTOCOL *PciIo;
//
// Get our context back.
//
Status = gBS->OpenProtocol (
Controller,
&gEfiSimpleNetworkProtocolGuid,
(VOID **) &SnpProtocol,
This->DriverBindingHandle,
Controller,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (EFI_ERROR (Status)) {
return EFI_UNSUPPORTED;
}
Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (SnpProtocol);
Status = gBS->UninstallProtocolInterface (
Controller,
&gEfiSimpleNetworkProtocolGuid,
&Snp->Snp
);
if (EFI_ERROR (Status)) {
return Status;
}
//
// Close EXIT_BOOT_SERIVES Event
//
gBS->CloseEvent (Snp->ExitBootServicesEvent);
Status = gBS->CloseProtocol (
Controller,
&gEfiNetworkInterfaceIdentifierProtocolGuid_31,
This->DriverBindingHandle,
Controller
);
Status = gBS->CloseProtocol (
Controller,
&gEfiDevicePathProtocolGuid,
This->DriverBindingHandle,
Controller
);
PxeShutdown (Snp);
PxeStop (Snp);
FreePool (Snp->RecycledTxBuf);
PciIo = Snp->PciIo;
PciIo->FreeBuffer (
PciIo,
SNP_MEM_PAGES (4096),
Snp->Cpb
);
PciIo->FreeBuffer (
PciIo,
SNP_MEM_PAGES (sizeof (SNP_DRIVER)),
Snp
);
return Status;
}
//
// Simple Network Protocol Driver Global Variables
//
EFI_DRIVER_BINDING_PROTOCOL gSimpleNetworkDriverBinding = {
SimpleNetworkDriverSupported,
SimpleNetworkDriverStart,
SimpleNetworkDriverStop,
0xa,
NULL,
NULL
};
/**
The SNP driver entry point.
@param ImageHandle The driver image handle.
@param SystemTable The system table.
@retval EFI_SUCEESS Initialization routine has found UNDI hardware,
loaded it's ROM, and installed a notify event for
the Network Indentifier Interface Protocol
successfully.
@retval Other Return value from HandleProtocol for
DeviceIoProtocol or LoadedImageProtocol
**/
EFI_STATUS
EFIAPI
InitializeSnpNiiDriver (
IN EFI_HANDLE ImageHandle,
IN EFI_SYSTEM_TABLE *SystemTable
)
{
return EfiLibInstallDriverBindingComponentName2 (
ImageHandle,
SystemTable,
&gSimpleNetworkDriverBinding,
ImageHandle,
&gSimpleNetworkComponentName,
&gSimpleNetworkComponentName2
);
}

1033
NetworkPkg/SnpDxe/Snp.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,77 @@
## @file
# This module produces EFI SNP Protocol.
#
# This module produces Simple Network Protocol upon EFI Network Interface
# Identifier Protocol, to provide a packet level interface to a network adapter.
#
# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
##
[Defines]
INF_VERSION = 0x00010005
BASE_NAME = SnpDxe
MODULE_UNI_FILE = SnpDxe.uni
FILE_GUID = A2f436EA-A127-4EF8-957C-8048606FF670
MODULE_TYPE = UEFI_DRIVER
VERSION_STRING = 1.0
ENTRY_POINT = InitializeSnpNiiDriver
UNLOAD_IMAGE = NetLibDefaultUnload
#
# The following information is for reference only and not required by the build tools.
#
# VALID_ARCHITECTURES = IA32 X64 EBC
#
# DRIVER_BINDING = mSimpleNetworkDriverBinding
# COMPONENT_NAME = gSimpleNetworkComponentName
# COMPONENT_NAME2 = gSimpleNetworkComponentName2
#
[Sources]
Receive.c
Snp.h
Nvdata.c
Get_status.c
Start.c
Snp.c
Stop.c
Statistics.c
Reset.c
Shutdown.c
Mcast_ip_to_mac.c
Transmit.c
WaitForPacket.c
Receive_filters.c
Initialize.c
ComponentName.c
Callback.c
Station_address.c
[Packages]
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec
[LibraryClasses]
UefiLib
BaseLib
UefiBootServicesTableLib
UefiDriverEntryPoint
BaseMemoryLib
DebugLib
NetLib
[Guids]
gEfiEventExitBootServicesGuid ## SOMETIMES_CONSUMES ## Event
[Protocols]
gEfiSimpleNetworkProtocolGuid ## BY_START
gEfiDevicePathProtocolGuid ## TO_START
gEfiNetworkInterfaceIdentifierProtocolGuid_31 ## TO_START
gEfiPciIoProtocolGuid ## TO_START
[UserExtensions.TianoCore."ExtraFiles"]
SnpDxeExtra.uni

View File

@@ -0,0 +1,17 @@
// /** @file
// This module produces EFI SNP Protocol.
//
// This module produces Simple Network Protocol upon EFI Network Interface
// Identifier Protocol, to provide a packet level interface to a network adapter.
//
// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//
// **/
#string STR_MODULE_ABSTRACT #language en-US "Produces EFI SNP Protocol"
#string STR_MODULE_DESCRIPTION #language en-US "This module produces Simple Network Protocol upon EFI Network Interface Identifier Protocol to provide a packet level interface to a network adapter."

View File

@@ -0,0 +1,14 @@
// /** @file
// SnpDxe Localized Strings and Content
//
// Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
//
// SPDX-License-Identifier: BSD-2-Clause-Patent
//
// **/
#string STR_PROPERTIES_MODULE_NAME
#language en-US
"SNP DXE Driver"

162
NetworkPkg/SnpDxe/Start.c Normal file
View File

@@ -0,0 +1,162 @@
/** @file
Implementation of starting a network adapter.
Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Snp.h"
/**
Call UNDI to start the interface and changes the snp state.
@param Snp pointer to snp driver structure.
@retval EFI_SUCCESS UNDI is started successfully.
@retval EFI_DEVICE_ERROR UNDI could not be started.
**/
EFI_STATUS
PxeStart (
IN SNP_DRIVER *Snp
)
{
PXE_CPB_START_31 *Cpb31;
Cpb31 = Snp->Cpb;
//
// Initialize UNDI Start CDB for H/W UNDI
//
Snp->Cdb.OpCode = PXE_OPCODE_START;
Snp->Cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
Snp->Cdb.DBsize = PXE_DBSIZE_NOT_USED;
Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
Snp->Cdb.DBaddr = PXE_DBADDR_NOT_USED;
Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
Snp->Cdb.IFnum = Snp->IfNum;
Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
//
// Make changes to H/W UNDI Start CDB if this is
// a S/W UNDI.
//
if (Snp->IsSwUndi) {
Snp->Cdb.CPBsize = (UINT16) sizeof (PXE_CPB_START_31);
Snp->Cdb.CPBaddr = (UINT64)(UINTN) Cpb31;
Cpb31->Delay = (UINT64)(UINTN) &SnpUndi32CallbackDelay;
Cpb31->Block = (UINT64)(UINTN) &SnpUndi32CallbackBlock;
//
// Virtual == Physical. This can be set to zero.
//
Cpb31->Virt2Phys = (UINT64)(UINTN) 0;
Cpb31->Mem_IO = (UINT64)(UINTN) &SnpUndi32CallbackMemio;
Cpb31->Map_Mem = (UINT64)(UINTN) &SnpUndi32CallbackMap;
Cpb31->UnMap_Mem = (UINT64)(UINTN) &SnpUndi32CallbackUnmap;
Cpb31->Sync_Mem = (UINT64)(UINTN) &SnpUndi32CallbackSync;
Cpb31->Unique_ID = (UINT64)(UINTN) Snp;
}
//
// Issue UNDI command and check result.
//
DEBUG ((EFI_D_NET, "\nsnp->undi.start() "));
(*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
//
// UNDI could not be started. Return UNDI error.
//
DEBUG (
(EFI_D_ERROR,
"\nsnp->undi.start() %xh:%xh\n",
Snp->Cdb.StatCode,
Snp->Cdb.StatFlags)
);
return EFI_DEVICE_ERROR;
}
//
// Set simple network state to Started and return success.
//
Snp->Mode.State = EfiSimpleNetworkStarted;
return EFI_SUCCESS;
}
/**
Change the state of a network interface from "stopped" to "started."
This function starts a network interface. If the network interface successfully
starts, then EFI_SUCCESS will be returned.
@param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
@retval EFI_SUCCESS The network interface was started.
@retval EFI_ALREADY_STARTED The network interface is already in the started state.
@retval EFI_INVALID_PARAMETER This parameter was NULL or did not point to a valid
EFI_SIMPLE_NETWORK_PROTOCOL structure.
@retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
@retval EFI_UNSUPPORTED This function is not supported by the network interface.
**/
EFI_STATUS
EFIAPI
SnpUndi32Start (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This
)
{
SNP_DRIVER *Snp;
EFI_STATUS Status;
UINTN Index;
EFI_TPL OldTpl;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
switch (Snp->Mode.State) {
case EfiSimpleNetworkStopped:
break;
case EfiSimpleNetworkStarted:
case EfiSimpleNetworkInitialized:
Status = EFI_ALREADY_STARTED;
goto ON_EXIT;
default:
Status = EFI_DEVICE_ERROR;
goto ON_EXIT;
}
Status = PxeStart (Snp);
if (EFI_ERROR (Status)) {
goto ON_EXIT;
}
//
// clear the map_list in SNP structure
//
for (Index = 0; Index < MAX_MAP_LENGTH; Index++) {
Snp->MapList[Index].VirtualAddress = 0;
Snp->MapList[Index].MapCookie = 0;
}
Snp->Mode.MCastFilterCount = 0;
ON_EXIT:
gBS->RestoreTPL (OldTpl);
return Status;
}

View File

@@ -0,0 +1,243 @@
/** @file
Implementation of reading the MAC address of a network adapter.
Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Snp.h"
/**
Call UNDI to read the MAC address of the NIC and update the mode structure
with the address.
@param Snp Pointer to snp driver structure.
@retval EFI_SUCCESS The MAC address of the NIC is read successfully.
@retval EFI_DEVICE_ERROR Failed to read the MAC address of the NIC.
**/
EFI_STATUS
PxeGetStnAddr (
SNP_DRIVER *Snp
)
{
PXE_DB_STATION_ADDRESS *Db;
Db = Snp->Db;
Snp->Cdb.OpCode = PXE_OPCODE_STATION_ADDRESS;
Snp->Cdb.OpFlags = PXE_OPFLAGS_STATION_ADDRESS_READ;
Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
Snp->Cdb.DBsize = (UINT16) sizeof (PXE_DB_STATION_ADDRESS);
Snp->Cdb.DBaddr = (UINT64)(UINTN) Db;
Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
Snp->Cdb.IFnum = Snp->IfNum;
Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
//
// Issue UNDI command and check result.
//
DEBUG ((EFI_D_NET, "\nsnp->undi.station_addr() "));
(*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
DEBUG (
(EFI_D_ERROR,
"\nsnp->undi.station_addr() %xh:%xh\n",
Snp->Cdb.StatFlags,
Snp->Cdb.StatCode)
);
return EFI_DEVICE_ERROR;
}
//
// Set new station address in SNP->Mode structure and return success.
//
CopyMem (
&(Snp->Mode.CurrentAddress),
&Db->StationAddr,
Snp->Mode.HwAddressSize
);
CopyMem (
&Snp->Mode.BroadcastAddress,
&Db->BroadcastAddr,
Snp->Mode.HwAddressSize
);
CopyMem (
&Snp->Mode.PermanentAddress,
&Db->PermanentAddr,
Snp->Mode.HwAddressSize
);
return EFI_SUCCESS;
}
/**
Call UNDI to set a new MAC address for the NIC.
@param Snp Pointer to Snp driver structure.
@param NewMacAddr Pointer to a MAC address to be set for the NIC, if this is
NULL then this routine resets the mac address to the NIC's
original address.
**/
EFI_STATUS
PxeSetStnAddr (
SNP_DRIVER *Snp,
EFI_MAC_ADDRESS *NewMacAddr
)
{
PXE_CPB_STATION_ADDRESS *Cpb;
PXE_DB_STATION_ADDRESS *Db;
Cpb = Snp->Cpb;
Db = Snp->Db;
Snp->Cdb.OpCode = PXE_OPCODE_STATION_ADDRESS;
if (NewMacAddr == NULL) {
Snp->Cdb.OpFlags = PXE_OPFLAGS_STATION_ADDRESS_RESET;
Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
} else {
Snp->Cdb.OpFlags = PXE_OPFLAGS_STATION_ADDRESS_WRITE;
//
// Supplying a new address in the CPB will make undi change the mac address to the new one.
//
CopyMem (&Cpb->StationAddr, NewMacAddr, Snp->Mode.HwAddressSize);
Snp->Cdb.CPBsize = (UINT16) sizeof (PXE_CPB_STATION_ADDRESS);
Snp->Cdb.CPBaddr = (UINT64)(UINTN) Cpb;
}
Snp->Cdb.DBsize = (UINT16) sizeof (PXE_DB_STATION_ADDRESS);
Snp->Cdb.DBaddr = (UINT64)(UINTN) Db;
Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
Snp->Cdb.IFnum = Snp->IfNum;
Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
//
// Issue UNDI command and check result.
//
DEBUG ((EFI_D_NET, "\nsnp->undi.station_addr() "));
(*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
DEBUG (
(EFI_D_ERROR,
"\nsnp->undi.station_addr() %xh:%xh\n",
Snp->Cdb.StatFlags,
Snp->Cdb.StatCode)
);
//
// UNDI command failed. Return UNDI status to caller.
//
return EFI_DEVICE_ERROR;
}
//
// read the changed address and save it in SNP->Mode structure
//
PxeGetStnAddr (Snp);
return EFI_SUCCESS;
}
/**
Modifies or resets the current station address, if supported.
This function modifies or resets the current station address of a network
interface, if supported. If Reset is TRUE, then the current station address is
set to the network interface's permanent address. If Reset is FALSE, and the
network interface allows its station address to be modified, then the current
station address is changed to the address specified by New. If the network
interface does not allow its station address to be modified, then
EFI_INVALID_PARAMETER will be returned. If the station address is successfully
updated on the network interface, EFI_SUCCESS will be returned. If the driver
has not been initialized, EFI_DEVICE_ERROR will be returned.
@param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
@param Reset Flag used to reset the station address to the network interface's
permanent address.
@param New New station address to be used for the network interface.
@retval EFI_SUCCESS The network interface's station address was updated.
@retval EFI_NOT_STARTED The Simple Network Protocol interface has not been
started by calling Start().
@retval EFI_INVALID_PARAMETER The New station address was not accepted by the NIC.
@retval EFI_INVALID_PARAMETER Reset is FALSE and New is NULL.
@retval EFI_DEVICE_ERROR The Simple Network Protocol interface has not
been initialized by calling Initialize().
@retval EFI_DEVICE_ERROR An error occurred attempting to set the new
station address.
@retval EFI_UNSUPPORTED The NIC does not support changing the network
interface's station address.
**/
EFI_STATUS
EFIAPI
SnpUndi32StationAddress (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
IN BOOLEAN Reset,
IN EFI_MAC_ADDRESS *New OPTIONAL
)
{
SNP_DRIVER *Snp;
EFI_STATUS Status;
EFI_TPL OldTpl;
//
// Check for invalid parameter combinations.
//
if ((This == NULL) ||
(!Reset && (New == NULL))) {
return EFI_INVALID_PARAMETER;
}
Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
//
// Return error if the SNP is not initialized.
//
switch (Snp->Mode.State) {
case EfiSimpleNetworkInitialized:
break;
case EfiSimpleNetworkStopped:
Status = EFI_NOT_STARTED;
goto ON_EXIT;
default:
Status = EFI_DEVICE_ERROR;
goto ON_EXIT;
}
if (Reset) {
Status = PxeSetStnAddr (Snp, NULL);
} else {
Status = PxeSetStnAddr (Snp, New);
}
ON_EXIT:
gBS->RestoreTPL (OldTpl);
return Status;
}

View File

@@ -0,0 +1,224 @@
/** @file
Implementation of collecting the statistics on a network interface.
Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Snp.h"
/**
Resets or collects the statistics on a network interface.
This function resets or collects the statistics on a network interface. If the
size of the statistics table specified by StatisticsSize is not big enough for
all the statistics that are collected by the network interface, then a partial
buffer of statistics is returned in StatisticsTable, StatisticsSize is set to
the size required to collect all the available statistics, and
EFI_BUFFER_TOO_SMALL is returned.
If StatisticsSize is big enough for all the statistics, then StatisticsTable
will be filled, StatisticsSize will be set to the size of the returned
StatisticsTable structure, and EFI_SUCCESS is returned.
If the driver has not been initialized, EFI_DEVICE_ERROR will be returned.
If Reset is FALSE, and both StatisticsSize and StatisticsTable are NULL, then
no operations will be performed, and EFI_SUCCESS will be returned.
If Reset is TRUE, then all of the supported statistics counters on this network
interface will be reset to zero.
@param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
@param Reset Set to TRUE to reset the statistics for the network interface.
@param StatisticsSize On input the size, in bytes, of StatisticsTable. On output
the size, in bytes, of the resulting table of statistics.
@param StatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that
contains the statistics. Type EFI_NETWORK_STATISTICS is
defined in "Related Definitions" below.
@retval EFI_SUCCESS The requested operation succeeded.
@retval EFI_NOT_STARTED The Simple Network Protocol interface has not been
started by calling Start().
@retval EFI_BUFFER_TOO_SMALL StatisticsSize is not NULL and StatisticsTable is
NULL. The current buffer size that is needed to
hold all the statistics is returned in StatisticsSize.
@retval EFI_BUFFER_TOO_SMALL StatisticsSize is not NULL and StatisticsTable is
not NULL. The current buffer size that is needed
to hold all the statistics is returned in
StatisticsSize. A partial set of statistics is
returned in StatisticsTable.
@retval EFI_INVALID_PARAMETER StatisticsSize is NULL and StatisticsTable is not
NULL.
@retval EFI_DEVICE_ERROR The Simple Network Protocol interface has not
been initialized by calling Initialize().
@retval EFI_DEVICE_ERROR An error was encountered collecting statistics
from the NIC.
@retval EFI_UNSUPPORTED The NIC does not support collecting statistics
from the network interface.
**/
EFI_STATUS
EFIAPI
SnpUndi32Statistics (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
IN BOOLEAN Reset,
IN OUT UINTN *StatisticsSize, OPTIONAL
IN OUT EFI_NETWORK_STATISTICS *StatisticsTable OPTIONAL
)
{
SNP_DRIVER *Snp;
PXE_DB_STATISTICS *Db;
UINT64 *Stp;
UINT64 Mask;
UINTN Size;
UINTN Index;
EFI_TPL OldTpl;
EFI_STATUS Status;
//
// Get pointer to SNP driver instance for *This.
//
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
//
// Return error if the SNP is not initialized.
//
switch (Snp->Mode.State) {
case EfiSimpleNetworkInitialized:
break;
case EfiSimpleNetworkStopped:
Status = EFI_NOT_STARTED;
goto ON_EXIT;
default:
Status = EFI_DEVICE_ERROR;
goto ON_EXIT;
}
//
// if we are not resetting the counters, we have to have a valid stat table
// with >0 size. if no reset, no table and no size, return success.
//
if (!Reset && StatisticsSize == NULL) {
Status = (StatisticsTable != NULL) ? EFI_INVALID_PARAMETER : EFI_SUCCESS;
goto ON_EXIT;
}
//
// Initialize UNDI Statistics CDB
//
Snp->Cdb.OpCode = PXE_OPCODE_STATISTICS;
Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
Snp->Cdb.IFnum = Snp->IfNum;
Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
if (Reset) {
Snp->Cdb.OpFlags = PXE_OPFLAGS_STATISTICS_RESET;
Snp->Cdb.DBsize = PXE_DBSIZE_NOT_USED;
Snp->Cdb.DBaddr = PXE_DBADDR_NOT_USED;
Db = Snp->Db;
} else {
Snp->Cdb.OpFlags = PXE_OPFLAGS_STATISTICS_READ;
Snp->Cdb.DBsize = (UINT16) sizeof (PXE_DB_STATISTICS);
Snp->Cdb.DBaddr = (UINT64)(UINTN) (Db = Snp->Db);
}
//
// Issue UNDI command and check result.
//
DEBUG ((EFI_D_NET, "\nsnp->undi.statistics() "));
(*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
switch (Snp->Cdb.StatCode) {
case PXE_STATCODE_SUCCESS:
break;
case PXE_STATCODE_UNSUPPORTED:
DEBUG (
(EFI_D_ERROR,
"\nsnp->undi.statistics() %xh:%xh\n",
Snp->Cdb.StatFlags,
Snp->Cdb.StatCode)
);
Status = EFI_UNSUPPORTED;
goto ON_EXIT;
default:
DEBUG (
(EFI_D_ERROR,
"\nsnp->undi.statistics() %xh:%xh\n",
Snp->Cdb.StatFlags,
Snp->Cdb.StatCode)
);
Status = EFI_DEVICE_ERROR;
goto ON_EXIT;
}
if (Reset) {
Status = EFI_SUCCESS;
goto ON_EXIT;
}
if (StatisticsTable == NULL) {
*StatisticsSize = sizeof (EFI_NETWORK_STATISTICS);
Status = EFI_BUFFER_TOO_SMALL;
goto ON_EXIT;
}
//
// Convert the UNDI statistics information to SNP statistics
// information.
//
ZeroMem (StatisticsTable, *StatisticsSize);
Stp = (UINT64 *) StatisticsTable;
Size = 0;
for (Index = 0, Mask = 1; Index < 64; Index++, Mask = LShiftU64 (Mask, 1), Stp++) {
//
// There must be room for a full UINT64. Partial
// numbers will not be stored.
//
if ((Index + 1) * sizeof (UINT64) > *StatisticsSize) {
break;
}
if ((Db->Supported & Mask) != 0) {
*Stp = Db->Data[Index];
Size = Index + 1;
} else {
SetMem (Stp, sizeof (UINT64), 0xFF);
}
}
//
// Compute size up to last supported statistic.
//
while (++Index < 64) {
if ((Db->Supported & (Mask = LShiftU64 (Mask, 1))) != 0) {
Size = Index;
}
}
Size *= sizeof (UINT64);
if (*StatisticsSize >= Size) {
*StatisticsSize = Size;
Status = EFI_SUCCESS;
} else {
*StatisticsSize = Size;
Status = EFI_BUFFER_TOO_SMALL;
}
ON_EXIT:
gBS->RestoreTPL (OldTpl);
return Status;
}

120
NetworkPkg/SnpDxe/Stop.c Normal file
View File

@@ -0,0 +1,120 @@
/** @file
Implementation of stopping a network interface.
Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Snp.h"
/**
Call UNDI to stop the interface and changes the snp state.
@param Snp Pointer to snp driver structure
@retval EFI_SUCCESS The network interface was stopped.
@retval EFI_DEVICE_ERROR SNP is not initialized.
**/
EFI_STATUS
PxeStop (
SNP_DRIVER *Snp
)
{
Snp->Cdb.OpCode = PXE_OPCODE_STOP;
Snp->Cdb.OpFlags = PXE_OPFLAGS_NOT_USED;
Snp->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
Snp->Cdb.DBsize = PXE_DBSIZE_NOT_USED;
Snp->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
Snp->Cdb.DBaddr = PXE_DBADDR_NOT_USED;
Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
Snp->Cdb.IFnum = Snp->IfNum;
Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
//
// Issue UNDI command
//
DEBUG ((EFI_D_NET, "\nsnp->undi.stop() "));
(*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);
if (Snp->Cdb.StatCode != PXE_STATCODE_SUCCESS) {
DEBUG (
(EFI_D_WARN,
"\nsnp->undi.stop() %xh:%xh\n",
Snp->Cdb.StatFlags,
Snp->Cdb.StatCode)
);
return EFI_DEVICE_ERROR;
}
//
// Set simple network state to Started and return success.
//
Snp->Mode.State = EfiSimpleNetworkStopped;
return EFI_SUCCESS;
}
/**
Changes the state of a network interface from "started" to "stopped."
This function stops a network interface. This call is only valid if the network
interface is in the started state. If the network interface was successfully
stopped, then EFI_SUCCESS will be returned.
@param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL
instance.
@retval EFI_SUCCESS The network interface was stopped.
@retval EFI_NOT_STARTED The network interface has not been started.
@retval EFI_INVALID_PARAMETER This parameter was NULL or did not point to a
valid EFI_SIMPLE_NETWORK_PROTOCOL structure.
@retval EFI_DEVICE_ERROR The command could not be sent to the network
interface.
@retval EFI_UNSUPPORTED This function is not supported by the network
interface.
**/
EFI_STATUS
EFIAPI
SnpUndi32Stop (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This
)
{
SNP_DRIVER *Snp;
EFI_TPL OldTpl;
EFI_STATUS Status;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
switch (Snp->Mode.State) {
case EfiSimpleNetworkStarted:
break;
case EfiSimpleNetworkStopped:
Status = EFI_NOT_STARTED;
goto ON_EXIT;
default:
Status = EFI_DEVICE_ERROR;
goto ON_EXIT;
}
Status = PxeStop (Snp);
ON_EXIT:
gBS->RestoreTPL (OldTpl);
return Status;
}

View File

@@ -0,0 +1,353 @@
/** @file
Implementation of transmitting a packet.
Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Snp.h"
/**
Call UNDI to create the meadia header for the given data buffer.
@param Snp Pointer to SNP driver structure.
@param MacHeaderPtr Address where the media header will be filled in.
@param HeaderSize Size of the memory at MacHeaderPtr.
@param Buffer Data buffer pointer.
@param BufferSize Size of data in the Buffer
@param DestAddr Address of the destination mac address buffer.
@param SrcAddr Address of the source mac address buffer.
@param ProtocolPtr Address of the protocol type.
@retval EFI_SUCCESS Successfully completed the undi call.
@retval Other Error return from undi call.
**/
EFI_STATUS
PxeFillHeader (
SNP_DRIVER *Snp,
VOID *MacHeaderPtr,
UINTN HeaderSize,
VOID *Buffer,
UINTN BufferSize,
EFI_MAC_ADDRESS *DestAddr,
EFI_MAC_ADDRESS *SrcAddr,
UINT16 *ProtocolPtr
)
{
PXE_CPB_FILL_HEADER_FRAGMENTED *Cpb;
Cpb = Snp->Cpb;
if (SrcAddr != NULL) {
CopyMem (
(VOID *) Cpb->SrcAddr,
(VOID *) SrcAddr,
Snp->Mode.HwAddressSize
);
} else {
CopyMem (
(VOID *) Cpb->SrcAddr,
(VOID *) &(Snp->Mode.CurrentAddress),
Snp->Mode.HwAddressSize
);
}
CopyMem (
(VOID *) Cpb->DestAddr,
(VOID *) DestAddr,
Snp->Mode.HwAddressSize
);
//
// we need to do the byte swapping
//
Cpb->Protocol = (UINT16) PXE_SWAP_UINT16 (*ProtocolPtr);
Cpb->PacketLen = (UINT32) (BufferSize);
Cpb->MediaHeaderLen = (UINT16) HeaderSize;
Cpb->FragCnt = 2;
Cpb->reserved = 0;
Cpb->FragDesc[0].FragAddr = (UINT64)(UINTN) MacHeaderPtr;
Cpb->FragDesc[0].FragLen = (UINT32) HeaderSize;
Cpb->FragDesc[1].FragAddr = (UINT64)(UINTN) Buffer;
Cpb->FragDesc[1].FragLen = (UINT32) BufferSize;
Cpb->FragDesc[0].reserved = Cpb->FragDesc[1].reserved = 0;
Snp->Cdb.OpCode = PXE_OPCODE_FILL_HEADER;
Snp->Cdb.OpFlags = PXE_OPFLAGS_FILL_HEADER_FRAGMENTED;
Snp->Cdb.DBsize = PXE_DBSIZE_NOT_USED;
Snp->Cdb.DBaddr = PXE_DBADDR_NOT_USED;
Snp->Cdb.CPBsize = (UINT16) sizeof (PXE_CPB_FILL_HEADER_FRAGMENTED);
Snp->Cdb.CPBaddr = (UINT64)(UINTN) Cpb;
Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
Snp->Cdb.IFnum = Snp->IfNum;
Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
//
// Issue UNDI command and check result.
//
DEBUG ((EFI_D_NET, "\nSnp->undi.fill_header() "));
(*Snp->IssueUndi32Command) ((UINT64) (UINTN) &Snp->Cdb);
switch (Snp->Cdb.StatCode) {
case PXE_STATCODE_SUCCESS:
return EFI_SUCCESS;
case PXE_STATCODE_INVALID_PARAMETER:
DEBUG (
(EFI_D_ERROR,
"\nSnp->undi.fill_header() %xh:%xh\n",
Snp->Cdb.StatFlags,
Snp->Cdb.StatCode)
);
return EFI_INVALID_PARAMETER;
default:
DEBUG (
(EFI_D_ERROR,
"\nSnp->undi.fill_header() %xh:%xh\n",
Snp->Cdb.StatFlags,
Snp->Cdb.StatCode)
);
return EFI_DEVICE_ERROR;
}
}
/**
This routine calls undi to transmit the given data buffer
@param Snp pointer to SNP driver structure
@param Buffer data buffer pointer
@param BufferSize Size of data in the Buffer
@retval EFI_SUCCESS if successfully completed the undi call
@retval Other error return from undi call.
**/
EFI_STATUS
PxeTransmit (
SNP_DRIVER *Snp,
VOID *Buffer,
UINTN BufferSize
)
{
PXE_CPB_TRANSMIT *Cpb;
EFI_STATUS Status;
Cpb = Snp->Cpb;
Cpb->FrameAddr = (UINT64) (UINTN) Buffer;
Cpb->DataLen = (UINT32) BufferSize;
Cpb->MediaheaderLen = 0;
Cpb->reserved = 0;
Snp->Cdb.OpFlags = PXE_OPFLAGS_TRANSMIT_WHOLE;
Snp->Cdb.CPBsize = (UINT16) sizeof (PXE_CPB_TRANSMIT);
Snp->Cdb.CPBaddr = (UINT64)(UINTN) Cpb;
Snp->Cdb.OpCode = PXE_OPCODE_TRANSMIT;
Snp->Cdb.DBsize = PXE_DBSIZE_NOT_USED;
Snp->Cdb.DBaddr = PXE_DBADDR_NOT_USED;
Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
Snp->Cdb.IFnum = Snp->IfNum;
Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
//
// Issue UNDI command and check result.
//
DEBUG ((EFI_D_NET, "\nSnp->undi.transmit() "));
DEBUG ((EFI_D_NET, "\nSnp->Cdb.OpCode == %x", Snp->Cdb.OpCode));
DEBUG ((EFI_D_NET, "\nSnp->Cdb.CPBaddr == %LX", Snp->Cdb.CPBaddr));
DEBUG ((EFI_D_NET, "\nSnp->Cdb.DBaddr == %LX", Snp->Cdb.DBaddr));
DEBUG ((EFI_D_NET, "\nCpb->FrameAddr == %LX\n", Cpb->FrameAddr));
(*Snp->IssueUndi32Command) ((UINT64) (UINTN) &Snp->Cdb);
DEBUG ((EFI_D_NET, "\nexit Snp->undi.transmit() "));
//
// we will unmap the buffers in get_status call, not here
//
switch (Snp->Cdb.StatCode) {
case PXE_STATCODE_SUCCESS:
return EFI_SUCCESS;
case PXE_STATCODE_BUFFER_FULL:
case PXE_STATCODE_QUEUE_FULL:
case PXE_STATCODE_BUSY:
Status = EFI_NOT_READY;
DEBUG (
(EFI_D_NET,
"\nSnp->undi.transmit() %xh:%xh\n",
Snp->Cdb.StatFlags,
Snp->Cdb.StatCode)
);
break;
default:
DEBUG (
(EFI_D_ERROR,
"\nSnp->undi.transmit() %xh:%xh\n",
Snp->Cdb.StatFlags,
Snp->Cdb.StatCode)
);
Status = EFI_DEVICE_ERROR;
}
return Status;
}
/**
Places a packet in the transmit queue of a network interface.
This function places the packet specified by Header and Buffer on the transmit
queue. If HeaderSize is nonzero and HeaderSize is not equal to
This->Mode->MediaHeaderSize, then EFI_INVALID_PARAMETER will be returned. If
BufferSize is less than This->Mode->MediaHeaderSize, then EFI_BUFFER_TOO_SMALL
will be returned. If Buffer is NULL, then EFI_INVALID_PARAMETER will be
returned. If HeaderSize is nonzero and DestAddr or Protocol is NULL, then
EFI_INVALID_PARAMETER will be returned. If the transmit engine of the network
interface is busy, then EFI_NOT_READY will be returned. If this packet can be
accepted by the transmit engine of the network interface, the packet contents
specified by Buffer will be placed on the transmit queue of the network
interface, and EFI_SUCCESS will be returned. GetStatus() can be used to
determine when the packet has actually been transmitted. The contents of the
Buffer must not be modified until the packet has actually been transmitted.
The Transmit() function performs nonblocking I/O. A caller who wants to perform
blocking I/O, should call Transmit(), and then GetStatus() until the
transmitted buffer shows up in the recycled transmit buffer.
If the driver has not been initialized, EFI_DEVICE_ERROR will be returned.
@param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
@param HeaderSize The size, in bytes, of the media header to be filled in by the
Transmit() function. If HeaderSize is nonzero, then it must
be equal to This->Mode->MediaHeaderSize and the DestAddr and
Protocol parameters must not be NULL.
@param BufferSize The size, in bytes, of the entire packet (media header and
data) to be transmitted through the network interface.
@param Buffer A pointer to the packet (media header followed by data) to be
transmitted. This parameter cannot be NULL. If HeaderSize is
zero, then the media header in Buffer must already be filled
in by the caller. If HeaderSize is nonzero, then the media
header will be filled in by the Transmit() function.
@param SrcAddr The source HW MAC address. If HeaderSize is zero, then this
parameter is ignored. If HeaderSize is nonzero and SrcAddr
is NULL, then This->Mode->CurrentAddress is used for the
source HW MAC address.
@param DestAddr The destination HW MAC address. If HeaderSize is zero, then
this parameter is ignored.
@param Protocol The type of header to build. If HeaderSize is zero, then this
parameter is ignored. See RFC 1700, section "Ether Types,"
for examples.
@retval EFI_SUCCESS The packet was placed on the transmit queue.
@retval EFI_NOT_STARTED The network interface has not been started.
@retval EFI_NOT_READY The network interface is too busy to accept this
transmit request.
@retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
@retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported
value.
@retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
@retval EFI_UNSUPPORTED This function is not supported by the network interface.
**/
EFI_STATUS
EFIAPI
SnpUndi32Transmit (
IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
IN UINTN HeaderSize,
IN UINTN BufferSize,
IN VOID *Buffer,
IN EFI_MAC_ADDRESS *SrcAddr, OPTIONAL
IN EFI_MAC_ADDRESS *DestAddr, OPTIONAL
IN UINT16 *Protocol OPTIONAL
)
{
SNP_DRIVER *Snp;
EFI_STATUS Status;
EFI_TPL OldTpl;
if (This == NULL) {
return EFI_INVALID_PARAMETER;
}
Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
if (Snp == NULL) {
return EFI_DEVICE_ERROR;
}
switch (Snp->Mode.State) {
case EfiSimpleNetworkInitialized:
break;
case EfiSimpleNetworkStopped:
Status = EFI_NOT_STARTED;
goto ON_EXIT;
default:
Status = EFI_DEVICE_ERROR;
goto ON_EXIT;
}
if (Buffer == NULL) {
Status = EFI_INVALID_PARAMETER;
goto ON_EXIT;
}
if (BufferSize < Snp->Mode.MediaHeaderSize) {
Status = EFI_BUFFER_TOO_SMALL;
goto ON_EXIT;
}
//
// if the HeaderSize is non-zero, we need to fill up the header and for that
// we need the destination address and the protocol
//
if (HeaderSize != 0) {
if (HeaderSize != Snp->Mode.MediaHeaderSize || DestAddr == 0 || Protocol == 0) {
Status = EFI_INVALID_PARAMETER;
goto ON_EXIT;
}
Status = PxeFillHeader (
Snp,
Buffer,
HeaderSize,
(UINT8 *) Buffer + HeaderSize,
BufferSize - HeaderSize,
DestAddr,
SrcAddr,
Protocol
);
if (EFI_ERROR (Status)) {
goto ON_EXIT;
}
}
Status = PxeTransmit (Snp, Buffer, BufferSize);
ON_EXIT:
gBS->RestoreTPL (OldTpl);
return Status;
}

View File

@@ -0,0 +1,86 @@
/** @file
Event handler to check for available packet.
Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "Snp.h"
/**
Nofication call back function for WaitForPacket event.
@param Event EFI Event.
@param SnpPtr Pointer to SNP_DRIVER structure.
**/
VOID
EFIAPI
SnpWaitForPacketNotify (
EFI_EVENT Event,
VOID *SnpPtr
)
{
PXE_DB_GET_STATUS PxeDbGetStatus;
//
// Do nothing if either parameter is a NULL pointer.
//
if (Event == NULL || SnpPtr == NULL) {
return ;
}
//
// Do nothing if the SNP interface is not initialized.
//
switch (((SNP_DRIVER *) SnpPtr)->Mode.State) {
case EfiSimpleNetworkInitialized:
break;
case EfiSimpleNetworkStopped:
case EfiSimpleNetworkStarted:
default:
return ;
}
//
// Fill in CDB for UNDI GetStatus().
//
((SNP_DRIVER *) SnpPtr)->Cdb.OpCode = PXE_OPCODE_GET_STATUS;
((SNP_DRIVER *) SnpPtr)->Cdb.OpFlags = 0;
((SNP_DRIVER *) SnpPtr)->Cdb.CPBsize = PXE_CPBSIZE_NOT_USED;
((SNP_DRIVER *) SnpPtr)->Cdb.CPBaddr = PXE_CPBADDR_NOT_USED;
((SNP_DRIVER *) SnpPtr)->Cdb.DBsize = (UINT16) (sizeof (UINT32) * 2);
((SNP_DRIVER *) SnpPtr)->Cdb.DBaddr = (UINT64)(UINTN) (((SNP_DRIVER *) SnpPtr)->Db);
((SNP_DRIVER *) SnpPtr)->Cdb.StatCode = PXE_STATCODE_INITIALIZE;
((SNP_DRIVER *) SnpPtr)->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;
((SNP_DRIVER *) SnpPtr)->Cdb.IFnum = ((SNP_DRIVER *) SnpPtr)->IfNum;
((SNP_DRIVER *) SnpPtr)->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;
//
// Clear contents of DB buffer.
//
ZeroMem (((SNP_DRIVER *) SnpPtr)->Db, sizeof (UINT32) * 2);
//
// Issue UNDI command and check result.
//
(*((SNP_DRIVER *) SnpPtr)->IssueUndi32Command) ((UINT64)(UINTN) &((SNP_DRIVER *) SnpPtr)->Cdb);
if (((SNP_DRIVER *) SnpPtr)->Cdb.StatCode != EFI_SUCCESS) {
return ;
}
//
// We might have a packet. Check the receive length and signal
// the event if the length is not zero.
//
CopyMem (
&PxeDbGetStatus,
((SNP_DRIVER *) SnpPtr)->Db,
sizeof (UINT32) * 2
);
if (PxeDbGetStatus.RxFrameLen != 0) {
gBS->SignalEvent (Event);
}
}