From c5380674df9ef63763a8c8abcc76694795299704 Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Wed, 2 Jul 2014 17:35:56 +0200 Subject: [PATCH] vbox: add network support - support e1000 model by default and add support for pcnet model - add Genode xml config option to enable network models Fixes #1201 --- repos/ports/lib/mk/virtualbox-common.inc | 2 + repos/ports/lib/mk/virtualbox-devices.mk | 3 + repos/ports/lib/mk/virtualbox-drivers.mk | 4 + repos/ports/lib/mk/virtualbox-runtime.mk | 2 + repos/ports/ports/virtualbox.hash | 2 +- repos/ports/run/virtualbox.run | 22 +- repos/ports/src/virtualbox/devices.cc | 5 + repos/ports/src/virtualbox/drivers.cc | 1 + repos/ports/src/virtualbox/dummies.cc | 7 +- repos/ports/src/virtualbox/guest_memory.h | 13 + repos/ports/src/virtualbox/iommio.cc | 19 +- repos/ports/src/virtualbox/ioport.cc | 12 +- repos/ports/src/virtualbox/libc.cc | 1 + repos/ports/src/virtualbox/main.cc | 37 +- repos/ports/src/virtualbox/network.cpp | 492 ++++++++++++++++++++++ repos/ports/src/virtualbox/network.patch | 131 ++++++ repos/ports/src/virtualbox/pgm.cc | 3 - 17 files changed, 733 insertions(+), 23 deletions(-) create mode 100644 repos/ports/src/virtualbox/network.cpp create mode 100644 repos/ports/src/virtualbox/network.patch diff --git a/repos/ports/lib/mk/virtualbox-common.inc b/repos/ports/lib/mk/virtualbox-common.inc index 60f46b6b1..e3611d673 100644 --- a/repos/ports/lib/mk/virtualbox-common.inc +++ b/repos/ports/lib/mk/virtualbox-common.inc @@ -37,6 +37,8 @@ VBOX_CC_OPT += -DUSE_SDL VBOX_CC_OPT += -DRTLOG_REL_ENABLED -DRT_STRICT -DVBOX_STRICT +# Enable Intel Network model E1000 +VBOX_CC_OPT += -DVBOX_WITH_E1000 VIRTUALBOX_VERSION_MAJOR := $(shell cat $(VIRTUALBOX_DIR)/Config.kmk | grep "VBOX_VERSION_MAJOR = " | grep -v "'VBOX_VERSION_MAJOR" | sed "s/^.*= //") VIRTUALBOX_VERSION_MINOR := $(shell cat $(VIRTUALBOX_DIR)/Config.kmk | grep "VBOX_VERSION_MINOR = " | grep -v "'VBOX_VERSION_MINOR" | sed "s/^.*= //") diff --git a/repos/ports/lib/mk/virtualbox-devices.mk b/repos/ports/lib/mk/virtualbox-devices.mk index 616bfe9e8..76b72c594 100644 --- a/repos/ports/lib/mk/virtualbox-devices.mk +++ b/repos/ports/lib/mk/virtualbox-devices.mk @@ -23,6 +23,9 @@ SRC_CC += Devices/Storage/DevATA.cpp SRC_CC += Devices/Storage/Debug.cpp SRC_CC += Devices/Storage/fdc.c SRC_CC += Devices/Storage/DrvRawImage.cpp +SRC_CC += Devices/Network/DevE1000.cpp +SRC_CC += Devices/Network/DevE1000Phy.cpp +SRC_CC += Devices/Network/DevEEPROM.cpp SRC_CC += Devices/Network/DevPCNet.cpp SRC_CC += Devices/VMMDev/VMMDev.cpp SRC_CC += Devices/VMMDev/VMMDevHGCM.cpp diff --git a/repos/ports/lib/mk/virtualbox-drivers.mk b/repos/ports/lib/mk/virtualbox-drivers.mk index a736dad79..591cea5ea 100644 --- a/repos/ports/lib/mk/virtualbox-drivers.mk +++ b/repos/ports/lib/mk/virtualbox-drivers.mk @@ -11,6 +11,10 @@ SRC_CC += Devices/Serial/DrvRawFile.cpp SRC_CC += Devices/Serial/DrvHostSerial.cpp SRC_CC += Main/src-client/MouseImpl.cpp +SRC_CC += network.cpp + +vpath network.cpp $(REP_DIR)/src/virtualbox + # includes needed by 'MouseImpl.cpp' INC_DIR += $(VBOX_DIR)/Main/include INC_DIR += $(VBOX_DIR)/Frontends/VBoxBFE diff --git a/repos/ports/lib/mk/virtualbox-runtime.mk b/repos/ports/lib/mk/virtualbox-runtime.mk index 239d852bf..3101fe979 100644 --- a/repos/ports/lib/mk/virtualbox-runtime.mk +++ b/repos/ports/lib/mk/virtualbox-runtime.mk @@ -34,7 +34,9 @@ SRC_CC += Runtime/common/log/logrel.cpp \ SRC_CC += Runtime/common/err/RTErrConvertFromErrno.cpp SRC_CC += Runtime/common/alloc/memcache.cpp SRC_CC += Runtime/common/alloc/heapoffset.cpp +SRC_CC += Runtime/common/checksum/crc32.cpp SRC_CC += Runtime/common/checksum/md5.cpp +SRC_CC += Runtime/common/checksum/ipv4.cpp SRC_CC += Runtime/common/log/log.cpp SRC_CC += Runtime/common/log/log.cpp SRC_CC += Runtime/common/log/logellipsis.cpp diff --git a/repos/ports/ports/virtualbox.hash b/repos/ports/ports/virtualbox.hash index 798f0b0dd..19738aa81 100644 --- a/repos/ports/ports/virtualbox.hash +++ b/repos/ports/ports/virtualbox.hash @@ -1 +1 @@ -a1463e45f4bcb23ee32da9cce87bc1a85289e165 +64bd2d2de0305c36048e46c05af5bc6578533ed3 diff --git a/repos/ports/run/virtualbox.run b/repos/ports/run/virtualbox.run index 6fc2425ab..3c66a4078 100644 --- a/repos/ports/run/virtualbox.run +++ b/repos/ports/run/virtualbox.run @@ -1,3 +1,5 @@ +set use_net 0 + set build_components { core init virtualbox drivers/input @@ -9,6 +11,8 @@ lappend_if [have_spec acpi] build_components drivers/acpi lappend_if [have_spec pci] build_components drivers/pci lappend_if [have_spec x86] build_components drivers/rtc +lappend_if [expr $use_net] build_components drivers/nic + build $build_components create_boot_directory @@ -38,7 +42,7 @@ set config { append_if [have_spec acpi] config { - + @@ -85,13 +89,25 @@ append_if [have_spec x86] config { } +append_if [expr $use_net] config { + + + + +} + append config { - +} + +append_if [expr $use_net] config { + } + +append config { @@ -120,6 +136,8 @@ append boot_modules { ld.lib.so libc.lib.so libm.lib.so pthread.lib.so libc_lock_pipe.lib.so libc_terminal.lib.so libiconv.lib.so } +append_if [expr $use_net] boot_modules { nic_drv } + build_boot_image $boot_modules append qemu_args " -m 512 " diff --git a/repos/ports/src/virtualbox/devices.cc b/repos/ports/src/virtualbox/devices.cc index bd899fda5..f219d3e4f 100644 --- a/repos/ports/src/virtualbox/devices.cc +++ b/repos/ports/src/virtualbox/devices.cc @@ -97,6 +97,11 @@ extern "C" int VBoxDevicesRegister(PPDMDEVREGCB pCallbacks, uint32_t u32Version) if (RT_FAILURE(rc)) return rc; + /* Ethernet E1000 controller */ + rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceE1000); + if (RT_FAILURE(rc)) + return rc; + /* Serial device */ rc = pCallbacks->pfnRegister(pCallbacks, &g_DeviceSerialPort); if (RT_FAILURE(rc)) diff --git a/repos/ports/src/virtualbox/drivers.cc b/repos/ports/src/virtualbox/drivers.cc index 7796cf036..2b7f393c2 100644 --- a/repos/ports/src/virtualbox/drivers.cc +++ b/repos/ports/src/virtualbox/drivers.cc @@ -33,6 +33,7 @@ extern "C" int VBoxDriversRegister(PCPDMDRVREGCB pCallbacks, uint32_t u32Version &g_DrvRawFile, &g_DrvHostSerial, &g_DrvVD, + &g_DrvHostInterface, 0 }; diff --git a/repos/ports/src/virtualbox/dummies.cc b/repos/ports/src/virtualbox/dummies.cc index c08bec294..b7e8fc5af 100644 --- a/repos/ports/src/virtualbox/dummies.cc +++ b/repos/ports/src/virtualbox/dummies.cc @@ -161,10 +161,6 @@ DUMMY(-1, PGMGetHostMode) CHECKED_DUMMY(0, poll) /* needed by 'DrvHostSerial.cpp' */ DUMMY(-1, pthread_key_delete) -DUMMY(-1, RTCrc32); -DUMMY(-1, RTCrc32Start) -DUMMY(-1, RTCrc32Finish) -DUMMY(-1, RTCrc32Process) DUMMY(-1, RTMemExecFree) DUMMY(-1, RTMemPageFree) DUMMY(-1, RTPathAppend) @@ -218,7 +214,6 @@ DUMMY(-1, RTAvlU32Insert) CHECKED_DUMMY( 0, IOMR3Init) int IOMR3IOPortRegisterR0() { return 0; } int IOMR3IOPortRegisterRC() { return 0; } -DUMMY(-1, IOMR3MmioDeregister) CHECKED_DUMMY( 0, IOMR3MmioRegisterR0) CHECKED_DUMMY( 0, IOMR3MmioRegisterRC) void IOMR3Relocate() { } @@ -281,6 +276,8 @@ DUMMY(-1, RTSymlinkCreate) DUMMY(-1, RTSymlinkRead) DUMMY(-1, RTSymlinkDelete) +DUMMY(-1, RTNetIPv6PseudoChecksumEx) + CHECKED_DUMMY(0, futimes) CHECKED_DUMMY(0, lutimes) diff --git a/repos/ports/src/virtualbox/guest_memory.h b/repos/ports/src/virtualbox/guest_memory.h index 0b6165413..d6640bbe8 100644 --- a/repos/ports/src/virtualbox/guest_memory.h +++ b/repos/ports/src/virtualbox/guest_memory.h @@ -257,6 +257,19 @@ class Guest_memory pfnReadCallback, pfnFillCallback, fFlags)); } + + bool remove_mmio_mapping(RTGCPHYS const GCPhys, RTGCPHYS const size) + { + Region *r = _lookup(GCPhys, _mmio_regions, size); + if (!r) + return false; + + _mmio_regions.remove(r); + delete r; + return true; + } + + void dump() const { Genode::printf("guest-physical to VMM-local RAM mappings:\n"); diff --git a/repos/ports/src/virtualbox/iommio.cc b/repos/ports/src/virtualbox/iommio.cc index 397764bbc..b748fea38 100644 --- a/repos/ports/src/virtualbox/iommio.cc +++ b/repos/ports/src/virtualbox/iommio.cc @@ -29,8 +29,9 @@ int IOMR3MmioRegisterR3(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, R3PTRTYPE(PFNIOMMMIOFILL) pfnFillCallback, uint32_t fFlags, const char *pszDesc) { - PLOG("IOMR3MmioRegisterR3: GCPhys=0x%lx cb=0x%zx pszDesc=%s rd=%p wr=%p fl=%p", - (long)GCPhysStart, (size_t)cbRange, pszDesc, + PLOG("%s: GCPhys=0x%lx cb=0x%x pszDesc=%s rd=%p wr=%p fl=%p", + __PRETTY_FUNCTION__, + (long)GCPhysStart, cbRange, pszDesc, pfnWriteCallback, pfnReadCallback, pfnFillCallback); REMR3NotifyHandlerPhysicalRegister(pVM, PGMPHYSHANDLERTYPE_MMIO, @@ -45,6 +46,20 @@ int IOMR3MmioRegisterR3(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, } +int IOMR3MmioDeregister(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, + uint32_t cbRange) +{ + PLOG("%s: GCPhys=0x%lx cb=0x%x", __PRETTY_FUNCTION__, GCPhysStart, cbRange); + + bool status = guest_memory()->remove_mmio_mapping(GCPhysStart, cbRange); + if (status) + return VINF_SUCCESS; + + + return !VINF_SUCCESS; +} + + VBOXSTRICTRC IOMMMIOWrite(PVM pVM, RTGCPHYS GCPhys, uint32_t u32Value, size_t cbValue) { // PDBG("GCPhys=0x%x, u32Value=0x%x, cbValue=%zd", GCPhys, u32Value, cbValue); diff --git a/repos/ports/src/virtualbox/ioport.cc b/repos/ports/src/virtualbox/ioport.cc index 73556ddb8..cab674146 100644 --- a/repos/ports/src/virtualbox/ioport.cc +++ b/repos/ports/src/virtualbox/ioport.cc @@ -22,6 +22,8 @@ #include #include +static bool verbose = false; + class Guest_ioports { struct Range; @@ -263,8 +265,9 @@ IOMR3IOPortRegisterR3(PVM pVM, PPDMDEVINS pDevIns, R3PTRTYPE(PFNIOMIOPORTINSTRING) pfnInStringCallback, const char *pszDesc) { - PLOG("register I/O port range 0x%x-0x%x '%s'", - PortStart, PortStart + cPorts - 1, pszDesc); + if (verbose) + PLOG("register I/O port range 0x%x-0x%x '%s'", + PortStart, PortStart + cPorts - 1, pszDesc); return guest_ioports()->add_range(pDevIns, PortStart, cPorts, pvUser, pfnOutCallback, pfnInCallback, @@ -275,8 +278,9 @@ IOMR3IOPortRegisterR3(PVM pVM, PPDMDEVINS pDevIns, int IOMR3IOPortDeregister(PVM pVM, PPDMDEVINS pDevIns, RTIOPORT PortStart, RTUINT cPorts) { - PLOG("deregister I/O port range 0x%x-0x%x", - PortStart, PortStart + cPorts - 1); + if (verbose) + PLOG("deregister I/O port range 0x%x-0x%x", + PortStart, PortStart + cPorts - 1); return guest_ioports()->remove_range(pDevIns, PortStart, cPorts); } diff --git a/repos/ports/src/virtualbox/libc.cc b/repos/ports/src/virtualbox/libc.cc index 41f286b7f..21e2de3cb 100644 --- a/repos/ports/src/virtualbox/libc.cc +++ b/repos/ports/src/virtualbox/libc.cc @@ -105,6 +105,7 @@ extern "C" char *getenv(const char *name) // "+rem_run.e.l.f" // "+pgm.e.l.f" "+pdm" +// "+dev_pcnet.e.l.f" // "+dev_pic.e.l.f" // "+dev_apic.e.l.f" // "+dev_vmm.e.l.f" diff --git a/repos/ports/src/virtualbox/main.cc b/repos/ports/src/virtualbox/main.cc index f0be1dd35..b49fa1fd2 100644 --- a/repos/ports/src/virtualbox/main.cc +++ b/repos/ports/src/virtualbox/main.cc @@ -20,6 +20,7 @@ /* libc includes */ #include +#include /* libc memory allocator */ #include @@ -65,9 +66,7 @@ namespace { if (_argc >= MAX_ARGS - 1) throw Too_many_arguments(); - /* XXX yes const-casting hurts but main() needs char**, if in - * doubt we should strdup() here, right? */ - _argv[_argc++] = const_cast(arg); + _argv[_argc++] = strdup(arg); } char *** argvp() { @@ -170,7 +169,7 @@ int main() try { Xml_node::Attribute overlay = node.attribute("overlay"); overlay.value(c_type, sizeof(c_type)); - if (!strcmp(c_type, "yes")) + if (!Genode::strcmp(c_type, "yes")) bOverlay = true; } catch (...) { } type.value(c_type, sizeof(c_type)); @@ -239,9 +238,35 @@ int main() } } catch(Genode::Xml_node::Nonexistent_sub_node) { } - PINF("start %s image '%s' with %zu MB guest memory=%zu and %u shared folders", + /* network setup */ + unsigned net = 0; + try { + using namespace Genode; + for (Xml_node node = config()->xml_node().sub_node("net"); + true; node = node.next("net")) { + + net ++; + + char buf [10]; + Genode::snprintf(buf, sizeof(buf), "-hifdev%d", net); + args.add(buf); + + /* read out network model, if not set use e1000 */ + try { + Xml_node::Attribute model = node.attribute("model"); + char * c_model = new char[model.value_size() + 1]; + model.value(c_model, model.value_size() + 1); + args.add(c_model); + } catch(Genode::Xml_node::Nonexistent_attribute) { + args.add("e1000"); + } + } + } catch(Genode::Xml_node::Nonexistent_sub_node) { } + + PINF("start %s image '%s' with %zu MB guest memory=%zu, %u shared folders," + " %u network connections", c_type, c_file, vm_size / 1024 / 1024, - Genode::env()->ram_session()->avail(), shares); + Genode::env()->ram_session()->avail(), shares, net); if (RT_FAILURE(RTR3InitExe(args.argc(), args.argvp(), 0))) { PERR("Intialization of VBox Runtime failed."); diff --git a/repos/ports/src/virtualbox/network.cpp b/repos/ports/src/virtualbox/network.cpp new file mode 100644 index 000000000..3684da5fb --- /dev/null +++ b/repos/ports/src/virtualbox/network.cpp @@ -0,0 +1,492 @@ +/** + * Genode network session driver, + * derived from src/VBox/Devices/Network/DrvTAP.cpp. + */ + +/* + * Copyright (C) 2014 Genode Labs GmbH + * + * This file is distributed under the terms of the GNU General Public License + * version 2. + */ + +/* + * Copyright (C) 2006-2012 Oracle Corporation + * + * This file is part of VirtualBox Open Source Edition (OSE), as + * available from http://www.virtualbox.org. This file is free software; + * you can redistribute it and/or modify it under the terms of the GNU + * General Public License (GPL) as published by the Free Software + * Foundation, in version 2 as it comes in the "COPYING" file of the + * VirtualBox OSE distribution. VirtualBox OSE is distributed in the + * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. + */ + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#define LOG_GROUP LOG_GROUP_DRV_TUN +#include +#include +#include +#include + +#include +#include + +#include "VBoxDD.h" + +#include +#include + +/******************************************************************************* +* Structures and Typedefs * +*******************************************************************************/ +/** + * TAP driver instance data. + * + * @implements PDMINETWORKUP + */ +typedef struct DRVTAP +{ + /** The network interface. */ + PDMINETWORKUP INetworkUp; + /** The network interface. */ + PPDMINETWORKDOWN pIAboveNet; + /** Pointer to the driver instance. */ + PPDMDRVINS pDrvIns; + /** Reader thread. */ + PPDMTHREAD pThread; + + /** @todo The transmit thread. */ + /** Transmit lock used by drvTAPNetworkUp_BeginXmit. */ + RTCRITSECT XmitLock; + + Nic::Session *nic_session; + + PDMINETWORKCONFIG INetworkConfig; + +} DRVTAP, *PDRVTAP; + + +/** Converts a pointer to TAP::INetworkUp to a PRDVTAP. */ +#define PDMINETWORKUP_2_DRVTAP(pInterface) ( (PDRVTAP)((uintptr_t)pInterface - RT_OFFSETOF(DRVTAP, INetworkUp)) ) +#define PDMINETWORKCONFIG_2_DRVTAP(pInterface) ( (PDRVTAP)((uintptr_t)pInterface - RT_OFFSETOF(DRVTAP, INetworkConfig)) ) + + +/******************************************************************************* +* Internal Functions * +*******************************************************************************/ + +static int net_send_packet(void * packet, uint32_t packet_len, Nic::Session * nic) { + + /* allocate transmit packet */ + Packet_descriptor tx_packet; + try { + tx_packet = nic->tx()->alloc_packet(packet_len); + } catch (Nic::Session::Tx::Source::Packet_alloc_failed) { + PERR("tx packet alloc failed"); + return VERR_NO_MEMORY; + } + + /* fill packet with content */ + char * stream_buffer = nic->tx()->packet_content(tx_packet); + memcpy(stream_buffer, packet, packet_len); + + nic->tx()->submit_packet(tx_packet); + + /* wait for acknowledgement */ + Packet_descriptor ack_tx_packet = nic->tx()->get_acked_packet(); + + if (ack_tx_packet.size() != tx_packet.size() || + ack_tx_packet.offset() != tx_packet.offset()) + PERR("unexpected acked packet"); + + nic->tx()->release_packet(tx_packet); + + return VINF_SUCCESS; +} + +/** + * @interface_method_impl{PDMINETWORKUP,pfnBeginXmit} + */ +static DECLCALLBACK(int) drvTAPNetworkUp_BeginXmit(PPDMINETWORKUP pInterface, bool fOnWorkerThread) +{ + PDRVTAP pThis = PDMINETWORKUP_2_DRVTAP(pInterface); + int rc = RTCritSectTryEnter(&pThis->XmitLock); + if (RT_FAILURE(rc)) + { + /** @todo XMIT thread */ + rc = VERR_TRY_AGAIN; + } + return rc; +} + + +/** + * @interface_method_impl{PDMINETWORKUP,pfnAllocBuf} + */ +static DECLCALLBACK(int) drvTAPNetworkUp_AllocBuf(PPDMINETWORKUP pInterface, size_t cbMin, + PCPDMNETWORKGSO pGso, PPPDMSCATTERGATHER ppSgBuf) +{ + PDRVTAP pThis = PDMINETWORKUP_2_DRVTAP(pInterface); + Assert(RTCritSectIsOwner(&pThis->XmitLock)); + + /* + * Allocate a scatter / gather buffer descriptor that is immediately + * followed by the buffer space of its single segment. The GSO context + * comes after that again. + */ + PPDMSCATTERGATHER pSgBuf = (PPDMSCATTERGATHER)RTMemAlloc( RT_ALIGN_Z(sizeof(*pSgBuf), 16) + + RT_ALIGN_Z(cbMin, 16) + + (pGso ? RT_ALIGN_Z(sizeof(*pGso), 16) : 0)); + if (!pSgBuf) + return VERR_NO_MEMORY; + + /* + * Initialize the S/G buffer and return. + */ + pSgBuf->fFlags = PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1; + pSgBuf->cbUsed = 0; + pSgBuf->cbAvailable = RT_ALIGN_Z(cbMin, 16); + pSgBuf->pvAllocator = NULL; + if (!pGso) + pSgBuf->pvUser = NULL; + else + { + pSgBuf->pvUser = (uint8_t *)(pSgBuf + 1) + pSgBuf->cbAvailable; + *(PPDMNETWORKGSO)pSgBuf->pvUser = *pGso; + } + pSgBuf->cSegs = 1; + pSgBuf->aSegs[0].cbSeg = pSgBuf->cbAvailable; + pSgBuf->aSegs[0].pvSeg = pSgBuf + 1; + +#if 0 /* poison */ + memset(pSgBuf->aSegs[0].pvSeg, 'F', pSgBuf->aSegs[0].cbSeg); +#endif + *ppSgBuf = pSgBuf; + return VINF_SUCCESS; +} + + +/** + * @interface_method_impl{PDMINETWORKUP,pfnFreeBuf} + */ +static DECLCALLBACK(int) drvTAPNetworkUp_FreeBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf) +{ + PDRVTAP pThis = PDMINETWORKUP_2_DRVTAP(pInterface); + Assert(RTCritSectIsOwner(&pThis->XmitLock)); + if (pSgBuf) + { + Assert((pSgBuf->fFlags & PDMSCATTERGATHER_FLAGS_MAGIC_MASK) == PDMSCATTERGATHER_FLAGS_MAGIC); + pSgBuf->fFlags = 0; + RTMemFree(pSgBuf); + } + return VINF_SUCCESS; +} + + +/** + * @interface_method_impl{PDMINETWORKUP,pfnSendBuf} + */ +static DECLCALLBACK(int) drvTAPNetworkUp_SendBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread) +{ + PDRVTAP pThis = PDMINETWORKUP_2_DRVTAP(pInterface); + + AssertPtr(pSgBuf); + Assert((pSgBuf->fFlags & PDMSCATTERGATHER_FLAGS_MAGIC_MASK) == PDMSCATTERGATHER_FLAGS_MAGIC); + Assert(RTCritSectIsOwner(&pThis->XmitLock)); + + /* Set an FTM checkpoint as this operation changes the state permanently. */ + PDMDrvHlpFTSetCheckpoint(pThis->pDrvIns, FTMCHECKPOINTTYPE_NETWORK); + + int rc; + if (!pSgBuf->pvUser) + { + Log2(("drvTAPSend: pSgBuf->aSegs[0].pvSeg=%p pSgBuf->cbUsed=%#x\n" + "%.*Rhxd\n", + pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed, pSgBuf->cbUsed, pSgBuf->aSegs[0].pvSeg)); + + rc = net_send_packet(pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed, pThis->nic_session); + } + else + { + uint8_t abHdrScratch[256]; + uint8_t const *pbFrame = (uint8_t const *)pSgBuf->aSegs[0].pvSeg; + PCPDMNETWORKGSO pGso = (PCPDMNETWORKGSO)pSgBuf->pvUser; + uint32_t const cSegs = PDMNetGsoCalcSegmentCount(pGso, pSgBuf->cbUsed); Assert(cSegs > 1); + rc = VINF_SUCCESS; + for (size_t iSeg = 0; iSeg < cSegs; iSeg++) + { + uint32_t cbSegFrame; + void *pvSegFrame = PDMNetGsoCarveSegmentQD(pGso, (uint8_t *)pbFrame, pSgBuf->cbUsed, abHdrScratch, + iSeg, cSegs, &cbSegFrame); + rc = net_send_packet(pvSegFrame, cbSegFrame, pThis->nic_session); + if (RT_FAILURE(rc)) + break; + } + } + + pSgBuf->fFlags = 0; + RTMemFree(pSgBuf); + + AssertRC(rc); + if (RT_FAILURE(rc)) + rc = rc == VERR_NO_MEMORY ? VERR_NET_NO_BUFFER_SPACE : VERR_NET_DOWN; + return rc; +} + + +/** + * @interface_method_impl{PDMINETWORKUP,pfnEndXmit} + */ +static DECLCALLBACK(void) drvTAPNetworkUp_EndXmit(PPDMINETWORKUP pInterface) +{ + PDRVTAP pThis = PDMINETWORKUP_2_DRVTAP(pInterface); + RTCritSectLeave(&pThis->XmitLock); +} + + +/** + * @interface_method_impl{PDMINETWORKUP,pfnSetPromiscuousMode} + */ +static DECLCALLBACK(void) drvTAPNetworkUp_SetPromiscuousMode(PPDMINETWORKUP pInterface, bool fPromiscuous) +{ + LogFlow(("drvTAPNetworkUp_SetPromiscuousMode: fPromiscuous=%d\n", fPromiscuous)); + /* nothing to do */ +} + + +/** + * Notification on link status changes. + * + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param enmLinkState The new link state. + * @thread EMT + */ +static DECLCALLBACK(void) drvTAPNetworkUp_NotifyLinkChanged(PPDMINETWORKUP pInterface, PDMNETWORKLINKSTATE enmLinkState) +{ + LogFlow(("drvTAPNetworkUp_NotifyLinkChanged: enmLinkState=%d\n", enmLinkState)); + /** @todo take action on link down and up. Stop the polling and such like. */ +} + + + +static DECLCALLBACK(int) drvGetMac(PPDMINETWORKCONFIG pInterface, PRTMAC pMac) +{ + PDRVTAP pThis = PDMINETWORKCONFIG_2_DRVTAP(pInterface); + + static_assert (sizeof(*pMac) == sizeof(pThis->nic_session->mac_address()), + "should be equal"); + memcpy(pMac, pThis->nic_session->mac_address().addr, sizeof(*pMac)); + return VINF_SUCCESS; +} + + +/** + * Asynchronous I/O thread for handling receive. + * + * @returns VINF_SUCCESS (ignored). + * @param Thread Thread handle. + * @param pvUser Pointer to a DRVTAP structure. + */ +static DECLCALLBACK(int) drvTAPAsyncIoThread(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) +{ + PDRVTAP pThis = PDMINS_2_DATA(pDrvIns, PDRVTAP); + LogFlow(("drvTAPAsyncIoThread: pThis=%p\n", pThis)); + + if (pThread->enmState == PDMTHREADSTATE_INITIALIZING) + return VINF_SUCCESS; + + Nic::Session * nic = pThis->nic_session; + + while (pThread->enmState == PDMTHREADSTATE_RUNNING) + { + Packet_descriptor rx_packet = nic->rx()->get_packet(); + + /* send it to the network bus */ + char * rx_content = nic->rx()->packet_content(rx_packet); + + int rc1 = pThis->pIAboveNet->pfnWaitReceiveAvail(pThis->pIAboveNet, + RT_INDEFINITE_WAIT); + if (RT_FAILURE(rc1)) + continue; + + rc1 = pThis->pIAboveNet->pfnReceive(pThis->pIAboveNet, rx_content, + rx_packet.size()); + AssertRC(rc1); + + /* acknowledge received packet */ + nic->rx()->acknowledge_packet(rx_packet); + } + + return VINF_SUCCESS; +} + + +/** + * Unblock the send thread so it can respond to a state change. + * + * @returns VBox status code. + * @param pDevIns The pcnet device instance. + * @param pThread The send thread. + */ +static DECLCALLBACK(int) drvTapAsyncIoWakeup(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) +{ + PDRVTAP pThis = PDMINS_2_DATA(pDrvIns, PDRVTAP); + Assert(!"Not implemented"); + return VINF_SUCCESS; +} + + +/* -=-=-=-=- PDMIBASE -=-=-=-=- */ + +/** + * @interface_method_impl{PDMIBASE,pfnQueryInterface} + */ +static DECLCALLBACK(void *) drvTAPQueryInterface(PPDMIBASE pInterface, const char *pszIID) +{ + PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface); + PDRVTAP pThis = PDMINS_2_DATA(pDrvIns, PDRVTAP); + + PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase); + PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKUP, &pThis->INetworkUp); + PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONFIG, &pThis->INetworkConfig); + return NULL; +} + +/* -=-=-=-=- PDMDRVREG -=-=-=-=- */ + +static DECLCALLBACK(void) drvTAPDestruct(PPDMDRVINS pDrvIns) +{ + Assert(!"Not implemented"); +} + +/** + * Construct a TAP network transport driver instance. + * + * @copydoc FNPDMDRVCONSTRUCT + */ +static DECLCALLBACK(int) drvTAPConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags) +{ + PDRVTAP pThis = PDMINS_2_DATA(pDrvIns, PDRVTAP); + PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns); + + /* + * Init the static parts. + */ + pThis->pDrvIns = pDrvIns; + + /* IBase */ + pDrvIns->IBase.pfnQueryInterface = drvTAPQueryInterface; + /* INetwork */ + pThis->INetworkUp.pfnBeginXmit = drvTAPNetworkUp_BeginXmit; + pThis->INetworkUp.pfnAllocBuf = drvTAPNetworkUp_AllocBuf; + pThis->INetworkUp.pfnFreeBuf = drvTAPNetworkUp_FreeBuf; + pThis->INetworkUp.pfnSendBuf = drvTAPNetworkUp_SendBuf; + pThis->INetworkUp.pfnEndXmit = drvTAPNetworkUp_EndXmit; + pThis->INetworkUp.pfnSetPromiscuousMode = drvTAPNetworkUp_SetPromiscuousMode; + pThis->INetworkUp.pfnNotifyLinkChanged = drvTAPNetworkUp_NotifyLinkChanged; + + /* INetworkConfig - used on Genode to request Mac address of nic_session */ + pThis->INetworkConfig.pfnGetMac = drvGetMac; + + /* + * Setup Genode nic_session connection + */ + Nic::Packet_allocator *tx_block_alloc = + new (Genode::env()->heap()) Nic::Packet_allocator(Genode::env()->heap()); + + enum { + PACKET_SIZE = Nic::Packet_allocator::DEFAULT_PACKET_SIZE, + BUF_SIZE = Nic::Session::QUEUE_SIZE * PACKET_SIZE, + }; + + try { + pThis->nic_session = new Nic::Connection(tx_block_alloc, BUF_SIZE, + BUF_SIZE); + } catch (...) { + return VERR_HOSTIF_INIT_FAILED; + } + + /* + * Check that no-one is attached to us. + */ + AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER, + ("Configuration error: Not possible to attach anything to this driver!\n"), + VERR_PDM_DRVINS_NO_ATTACH); + + /* + * Query the network port interface. + */ + pThis->pIAboveNet = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKDOWN); + if (!pThis->pIAboveNet) + return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE, + N_("Configuration error: The above device/driver didn't export the network port interface")); + + /* + * Create the transmit lock. + */ + int rc = RTCritSectInit(&pThis->XmitLock); + AssertRCReturn(rc, rc); + + /* + * Create the async I/O thread. + */ + rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pThread, pThis, drvTAPAsyncIoThread, drvTapAsyncIoWakeup, 128 * _1K, RTTHREADTYPE_IO, "TAP"); + AssertRCReturn(rc, rc); + + return rc; +} + + +/** + * TAP network transport driver registration record. + */ +const PDMDRVREG g_DrvHostInterface = +{ + /* u32Version */ + PDM_DRVREG_VERSION, + /* szName */ + "HostInterface", + /* szRCMod */ + "", + /* szR0Mod */ + "", + /* pszDescription */ + "Genode Network Session Driver", + /* fFlags */ + PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT, + /* fClass. */ + PDM_DRVREG_CLASS_NETWORK, + /* cMaxInstances */ + ~0U, + /* cbInstance */ + sizeof(DRVTAP), + /* pfnConstruct */ + drvTAPConstruct, + /* pfnDestruct */ + drvTAPDestruct, + /* pfnRelocate */ + NULL, + /* pfnIOCtl */ + NULL, + /* pfnPowerOn */ + NULL, + /* pfnReset */ + NULL, + /* pfnSuspend */ + NULL, /** @todo Do power on, suspend and resume handlers! */ + /* pfnResume */ + NULL, + /* pfnAttach */ + NULL, + /* pfnDetach */ + NULL, + /* pfnPowerOff */ + NULL, + /* pfnSoftReset */ + NULL, + /* u32EndVersion */ + PDM_DRVREG_VERSION +}; diff --git a/repos/ports/src/virtualbox/network.patch b/repos/ports/src/virtualbox/network.patch new file mode 100644 index 000000000..bc3538ab9 --- /dev/null +++ b/repos/ports/src/virtualbox/network.patch @@ -0,0 +1,131 @@ ++++ src/app/virtualbox/src/VBox/Devices/Network/DevE1000.cpp +@@ -7536,6 +7536,39 @@ + pState->INetworkConfig.pfnGetLinkState = e1kGetLinkState; + pState->INetworkConfig.pfnSetLinkState = e1kSetLinkState; + ++ /* For Genode attach already here to be able to overwrite mac address */ ++ rc = PDMDevHlpDriverAttach(pDevIns, 0, &pState->IBase, &pState->pDrvBase, "Network Port"); ++ if (RT_SUCCESS(rc)) ++ { ++ /* Genode: read out the mac address from nic_session interface */ ++ PPDMINETWORKCONFIG pDrvConfig = PDMIBASE_QUERY_INTERFACE(pState->pDrvBase, PDMINETWORKCONFIG); ++ Assert(pDrvConfig && pDrvConfig->pfnGetMac); ++ pDrvConfig->pfnGetMac(pDrvConfig, &pState->macConfigured); ++ ++ if (rc == VINF_NAT_DNS) ++ { ++ PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT", ++ N_("A Domain Name Server (DNS) for NAT networking could not be determined. Ensure that your host is correctly connected to an ISP. If you ignore this warning the guest will not be able to perform nameserver lookups and it will probably observe delays if trying so")); ++ } ++ pState->pDrvR3 = PDMIBASE_QUERY_INTERFACE(pState->pDrvBase, PDMINETWORKUP); ++ AssertMsgReturn(pState->pDrvR3, ("Failed to obtain the PDMINETWORKUP interface!\n"), ++ VERR_PDM_MISSING_INTERFACE_BELOW); ++ ++ pState->pDrvR0 = PDMIBASER0_QUERY_INTERFACE(PDMIBASE_QUERY_INTERFACE(pState->pDrvBase, PDMIBASER0), PDMINETWORKUP); ++ pState->pDrvRC = PDMIBASERC_QUERY_INTERFACE(PDMIBASE_QUERY_INTERFACE(pState->pDrvBase, PDMIBASERC), PDMINETWORKUP); ++ } ++ else if ( rc == VERR_PDM_NO_ATTACHED_DRIVER ++ || rc == VERR_PDM_CFG_MISSING_DRIVER_NAME) ++ { ++ /* No error! */ ++ E1kLog(("%s This adapter is not attached to any network!\n", INSTANCE(pState))); ++ } ++ else ++ return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach the network LUN")); ++ ++ ++ ++ + /* Initialize the EEPROM */ + pState->eeprom.init(pState->macConfigured); + +@@ -7696,30 +7729,6 @@ + return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach the status LUN")); + pState->pLedsConnector = PDMIBASE_QUERY_INTERFACE(pBase, PDMILEDCONNECTORS); + +- rc = PDMDevHlpDriverAttach(pDevIns, 0, &pState->IBase, &pState->pDrvBase, "Network Port"); +- if (RT_SUCCESS(rc)) +- { +- if (rc == VINF_NAT_DNS) +- { +- PDMDevHlpVMSetRuntimeError(pDevIns, 0 /*fFlags*/, "NoDNSforNAT", +- N_("A Domain Name Server (DNS) for NAT networking could not be determined. Ensure that your host is correctly connected to an ISP. If you ignore this warning the guest will not be able to perform nameserver lookups and it will probably observe delays if trying so")); +- } +- pState->pDrvR3 = PDMIBASE_QUERY_INTERFACE(pState->pDrvBase, PDMINETWORKUP); +- AssertMsgReturn(pState->pDrvR3, ("Failed to obtain the PDMINETWORKUP interface!\n"), +- VERR_PDM_MISSING_INTERFACE_BELOW); +- +- pState->pDrvR0 = PDMIBASER0_QUERY_INTERFACE(PDMIBASE_QUERY_INTERFACE(pState->pDrvBase, PDMIBASER0), PDMINETWORKUP); +- pState->pDrvRC = PDMIBASERC_QUERY_INTERFACE(PDMIBASE_QUERY_INTERFACE(pState->pDrvBase, PDMIBASERC), PDMINETWORKUP); +- } +- else if ( rc == VERR_PDM_NO_ATTACHED_DRIVER +- || rc == VERR_PDM_CFG_MISSING_DRIVER_NAME) +- { +- /* No error! */ +- E1kLog(("%s This adapter is not attached to any network!\n", INSTANCE(pState))); +- } +- else +- return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to attach the network LUN")); +- + rc = RTSemEventCreate(&pState->hEventMoreRxDescAvail); + if (RT_FAILURE(rc)) + return rc; ++++ src/app/virtualbox/src/VBox/Devices/Network/DevPCNet.cpp +@@ -5331,6 +5331,11 @@ + rc = PDMDevHlpDriverAttach(pDevIns, 0, &pThis->IBase, &pThis->pDrvBase, "Network Port"); + if (RT_SUCCESS(rc)) + { ++ /* Genode: read out the mac address from nic_session interface */ ++ PPDMINETWORKCONFIG pDrvConfig = PDMIBASE_QUERY_INTERFACE(pThis->pDrvBase, PDMINETWORKCONFIG); ++ Assert(pDrvConfig && pDrvConfig->pfnGetMac); ++ pDrvConfig->pfnGetMac(pDrvConfig, &pThis->MacConfigured); ++ + if (rc == VINF_NAT_DNS) + { + #ifdef RT_OS_LINUX ++++ src/app/virtualbox/src/VBox/Frontends/VBoxBFE/VBoxBFE.cpp +@@ -1601,11 +1630,14 @@ + /* + * Network adapters + */ +- rc = CFGMR3InsertNode(pDevices, "pcnet", &pDev); UPDATE_RC(); + for (ULONG ulInstance = 0; ulInstance < NetworkAdapterCount; ulInstance++) + { + if (g_aNetDevs[ulInstance].enmType != BFENETDEV::NOT_CONFIGURED) + { ++ /* On Genode we use pszName to select the device model */ ++ const char * device_model = g_aNetDevs[ulInstance].pszName; ++ rc = CFGMR3InsertNode(pDevices, device_model, &pDev); UPDATE_RC(); ++ + char szInstance[4]; + RTStrPrintf(szInstance, sizeof(szInstance), "%lu", ulInstance); + rc = CFGMR3InsertNode(pDev, szInstance, &pInst); UPDATE_RC(); +@@ -1616,6 +1650,10 @@ + rc = CFGMR3InsertNode(pInst, "Config", &pCfg); UPDATE_RC(); + rc = CFGMR3InsertBytes(pCfg, "MAC", &g_aNetDevs[ulInstance].Mac, sizeof(RTMAC)); + UPDATE_RC(); ++ if (!strcmp("e1000", device_model)) { ++ rc = CFGMR3InsertInteger(pCfg, "CableConnected", 1); UPDATE_RC(); ++ rc = CFGMR3InsertInteger(pCfg, "AdapterType", 0); UPDATE_RC(); ++ } + + /* + * Enable the packet sniffer if requested. +@@ -1747,10 +1785,15 @@ + + + #else +- FatalError("Name based HIF devices not implemented yet for this host platform\n"); +- return VERR_NOT_IMPLEMENTED; ++// FatalError("Name based HIF devices not implemented yet for this host platform\n"); ++// return VERR_NOT_IMPLEMENTED; + #endif + } ++ ++ rc = CFGMR3InsertNode(pInst, "LUN#999", &pLunL0); UPDATE_RC(); ++ rc = CFGMR3InsertString(pLunL0, "Driver", "MainStatus"); UPDATE_RC(); ++ rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); UPDATE_RC(); ++ rc = CFGMR3InsertInteger(pCfg, "papLeds", (uintptr_t)&mapFDLeds[0]); UPDATE_RC(); + } + else if (g_aNetDevs[ulInstance].enmType == BFENETDEV::INTNET) + { diff --git a/repos/ports/src/virtualbox/pgm.cc b/repos/ports/src/virtualbox/pgm.cc index 2702a154d..9b218cec8 100644 --- a/repos/ports/src/virtualbox/pgm.cc +++ b/repos/ports/src/virtualbox/pgm.cc @@ -57,7 +57,6 @@ int PGMR3PhysRomRegister(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, try { guest_memory()->add_rom_mapping(GCPhys, cb, pvBinary, pDevIns); - guest_memory()->dump(); /* * XXX Try to understand the fShadowed condition @@ -256,8 +255,6 @@ int PGMR3PhysRegisterRam(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, guest_memory()->add_ram_mapping(GCPhys, cb, pv); - guest_memory()->dump(); - REMR3NotifyPhysRamRegister(pVM, GCPhys, cb, REM_NOTIFY_PHYS_RAM_FLAGS_RAM); } catch (Guest_memory::Region_conflict) {