From 1c447d98e9e7f846075c609eeebda99601341843 Mon Sep 17 00:00:00 2001 From: Markus Partheymueller Date: Thu, 11 Oct 2012 14:41:29 +0200 Subject: [PATCH] vancouver: Network support Vancouver is now able to use the Intel 82576 device model from NUL to give VMs access to the network via the nic_bridge service. In order to integrate the device model, it had to be renamed to i82576 due to XML limitations. This is done by a patch applied via the 'make prepare' mechanism. Although current network card models in Vancouver panic if they can't get a MAC address, the OP_GET_MAC hostop now fails gracefully in the case where no nic_drv or nic_bridge is available. --- ports/ports/vancouver.mk | 25 ++++++ ports/src/vancouver/device_model_registry.cc | 11 +++ ports/src/vancouver/main.cc | 87 ++++++++++++++++++- ports/src/vancouver/network.cc | 51 +++++++++++ ports/src/vancouver/network.h | 51 +++++++++++ ports/src/vancouver/rename-82576-i82576.patch | 13 +++ ports/src/vancouver/target.mk | 11 +-- 7 files changed, 239 insertions(+), 10 deletions(-) create mode 100644 ports/src/vancouver/network.cc create mode 100644 ports/src/vancouver/network.h create mode 100644 ports/src/vancouver/rename-82576-i82576.patch diff --git a/ports/ports/vancouver.mk b/ports/ports/vancouver.mk index 6d264acc2..f5bdc96f9 100644 --- a/ports/ports/vancouver.mk +++ b/ports/ports/vancouver.mk @@ -12,6 +12,18 @@ $(call check_tool,git) # PORTS += $(VANCOUVER) +# +# We need to execute some python scripts for preparing the i82576vf +# device model. +# +PYTHON2 := $(notdir $(lastword $(shell which python2 python2.{4,5,6,7,8}))) +ifeq ($(PYTHON2),) +prepare: python_not_installed +python_not_installed: + $(ECHO) "Error: Vancouver needs Python 2 to be installed" + @false; +endif + prepare:: $(CONTRIB_DIR)/$(VANCOUVER) # @@ -23,7 +35,20 @@ $(DOWNLOAD_DIR)/$(VANCOUVER)/.git: git reset --hard $(VANCOUVER_REV) && \ cd ../.. && touch $@ +I82576VF_DIR = $(CONTRIB_DIR)/$(VANCOUVER)/julian/model/82576vf + $(CONTRIB_DIR)/$(VANCOUVER)/.git: $(DOWNLOAD_DIR)/$(VANCOUVER)/.git $(VERBOSE)git clone $(DOWNLOAD_DIR)/$(VANCOUVER) $(CONTRIB_DIR)/$(VANCOUVER) + $(VERBOSE)patch -d $(CONTRIB_DIR)/$(VANCOUVER) -N -p1 < src/vancouver/rename-82576-i82576.patch + @# fix python version in code generator scripts + $(VERBOSE)sed -i "s/env python2/env $(PYTHON2)/" $(I82576VF_DIR)/genreg.py + $(VERBOSE)sed -i "s/env python2/env $(PYTHON2)/" $(I82576VF_DIR)/genreg2.py + @# call code generators + $(VERBOSE)cd $(I82576VF_DIR); \ + ./genreg.py reg_pci.py ../../../vancouver/include/model/82576vfpci.inc + $(VERBOSE)cd $(I82576VF_DIR); \ + ./genreg.py reg_mmio.py ../../../vancouver/include/model/82576vfmmio.inc + $(VERBOSE)cd $(I82576VF_DIR); \ + ./genreg2.py reg_mmio.py ../../../vancouver/include/model/82576vfmmio_vnet.inc $(CONTRIB_DIR)/$(VANCOUVER): $(CONTRIB_DIR)/$(VANCOUVER)/.git diff --git a/ports/src/vancouver/device_model_registry.cc b/ports/src/vancouver/device_model_registry.cc index 76d1dfe68..b5fd7b62c 100644 --- a/ports/src/vancouver/device_model_registry.cc +++ b/ports/src/vancouver/device_model_registry.cc @@ -1,19 +1,28 @@ /* * \brief Meta-data registry about the device models of Vancouver * \author Norman Feske + * \author Markus Partheymueller * \date 2011-11-18 */ /* * Copyright (C) 2011-2013 Genode Labs GmbH + * Copyright (C) 2012 Intel Corporation * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. + * + * The code is partially based on the Vancouver VMM, which is distributed + * under the terms of the GNU General Public License version 2. + * + * Modifications by Intel Corporation are contributed under the terms and + * conditions of the GNU General Public License version 2. */ /* local includes */ #include + Device_model_registry *device_model_registry() { static Device_model_registry inst; @@ -72,6 +81,8 @@ MODEL_INFO(pmtimer, "io_port") MODEL_INFO(pcihostbridge, "bus_num", "bus_count", "io_base", "mem_base") +MODEL_INFO(i82576vf, "promisc", "mem_mmio", "mem_msix", "txpoll_us", "rx_map") + MODEL_INFO_NO_ARG(vbios_disk) MODEL_INFO_NO_ARG(vbios_keyboard) MODEL_INFO_NO_ARG(vbios_mem) diff --git a/ports/src/vancouver/main.cc b/ports/src/vancouver/main.cc index 7ef332b7c..629895085 100644 --- a/ports/src/vancouver/main.cc +++ b/ports/src/vancouver/main.cc @@ -43,6 +43,8 @@ #include #include #include +#include +#include #include #include #include @@ -60,6 +62,7 @@ #include #include #include +#include enum { PAGE_SIZE_LOG2 = 12UL, @@ -72,6 +75,12 @@ enum { verbose_debug = false }; enum { verbose_npt = false }; enum { verbose_io = false }; +static Genode::Native_utcb utcb_backup; +Genode::Lock *utcb_lock() +{ + static Genode::Lock inst; + return &inst; +} /** * Semaphore used as global lock @@ -983,6 +992,7 @@ class Vcpu_dispatcher : public Genode::Thread, } }; +const void * _forward_pkt; class Machine : public StaticReceiver { @@ -999,6 +1009,8 @@ class Machine : public StaticReceiver bool _alloc_fb_mem; /* For detecting FB alloc message */ + Nic::Session *_nic; + public: /********************************************* @@ -1173,7 +1185,38 @@ class Machine : public StaticReceiver return true; } + case MessageHostOp::OP_GET_MAC: + { + Genode::Allocator_avl * tx_block_alloc = + new Genode::Allocator_avl(Genode::env()->heap()); + try { + _nic = new Nic::Connection(tx_block_alloc); + } catch (...) { + Logging::printf("No NIC connection possible!\n"); + return false; + } + + PINF("Our mac address is %2x:%2x:%2x:%2x:%2x:%2x\n", + _nic->mac_address().addr[0], + _nic->mac_address().addr[1], + _nic->mac_address().addr[2], + _nic->mac_address().addr[3], + _nic->mac_address().addr[4], + _nic->mac_address().addr[5] + ); + msg.mac = ((Genode::uint64_t)_nic->mac_address().addr[0] & 0xff) << 40 | + ((Genode::uint64_t)_nic->mac_address().addr[1] & 0xff) << 32 | + ((Genode::uint64_t)_nic->mac_address().addr[2] & 0xff) << 24 | + ((Genode::uint64_t)_nic->mac_address().addr[3] & 0xff) << 16 | + ((Genode::uint64_t)_nic->mac_address().addr[4] & 0xff) << 8 | + ((Genode::uint64_t)_nic->mac_address().addr[5] & 0xff); + + /* Start receiver thread for this MAC */ + Vancouver_network * netreceiver = new Vancouver_network(_motherboard, _nic); + + return true; + } default: PWRN("HostOp %d not implemented", msg.type); @@ -1233,9 +1276,47 @@ class Machine : public StaticReceiver bool receive(MessageNetwork &msg) { - if (verbose_debug) - PDBG("MessageNetwork"); - return false; + if (msg.type != MessageNetwork::PACKET) return false; + + Genode::Lock::Guard guard(*utcb_lock()); + utcb_backup = *Genode::Thread_base::myself()->utcb(); + + if (msg.buffer == _forward_pkt) { + /* don't end in an endless forwarding loop */ + return false; + } + + /* allocate transmit packet */ + Packet_descriptor tx_packet; + try { + tx_packet = _nic->tx()->alloc_packet(msg.len); + } catch (Nic::Session::Tx::Source::Packet_alloc_failed) { + PERR("tx packet alloc failed"); + return false; + } + + /* fill packet with content */ + char *tx_content = _nic->tx()->packet_content(tx_packet); + _forward_pkt = tx_content; + for (unsigned i = 0; i < msg.len; i++) { + tx_content[i] = msg.buffer[i]; + } + _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"); + } + + /* release sent packet to free the space in the tx communication buffer */ + _nic->tx()->release_packet(tx_packet); + + *Genode::Thread_base::myself()->utcb() = utcb_backup; + + return true; } bool receive(MessagePciConfig &msg) diff --git a/ports/src/vancouver/network.cc b/ports/src/vancouver/network.cc new file mode 100644 index 000000000..27a5a15b1 --- /dev/null +++ b/ports/src/vancouver/network.cc @@ -0,0 +1,51 @@ +/* + * \brief Network receive handler per MAC address + * \author Markus Partheymueller + * \date 2012-07-31 + */ + +/* + * Copyright (C) 2012 Intel Corporation + * Copyright (C) 2013 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + * + * The code is partially based on the Vancouver VMM, which is distributed + * under the terms of the GNU General Public License version 2. + * + * Modifications by Intel Corporation are contributed under the terms and + * conditions of the GNU General Public License version 2. + */ + +/* local includes */ +#include + +extern const void * _forward_pkt; + + +Vancouver_network::Vancouver_network(Motherboard &mb, Nic::Session * nic) +: _mb(mb), _nic(nic) +{ + start(); +} + + +void Vancouver_network::entry() +{ + Logging::printf("Hello, this is the network receiver.\n"); + + while (true) { + Packet_descriptor rx_packet = _nic->rx()->get_packet(); + + /* send it to the network bus */ + char * rx_content = _nic->rx()->packet_content(rx_packet); + _forward_pkt = rx_content; + MessageNetwork msg((unsigned char *)rx_content, rx_packet.size(), 0); + _mb.bus_network.send(msg); + _forward_pkt = 0; + + /* acknowledge received packet */ + _nic->rx()->acknowledge_packet(rx_packet); + } +} diff --git a/ports/src/vancouver/network.h b/ports/src/vancouver/network.h new file mode 100644 index 000000000..2be8b1514 --- /dev/null +++ b/ports/src/vancouver/network.h @@ -0,0 +1,51 @@ +/* + * \brief Network receive handler per MAC address + * \author Markus Partheymueller + * \date 2012-07-31 + */ + +/* + * Copyright (C) 2012 Intel Corporation + * Copyright (C) 2013 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + * + * The code is partially based on the Vancouver VMM, which is distributed + * under the terms of the GNU General Public License version 2. + * + * Modifications by Intel Corporation are contributed under the terms and + * conditions of the GNU General Public License version 2. + */ + +#ifndef _NETWORK_H_ +#define _NETWORK_H_ + +/* Genode includes */ +#include + +/* NOVA userland includes */ +#include + +using Genode::List; +using Genode::Thread; + +class Vancouver_network : public Thread<4096> +{ + private: + + Motherboard &_mb; + Nic::Session *_nic; + + public: + + /* initialisation */ + void entry(); + + /** + * Constructor + */ + Vancouver_network(Motherboard &mb, Nic::Session *nic); +}; + +#endif /* _NETWORK_H_ */ diff --git a/ports/src/vancouver/rename-82576-i82576.patch b/ports/src/vancouver/rename-82576-i82576.patch new file mode 100644 index 000000000..b17eb3a23 --- /dev/null +++ b/ports/src/vancouver/rename-82576-i82576.patch @@ -0,0 +1,13 @@ +diff --git a/julian/model/82576vf.cc b/julian/model/82576vf.cc +index b4d29a5..db8d2f3 100644 +--- a/julian/model/82576vf.cc ++++ b/julian/model/82576vf.cc +@@ -950,7 +950,7 @@ public: + + }; + +-PARAM_HANDLER(82576vf, ++PARAM_HANDLER(i82576vf, + "82576vf:[promisc][,mem_mmio][,mem_msix][,txpoll_us][,rx_map] - attach an Intel 82576VF to the PCI bus.", + "promisc - if !=0, be always promiscuous (use for Linux VMs that need it for bridging) (Default 1)", + "txpoll_us - if !=0, map TX registers to guest and poll them every txpoll_us microseconds. (Default 0)", diff --git a/ports/src/vancouver/target.mk b/ports/src/vancouver/target.mk index e9a841c02..2b9903e3e 100644 --- a/ports/src/vancouver/target.mk +++ b/ports/src/vancouver/target.mk @@ -12,24 +12,21 @@ endif LIBS += cxx env blit thread alarm signal server SRC_CC = main.cc nova_user_env.cc device_model_registry.cc -SRC_CC += console.cc keyboard.cc +SRC_CC += console.cc keyboard.cc network.cc SRC_BIN = mono.tff -# -# '82576vfmmio.inc' is apparently missing from the NOVA userland distribution. -# So let's skip building the 82576vf device model for now. -# -FILTER_OUT = model/82576vf.cc - MODEL_SRC_CC += $(notdir $(wildcard $(VANCOUVER_DIR)/model/*.cc)) EXECUTOR_SRC_CC += $(notdir $(wildcard $(VANCOUVER_DIR)/executor/*.cc)) SERVICE_SRC_CC += hostsink.cc SRC_CC += $(filter-out $(FILTER_OUT),$(addprefix model/,$(MODEL_SRC_CC))) +SRC_CC += $(CONTRIB_DIR)/julian/model/82576vf.cc SRC_CC += $(filter-out $(FILTER_OUT),$(addprefix executor/,$(EXECUTOR_SRC_CC))) SRC_CC += base/service/hostsink.cc base/lib/runtime/string.cc INC_DIR += $(PRG_DIR) +INC_DIR += $(CONTRIB_DIR)/julian/model +INC_DIR += $(CONTRIB_DIR)/julian/include INC_DIR += $(VANCOUVER_DIR)/model INC_DIR += $(VANCOUVER_DIR)/executor INC_DIR += $(VANCOUVER_DIR)/include