boot/platform/efi: Add network booting support
Similar to open firmware implementation. This allows to load the kernel from a remote_disk_server. IP address is recovered using LoadOptions with a syntax similar to the Linux kernel network boot "ip" parameter. If this is not set, no network booting is attempted, in order to not slow down normal booting by waiting on network traffic. Change-Id: I17738bbcde85921672965b9936a2b484f1e57c6c Reviewed-on: https://review.haiku-os.org/c/haiku/+/3678 Reviewed-by: waddlesplash <[email protected]> Reviewed-by: Adrien Destugues <[email protected]> Tested-by: Commit checker robot <[email protected]>
This commit is contained in:
committed by
Adrien Destugues
parent
ea58f1fc7c
commit
b157c2179a
@@ -13,7 +13,7 @@ extern efi_guid DevicePathProtocol;
|
|||||||
typedef struct efi_device_path_protocol {
|
typedef struct efi_device_path_protocol {
|
||||||
uint8_t Type;
|
uint8_t Type;
|
||||||
uint8_t SubType;
|
uint8_t SubType;
|
||||||
uint8_t Length[2];
|
uint16_t Length;
|
||||||
} efi_device_path_protocol;
|
} efi_device_path_protocol;
|
||||||
|
|
||||||
#define DEVICE_PATH_HARDWARE 0x01
|
#define DEVICE_PATH_HARDWARE 0x01
|
||||||
|
|||||||
@@ -12,6 +12,9 @@
|
|||||||
{0x5b1b31a1, 0x9562, 0x11d2, {0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}}
|
{0x5b1b31a1, 0x9562, 0x11d2, {0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b}}
|
||||||
extern efi_guid LoadedImageProtocol;
|
extern efi_guid LoadedImageProtocol;
|
||||||
|
|
||||||
|
#define EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID \
|
||||||
|
{0xbc62157e, 0x3e33, 0x4fec, {0x99, 0x20, 0x2d, 0x3b, 0x36, 0xd7, 0x50, 0xdf}}
|
||||||
|
|
||||||
#define EFI_LOADED_IMAGE_PROTOCOL_REVISION 0x1000
|
#define EFI_LOADED_IMAGE_PROTOCOL_REVISION 0x1000
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
@@ -94,8 +94,8 @@ for platform in [ MultiBootSubDirSetup ] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
local kernelC++Header = [ FDirName $(HAIKU_TOP) headers private kernel util
|
local kernelC++Header = [ FDirName $(HAIKU_TOP) headers private
|
||||||
kernel_cpp.h ] ;
|
kernel util kernel_cpp.h ] ;
|
||||||
|
|
||||||
SubDirC++Flags -fno-rtti -include $(kernelC++Header) ;
|
SubDirC++Flags -fno-rtti -include $(kernelC++Header) ;
|
||||||
}
|
}
|
||||||
@@ -123,6 +123,7 @@ for platform in [ MultiBootSubDirSetup ] {
|
|||||||
driver_settings.cpp
|
driver_settings.cpp
|
||||||
|
|
||||||
# utils
|
# utils
|
||||||
|
convertutf.cpp
|
||||||
kernel_cpp.cpp
|
kernel_cpp.cpp
|
||||||
KMessage.cpp
|
KMessage.cpp
|
||||||
list.cpp
|
list.cpp
|
||||||
@@ -153,7 +154,8 @@ for platform in [ MultiBootSubDirSetup ] {
|
|||||||
;
|
;
|
||||||
|
|
||||||
# Tell Jam where to find the utility sources
|
# Tell Jam where to find the utility sources
|
||||||
SEARCH on [ FGristFiles kernel_cpp.cpp list.cpp ring_buffer.cpp StringHash.cpp ]
|
SEARCH on [ FGristFiles convertutf.cpp kernel_cpp.cpp list.cpp
|
||||||
|
ring_buffer.cpp StringHash.cpp ]
|
||||||
= [ FDirName $(HAIKU_TOP) src system kernel util ] ;
|
= [ FDirName $(HAIKU_TOP) src system kernel util ] ;
|
||||||
|
|
||||||
SEARCH on [ FGristFiles KMessage.cpp ]
|
SEARCH on [ FGristFiles KMessage.cpp ]
|
||||||
@@ -166,19 +168,25 @@ for platform in [ MultiBootSubDirSetup ] {
|
|||||||
= [ FDirName $(HAIKU_TOP) src system libroot os ] ;
|
= [ FDirName $(HAIKU_TOP) src system libroot os ] ;
|
||||||
|
|
||||||
SEARCH on [ FGristFiles amiga_rdb.cpp ]
|
SEARCH on [ FGristFiles amiga_rdb.cpp ]
|
||||||
= [ FDirName $(HAIKU_TOP) src add-ons kernel partitioning_systems amiga ] ;
|
= [ FDirName $(HAIKU_TOP) src add-ons kernel partitioning_systems
|
||||||
|
amiga ] ;
|
||||||
|
|
||||||
SEARCH on [ FGristFiles apple.cpp ]
|
SEARCH on [ FGristFiles apple.cpp ]
|
||||||
= [ FDirName $(HAIKU_TOP) src add-ons kernel partitioning_systems apple ] ;
|
= [ FDirName $(HAIKU_TOP) src add-ons kernel partitioning_systems
|
||||||
|
apple ] ;
|
||||||
|
|
||||||
SEARCH on [ FGristFiles gpt.cpp Header.cpp crc32.cpp utility.cpp ]
|
SEARCH on [ FGristFiles gpt.cpp Header.cpp crc32.cpp utility.cpp ]
|
||||||
= [ FDirName $(HAIKU_TOP) src add-ons kernel partitioning_systems gpt ] ;
|
= [ FDirName $(HAIKU_TOP) src add-ons kernel partitioning_systems
|
||||||
|
gpt ] ;
|
||||||
|
|
||||||
SEARCH on [ FGristFiles intel.cpp PartitionMap.cpp PartitionMapParser.cpp ]
|
SEARCH on [ FGristFiles intel.cpp PartitionMap.cpp
|
||||||
= [ FDirName $(HAIKU_TOP) src add-ons kernel partitioning_systems intel ] ;
|
PartitionMapParser.cpp ]
|
||||||
|
= [ FDirName $(HAIKU_TOP) src add-ons kernel partitioning_systems
|
||||||
|
intel ] ;
|
||||||
|
|
||||||
SEARCH on [ FGristFiles stage2_crt0.S ]
|
SEARCH on [ FGristFiles stage2_crt0.S ]
|
||||||
= [ FDirName $(HAIKU_TOP) src system boot arch $(TARGET_KERNEL_ARCH_DIR) ] ;
|
= [ FDirName $(HAIKU_TOP) src system boot arch
|
||||||
|
$(TARGET_KERNEL_ARCH_DIR) ] ;
|
||||||
|
|
||||||
SEARCH on [ FGristFiles DataIO.cpp Referenceable.cpp ]
|
SEARCH on [ FGristFiles DataIO.cpp Referenceable.cpp ]
|
||||||
= [ FDirName $(HAIKU_TOP) src kits support ] ;
|
= [ FDirName $(HAIKU_TOP) src kits support ] ;
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ local platform_src =
|
|||||||
video.cpp
|
video.cpp
|
||||||
debug.cpp
|
debug.cpp
|
||||||
mmu.cpp
|
mmu.cpp
|
||||||
|
network.cpp
|
||||||
heap.cpp
|
heap.cpp
|
||||||
acpi.cpp
|
acpi.cpp
|
||||||
timer.cpp
|
timer.cpp
|
||||||
|
|||||||
@@ -8,6 +8,9 @@
|
|||||||
#include <boot/platform.h>
|
#include <boot/platform.h>
|
||||||
#include <boot/stage2.h>
|
#include <boot/stage2.h>
|
||||||
|
|
||||||
|
#include <boot/net/NetStack.h>
|
||||||
|
#include <boot/net/RemoteDisk.h>
|
||||||
|
|
||||||
#include "Header.h"
|
#include "Header.h"
|
||||||
|
|
||||||
#include "efi_platform.h"
|
#include "efi_platform.h"
|
||||||
@@ -181,6 +184,20 @@ platform_add_boot_device(struct stage2_args *args, NodeList *devicesList)
|
|||||||
efi_block_io_protocol *blockIo;
|
efi_block_io_protocol *blockIo;
|
||||||
size_t memSize = 0;
|
size_t memSize = 0;
|
||||||
|
|
||||||
|
// If the bootloader was started from the network (net_stack_init will find
|
||||||
|
// the ip= parameter in the LoadOptions), add network booting as the first
|
||||||
|
// entry if available
|
||||||
|
status_t error = net_stack_init();
|
||||||
|
if (error != B_OK) {
|
||||||
|
TRACE("Can't init network...\n");
|
||||||
|
} else {
|
||||||
|
TRACE("Network is initialized! Search for remote disk...\n");
|
||||||
|
RemoteDisk *remoteDisk = RemoteDisk::FindAnyRemoteDisk();
|
||||||
|
if (remoteDisk != NULL) {
|
||||||
|
devicesList->Add(remoteDisk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Read to zero sized buffer to get memory needed for handles
|
// Read to zero sized buffer to get memory needed for handles
|
||||||
if (kBootServices->LocateHandle(ByProtocol, &BlockIoGUID, 0, &memSize, 0)
|
if (kBootServices->LocateHandle(ByProtocol, &BlockIoGUID, 0, &memSize, 0)
|
||||||
!= EFI_BUFFER_TOO_SMALL)
|
!= EFI_BUFFER_TOO_SMALL)
|
||||||
@@ -225,6 +242,7 @@ platform_add_boot_device(struct stage2_args *args, NodeList *devicesList)
|
|||||||
panic("Can't allocate memory for block devices!");
|
panic("Can't allocate memory for block devices!");
|
||||||
devicesList->Insert(device);
|
devicesList->Insert(device);
|
||||||
}
|
}
|
||||||
|
|
||||||
return devicesList->Count() > 0 ? B_OK : B_ENTRY_NOT_FOUND;
|
return devicesList->Count() > 0 ? B_OK : B_ENTRY_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,412 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2005, Ingo Weinhold <[email protected]>.
|
||||||
|
* Copyright 2010, Andreas Faerber <[email protected]>
|
||||||
|
* Copyright 2025, Adrien Destugues <[email protected]>
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <OS.h>
|
||||||
|
|
||||||
|
#include <util/convertutf.h>
|
||||||
|
|
||||||
|
#include <boot/platform.h>
|
||||||
|
#include <boot/net/Ethernet.h>
|
||||||
|
#include <boot/net/IP.h>
|
||||||
|
#include <boot/net/NetStack.h>
|
||||||
|
|
||||||
|
#include "efi_platform.h"
|
||||||
|
#include <efi/protocol/simple-network.h>
|
||||||
|
#include <efi/protocol/loaded-image.h>
|
||||||
|
|
||||||
|
|
||||||
|
static efi_guid sNetworkProtocolGUID = EFI_SIMPLE_NETWORK_PROTOCOL_GUID;
|
||||||
|
static efi_guid sLoadedImageProtocolGUID = EFI_LOADED_IMAGE_PROTOCOL_GUID;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static efi_guid sDevicePathProtocolGUID = EFI_DEVICE_PATH_PROTOCOL_GUID;
|
||||||
|
static efi_guid sLoadedImageDevicePathProtocolGUID = EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//#define TRACE_NETWORK
|
||||||
|
#ifdef TRACE_NETWORK
|
||||||
|
# define TRACE(x...) dprintf("efi/network: " x)
|
||||||
|
# define CALLED(x...) dprintf("efi/network: CALLED %s\n", __func__)
|
||||||
|
#else
|
||||||
|
# define TRACE(x...) ;
|
||||||
|
# define CALLED(x...) ;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define TRACE_ALWAYS(x...) dprintf("efi/network: " x)
|
||||||
|
|
||||||
|
|
||||||
|
class EFIEthernetInterface : public EthernetInterface {
|
||||||
|
public:
|
||||||
|
EFIEthernetInterface();
|
||||||
|
virtual ~EFIEthernetInterface();
|
||||||
|
|
||||||
|
status_t Init();
|
||||||
|
|
||||||
|
virtual mac_addr_t MACAddress() const;
|
||||||
|
|
||||||
|
virtual void * AllocateSendReceiveBuffer(size_t size);
|
||||||
|
virtual void FreeSendReceiveBuffer(void *buffer);
|
||||||
|
|
||||||
|
virtual ssize_t Send(const void *buffer, size_t size);
|
||||||
|
virtual ssize_t Receive(void *buffer, size_t size);
|
||||||
|
|
||||||
|
private:
|
||||||
|
status_t FindMACAddress();
|
||||||
|
|
||||||
|
private:
|
||||||
|
efi_simple_network_protocol* fNetwork;
|
||||||
|
mac_addr_t fMACAddress;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef TRACE_NETWORK
|
||||||
|
|
||||||
|
static void
|
||||||
|
hex_dump(const void *_data, int length)
|
||||||
|
{
|
||||||
|
uint8 *data = (uint8*)_data;
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
if (i % 4 == 0) {
|
||||||
|
if (i % 32 == 0) {
|
||||||
|
if (i != 0)
|
||||||
|
dprintf("\n");
|
||||||
|
dprintf("%03x: ", i);
|
||||||
|
} else
|
||||||
|
dprintf(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
dprintf("%02x", data[i]);
|
||||||
|
}
|
||||||
|
dprintf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // !TRACE_NETWORK
|
||||||
|
|
||||||
|
#define hex_dump(data, length)
|
||||||
|
|
||||||
|
#endif // !TRACE_NETWORK
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
EFIEthernetInterface::EFIEthernetInterface()
|
||||||
|
:
|
||||||
|
EthernetInterface(),
|
||||||
|
fNetwork(NULL),
|
||||||
|
fMACAddress(kNoMACAddress)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
EFIEthernetInterface::~EFIEthernetInterface()
|
||||||
|
{
|
||||||
|
if (fNetwork) {
|
||||||
|
fNetwork->Shutdown(fNetwork);
|
||||||
|
fNetwork->Stop(fNetwork);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
EFIEthernetInterface::FindMACAddress()
|
||||||
|
{
|
||||||
|
if (fNetwork == NULL)
|
||||||
|
return B_ERROR;
|
||||||
|
|
||||||
|
memcpy(&fMACAddress, &fNetwork->Mode->CurrentAddress,
|
||||||
|
sizeof(fMACAddress));
|
||||||
|
|
||||||
|
if (fMACAddress == kNoMACAddress) {
|
||||||
|
memcpy(&fMACAddress, &fNetwork->Mode->PermanentAddress,
|
||||||
|
sizeof(fMACAddress));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fMACAddress == kNoMACAddress)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
EFIEthernetInterface::Init()
|
||||||
|
{
|
||||||
|
CALLED();
|
||||||
|
|
||||||
|
efi_status status = kSystemTable->BootServices->LocateProtocol(
|
||||||
|
&sNetworkProtocolGUID, NULL, (void**)&fNetwork);
|
||||||
|
|
||||||
|
if (status != EFI_SUCCESS || fNetwork == NULL) {
|
||||||
|
fNetwork = NULL;
|
||||||
|
TRACE_ALWAYS("EFI reports network unavaiable\n");
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE_ALWAYS("EFI reports network avaiable\n");
|
||||||
|
|
||||||
|
// Attempt to locate IP address from command line arguments passed by
|
||||||
|
// the bootloader (for example, U-Boot bootargs variable)
|
||||||
|
// Recognize a subset of the ip= parameter as defined for Linux:
|
||||||
|
// https://www.kernel.org/doc/Documentation/filesystems/nfs/nfsroot.txt
|
||||||
|
efi_loaded_image_protocol* loadedImageProtocol;
|
||||||
|
status = kSystemTable->BootServices->LocateProtocol(
|
||||||
|
&sLoadedImageProtocolGUID, NULL, (void**)&loadedImageProtocol);
|
||||||
|
|
||||||
|
if (status == EFI_SUCCESS) {
|
||||||
|
char buffer[256];
|
||||||
|
utf16le_to_utf8((uint16*)loadedImageProtocol->LoadOptions,
|
||||||
|
loadedImageProtocol->LoadOptionsSize / 2, buffer, sizeof(buffer));
|
||||||
|
TRACE("Load options: %s\n", buffer);
|
||||||
|
|
||||||
|
char* base = buffer;
|
||||||
|
char* ptr = base;
|
||||||
|
while (*ptr != '\0') {
|
||||||
|
if (*ptr == '=') {
|
||||||
|
TRACE("Key at %ld: %s\n", ptr - base, base);
|
||||||
|
// Found a key-value separator, see if it's a known option
|
||||||
|
if (ptr - base != 2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (strncmp(base, "ip", 2) == 0) {
|
||||||
|
TRACE("Found ip configuration in command line\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// At any space, reset the base pointer to the start of the next
|
||||||
|
// key
|
||||||
|
if (*ptr == ' ') {
|
||||||
|
base = ptr + 1;
|
||||||
|
}
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*ptr != '=') {
|
||||||
|
TRACE("No keys found in load options\n");
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Point after the = sign
|
||||||
|
ptr++;
|
||||||
|
|
||||||
|
// Try to parse next part of the string as an IP address
|
||||||
|
// TODO also recognize autoconfig parameters (such as 'ip=dhcp')
|
||||||
|
TRACE("Found IP address from load options: %s\n", ptr);
|
||||||
|
ip_addr_t address = ip_parse_address(ptr);
|
||||||
|
SetIPAddress(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// TODO u-boot does not provide the IP address or the TFTP server URL in
|
||||||
|
// "loaded image" and "device path" protocols. That would allow to detect
|
||||||
|
// network booting without having to specify the ip in bootargs. Enable
|
||||||
|
// this if the information is available when network booting with other
|
||||||
|
// EFI implementations or if U-Boot grows support for it.
|
||||||
|
bool bootFromNetwork = false;
|
||||||
|
|
||||||
|
// Try the basic "device path" protocol
|
||||||
|
efi_device_path_protocol* devicePathProtocol;
|
||||||
|
status = kSystemTable->BootServices->LocateProtocol(
|
||||||
|
&sDevicePathProtocolGUID, NULL, (void**)&devicePathProtocol);
|
||||||
|
|
||||||
|
if (status == EFI_SUCCESS) {
|
||||||
|
for (;;) {
|
||||||
|
TRACE("Now scanning: Type %d SubType %d\n", devicePathProtocol->Type, devicePathProtocol->SubType);
|
||||||
|
if (devicePathProtocol->Type == DEVICE_PATH_END
|
||||||
|
&& devicePathProtocol->SubType == DEVICE_PATH_ENTIRE_END) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (devicePathProtocol->Type == DEVICE_PATH_MESSAGING
|
||||||
|
&& devicePathProtocol->SubType == DEVICE_PATH_MESSAGING_MAC) {
|
||||||
|
bootFromNetwork = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (devicePathProtocol->Type == DEVICE_PATH_MEDIA
|
||||||
|
&& devicePathProtocol->SubType == MEDIA_FILEPATH_DP) {
|
||||||
|
TRACE("Found device path, length %d: %s\n", devicePathProtocol->Length, ((char*)devicePathProtocol) + sizeof(efi_device_path_protocol));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (devicePathProtocol->Type == DEVICE_PATH_MESSAGING
|
||||||
|
&& devicePathProtocol->SubType == DEVICE_PATH_MESSAGING_IPV4) {
|
||||||
|
bootFromNetwork = true;
|
||||||
|
ip_addr_t* address = (ip_addr_t*)(devicePathProtocol + 1);
|
||||||
|
SetIPAddress(*address);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
devicePathProtocol = (efi_device_path_protocol*)(((uint8_t*)devicePathProtocol) + devicePathProtocol->Length);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TRACE("No device path protocol\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE_ALWAYS("IP address not found in device path protocol, try in loaded image\n");
|
||||||
|
|
||||||
|
// Try the "loaded image device path protocol" which provides more specific
|
||||||
|
// information
|
||||||
|
status = kSystemTable->BootServices->LocateProtocol(
|
||||||
|
&sLoadedImageDevicePathProtocolGUID, NULL, (void**)&devicePathProtocol);
|
||||||
|
|
||||||
|
if (status == EFI_SUCCESS) {
|
||||||
|
for (;;) {
|
||||||
|
TRACE("Now scanning: Type %d SubType %d\n", devicePathProtocol->Type, devicePathProtocol->SubType);
|
||||||
|
if (devicePathProtocol->Type == DEVICE_PATH_END
|
||||||
|
&& devicePathProtocol->SubType == DEVICE_PATH_ENTIRE_END) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (devicePathProtocol->Type == DEVICE_PATH_MESSAGING
|
||||||
|
&& devicePathProtocol->SubType == DEVICE_PATH_MESSAGING_MAC) {
|
||||||
|
bootFromNetwork = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (devicePathProtocol->Type == DEVICE_PATH_MEDIA
|
||||||
|
&& devicePathProtocol->SubType == MEDIA_FILEPATH_DP) {
|
||||||
|
TRACE("Found device path, length %d: %s\n", devicePathProtocol->Length, ((char*)devicePathProtocol) + sizeof(efi_device_path_protocol));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (devicePathProtocol->Type == DEVICE_PATH_MESSAGING
|
||||||
|
&& devicePathProtocol->SubType == DEVICE_PATH_MESSAGING_IPV4) {
|
||||||
|
bootFromNetwork = true;
|
||||||
|
ip_addr_t* address = (ip_addr_t*)(devicePathProtocol + 1);
|
||||||
|
SetIPAddress(*address);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
devicePathProtocol = (efi_device_path_protocol*)(((uint8_t*)devicePathProtocol) + devicePathProtocol->Length);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TRACE("No loaded image device path protocol\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bootFromNetwork)
|
||||||
|
return B_ENTRY_NOT_FOUND;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
status = fNetwork->Start(fNetwork);
|
||||||
|
|
||||||
|
if (status != EFI_SUCCESS) {
|
||||||
|
TRACE_ALWAYS("error starting network\n");
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = fNetwork->Initialize(fNetwork, 0, 0);
|
||||||
|
|
||||||
|
if (status != EFI_SUCCESS) {
|
||||||
|
TRACE_ALWAYS("error initializing network\n");
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FindMACAddress() != B_OK) {
|
||||||
|
TRACE_ALWAYS("failed to get MAC address\n");
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
mac_addr_t
|
||||||
|
EFIEthernetInterface::MACAddress() const
|
||||||
|
{
|
||||||
|
return fMACAddress;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void *
|
||||||
|
EFIEthernetInterface::AllocateSendReceiveBuffer(size_t size)
|
||||||
|
{
|
||||||
|
return malloc(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
EFIEthernetInterface::FreeSendReceiveBuffer(void *buffer)
|
||||||
|
{
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
EFIEthernetInterface::Send(const void *buffer, size_t size)
|
||||||
|
{
|
||||||
|
TRACE("EFIEthernetInterface::Send(%p, %lu)\n", buffer, size);
|
||||||
|
|
||||||
|
if (!buffer)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
hex_dump(buffer, size);
|
||||||
|
|
||||||
|
efi_status status = fNetwork->Transmit(fNetwork, 0, size,
|
||||||
|
const_cast<void*>(buffer), NULL, NULL, NULL);
|
||||||
|
|
||||||
|
if (status != EFI_SUCCESS) {
|
||||||
|
TRACE("Send: Result is %lx\n", status);
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ssize_t
|
||||||
|
EFIEthernetInterface::Receive(void *buffer, size_t size)
|
||||||
|
{
|
||||||
|
if (!buffer)
|
||||||
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
efi_status status = fNetwork->Receive(fNetwork, NULL, &size, buffer,
|
||||||
|
NULL, NULL, NULL);
|
||||||
|
|
||||||
|
if (status == EFI_NOT_READY)
|
||||||
|
return B_WOULD_BLOCK;
|
||||||
|
|
||||||
|
if (status != EFI_SUCCESS) {
|
||||||
|
TRACE("EFIEthernetInterface::Receive(%p, %lu): %ld\n", buffer, size, status);
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
hex_dump(buffer, size);
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark -
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
platform_net_stack_init()
|
||||||
|
{
|
||||||
|
// create an EthernetInterface object for the device
|
||||||
|
EFIEthernetInterface *interface = new(nothrow) EFIEthernetInterface;
|
||||||
|
if (!interface)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
status_t error = interface->Init();
|
||||||
|
if (error != B_OK) {
|
||||||
|
delete interface;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add it to the net stack
|
||||||
|
error = NetStack::Default()->AddEthernetInterface(interface);
|
||||||
|
if (error != B_OK) {
|
||||||
|
delete interface;
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user