From a933ad6dbc4c65c3344084dcbc9ea6a2817e9c8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= Date: Sat, 14 Sep 2013 11:48:37 +0200 Subject: [PATCH] virtio_net: initial skeleton driver. --- src/add-ons/kernel/drivers/network/Jamfile | 1 + .../kernel/drivers/network/virtio/Jamfile | 8 + .../drivers/network/virtio/virtio_net.cpp | 317 ++++++++++++++++++ .../drivers/network/virtio/virtio_net.h | 202 +++++++++++ 4 files changed, 528 insertions(+) create mode 100644 src/add-ons/kernel/drivers/network/virtio/Jamfile create mode 100644 src/add-ons/kernel/drivers/network/virtio/virtio_net.cpp create mode 100644 src/add-ons/kernel/drivers/network/virtio/virtio_net.h diff --git a/src/add-ons/kernel/drivers/network/Jamfile b/src/add-ons/kernel/drivers/network/Jamfile index 2940c7eb1e..224ba0c195 100644 --- a/src/add-ons/kernel/drivers/network/Jamfile +++ b/src/add-ons/kernel/drivers/network/Jamfile @@ -9,6 +9,7 @@ SubInclude HAIKU_TOP src add-ons kernel drivers network usb_asix ; SubInclude HAIKU_TOP src add-ons kernel drivers network usb_davicom ; SubInclude HAIKU_TOP src add-ons kernel drivers network usb_ecm ; SubInclude HAIKU_TOP src add-ons kernel drivers network via_rhine ; +SubInclude HAIKU_TOP src add-ons kernel drivers network virtio ; SubInclude HAIKU_TOP src add-ons kernel drivers network vlance ; SubInclude HAIKU_TOP src add-ons kernel drivers network wb840 ; diff --git a/src/add-ons/kernel/drivers/network/virtio/Jamfile b/src/add-ons/kernel/drivers/network/virtio/Jamfile new file mode 100644 index 0000000000..f8131115f2 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/virtio/Jamfile @@ -0,0 +1,8 @@ +SubDir HAIKU_TOP src add-ons kernel drivers network virtio ; + +UsePrivateKernelHeaders ; +UsePrivateHeaders drivers net virtio ; + +KernelAddon virtio_net : + virtio_net.cpp +; diff --git a/src/add-ons/kernel/drivers/network/virtio/virtio_net.cpp b/src/add-ons/kernel/drivers/network/virtio/virtio_net.cpp new file mode 100644 index 0000000000..92801feadf --- /dev/null +++ b/src/add-ons/kernel/drivers/network/virtio/virtio_net.cpp @@ -0,0 +1,317 @@ +/* + * Copyright 2013, Jérôme Duval, korli@users.berlios.de. + * Distributed under the terms of the MIT License. + */ + + +#include +#include + +#define ETHER_ADDR_LEN ETHER_ADDRESS_LENGTH +#include "virtio_net.h" + + + +#define VIRTIO_NET_DRIVER_MODULE_NAME "drivers/network/virtio_net/driver_v1" +#define VIRTIO_NET_DEVICE_MODULE_NAME "drivers/network/virtio_net/device_v1" +#define VIRTIO_NET_DEVICE_ID_GENERATOR "virtio_net/device_id" + + +typedef struct { + device_node* node; + ::virtio_device virtio_device; + virtio_device_interface* virtio; + + uint32 features; + +} virtio_net_driver_info; + + +typedef struct { + virtio_net_driver_info* info; +} virtio_net_handle; + + +#include +#include +#include + +#include + + +#define TRACE_VIRTIO_NET +#ifdef TRACE_VIRTIO_NET +# define TRACE(x...) dprintf("virtio_net: " x) +#else +# define TRACE(x...) ; +#endif +#define ERROR(x...) dprintf("\33[33mvirtio_net:\33[0m " x) +#define CALLED() TRACE("CALLED %s\n", __PRETTY_FUNCTION__) + + +static device_manager_info* sDeviceManager; + + +const char * +get_feature_name(uint32 feature) +{ + switch (feature) { + } + return NULL; +} + + +// #pragma mark - device module API + + +static status_t +virtio_net_init_device(void* _info, void** _cookie) +{ + CALLED(); + virtio_net_driver_info* info = (virtio_net_driver_info*)_info; + + device_node* parent = sDeviceManager->get_parent_node(info->node); + sDeviceManager->get_driver(parent, (driver_module_info **)&info->virtio, + (void **)&info->virtio_device); + sDeviceManager->put_node(parent); + + info->virtio->negociate_features(info->virtio_device, + 0, &info->features, &get_feature_name); + + // TODO read config + // TODO alloc queues and setup interrupts + + *_cookie = info; + return B_OK; +} + + +static void +virtio_net_uninit_device(void* _cookie) +{ + CALLED(); + virtio_net_driver_info* info = (virtio_net_driver_info*)_cookie; +} + + +static status_t +virtio_net_open(void* _info, const char* path, int openMode, void** _cookie) +{ + CALLED(); + virtio_net_driver_info* info = (virtio_net_driver_info*)_info; + + virtio_net_handle* handle = (virtio_net_handle*)malloc( + sizeof(virtio_net_handle)); + if (handle == NULL) + return B_NO_MEMORY; + + handle->info = info; + + *_cookie = handle; + return B_OK; +} + + +static status_t +virtio_net_close(void* cookie) +{ + //virtio_net_handle* handle = (virtio_net_handle*)cookie; + CALLED(); + + return B_OK; +} + + +static status_t +virtio_net_free(void* cookie) +{ + CALLED(); + virtio_net_handle* handle = (virtio_net_handle*)cookie; + + free(handle); + return B_OK; +} + + +static status_t +virtio_net_read(void* cookie, off_t pos, void* buffer, size_t* _length) +{ + CALLED(); + virtio_net_handle* handle = (virtio_net_handle*)cookie; + // TODO implement + return B_ERROR; +} + + +static status_t +virtio_net_write(void* cookie, off_t pos, const void* buffer, + size_t* _length) +{ + CALLED(); + virtio_net_handle* handle = (virtio_net_handle*)cookie; + // TODO implement + return B_ERROR; +} + + +static status_t +virtio_net_ioctl(void* cookie, uint32 op, void* buffer, size_t length) +{ + CALLED(); + virtio_net_handle* handle = (virtio_net_handle*)cookie; + virtio_net_driver_info* info = handle->info; + + TRACE("ioctl(op = %ld)\n", op); + + switch (op) { + } + + return B_DEV_INVALID_IOCTL; +} + + +// #pragma mark - driver module API + + +static float +virtio_net_supports_device(device_node *parent) +{ + CALLED(); + const char *bus; + uint16 deviceType; + + // make sure parent is really the Virtio bus manager + if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)) + return -1; + + if (strcmp(bus, "virtio")) + return 0.0; + + // check whether it's really a Direct Access Device + if (sDeviceManager->get_attr_uint16(parent, VIRTIO_DEVICE_TYPE_ITEM, + &deviceType, true) != B_OK || deviceType != VIRTIO_DEVICE_ID_NETWORK) + return 0.0; + + TRACE("Virtio network device found!\n"); + + return 0.6; +} + + +static status_t +virtio_net_register_device(device_node *node) +{ + CALLED(); + + // ready to register + device_attr attrs[] = { + { NULL } + }; + + return sDeviceManager->register_node(node, VIRTIO_NET_DRIVER_MODULE_NAME, + attrs, NULL, NULL); +} + + +static status_t +virtio_net_init_driver(device_node *node, void **cookie) +{ + CALLED(); + + virtio_net_driver_info* info = (virtio_net_driver_info*)malloc( + sizeof(virtio_net_driver_info)); + if (info == NULL) + return B_NO_MEMORY; + + memset(info, 0, sizeof(*info)); + + info->node = node; + + *cookie = info; + return B_OK; +} + + +static void +virtio_net_uninit_driver(void *_cookie) +{ + CALLED(); + virtio_net_driver_info* info = (virtio_net_driver_info*)_cookie; + free(info); +} + + +static status_t +virtio_net_register_child_devices(void* _cookie) +{ + CALLED(); + virtio_net_driver_info* info = (virtio_net_driver_info*)_cookie; + status_t status; + + int32 id = sDeviceManager->create_id(VIRTIO_NET_DEVICE_ID_GENERATOR); + if (id < 0) + return id; + + char name[64]; + snprintf(name, sizeof(name), "net/virtio/%" B_PRId32, + id); + + status = sDeviceManager->publish_device(info->node, name, + VIRTIO_NET_DEVICE_MODULE_NAME); + + return status; +} + + +// #pragma mark - + + +module_dependency module_dependencies[] = { + {B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&sDeviceManager}, + {} +}; + +struct device_module_info sVirtioNetDevice = { + { + VIRTIO_NET_DEVICE_MODULE_NAME, + 0, + NULL + }, + + virtio_net_init_device, + virtio_net_uninit_device, + NULL, // remove, + + virtio_net_open, + virtio_net_close, + virtio_net_free, + virtio_net_read, + virtio_net_write, + NULL, // io + virtio_net_ioctl, + + NULL, // select + NULL, // deselect +}; + +struct driver_module_info sVirtioNetDriver = { + { + VIRTIO_NET_DRIVER_MODULE_NAME, + 0, + NULL + }, + + virtio_net_supports_device, + virtio_net_register_device, + virtio_net_init_driver, + virtio_net_uninit_driver, + virtio_net_register_child_devices, + NULL, // rescan + NULL, // removed +}; + +module_info* modules[] = { + (module_info*)&sVirtioNetDriver, + (module_info*)&sVirtioNetDevice, + NULL +}; diff --git a/src/add-ons/kernel/drivers/network/virtio/virtio_net.h b/src/add-ons/kernel/drivers/network/virtio/virtio_net.h new file mode 100644 index 0000000000..315b730006 --- /dev/null +++ b/src/add-ons/kernel/drivers/network/virtio/virtio_net.h @@ -0,0 +1,202 @@ +/*- + * This header is BSD licensed so anyone can use the definitions to implement + * compatible drivers/servers. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of IBM nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#ifndef _VIRTIO_NET_H +#define _VIRTIO_NET_H + +/* The feature bitmap for virtio net */ +#define VIRTIO_NET_F_CSUM 0x00001 /* Host handles pkts w/ partial csum */ +#define VIRTIO_NET_F_GUEST_CSUM 0x00002 /* Guest handles pkts w/ partial csum*/ +#define VIRTIO_NET_F_MAC 0x00020 /* Host has given MAC address. */ +#define VIRTIO_NET_F_GSO 0x00040 /* Host handles pkts w/ any GSO type */ +#define VIRTIO_NET_F_GUEST_TSO4 0x00080 /* Guest can handle TSOv4 in. */ +#define VIRTIO_NET_F_GUEST_TSO6 0x00100 /* Guest can handle TSOv6 in. */ +#define VIRTIO_NET_F_GUEST_ECN 0x00200 /* Guest can handle TSO[6] w/ ECN in.*/ +#define VIRTIO_NET_F_GUEST_UFO 0x00400 /* Guest can handle UFO in. */ +#define VIRTIO_NET_F_HOST_TSO4 0x00800 /* Host can handle TSOv4 in. */ +#define VIRTIO_NET_F_HOST_TSO6 0x01000 /* Host can handle TSOv6 in. */ +#define VIRTIO_NET_F_HOST_ECN 0x02000 /* Host can handle TSO[6] w/ ECN in. */ +#define VIRTIO_NET_F_HOST_UFO 0x04000 /* Host can handle UFO in. */ +#define VIRTIO_NET_F_MRG_RXBUF 0x08000 /* Host can merge receive buffers. */ +#define VIRTIO_NET_F_STATUS 0x10000 /* virtio_net_config.status available*/ +#define VIRTIO_NET_F_CTRL_VQ 0x20000 /* Control channel available */ +#define VIRTIO_NET_F_CTRL_RX 0x40000 /* Control channel RX mode support */ +#define VIRTIO_NET_F_CTRL_VLAN 0x80000 /* Control channel VLAN filtering */ +#define VIRTIO_NET_F_CTRL_RX_EXTRA 0x100000 /* Extra RX mode control support */ +#define VIRTIO_NET_F_GUEST_ANNOUNCE 0x200000 /* Announce device on network */ +#define VIRTIO_NET_F_MQ 0x400000 /* Device supports RFS */ +#define VIRTIO_NET_F_CTRL_MAC_ADDR 0x800000 /* Set MAC address */ + +#define VIRTIO_NET_S_LINK_UP 1 /* Link is up */ + +struct virtio_net_config { + /* The config defining mac address (if VIRTIO_NET_F_MAC) */ + uint8_t mac[ETHER_ADDR_LEN]; + /* See VIRTIO_NET_F_STATUS and VIRTIO_NET_S_* above */ + uint16_t status; + /* Maximum number of each of transmit and receive queues; + * see VIRTIO_NET_F_MQ and VIRTIO_NET_CTRL_MQ. + * Legal values are between 1 and 0x8000. + */ + uint16_t max_virtqueue_pairs; +} _PACKED; + +/* + * This is the first element of the scatter-gather list. If you don't + * specify GSO or CSUM features, you can simply ignore the header. + */ +struct virtio_net_hdr { +#define VIRTIO_NET_HDR_F_NEEDS_CSUM 1 /* Use csum_start,csum_offset*/ +#define VIRTIO_NET_HDR_F_DATA_VALID 2 /* Csum is valid */ + uint8_t flags; +#define VIRTIO_NET_HDR_GSO_NONE 0 /* Not a GSO frame */ +#define VIRTIO_NET_HDR_GSO_TCPV4 1 /* GSO frame, IPv4 TCP (TSO) */ +#define VIRTIO_NET_HDR_GSO_UDP 3 /* GSO frame, IPv4 UDP (UFO) */ +#define VIRTIO_NET_HDR_GSO_TCPV6 4 /* GSO frame, IPv6 TCP */ +#define VIRTIO_NET_HDR_GSO_ECN 0x80 /* TCP has ECN set */ + uint8_t gso_type; + uint16_t hdr_len; /* Ethernet + IP + tcp/udp hdrs */ + uint16_t gso_size; /* Bytes to append to hdr_len per frame */ + uint16_t csum_start; /* Position to start checksumming from */ + uint16_t csum_offset; /* Offset after that to place checksum */ +}; + +/* + * This is the version of the header to use when the MRG_RXBUF + * feature has been negotiated. + */ +struct virtio_net_hdr_mrg_rxbuf { + struct virtio_net_hdr hdr; + uint16_t num_buffers; /* Number of merged rx buffers */ +}; + +/* + * Control virtqueue data structures + * + * The control virtqueue expects a header in the first sg entry + * and an ack/status response in the last entry. Data for the + * command goes in between. + */ +struct virtio_net_ctrl_hdr { + uint8_t net_class; // was renamed from class for c++ + uint8_t cmd; +} _PACKED; + +#define VIRTIO_NET_OK 0 +#define VIRTIO_NET_ERR 1 + +/* + * Control the RX mode, ie. promiscuous, allmulti, etc... + * All commands require an "out" sg entry containing a 1 byte + * state value, zero = disable, non-zero = enable. Commands + * 0 and 1 are supported with the VIRTIO_NET_F_CTRL_RX feature. + * Commands 2-5 are added with VIRTIO_NET_F_CTRL_RX_EXTRA. + */ +#define VIRTIO_NET_CTRL_RX 0 +#define VIRTIO_NET_CTRL_RX_PROMISC 0 +#define VIRTIO_NET_CTRL_RX_ALLMULTI 1 +#define VIRTIO_NET_CTRL_RX_ALLUNI 2 +#define VIRTIO_NET_CTRL_RX_NOMULTI 3 +#define VIRTIO_NET_CTRL_RX_NOUNI 4 +#define VIRTIO_NET_CTRL_RX_NOBCAST 5 + +/* + * Control the MAC filter table. + * + * The MAC filter table is managed by the hypervisor, the guest should + * assume the size is infinite. Filtering should be considered + * non-perfect, ie. based on hypervisor resources, the guest may + * received packets from sources not specified in the filter list. + * + * In addition to the class/cmd header, the TABLE_SET command requires + * two out scatterlists. Each contains a 4 byte count of entries followed + * by a concatenated byte stream of the ETH_ALEN MAC addresses. The + * first sg list contains unicast addresses, the second is for multicast. + * This functionality is present if the VIRTIO_NET_F_CTRL_RX feature + * is available. + * + * The ADDR_SET command requests one out scatterlist, it contains a + * 6 bytes MAC address. This functionality is present if the + * VIRTIO_NET_F_CTRL_MAC_ADDR feature is available. + */ +struct virtio_net_ctrl_mac { + uint32_t entries; + uint8_t macs[][ETHER_ADDR_LEN]; +} _PACKED; + +#define VIRTIO_NET_CTRL_MAC 1 +#define VIRTIO_NET_CTRL_MAC_TABLE_SET 0 +#define VIRTIO_NET_CTRL_MAC_ADDR_SET 1 + +/* + * Control VLAN filtering + * + * The VLAN filter table is controlled via a simple ADD/DEL interface. + * VLAN IDs not added may be filtered by the hypervisor. Del is the + * opposite of add. Both commands expect an out entry containing a 2 + * byte VLAN ID. VLAN filtering is available with the + * VIRTIO_NET_F_CTRL_VLAN feature bit. + */ +#define VIRTIO_NET_CTRL_VLAN 2 +#define VIRTIO_NET_CTRL_VLAN_ADD 0 +#define VIRTIO_NET_CTRL_VLAN_DEL 1 + +/* + * Control link announce acknowledgement + * + * The command VIRTIO_NET_CTRL_ANNOUNCE_ACK is used to indicate that + * driver has recevied the notification; device would clear the + * VIRTIO_NET_S_ANNOUNCE bit in the status field after it receives + * this command. + */ +#define VIRTIO_NET_CTRL_ANNOUNCE 3 +#define VIRTIO_NET_CTRL_ANNOUNCE_ACK 0 + +/* + * Control Receive Flow Steering + * + * The command VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET enables Receive Flow + * Steering, specifying the number of the transmit and receive queues + * that will be used. After the command is consumed and acked by the + * device, the device will not steer new packets on receive virtqueues + * other than specified nor read from transmit virtqueues other than + * specified. Accordingly, driver should not transmit new packets on + * virtqueues other than specified. + */ +struct virtio_net_ctrl_mq { + uint16_t virtqueue_pairs; +} _PACKED; + +#define VIRTIO_NET_CTRL_MQ 4 +#define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET 0 +#define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN 1 +#define VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX 0x8000 + +#endif /* _VIRTIO_NET_H */