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.
|
# You'll need to pass it "-i 0xf00d" to get it to recognise this device.
|
||||||
gEmbeddedTokenSpaceGuid.PcdAndroidFastbootUsbVendorId|0xf00d|UINT32|0x00000022
|
gEmbeddedTokenSpaceGuid.PcdAndroidFastbootUsbVendorId|0xf00d|UINT32|0x00000022
|
||||||
gEmbeddedTokenSpaceGuid.PcdAndroidFastbootUsbProductId|0xbeef|UINT32|0x00000023
|
gEmbeddedTokenSpaceGuid.PcdAndroidFastbootUsbProductId|0xbeef|UINT32|0x00000023
|
||||||
|
gEmbeddedTokenSpaceGuid.PcdAndroidFastbootTcpPort|1234|UINT32|0x00000024
|
||||||
|
|
||||||
[PcdsFixedAtBuild.ARM]
|
[PcdsFixedAtBuild.ARM]
|
||||||
gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize|32|UINT8|0x00000010
|
gEmbeddedTokenSpaceGuid.PcdPrePiCpuMemorySize|32|UINT8|0x00000010
|
||||||
|
|
|
@ -256,6 +256,7 @@
|
||||||
|
|
||||||
EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.inf
|
EmbeddedPkg/Application/AndroidFastboot/AndroidFastbootApp.inf
|
||||||
EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsbDxe.inf
|
EmbeddedPkg/Drivers/AndroidFastbootTransportUsbDxe/FastbootTransportUsbDxe.inf
|
||||||
|
EmbeddedPkg/Drivers/AndroidFastbootTransportTcpDxe/FastbootTransportTcpDxe.inf
|
||||||
|
|
||||||
# Drivers
|
# Drivers
|
||||||
EmbeddedPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.inf
|
EmbeddedPkg/Drivers/Isp1761UsbDxe/Isp1761UsbDxe.inf
|
||||||
|
|
Loading…
Reference in New Issue