mirror of https://github.com/acidanthera/audk.git
EmbeddedPkg/AndroidFastbootTransportTcpDxe: Implemented Android FastBoot over TCP
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Brendan Jackman <brendan.jackman@arm.com> Reviewed-by: Olivier Martin <olivier.martin@arm.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15484 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
parent
8bb7f03ade
commit
4d6e1e5a06
|
@ -0,0 +1,688 @@
|
|||
/** @file
|
||||
#
|
||||
# Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
|
||||
#
|
||||
# This program and the accompanying materials
|
||||
# are licensed and made available under the terms and conditions of the BSD License
|
||||
# which accompanies this distribution. The full text of the license may be found at
|
||||
# http://opensource.org/licenses/bsd-license.php
|
||||
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#
|
||||
#
|
||||
#**/
|
||||
|
||||
#include <Protocol/AndroidFastbootTransport.h>
|
||||
#include <Protocol/Dhcp4.h>
|
||||
#include <Protocol/Tcp4.h>
|
||||
#include <Protocol/ServiceBinding.h>
|
||||
#include <Protocol/SimpleTextOut.h>
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/PrintLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/UefiDriverEntryPoint.h>
|
||||
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||
|
||||
#include <Guid/Hostname.h>
|
||||
|
||||
#define IP4_ADDR_TO_STRING(IpAddr, IpAddrString) UnicodeSPrint ( \
|
||||
IpAddrString, \
|
||||
16 * 2, \
|
||||
L"%d.%d.%d.%d", \
|
||||
IpAddr.Addr[0], \
|
||||
IpAddr.Addr[1], \
|
||||
IpAddr.Addr[2], \
|
||||
IpAddr.Addr[3] \
|
||||
);
|
||||
|
||||
// Fastboot says max packet size is 512, but FASTBOOT_TRANSPORT_PROTOCOL
|
||||
// doesn't place a limit on the size of buffers returned by Receive.
|
||||
// (This isn't actually a packet size - it's just the size of the buffers we
|
||||
// pass to the TCP driver to fill with received data.)
|
||||
// We can achieve much better performance by doing this in larger chunks.
|
||||
#define RX_FRAGMENT_SIZE 2048
|
||||
|
||||
STATIC EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *mTextOut;
|
||||
|
||||
STATIC EFI_TCP4_PROTOCOL *mTcpConnection;
|
||||
STATIC EFI_TCP4_PROTOCOL *mTcpListener;
|
||||
|
||||
STATIC EFI_EVENT mReceiveEvent;
|
||||
|
||||
STATIC EFI_SERVICE_BINDING_PROTOCOL *mTcpServiceBinding;
|
||||
STATIC EFI_HANDLE mTcpHandle = NULL;
|
||||
|
||||
// We only ever use one IO token for receive and one for transmit. To save
|
||||
// repeatedly allocating and freeing, just allocate statically and re-use.
|
||||
#define NUM_RX_TOKENS 16
|
||||
#define TOKEN_NEXT(Index) (((Index) + 1) % NUM_RX_TOKENS)
|
||||
|
||||
STATIC UINTN mNextSubmitIndex;
|
||||
STATIC UINTN mNextReceiveIndex;
|
||||
STATIC EFI_TCP4_IO_TOKEN mReceiveToken[NUM_RX_TOKENS];
|
||||
STATIC EFI_TCP4_RECEIVE_DATA mRxData[NUM_RX_TOKENS];
|
||||
STATIC EFI_TCP4_IO_TOKEN mTransmitToken;
|
||||
STATIC EFI_TCP4_TRANSMIT_DATA mTxData;
|
||||
// We also reuse the accept token
|
||||
STATIC EFI_TCP4_LISTEN_TOKEN mAcceptToken;
|
||||
// .. and the close token
|
||||
STATIC EFI_TCP4_CLOSE_TOKEN mCloseToken;
|
||||
|
||||
// List type for queued received packets
|
||||
typedef struct _FASTBOOT_TCP_PACKET_LIST {
|
||||
LIST_ENTRY Link;
|
||||
VOID *Buffer;
|
||||
UINTN BufferSize;
|
||||
} FASTBOOT_TCP_PACKET_LIST;
|
||||
|
||||
STATIC LIST_ENTRY mPacketListHead;
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
EFIAPI
|
||||
DataReceived (
|
||||
IN EFI_EVENT Event,
|
||||
IN VOID *Context
|
||||
);
|
||||
|
||||
/*
|
||||
Helper function to set up a receive IO token and call Tcp->Receive
|
||||
*/
|
||||
STATIC
|
||||
EFI_STATUS
|
||||
SubmitRecieveToken (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
VOID *FragmentBuffer;
|
||||
|
||||
Status = EFI_SUCCESS;
|
||||
|
||||
FragmentBuffer = AllocatePool (RX_FRAGMENT_SIZE);
|
||||
ASSERT (FragmentBuffer != NULL);
|
||||
if (FragmentBuffer == NULL) {
|
||||
DEBUG ((EFI_D_ERROR, "TCP Fastboot out of resources"));
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
mRxData[mNextSubmitIndex].DataLength = RX_FRAGMENT_SIZE;
|
||||
mRxData[mNextSubmitIndex].FragmentTable[0].FragmentLength = RX_FRAGMENT_SIZE;
|
||||
mRxData[mNextSubmitIndex].FragmentTable[0].FragmentBuffer = FragmentBuffer;
|
||||
|
||||
Status = mTcpConnection->Receive (mTcpConnection, &mReceiveToken[mNextSubmitIndex]);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "TCP Receive: %r\n", Status));
|
||||
FreePool (FragmentBuffer);
|
||||
}
|
||||
|
||||
mNextSubmitIndex = TOKEN_NEXT (mNextSubmitIndex);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/*
|
||||
Event notify function for when we have closed our TCP connection.
|
||||
We can now start listening for another connection.
|
||||
*/
|
||||
STATIC
|
||||
VOID
|
||||
ConnectionClosed (
|
||||
IN EFI_EVENT Event,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
// Possible bug in EDK2 TCP4 driver: closing a connection doesn't remove its
|
||||
// PCB from the list of live connections. Subsequent attempts to Configure()
|
||||
// a TCP instance with the same local port will fail with INVALID_PARAMETER.
|
||||
// Calling Configure with NULL is a workaround for this issue.
|
||||
Status = mTcpConnection->Configure (mTcpConnection, NULL);
|
||||
|
||||
mTcpConnection = NULL;
|
||||
|
||||
Status = mTcpListener->Accept (mTcpListener, &mAcceptToken);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "TCP Accept: %r\n", Status));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC
|
||||
VOID
|
||||
CloseReceiveEvents (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
UINTN Index;
|
||||
|
||||
for (Index = 0; Index < NUM_RX_TOKENS; Index++) {
|
||||
gBS->CloseEvent (mReceiveToken[Index].CompletionToken.Event);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Event notify function to be called when we receive TCP data.
|
||||
*/
|
||||
STATIC
|
||||
VOID
|
||||
EFIAPI
|
||||
DataReceived (
|
||||
IN EFI_EVENT Event,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
FASTBOOT_TCP_PACKET_LIST *NewEntry;
|
||||
EFI_TCP4_IO_TOKEN *ReceiveToken;
|
||||
|
||||
ReceiveToken = &mReceiveToken[mNextReceiveIndex];
|
||||
|
||||
Status = ReceiveToken->CompletionToken.Status;
|
||||
|
||||
if (Status == EFI_CONNECTION_FIN) {
|
||||
//
|
||||
// Remote host closed connection. Close our end.
|
||||
//
|
||||
|
||||
CloseReceiveEvents ();
|
||||
|
||||
Status = mTcpConnection->Close (mTcpConnection, &mCloseToken);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Add an element to the receive queue
|
||||
//
|
||||
|
||||
NewEntry = AllocatePool (sizeof (FASTBOOT_TCP_PACKET_LIST));
|
||||
if (NewEntry == NULL) {
|
||||
DEBUG ((EFI_D_ERROR, "TCP Fastboot: Out of resources\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
mNextReceiveIndex = TOKEN_NEXT (mNextReceiveIndex);
|
||||
|
||||
if (!EFI_ERROR (Status)) {
|
||||
NewEntry->Buffer
|
||||
= ReceiveToken->Packet.RxData->FragmentTable[0].FragmentBuffer;
|
||||
NewEntry->BufferSize
|
||||
= ReceiveToken->Packet.RxData->FragmentTable[0].FragmentLength;
|
||||
|
||||
// Prepare to receive more data
|
||||
SubmitRecieveToken();
|
||||
} else {
|
||||
// Fatal receive error. Put an entry with NULL in the queue, signifying
|
||||
// to return EFI_DEVICE_ERROR from TcpFastbootTransportReceive.
|
||||
NewEntry->Buffer = NULL;
|
||||
NewEntry->BufferSize = 0;
|
||||
|
||||
DEBUG ((EFI_D_ERROR, "\nTCP Fastboot Receive error: %r\n", Status));
|
||||
}
|
||||
|
||||
InsertTailList (&mPacketListHead, &NewEntry->Link);
|
||||
|
||||
Status = gBS->SignalEvent (mReceiveEvent);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Event notify function to be called when we accept an incoming TCP connection.
|
||||
*/
|
||||
STATIC
|
||||
VOID
|
||||
EFIAPI
|
||||
ConnectionAccepted (
|
||||
IN EFI_EVENT Event,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
EFI_TCP4_LISTEN_TOKEN *AcceptToken;
|
||||
EFI_STATUS Status;
|
||||
UINTN Index;
|
||||
|
||||
AcceptToken = (EFI_TCP4_LISTEN_TOKEN *) Context;
|
||||
Status = AcceptToken->CompletionToken.Status;
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "TCP Fastboot: Connection Error: %r\n", Status));
|
||||
return;
|
||||
}
|
||||
DEBUG ((EFI_D_ERROR, "TCP Fastboot: Connection Received.\n"));
|
||||
|
||||
//
|
||||
// Accepting a new TCP connection creates a new instance of the TCP protocol.
|
||||
// Open it and prepare to receive on it.
|
||||
//
|
||||
|
||||
Status = gBS->OpenProtocol (
|
||||
AcceptToken->NewChildHandle,
|
||||
&gEfiTcp4ProtocolGuid,
|
||||
(VOID **) &mTcpConnection,
|
||||
gImageHandle,
|
||||
NULL,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "Open TCP Connection: %r\n", Status));
|
||||
return;
|
||||
}
|
||||
|
||||
mNextSubmitIndex = 0;
|
||||
mNextReceiveIndex = 0;
|
||||
|
||||
for (Index = 0; Index < NUM_RX_TOKENS; Index++) {
|
||||
Status = gBS->CreateEvent (
|
||||
EVT_NOTIFY_SIGNAL,
|
||||
TPL_CALLBACK,
|
||||
DataReceived,
|
||||
NULL,
|
||||
&(mReceiveToken[Index].CompletionToken.Event)
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
}
|
||||
|
||||
for (Index = 0; Index < NUM_RX_TOKENS; Index++) {
|
||||
SubmitRecieveToken();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Set up TCP Fastboot transport: Configure the network device via DHCP then
|
||||
start waiting for a TCP connection on the Fastboot port.
|
||||
*/
|
||||
EFI_STATUS
|
||||
TcpFastbootTransportStart (
|
||||
EFI_EVENT ReceiveEvent
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_HANDLE NetDeviceHandle;
|
||||
EFI_HANDLE *HandleBuffer;
|
||||
EFI_IP4_MODE_DATA Ip4ModeData;
|
||||
UINTN NumHandles;
|
||||
UINTN HostnameSize = 256;
|
||||
CHAR8 Hostname[256];
|
||||
CHAR16 HostnameUnicode[256] = L"<no hostname>";
|
||||
CHAR16 IpAddrString[16];
|
||||
UINTN Index;
|
||||
|
||||
EFI_TCP4_CONFIG_DATA TcpConfigData = {
|
||||
0x00, // IPv4 Type of Service
|
||||
255, // IPv4 Time to Live
|
||||
{ // AccessPoint:
|
||||
TRUE, // Use default address
|
||||
{0, 0, 0, 0}, // IP Address (ignored - use default)
|
||||
{0, 0, 0, 0}, // Subnet mask (ignored - use default)
|
||||
FixedPcdGet32 (PcdAndroidFastbootTcpPort), // Station port
|
||||
{0, 0, 0, 0}, // Remote address: accept any
|
||||
0, // Remote Port: accept any
|
||||
FALSE // ActiveFlag: be a "server"
|
||||
},
|
||||
NULL // Default advanced TCP options
|
||||
};
|
||||
|
||||
mReceiveEvent = ReceiveEvent;
|
||||
InitializeListHead (&mPacketListHead);
|
||||
|
||||
mTextOut->OutputString (mTextOut, L"Initialising TCP Fastboot transport...\r\n");
|
||||
|
||||
//
|
||||
// Open a passive TCP instance
|
||||
//
|
||||
|
||||
Status = gBS->LocateHandleBuffer (
|
||||
ByProtocol,
|
||||
&gEfiTcp4ServiceBindingProtocolGuid,
|
||||
NULL,
|
||||
&NumHandles,
|
||||
&HandleBuffer
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "Find TCP Service Binding: %r\n", Status));
|
||||
return Status;
|
||||
}
|
||||
|
||||
// We just use the first network device
|
||||
NetDeviceHandle = HandleBuffer[0];
|
||||
|
||||
Status = gBS->OpenProtocol (
|
||||
NetDeviceHandle,
|
||||
&gEfiTcp4ServiceBindingProtocolGuid,
|
||||
(VOID **) &mTcpServiceBinding,
|
||||
gImageHandle,
|
||||
NULL,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "Open TCP Service Binding: %r\n", Status));
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = mTcpServiceBinding->CreateChild (mTcpServiceBinding, &mTcpHandle);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "TCP ServiceBinding Create: %r\n", Status));
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = gBS->OpenProtocol (
|
||||
mTcpHandle,
|
||||
&gEfiTcp4ProtocolGuid,
|
||||
(VOID **) &mTcpListener,
|
||||
gImageHandle,
|
||||
NULL,
|
||||
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "Open TCP Protocol: %r\n", Status));
|
||||
}
|
||||
|
||||
//
|
||||
// Set up re-usable tokens
|
||||
//
|
||||
|
||||
for (Index = 0; Index < NUM_RX_TOKENS; Index++) {
|
||||
mRxData[Index].UrgentFlag = FALSE;
|
||||
mRxData[Index].FragmentCount = 1;
|
||||
mReceiveToken[Index].Packet.RxData = &mRxData[Index];
|
||||
}
|
||||
|
||||
mTxData.Push = TRUE;
|
||||
mTxData.Urgent = FALSE;
|
||||
mTxData.FragmentCount = 1;
|
||||
mTransmitToken.Packet.TxData = &mTxData;
|
||||
|
||||
Status = gBS->CreateEvent (
|
||||
EVT_NOTIFY_SIGNAL,
|
||||
TPL_CALLBACK,
|
||||
ConnectionAccepted,
|
||||
&mAcceptToken,
|
||||
&mAcceptToken.CompletionToken.Event
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
Status = gBS->CreateEvent (
|
||||
EVT_NOTIFY_SIGNAL,
|
||||
TPL_CALLBACK,
|
||||
ConnectionClosed,
|
||||
&mCloseToken,
|
||||
&mCloseToken.CompletionToken.Event
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
//
|
||||
// Configure the TCP instance
|
||||
//
|
||||
|
||||
Status = mTcpListener->Configure (mTcpListener, &TcpConfigData);
|
||||
if (Status == EFI_NO_MAPPING) {
|
||||
// Wait until the IP configuration process (probably DHCP) has finished
|
||||
do {
|
||||
Status = mTcpListener->GetModeData (mTcpListener,
|
||||
NULL, NULL,
|
||||
&Ip4ModeData,
|
||||
NULL, NULL
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
} while (!Ip4ModeData.IsConfigured);
|
||||
Status = mTcpListener->Configure (mTcpListener, &TcpConfigData);
|
||||
} else if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "TCP Configure: %r\n", Status));
|
||||
return Status;
|
||||
}
|
||||
|
||||
//
|
||||
// Tell the user our address and hostname
|
||||
//
|
||||
IP4_ADDR_TO_STRING (Ip4ModeData.ConfigData.StationAddress, IpAddrString);
|
||||
|
||||
// Look up hostname
|
||||
Status = gRT->GetVariable (
|
||||
L"Hostname",
|
||||
&gEfiHostnameVariableGuid,
|
||||
NULL,
|
||||
&HostnameSize,
|
||||
&Hostname
|
||||
);
|
||||
if (!EFI_ERROR (Status) && HostnameSize != 0) {
|
||||
AsciiStrToUnicodeStr (Hostname, HostnameUnicode);
|
||||
}
|
||||
|
||||
// Hostname variable is not null-terminated.
|
||||
Hostname[HostnameSize] = L'\0';
|
||||
|
||||
mTextOut->OutputString (mTextOut, L"TCP Fastboot transport configured.");
|
||||
mTextOut->OutputString (mTextOut, L"\r\nIP address: ");
|
||||
mTextOut->OutputString (mTextOut ,IpAddrString);
|
||||
mTextOut->OutputString (mTextOut, L"\r\n");
|
||||
mTextOut->OutputString (mTextOut, L"\r\nhostname: ");
|
||||
mTextOut->OutputString (mTextOut, HostnameUnicode);
|
||||
mTextOut->OutputString (mTextOut, L"\r\n");
|
||||
|
||||
//
|
||||
// Start listening for a connection
|
||||
//
|
||||
|
||||
Status = mTcpListener->Accept (mTcpListener, &mAcceptToken);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "TCP Accept: %r\n", Status));
|
||||
return Status;
|
||||
}
|
||||
|
||||
mTextOut->OutputString (mTextOut, L"TCP Fastboot transport initialised.\r\n");
|
||||
|
||||
FreePool (HandleBuffer);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
TcpFastbootTransportStop (
|
||||
VOID
|
||||
)
|
||||
{
|
||||
EFI_TCP4_CLOSE_TOKEN CloseToken;
|
||||
EFI_STATUS Status;
|
||||
UINTN EventIndex;
|
||||
FASTBOOT_TCP_PACKET_LIST *Entry;
|
||||
FASTBOOT_TCP_PACKET_LIST *NextEntry;
|
||||
|
||||
// Close any existing TCP connection, blocking until it's done.
|
||||
if (mTcpConnection != NULL) {
|
||||
CloseReceiveEvents ();
|
||||
|
||||
CloseToken.AbortOnClose = FALSE;
|
||||
|
||||
Status = gBS->CreateEvent (0, 0, NULL, NULL, &CloseToken.CompletionToken.Event);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
Status = mTcpConnection->Close (mTcpConnection, &CloseToken);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
Status = gBS->WaitForEvent (
|
||||
1,
|
||||
&CloseToken.CompletionToken.Event,
|
||||
&EventIndex
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
ASSERT_EFI_ERROR (CloseToken.CompletionToken.Status);
|
||||
|
||||
// Possible bug in EDK2 TCP4 driver: closing a connection doesn't remove its
|
||||
// PCB from the list of live connections. Subsequent attempts to Configure()
|
||||
// a TCP instance with the same local port will fail with INVALID_PARAMETER.
|
||||
// Calling Configure with NULL is a workaround for this issue.
|
||||
Status = mTcpConnection->Configure (mTcpConnection, NULL);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
}
|
||||
|
||||
|
||||
gBS->CloseEvent (mAcceptToken.CompletionToken.Event);
|
||||
|
||||
// Stop listening for connections.
|
||||
// Ideally we would do this with Cancel, but it isn't implemented by EDK2.
|
||||
// So we just "reset this TCPv4 instance brutally".
|
||||
Status = mTcpListener->Configure (mTcpListener, NULL);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
Status = mTcpServiceBinding->DestroyChild (mTcpServiceBinding, &mTcpHandle);
|
||||
|
||||
// Free any data the user didn't pick up
|
||||
Entry = (FASTBOOT_TCP_PACKET_LIST *) GetFirstNode (&mPacketListHead);
|
||||
while (!IsNull (&mPacketListHead, &Entry->Link)) {
|
||||
NextEntry = (FASTBOOT_TCP_PACKET_LIST *) GetNextNode (&mPacketListHead, &Entry->Link);
|
||||
|
||||
RemoveEntryList (&Entry->Link);
|
||||
if (Entry->Buffer) {
|
||||
FreePool (Entry->Buffer);
|
||||
}
|
||||
FreePool (Entry);
|
||||
|
||||
Entry = NextEntry;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
Event notify function for when data has been sent. Free resources and report
|
||||
errors.
|
||||
Context should point to the transmit IO token passed to
|
||||
TcpConnection->Transmit.
|
||||
*/
|
||||
STATIC
|
||||
VOID
|
||||
DataSent (
|
||||
EFI_EVENT Event,
|
||||
VOID *Context
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
Status = mTransmitToken.CompletionToken.Status;
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "TCP Fastboot transmit result: %r\n", Status));
|
||||
gBS->SignalEvent (*(EFI_EVENT *) Context);
|
||||
}
|
||||
|
||||
FreePool (mTransmitToken.Packet.TxData->FragmentTable[0].FragmentBuffer);
|
||||
}
|
||||
|
||||
EFI_STATUS
|
||||
TcpFastbootTransportSend (
|
||||
IN UINTN BufferSize,
|
||||
IN CONST VOID *Buffer,
|
||||
IN EFI_EVENT *FatalErrorEvent
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
if (BufferSize > 512) {
|
||||
return EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
//
|
||||
// Build transmit IO token
|
||||
//
|
||||
|
||||
// Create an event so we are notified when a transmission is complete.
|
||||
// We use this to free resources and report errors.
|
||||
Status = gBS->CreateEvent (
|
||||
EVT_NOTIFY_SIGNAL,
|
||||
TPL_CALLBACK,
|
||||
DataSent,
|
||||
FatalErrorEvent,
|
||||
&mTransmitToken.CompletionToken.Event
|
||||
);
|
||||
ASSERT_EFI_ERROR (Status);
|
||||
|
||||
mTxData.DataLength = BufferSize;
|
||||
|
||||
mTxData.FragmentTable[0].FragmentLength = BufferSize;
|
||||
mTxData.FragmentTable[0].FragmentBuffer = AllocateCopyPool (
|
||||
BufferSize,
|
||||
Buffer
|
||||
);
|
||||
|
||||
Status = mTcpConnection->Transmit (mTcpConnection, &mTransmitToken);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "TCP Transmit: %r\n", Status));
|
||||
return Status;
|
||||
}
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
EFI_STATUS
|
||||
TcpFastbootTransportReceive (
|
||||
OUT UINTN *BufferSize,
|
||||
OUT VOID **Buffer
|
||||
)
|
||||
{
|
||||
FASTBOOT_TCP_PACKET_LIST *Entry;
|
||||
|
||||
if (IsListEmpty (&mPacketListHead)) {
|
||||
return EFI_NOT_READY;
|
||||
}
|
||||
|
||||
Entry = (FASTBOOT_TCP_PACKET_LIST *) GetFirstNode (&mPacketListHead);
|
||||
|
||||
if (Entry->Buffer == NULL) {
|
||||
// There was an error receiving this packet.
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
*Buffer = Entry->Buffer;
|
||||
*BufferSize = Entry->BufferSize;
|
||||
|
||||
RemoveEntryList (&Entry->Link);
|
||||
FreePool (Entry);
|
||||
|
||||
return EFI_SUCCESS;
|
||||
}
|
||||
|
||||
FASTBOOT_TRANSPORT_PROTOCOL mTransportProtocol = {
|
||||
TcpFastbootTransportStart,
|
||||
TcpFastbootTransportStop,
|
||||
TcpFastbootTransportSend,
|
||||
TcpFastbootTransportReceive
|
||||
};
|
||||
|
||||
EFI_STATUS
|
||||
TcpFastbootTransportEntryPoint (
|
||||
IN EFI_HANDLE ImageHandle,
|
||||
IN EFI_SYSTEM_TABLE *SystemTable
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
|
||||
|
||||
Status = gBS->LocateProtocol(
|
||||
&gEfiSimpleTextOutProtocolGuid,
|
||||
NULL,
|
||||
(VOID **) &mTextOut
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "Fastboot: Open Text Output Protocol: %r\n", Status));
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = gBS->InstallProtocolInterface (
|
||||
&ImageHandle,
|
||||
&gAndroidFastbootTransportProtocolGuid,
|
||||
EFI_NATIVE_INTERFACE,
|
||||
&mTransportProtocol
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
DEBUG ((EFI_D_ERROR, "Fastboot: Install transport Protocol: %r\n", Status));
|
||||
}
|
||||
|
||||
return Status;
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
#/** @file
|
||||
#
|
||||
# Copyright (c) 2014, ARM Ltd. All rights reserved.<BR>
|
||||
#
|
||||
# This program and the accompanying materials
|
||||
# are licensed and made available under the terms and conditions of the BSD License
|
||||
# which accompanies this distribution. The full text of the license may be found at
|
||||
# http://opensource.org/licenses/bsd-license.php
|
||||
# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#
|
||||
#
|
||||
#**/
|
||||
|
||||
[Defines]
|
||||
INF_VERSION = 0x00010005
|
||||
BASE_NAME = TcpFastbootTransportDxe
|
||||
FILE_GUID = 86787704-8fed-11e3-b3ff-f33b73acfec2
|
||||
MODULE_TYPE = UEFI_DRIVER
|
||||
VERSION_STRING = 1.0
|
||||
ENTRY_POINT = TcpFastbootTransportEntryPoint
|
||||
|
||||
[Sources.common]
|
||||
FastbootTransportTcp.c
|
||||
|
||||
[LibraryClasses]
|
||||
BaseLib
|
||||
BaseMemoryLib
|
||||
DebugLib
|
||||
MemoryAllocationLib
|
||||
PrintLib
|
||||
UefiBootServicesTableLib
|
||||
UefiDriverEntryPoint
|
||||
UefiRuntimeServicesTableLib
|
||||
|
||||
[Protocols]
|
||||
gAndroidFastbootTransportProtocolGuid
|
||||
gEfiDhcp4ProtocolGuid
|
||||
gEfiDhcp4ServiceBindingProtocolGuid
|
||||
gEfiTcp4ServiceBindingProtocolGuid
|
||||
gEfiSimpleTextOutProtocolGuid
|
||||
gEfiTcp4ProtocolGuid
|
||||
gEfiSimpleTextOutProtocolGuid
|
||||
|
||||
[Packages]
|
||||
MdePkg/MdePkg.dec
|
||||
MdeModulePkg/MdeModulePkg.dec
|
||||
EmbeddedPkg/EmbeddedPkg.dec
|
||||
|
||||
[Guids]
|
||||
gEfiHostnameVariableGuid
|
||||
|
||||
[FixedPcd]
|
||||
gEmbeddedTokenSpaceGuid.PcdAndroidFastbootTcpPort
|
|
@ -138,6 +138,7 @@
|
|||
# You'll need to pass it "-i 0xf00d" to get it to recognise this device.
|
||||
gEmbeddedTokenSpaceGuid.PcdAndroidFastbootUsbVendorId|0xf00d|UINT32|0x00000022
|
||||
gEmbeddedTokenSpaceGuid.PcdAndroidFastbootUsbProductId|0xbeef|UINT32|0x00000023
|
||||
gEmbeddedTokenSpaceGuid.PcdAndroidFastbootTcpPort|1234|UINT32|0x00000024
|
||||
|
||||
[PcdsFixedAtBuild.ARM]
|
||||
gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize|32|UINT8|0x00000010
|
||||
|
|
|
@ -256,6 +256,7 @@
|
|||
|
||||
EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.inf
|
||||
EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsbDxe.inf
|
||||
EmbeddedPkg/Drivers/AndroidFastbootTransportTcpDxe/FastbootTransportTcpDxe.inf
|
||||
|
||||
# Drivers
|
||||
EmbeddedPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.inf
|
||||
|
|
Loading…
Reference in New Issue