dde_linux: USB client driver for NIC version 4.16

This commit is contained in:
Stefan Kalkowski 2018-08-22 13:52:41 +02:00 committed by Christian Helmuth
parent b32a3cd4d9
commit 2882bd48e6
19 changed files with 3370 additions and 39 deletions

View File

@ -0,0 +1,33 @@
USB_NET_CONTRIB_DIR := $(call select_from_ports,dde_linux)/src/drivers/usb_net
# architecture-dependent includes
ifeq ($(filter-out $(SPECS),x86),)
ARCH_SRC_INC_DIR += $(REP_DIR)/src/include/spec/x86
ifeq ($(filter-out $(SPECS),32bit),)
ARCH_SRC_INC_DIR += $(REP_DIR)/src/include/spec/x86_32
endif # 32bit
ifeq ($(filter-out $(SPECS),64bit),)
ARCH_SRC_INC_DIR += $(REP_DIR)/src/include/spec/x86_64
endif # 64bit
endif # x86
ifeq ($(filter-out $(SPECS),arm),)
ARCH_SRC_INC_DIR += $(REP_DIR)/src/include/spec/arm
ifeq ($(filter-out $(SPECS),arm_v6),)
ARCH_SRC_INC_DIR += $(REP_DIR)/src/include/spec/arm_v6
endif # arm_v6
ifeq ($(filter-out $(SPECS),arm_v7),)
ARCH_SRC_INC_DIR += $(REP_DIR)/src/include/spec/arm_v7
endif # arm_v7
endif # arm
#
# The order of include-search directories is important, we need to look into
# 'contrib' before falling back to our custom 'lx_emul.h' header.
#
INC_DIR += $(ARCH_SRC_INC_DIR)
INC_DIR += $(USB_NET_CONTRIB_DIR)/include
#INC_DIR += $(USB_NET_CONTRIB_DIR)/drivers/hid
#INC_DIR += $(USB_NET_CONTRIB_DIR)/drivers/input
INC_DIR += $(LIB_CACHE_DIR)/usb_net_include/include/include/include

View File

@ -0,0 +1,37 @@
ifeq ($(called_from_lib_mk),yes)
USB_NET_CONTRIB_DIR := $(call select_from_ports,dde_linux)/src/drivers/usb_net
LX_EMUL_H := $(REP_DIR)/src/drivers/usb_net/lx_emul.h
#
# Determine the header files included by the contrib code. For each
# of these header files we create a symlink to 'lx_emul.h'.
#
SCAN_DIRS := $(addprefix $(USB_NET_CONTRIB_DIR)/include/, asm-generic linux uapi net) \
$(addprefix $(USB_NET_CONTRIB_DIR)/, drivers net)
GEN_INCLUDES := $(shell grep -rIh "^\#include .*\/" $(SCAN_DIRS) |\
sed "s/^\#include [^<\"]*[<\"]\([^>\"]*\)[>\"].*/\1/" |\
sort | uniq)
#
# Filter out original Linux headers that exist in the contrib directory
#
NO_GEN_INCLUDES := $(shell cd $(USB_NET_CONTRIB_DIR)/; find include -name "*.h" |\
sed "s/.\///" | sed "s/.*include\///")
GEN_INCLUDES := $(filter-out $(NO_GEN_INCLUDES),$(GEN_INCLUDES))
#
# Put Linux headers in 'GEN_INC' dir, since some include use "../../" paths use
# three level include hierarchy
#
GEN_INC := $(shell pwd)/include/include/include
GEN_INCLUDES := $(addprefix $(GEN_INC)/,$(GEN_INCLUDES))
all: $(GEN_INCLUDES)
$(GEN_INCLUDES):
$(VERBOSE)mkdir -p $(dir $@)
$(VERBOSE)ln -s $(LX_EMUL_H) $@
endif
CC_CXX_WARN_STRICT =

View File

@ -0,0 +1,13 @@
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 9147f9f..c63ee5c 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -3281,7 +3281,7 @@ static inline void skb_remcsum_process(struct sk_buff *skb, void *ptr,
if (unlikely(skb->ip_summed != CHECKSUM_COMPLETE)) {
__skb_checksum_complete(skb);
- skb_postpull_rcsum(skb, skb->data, ptr - (void *)skb->data);
+ skb_postpull_rcsum(skb, skb->data, (unsigned char*)ptr - skb->data);
}
delta = remcsum_adjust(ptr, skb->csum, start, offset);

View File

@ -1 +1 @@
66e54dcbcd22c597db5794f080d92df114b88985
987b3081e335b0063655441c929a86a4627af72f

View File

@ -2,7 +2,8 @@ LICENSE := GPLv2
VERSION := 2
DOWNLOADS := dwc_otg.git usb.archive intel_fb.archive lxip.archive \
wifi.archive fec.archive libnl.archive wpa_supplicant.git \
fw.archive usb_host.archive dwc_otg_host.git usb_hid.archive
fw.archive usb_host.archive dwc_otg_host.git usb_hid.archive \
usb_net.archive
#
# Tools
@ -51,6 +52,14 @@ DIR(usb_hid) := $(SRC_DIR_USB_HID)
TAR_OPT(usb_hid) := --strip-components=1 --files-from - < <(sed 's/-x.x.x/-$(VERSION_USB_HID)/g' $(REP_DIR)/usb_hid.list)
HASH_INPUT += $(REP_DIR)/usb_hid.list
SRC_DIR_USB_NET := src/drivers/usb_net
VERSION_USB_NET := 4.16.3
URL(usb_net) := https://www.kernel.org/pub/linux/kernel/v4.x/linux-$(VERSION_USB_NET).tar.xz
SHA(usb_net) := 0d6971a81da97e38b974c5eba31a74803bfe41aabc46d406c3acda56306c81a3
DIR(usb_net) := $(SRC_DIR_USB_NET)
TAR_OPT(usb_net) := --strip-components=1 --files-from - < <(sed 's/-x.x.x/-$(VERSION_USB_NET)/g' $(REP_DIR)/usb_net.list)
HASH_INPUT += $(REP_DIR)/usb_net.list
#
# Raspberry Pi USB controller
#
@ -187,6 +196,10 @@ PATCH_OPT(patches/usb_hid_usbhid.patch) := $(USB_HID_OPT)
PATCH_OPT(patches/usb_hid_wacom_sys.patch) := $(USB_HID_OPT)
PATCH_OPT(patches/usb_hid_evdev.patch) := $(USB_HID_OPT)
# USB NET
USB_NET_OPT = -p1 -d$(SRC_DIR_USB_NET)
PATCH_OPT(patches/usb_net_skbuff_cast.patch) := $(USB_NET_OPT)
# INTEL FB
PATCH_OPT(patches/intel_fb_backlight.patch) := -p1 -d$(SRC_DIR_INTEL_FB)
PATCH_OPT(patches/intel_fb_drm.patch) := -p1 -d$(SRC_DIR_INTEL_FB)

View File

@ -127,7 +127,7 @@ append config {
<start name="usb_drv" caps="120"> }
append config "<binary name=\"[usb_host_drv_binary]\"/>"
append config {
<resource name="RAM" quantum="10M"/>
<resource name="RAM" quantum="11M"/>
<provides> <service name="Usb"/> </provides>
<config bios_handoff="no">
<report devices="yes"/>
@ -140,7 +140,7 @@ append config {
</start>
<start name="usb_hid_drv" caps="120">
<resource name="RAM" quantum="10M"/>
<resource name="RAM" quantum="11M"/>
<provides><service name="Input"/></provides>
<config use_report="yes" capslock_led="rom" numlock_led="rom" scrlock_led="rom"/>
<route>
@ -207,7 +207,6 @@ append_platform_drv_boot_modules
build_boot_image $boot_modules
append qemu_args " -nographic"
append qemu_args " -usb -usbdevice mouse -usbdevice keyboard"
append qemu_args " -device usb-ehci,id=ehci"
append xen_args { usbdevice=\["mouse","keyboard"\] }

View File

@ -13,29 +13,32 @@
set build_components {
core init
drivers/timer drivers/usb
drivers/timer
drivers/usb_host
drivers/usb_net
test/lwip/http_srv
lib/vfs/lwip
}
proc gpio_drv { } { if {[have_spec rpi] && [have_spec hw]} { return hw_gpio_drv }
if {[have_spec rpi] && [have_spec foc]} { return foc_gpio_drv }
return gpio_drv }
lappend_if [have_spec gpio] build_components drivers/gpio
source ${genode_dir}/repos/base/run/platform_drv.inc
append_platform_drv_build_components
lappend_if [have_spec gpio] build_components drivers/gpio
build $build_components
proc gpio_drv { } { if {[have_spec rpi] && [have_spec hw]} { return hw_gpio_drv }
if {[have_spec rpi] && [have_spec foc]} { return foc_gpio_drv }
return gpio_drv }
create_boot_directory
#
# Generate config
#
set config {
<config verbose="yes">
append config {
<config>
<parent-provides>
<service name="ROM"/>
<service name="IRQ"/>
@ -49,29 +52,7 @@ set config {
<default-route>
<any-service> <parent/> <any-child/> </any-service>
</default-route>
<default caps="100"/>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides> <service name="Timer"/> </provides>
</start>
<start name="usb_drv">
<resource name="RAM" quantum="24M"/>
<provides>
<service name="Nic"/>
</provides>
<config uhci="no" ohci="no" ehci="yes" xhci="yes">
<nic mac="02:00:00:00:01:01" />
</config>
</start>
<start name="test-lwip_httpsrv">
<resource name="RAM" quantum="4M"/>
<config>
<vfs> <dir name="dev"> <log/> </dir> </vfs>
<libc stdout="/dev/log" stderr="/dev/log"/>
</config>
</start>}
append_platform_drv_config
<default caps="200"/>}
append_if [have_spec gpio] config "
<start name=\"[gpio_drv]\">
@ -80,7 +61,50 @@ append_if [have_spec gpio] config "
<config/>
</start>"
append_platform_drv_config
append config {
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides>
</start>
<start name="usb_drv" caps="120"> }
append config "<binary name=\"[usb_host_drv_binary]\"/>"
append config {
<resource name="RAM" quantum="10M"/>
<provides> <service name="Usb"/> </provides>
<config bios_handoff="no">}
append_if [have_spec arndale] config {
<policy label_prefix="usb_net_drv" vendor_id="0x0b95" product_id="0x772a"/> }
append_if [expr [have_spec panda] || [have_spec rpi] ] config {
<policy label_prefix="usb_net_drv" vendor_id="0x0424" product_id="0xec00"/> }
append_if [have_spec x86] config {
<policy label_prefix="usb_net_drv" vendor_id="0x0b95" product_id="0x1790"/> }
append config {
</config>
<route>
<service name="Report"> <child name="report_rom"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>
<start name="usb_net_drv">
<resource name="RAM" quantum="10M"/>
<provides> <service name="Nic"/> </provides>
<config mac="02:00:00:00:01:01" />
</start>
<start name="test-lwip_httpsrv" caps="120">
<resource name="RAM" quantum="4M"/>
<config>
<vfs>
<dir name="dev"> <log/> </dir>
<dir name="socket"> <lwip dhcp="yes"/> </dir>
</vfs>
<libc stdout="/dev/log" stderr="/dev/log" socket="/socket"/>
</config>
</start>
</config>
}
@ -92,13 +116,15 @@ install_config $config
# generic modules
set boot_modules {
core ld.lib.so init timer usb_drv
libc.lib.so vfs.lib.so libm.lib.so lwip_legacy.lib.so posix.lib.so test-lwip_httpsrv
core init timer usb_net_drv
ld.lib.so libc.lib.so vfs.lib.so vfs_lwip.lib.so test-lwip_httpsrv
}
append_platform_drv_boot_modules
append boot_modules [usb_host_drv_binary]
lappend_if [have_spec gpio] boot_modules [gpio_drv]
append_platform_drv_boot_modules
build_boot_image $boot_modules
append qemu_args " -nographic"

View File

@ -0,0 +1,20 @@
USB NIC driver
##############
Driver for network interface cards connected via USB.
Configuration snippet:
!<start name="usb_net_drv">
! <resource name="RAM" quantum="10M"/>
! <provides> <service name="Nic"/> </provides>
! <config mac="2e:60:90:0c:4e:01" />
!</start>
There is the 'mac' attribute where one can specify the hardware address of
the network interface. This is necessary in case the EEPROM of the network card
cannot be accessed via the host controller making it impossible to retrieve the
devices hardware address. If this is the case and no 'mac' attribute is given a
fallback address will be assigned to the network device. Note that the fallback
address will always be the same.

View File

@ -0,0 +1,182 @@
/*
* \brief Freescale ethernet driver component
* \author Stefan Kalkowski
* \date 2017-11-01
*/
/*
* Copyright (C) 2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <component.h>
#include <lx_emul.h>
extern "C" {
#include <lxc.h>
};
void Session_component::_run_rx_task(void * args)
{
Rx_data *data = static_cast<Rx_data*>(args);
while (1) {
Lx::scheduler().current()->block_and_schedule();
int ret = 0;
struct napi_struct * n = data->napi;
for (;;) {
/* This NAPI_STATE_SCHED test is for avoiding a race
* with netpoll's poll_napi(). Only the entity which
* obtains the lock and sees NAPI_STATE_SCHED set will
* actually make the ->poll() call. Therefore we avoid
* accidentally calling ->poll() when NAPI is not scheduled.
*/
if (!test_bit(NAPI_STATE_SCHED, &n->state)) break;
int weight = n->weight;
int work = n->poll(n, weight);
ret += work;
if (work < weight) break;
Genode::warning("Too much incoming traffic, we should schedule RX more intelligent");
}
}
}
void Session_component::_run_tx_task(void * args)
{
Tx_data *data = static_cast<Tx_data*>(args);
while (1) {
Lx::scheduler().current()->block_and_schedule();
net_device * ndev = data->ndev;
struct sk_buff * skb = data->skb;
ndev->netdev_ops->ndo_start_xmit(skb, ndev);
}
}
bool Session_component::_send()
{
using namespace Genode;
/*
* We must not be called from another task, just from the
* packet stream dispatcher.
*/
if (Lx::scheduler().active()) {
warning("scheduler active");
return false;
}
if (!_tx.sink()->ready_to_ack()) { return false; }
if (!_tx.sink()->packet_avail()) { return false; }
Packet_descriptor packet = _tx.sink()->get_packet();
if (!packet.size()) {
warning("invalid tx packet");
return true;
}
enum { HEAD_ROOM = 8 };
struct sk_buff *skb = lxc_alloc_skb(packet.size() + HEAD_ROOM, HEAD_ROOM);
unsigned char *data = lxc_skb_put(skb, packet.size());
Genode::memcpy(data, _tx.sink()->packet_content(packet), packet.size());
_tx_data.ndev = _ndev;
_tx_data.skb = skb;
_tx_task.unblock();
Lx::scheduler().schedule();
_tx.sink()->acknowledge_packet(packet);
return true;
}
void Session_component::_handle_rx()
{
while (_rx.source()->ack_avail())
_rx.source()->release_packet(_rx.source()->get_acked_packet());
}
void Session_component::_handle_packet_stream()
{
_handle_rx();
while (_send()) continue;
}
void Session_component::unblock_rx_task(napi_struct * n)
{
_rx_data.napi = n;
_rx_task.unblock();
}
Nic::Mac_address Session_component::mac_address()
{
return _ndev ? Nic::Mac_address(_ndev->dev_addr) : Nic::Mac_address();
}
void Session_component::receive(struct sk_buff *skb)
{
_handle_rx();
if (!_rx.source()->ready_to_submit()) {
Genode::warning("not ready to receive packet");
return;
}
Skb s = skb_helper(skb);
try {
Nic::Packet_descriptor p = _rx.source()->alloc_packet(s.packet_size + s.frag_size);
void *buffer = _rx.source()->packet_content(p);
memcpy(buffer, s.packet, s.packet_size);
if (s.frag_size)
memcpy((char *)buffer + s.packet_size, s.frag, s.frag_size);
_rx.source()->submit_packet(p);
} catch (...) {
Genode::warning("failed to process received packet");
}
}
void Session_component::link_state(bool link)
{
if (link == _has_link) return;
_has_link = link;
_link_state_changed();
}
Session_component::Session_component(Genode::size_t const tx_buf_size,
Genode::size_t const rx_buf_size,
Genode::Allocator & rx_block_md_alloc,
Genode::Env & env,
Genode::Session_label label)
: Nic::Session_component(tx_buf_size, rx_buf_size, rx_block_md_alloc, env),
_ndev(_register_session_component(*this, label)),
_has_link(_ndev ? !(_ndev->state & (1UL << __LINK_STATE_NOCARRIER)) : false)
{
if (!_ndev) throw Genode::Service_denied();
}

View File

@ -0,0 +1,126 @@
/*
* \brief Freescale ethernet driver component
* \author Stefan Kalkowski
* \date 2017-11-01
*/
/*
* Copyright (C) 2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _SRC__DRIVERS__NIC__FEC__COMPONENT_H_
#define _SRC__DRIVERS__NIC__FEC__COMPONENT_H_
/* Genode includes */
#include <nic/component.h>
#include <root/component.h>
#include <lx_kit/scheduler.h>
extern "C" {
struct net_device;
struct napi_struct;
struct sk_buff;
}
class Session_component : public Nic::Session_component
{
private:
struct Tx_data
{
net_device * ndev;
sk_buff * skb;
};
struct Rx_data
{
struct napi_struct * napi;
};
net_device * _ndev = nullptr;
bool _has_link = false;
Tx_data _tx_data;
Rx_data _rx_data;
static void _run_tx_task(void * args);
static void _run_rx_task(void * args);
static net_device * _register_session_component(Session_component &,
Genode::Session_label);
Lx::Task _tx_task { _run_tx_task, &_tx_data, "tx_task",
Lx::Task::PRIORITY_1, Lx::scheduler() };
Lx::Task _rx_task { _run_rx_task, &_rx_data, "rx_task",
Lx::Task::PRIORITY_1, Lx::scheduler() };
bool _send();
void _handle_rx();
void _handle_packet_stream() override;
public:
Session_component(Genode::size_t const tx_buf_size,
Genode::size_t const rx_buf_size,
Genode::Allocator & rx_block_md_alloc,
Genode::Env & env,
Genode::Session_label label);
Nic::Mac_address mac_address() override;
bool link_state() override { return _has_link; }
void link_state(bool link);
void receive(struct sk_buff *skb);
void unblock_rx_task(napi_struct * n);
};
class Root : public Genode::Root_component<Session_component>
{
private:
Genode::Env &_env;
Genode::Allocator &_md_alloc;
protected:
Session_component *_create_session(const char *args)
{
using namespace Genode;
Session_label const label = label_from_args(args);
size_t ram_quota = Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
size_t tx_buf_size = Arg_string::find_arg(args, "tx_buf_size").ulong_value(0);
size_t rx_buf_size = Arg_string::find_arg(args, "rx_buf_size").ulong_value(0);
/* deplete ram quota by the memory needed for the session structure */
size_t session_size = max(4096UL, (unsigned long)sizeof(Session_component));
/*
* Check if donated ram quota suffices for both communication
* buffers and check for overflow
*/
if ((ram_quota < session_size) ||
(tx_buf_size + rx_buf_size < tx_buf_size ||
tx_buf_size + rx_buf_size > ram_quota - session_size)) {
Genode::error("insufficient 'ram_quota', got ", ram_quota, ", "
"need ", tx_buf_size + rx_buf_size + session_size);
throw Genode::Insufficient_ram_quota();
}
return new (Root::md_alloc())
Session_component(tx_buf_size, rx_buf_size,
_md_alloc, _env, label);
}
public:
Root(Genode::Env &env, Genode::Allocator &md_alloc)
: Genode::Root_component<Session_component>(&env.ep().rpc_ep(), &md_alloc),
_env(env), _md_alloc(md_alloc)
{ }
};
#endif /* _SRC__DRIVERS__NIC__FEC__COMPONENT_H_ */

View File

@ -0,0 +1,105 @@
/*
* \brief USB net driver
* \author Stefan Kalkowski
* \date 2018-06-27
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _SRC__DRIVERS__USB_NET__DRIVER_H_
#define _SRC__DRIVERS__USB_NET__DRIVER_H_
#include <base/allocator_avl.h>
#include <base/attached_rom_dataspace.h>
#include <base/heap.h>
#include <usb_session/connection.h>
#include <lx_kit/scheduler.h>
#include <component.h>
struct usb_device_id;
struct usb_interface;
struct usb_device;
struct Driver
{
using Label = Genode::String<64>;
struct Task
{
Lx::Task task;
Genode::Signal_handler<Task> handler;
void handle_signal()
{
task.unblock();
Lx::scheduler().schedule();
}
template <typename... ARGS>
Task(Genode::Entrypoint & ep, ARGS &&... args)
: task(args...), handler(ep, *this, &Task::handle_signal) {}
};
struct Device
{
using Le = Genode::List_element<Device>;
Le le { this };
Label label;
Driver &driver;
Genode::Env &env;
Genode::Allocator_avl &alloc;
Task state_task;
Task urb_task;
Usb::Connection usb { env, &alloc, label.string(),
512 * 1024, state_task.handler };
usb_device * udev = nullptr;
bool updated = true;
Device(Driver & drv, Label label);
~Device();
static void state_task_entry(void *);
static void urb_task_entry(void *);
void register_device();
void unregister_device();
void scan_interfaces(unsigned iface_idx);
void scan_altsettings(usb_interface * iface,
unsigned iface_idx, unsigned alt_idx);
void probe_interface(usb_interface *, usb_device_id *);
void remove_interface(usb_interface *);
};
struct Devices : Genode::List<Device::Le>
{
template <typename FN>
void for_each(FN const & fn)
{
Device::Le * cur = first();
for (Device::Le * next = cur ? cur->next() : nullptr; cur;
cur = next, next = cur ? cur->next() : nullptr)
fn(*cur->object());
}
};
Devices devices;
Genode::Env &env;
Genode::Entrypoint &ep { env.ep() };
Genode::Heap heap { env.ram(), env.rm() };
Genode::Allocator_avl alloc { &heap };
Root root { env, heap };
Genode::Constructible<Task> main_task;
Genode::Constructible<Genode::Attached_rom_dataspace> report_rom;
Driver(Genode::Env &env);
static void main_task_entry(void *);
};
#endif /* _SRC__DRIVERS__USB_HID__DRIVER_H_ */

View File

@ -0,0 +1,518 @@
#include <lx_emul.h>
#if 0
#define TRACE \
do { \
lx_printf("%s not implemented\n", __func__); \
} while (0)
#else
#define TRACE do { ; } while (0)
#endif
#define TRACE_AND_STOP \
do { \
lx_printf("%s not implemented\n", __func__); \
BUG(); \
} while (0)
struct page *alloc_pages(gfp_t gfp_mask, unsigned int order)
{
TRACE_AND_STOP;
return NULL;
}
u16 bitrev16(u16 in)
{
TRACE_AND_STOP;
return -1;
}
struct usb_cdc_parsed_header;
struct usb_interface;
int cdc_parse_cdc_header(struct usb_cdc_parsed_header *hdr, struct usb_interface *intf, u8 *buffer, int buflen)
{
TRACE_AND_STOP;
return -1;
}
u16 crc16(u16 crc, const u8 *buffer, size_t len)
{
TRACE_AND_STOP;
return -1;
}
__sum16 csum_fold(__wsum csum)
{
TRACE_AND_STOP;
return -1;
}
__wsum csum_partial(const void *buff, int len, __wsum sum)
{
TRACE_AND_STOP;
return -1;
}
void * dev_get_drvdata(const struct device *dev)
{
TRACE_AND_STOP;
return NULL;
}
int device_set_wakeup_enable(struct device *dev, bool enable)
{
TRACE_AND_STOP;
return -1;
}
struct sk_buff;
void dev_kfree_skb_any(struct sk_buff *skb)
{
TRACE_AND_STOP;
}
void dst_release(struct dst_entry *dst)
{
TRACE_AND_STOP;
}
struct net_device;
u32 ethtool_op_get_link(struct net_device *dev)
{
TRACE_AND_STOP;
return -1;
}
int ethtool_op_get_ts_info(struct net_device *dev, struct ethtool_ts_info *eti)
{
TRACE_AND_STOP;
return -1;
}
bool file_ns_capable(const struct file *file, struct user_namespace *ns, int cap)
{
TRACE_AND_STOP;
return -1;
}
void free_netdev(struct net_device * ndev)
{
TRACE_AND_STOP;
}
void free_uid(struct user_struct * user)
{
TRACE_AND_STOP;
}
struct mii_if_info;
int generic_mii_ioctl(struct mii_if_info *mii_if, struct mii_ioctl_data *mii_data, int cmd, unsigned int *duplex_changed)
{
TRACE_AND_STOP;
return -1;
}
void get_page(struct page *page)
{
TRACE_AND_STOP;
}
bool gfpflags_allow_blocking(const gfp_t gfp_flags)
{
TRACE_AND_STOP;
return -1;
}
bool gfp_pfmemalloc_allowed(gfp_t gfp_flags)
{
TRACE_AND_STOP;
return -1;
}
int hex2bin(u8 *dst, const char *src, size_t count)
{
TRACE_AND_STOP;
return -1;
}
int in_irq()
{
TRACE_AND_STOP;
return -1;
}
void *kmap_atomic(struct page *page)
{
TRACE_AND_STOP;
return NULL;
}
int memcmp(const void *s1, const void *s2, size_t size)
{
TRACE_AND_STOP;
return -1;
}
void mii_ethtool_get_link_ksettings( struct mii_if_info *mii, struct ethtool_link_ksettings *cmd)
{
TRACE_AND_STOP;
}
int mii_ethtool_set_link_ksettings( struct mii_if_info *mii, const struct ethtool_link_ksettings *cmd)
{
TRACE_AND_STOP;
return -1;
}
unsigned netdev_mc_count(struct net_device * dev)
{
TRACE;
return 1;
}
int netdev_mc_empty(struct net_device * ndev)
{
TRACE;
return 1;
}
void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64, const struct net_device_stats *netdev_stats)
{
TRACE_AND_STOP;
}
bool netdev_uses_dsa(struct net_device *dev)
{
TRACE;
return false;
}
void netif_device_attach(struct net_device *dev)
{
TRACE;
}
void netif_device_detach(struct net_device *dev)
{
TRACE_AND_STOP;
}
int netif_device_present(struct net_device * d)
{
TRACE;
return 1;
}
u32 netif_msg_init(int arg0, int arg1)
{
TRACE;
return 0;
}
void netif_start_queue(struct net_device *dev)
{
TRACE;
}
void netif_stop_queue(struct net_device *dev)
{
TRACE_AND_STOP;
}
void netif_trans_update(struct net_device *dev)
{
TRACE;
}
void netif_tx_wake_all_queues(struct net_device *dev)
{
TRACE_AND_STOP;
}
void netif_wake_queue(struct net_device * d)
{
TRACE;
}
const void *of_get_mac_address(struct device_node *np)
{
TRACE;
return NULL;
}
void pm_runtime_enable(struct device *dev)
{
TRACE;
}
void read_lock_bh(rwlock_t * l)
{
TRACE_AND_STOP;
}
void read_unlock_bh(rwlock_t * l)
{
TRACE_AND_STOP;
}
void unregister_netdev(struct net_device * dev)
{
TRACE_AND_STOP;
}
void secpath_reset(struct sk_buff * skb)
{
TRACE;
}
void __set_current_state(int state)
{
TRACE_AND_STOP;
}
void sg_init_table(struct scatterlist *sg, unsigned int arg)
{
TRACE_AND_STOP;
}
void sg_set_buf(struct scatterlist *sg, const void *buf, unsigned int buflen)
{
TRACE_AND_STOP;
}
void sg_set_page(struct scatterlist *sg, struct page *page, unsigned int len, unsigned int offset)
{
TRACE_AND_STOP;
}
void sk_free(struct sock *sk)
{
TRACE_AND_STOP;
}
void sock_efree(struct sk_buff *skb)
{
TRACE_AND_STOP;
}
void spin_lock_irq(spinlock_t *lock)
{
TRACE_AND_STOP;
}
void spin_lock_nested(spinlock_t *lock, int subclass)
{
TRACE;
}
void spin_unlock_irq(spinlock_t *lock)
{
TRACE_AND_STOP;
}
size_t strlcpy(char *dest, const char *src, size_t size)
{
TRACE_AND_STOP;
return -1;
}
void tasklet_kill(struct tasklet_struct *t)
{
TRACE_AND_STOP;
}
void trace_consume_skb(struct sk_buff *skb)
{
TRACE;
}
void trace_kfree_skb(struct sk_buff *skb, void *arg)
{
TRACE;
}
unsigned int u64_stats_fetch_begin_irq(const struct u64_stats_sync *p)
{
TRACE_AND_STOP;
return -1;
}
bool u64_stats_fetch_retry_irq(const struct u64_stats_sync *p, unsigned int s)
{
TRACE_AND_STOP;
return -1;
}
struct usb_device;
int usb_clear_halt(struct usb_device *dev, int pipe)
{
TRACE_AND_STOP;
return -1;
}
struct usb_driver;
int usb_driver_claim_interface(struct usb_driver *driver, struct usb_interface *iface, void *priv)
{
TRACE_AND_STOP;
return -1;
}
void usb_driver_release_interface(struct usb_driver *driver, struct usb_interface *iface)
{
TRACE_AND_STOP;
}
struct usb_anchor;
struct urb *usb_get_from_anchor(struct usb_anchor *anchor)
{
TRACE_AND_STOP;
return NULL;
}
struct urb *usb_get_urb(struct urb *urb)
{
TRACE_AND_STOP;
return NULL;
}
int usb_interrupt_msg(struct usb_device *usb_dev, unsigned int pipe, void *data, int len, int *actual_length, int timeout)
{
TRACE_AND_STOP;
return -1;
}
void usb_scuttle_anchored_urbs(struct usb_anchor *anchor)
{
TRACE_AND_STOP;
}
int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
{
TRACE_AND_STOP;
return -1;
}
ktime_t ktime_get_real(void)
{
TRACE_AND_STOP;
return -1;
}
void kunmap_atomic(void *addr)
{
TRACE_AND_STOP;
}
void might_sleep()
{
TRACE_AND_STOP;
}
bool page_is_pfmemalloc(struct page *page)
{
TRACE_AND_STOP;
return -1;
}
void put_page(struct page *page)
{
TRACE_AND_STOP;
}
struct usb_interface *usb_ifnum_to_if(const struct usb_device *dev, unsigned ifnum)
{
TRACE_AND_STOP;
return NULL;
}
void usb_kill_urb(struct urb *urb)
{
TRACE_AND_STOP;
}
int usb_set_interface(struct usb_device *dev, int ifnum, int alternate)
{
TRACE;
return 0;
}
int usb_unlink_urb(struct urb *urb)
{
TRACE_AND_STOP;
return -1;
}
void usleep_range(unsigned long min, unsigned long max)
{
TRACE;
}
void phy_stop(struct phy_device *phydev)
{
TRACE;
}
void phy_disconnect(struct phy_device *phydev)
{
TRACE;
}
void phy_print_status(struct phy_device *phydev)
{
TRACE;
}
int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd)
{
TRACE;
return 0;
}
typedef int phy_interface_t;
struct phy_device * phy_connect(struct net_device *dev, const char *bus_id, void (*handler)(struct net_device *), phy_interface_t interface)
{
TRACE;
return 0;
}
int genphy_resume(struct phy_device *phydev) { TRACE; return 0; }
void phy_start(struct phy_device *phydev) { TRACE; }
struct mii_bus;
void mdiobus_free(struct mii_bus *bus) { TRACE; }
void mdiobus_unregister(struct mii_bus *bus) { TRACE; }
struct mii_bus *mdiobus_alloc_size(size_t size)
{
TRACE_AND_STOP;
return NULL;
}
int __mdiobus_register(struct mii_bus *bus, struct module *owner)
{
TRACE_AND_STOP;
return -1;
}
int phy_ethtool_get_link_ksettings(struct net_device *ndev, struct ethtool_link_ksettings *cmd)
{
TRACE_AND_STOP;
return -1;
}
int phy_ethtool_set_link_ksettings(struct net_device *ndev, const struct ethtool_link_ksettings *cmd)
{
TRACE_AND_STOP;
return -1;
}
int phy_ethtool_nway_reset(struct net_device *ndev)
{
TRACE_AND_STOP;
return -1;
}
int sysctl_tstamp_allow_data;
struct user_namespace init_user_ns;

View File

@ -0,0 +1,539 @@
#include <base/env.h>
#include <usb_session/client.h>
#include <base/snprintf.h>
#include <nic_session/nic_session.h>
#include <util/xml_node.h>
#include <driver.h>
#include <lx_emul.h>
#include <lx_emul/extern_c_begin.h>
#include <linux/usb.h>
#include <lx_emul/extern_c_end.h>
#define TRACE do { ; } while (0)
#include <lx_emul/impl/kernel.h>
#include <lx_emul/impl/delay.h>
#include <lx_emul/impl/slab.h>
#include <lx_emul/impl/work.h>
#include <lx_emul/impl/spinlock.h>
#include <lx_emul/impl/mutex.h>
#include <lx_emul/impl/sched.h>
#include <lx_emul/impl/timer.h>
#include <lx_emul/impl/completion.h>
#include <lx_emul/impl/wait.h>
#include <lx_emul/impl/usb.h>
#include <lx_kit/backend_alloc.h>
#include <lx_emul/extern_c_begin.h>
#include <linux/mii.h>
static int usb_match_device(struct usb_device *dev,
const struct usb_device_id *id)
{
if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
id->idVendor != le16_to_cpu(dev->descriptor.idVendor))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) &&
id->idProduct != le16_to_cpu(dev->descriptor.idProduct))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) &&
(id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice)))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) &&
(id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice)))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) &&
(id->bDeviceClass != dev->descriptor.bDeviceClass))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) &&
(id->bDeviceSubClass != dev->descriptor.bDeviceSubClass))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) &&
(id->bDeviceProtocol != dev->descriptor.bDeviceProtocol))
return 0;
return 1;
}
static int usb_match_one_id_intf(struct usb_device *dev,
struct usb_host_interface *intf,
const struct usb_device_id *id)
{
if (dev->descriptor.bDeviceClass == USB_CLASS_VENDOR_SPEC &&
!(id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) &&
(id->match_flags & (USB_DEVICE_ID_MATCH_INT_CLASS |
USB_DEVICE_ID_MATCH_INT_SUBCLASS |
USB_DEVICE_ID_MATCH_INT_PROTOCOL |
USB_DEVICE_ID_MATCH_INT_NUMBER)))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS) &&
(id->bInterfaceClass != intf->desc.bInterfaceClass))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS) &&
(id->bInterfaceSubClass != intf->desc.bInterfaceSubClass))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL) &&
(id->bInterfaceProtocol != intf->desc.bInterfaceProtocol))
return 0;
if ((id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER) &&
(id->bInterfaceNumber != intf->desc.bInterfaceNumber))
return 0;
return 1;
}
int usb_match_one_id(struct usb_interface *interface,
const struct usb_device_id *id)
{
struct usb_host_interface *intf;
struct usb_device *dev;
if (id == NULL)
return 0;
intf = interface->cur_altsetting;
dev = interface_to_usbdev(interface);
if (!usb_match_device(dev, id))
return 0;
return usb_match_one_id_intf(dev, intf, id);
}
#include <lx_emul/extern_c_end.h>
class Addr_to_page_mapping : public Genode::List<Addr_to_page_mapping>::Element
{
private:
struct page *_page { nullptr };
static Genode::List<Addr_to_page_mapping> & _list()
{
static Genode::List<Addr_to_page_mapping> _l;
return _l;
}
public:
Addr_to_page_mapping(struct page *page)
: _page(page) { }
static void insert(struct page * page)
{
Addr_to_page_mapping *m = (Addr_to_page_mapping*)
Lx::Malloc::mem().alloc(sizeof (Addr_to_page_mapping));
m->_page = page;
_list().insert(m);
}
static struct page * remove(unsigned long addr)
{
for (Addr_to_page_mapping *m = _list().first(); m; m = m->next())
if ((unsigned long)m->_page->addr == addr) {
struct page * ret = m->_page;
_list().remove(m);
Lx::Malloc::mem().free(m);
return ret;
}
return nullptr;
}
};
struct Lx_driver
{
using Element = Genode::List_element<Lx_driver>;
using List = Genode::List<Element>;
usb_driver & drv;
Element le { this };
Lx_driver(usb_driver & drv) : drv(drv) { list().insert(&le); }
usb_device_id * match(usb_interface * iface)
{
struct usb_device_id * id = const_cast<usb_device_id*>(drv.id_table);
for (; id->idVendor || id->idProduct || id->bDeviceClass ||
id->bInterfaceClass || id->driver_info; id++)
if (usb_match_one_id(iface, id)) return id;
return nullptr;
}
int probe(usb_interface * iface, usb_device_id * id)
{
iface->dev.driver = &drv.drvwrap.driver;
if (drv.probe) return drv.probe(iface, id);
return 0;
}
static List & list()
{
static List _list;
return _list;
}
};
struct task_struct *current;
struct workqueue_struct *system_wq;
unsigned long jiffies;
Genode::Ram_dataspace_capability Lx::backend_alloc(Genode::addr_t size, Genode::Cache_attribute cached) {
return Lx_kit::env().env().ram().alloc(size, cached); }
int usb_register_driver(struct usb_driver * driver, struct module *, const char *)
{
INIT_LIST_HEAD(&driver->dynids.list);
if (driver) new (Lx::Malloc::mem()) Lx_driver(*driver);
return 0;
}
void Driver::Device::probe_interface(usb_interface * iface, usb_device_id * id)
{
using Le = Genode::List_element<Lx_driver>;
for (Le *le = Lx_driver::list().first(); le; le = le->next()) {
usb_device_id * id = le->object()->match(iface);
if (id && le->object()->probe(iface, id)) return;
}
}
void Driver::Device::remove_interface(usb_interface * iface)
{
to_usb_driver(iface->dev.driver)->disconnect(iface);
for (unsigned i = 0; i < iface->num_altsetting; i++) {
if (iface->altsetting[i].extra)
kfree(iface->altsetting[i].extra);
kfree(iface->altsetting[i].endpoint);
kfree(iface->altsetting);
}
kfree(iface);
}
long __wait_completion(struct completion *work, unsigned long timeout)
{
Lx::timer_update_jiffies();
struct process_timer timer { *Lx::scheduler().current() };
unsigned long expire = timeout + jiffies;
if (timeout) {
timer_setup(&timer.timer, process_timeout, 0);
mod_timer(&timer.timer, expire);
}
while (!work->done) {
if (timeout && expire <= jiffies) return 0;
Lx::Task * task = Lx::scheduler().current();
work->task = (void *)task;
task->block_and_schedule();
}
if (timeout) del_timer(&timer.timer);
work->done = 0;
return (expire > jiffies) ? (expire - jiffies) : 1;
}
u16 get_unaligned_le16(const void *p)
{
const struct __una_u16 *ptr = (const struct __una_u16 *)p;
return ptr->x;
}
u32 get_unaligned_le32(const void *p)
{
const struct __una_u32 *ptr = (const struct __una_u32 *)p;
return ptr->x;
}
enum { MAC_LEN = 17 };
static void snprint_mac(u8 *buf, u8 *mac)
{
for (int i = 0; i < ETH_ALEN; i++) {
Genode::snprintf((char *)&buf[i * 3], 3, "%02x", mac[i]);
if ((i * 3) < MAC_LEN)
buf[(i * 3) + 2] = ':';
}
buf[MAC_LEN] = 0;
}
static void random_ether_addr(u8 *addr)
{
using namespace Genode;
u8 str[MAC_LEN + 1];
u8 fallback[] = { 0x2e, 0x60, 0x90, 0x0c, 0x4e, 0x01 };
Nic::Mac_address mac;
Xml_node config_node = Lx_kit::env().config_rom().xml();
/* try using configured mac */
try {
Xml_node::Attribute mac_node = config_node.attribute("mac");
mac_node.value(&mac);
} catch (...) {
/* use fallback mac */
snprint_mac(str, fallback);
Genode::warning("No mac address or wrong format attribute in <nic> - using fallback (", str, ")");
Genode::memcpy(addr, fallback, ETH_ALEN);
return;
}
/* use configured mac*/
Genode::memcpy(addr, mac.addr, ETH_ALEN);
snprint_mac(str, (u8 *)mac.addr);
Genode::log("Using configured mac: ", str);
}
void eth_hw_addr_random(struct net_device *dev)
{
random_ether_addr(dev->dev_addr);
}
void eth_random_addr(u8 *addr)
{
random_ether_addr(addr);
}
struct net_device *alloc_etherdev(int sizeof_priv)
{
net_device *dev = (net_device*) kzalloc(sizeof(net_device), 0);
dev->mtu = 1500;
dev->hard_header_len = 0;
dev->priv = kzalloc(sizeof_priv, 0);
dev->dev_addr = (unsigned char*) kzalloc(ETH_ALEN, 0);
//memset(dev->_dev_addr, 0, sizeof(dev->_dev_addr));
return dev;
}
void *__alloc_percpu(size_t size, size_t align)
{
return kmalloc(size, 0);
}
int mii_nway_restart(struct mii_if_info *mii)
{
/* if autoneg is off, it's an error */
int bmcr = mii->mdio_read(mii->dev, mii->phy_id, MII_BMCR);
if (bmcr & BMCR_ANENABLE) {
printk("Reenable\n");
bmcr |= BMCR_ANRESTART;
mii->mdio_write(mii->dev, mii->phy_id, MII_BMCR, bmcr);
return 0;
}
return -EINVAL;
}
static net_device * single_net_device = nullptr;
int register_netdev(struct net_device *dev)
{
dev->state |= 1 << __LINK_STATE_START;
int err = dev->netdev_ops->ndo_open(dev);
if (err) return err;
if (dev->netdev_ops->ndo_set_rx_mode)
dev->netdev_ops->ndo_set_rx_mode(dev);
single_net_device = dev;
return 0;
};
net_device * Session_component::_register_session_component(Session_component & s,
Genode::Session_label policy)
{
if (single_net_device) single_net_device->session_component = (void*) &s;
return single_net_device;
}
void tasklet_schedule(struct tasklet_struct *t)
{
Lx::Work *lx_work = (Lx::Work *)tasklet_wq->task;
lx_work->schedule_tasklet(t);
lx_work->unblock();
}
struct workqueue_struct *create_singlethread_workqueue(char const *name)
{
workqueue_struct *wq = (workqueue_struct *)kzalloc(sizeof(workqueue_struct), 0);
Lx::Work *work = Lx::Work::alloc_work_queue(&Lx::Malloc::mem(), name);
wq->task = (void *)work;
return wq;
}
struct workqueue_struct *alloc_workqueue(const char *fmt, unsigned int flags,
int max_active, ...)
{
return create_singlethread_workqueue(fmt);
}
int dev_set_drvdata(struct device *dev, void *data)
{
dev->driver_data = data;
return 0;
}
int netif_running(const struct net_device *dev)
{
return dev->state & (1 << __LINK_STATE_START);
}
void netif_carrier_off(struct net_device *dev)
{
dev->state |= 1 << __LINK_STATE_NOCARRIER;
if (dev->session_component)
reinterpret_cast<Session_component*>(dev->session_component)->link_state(false);
}
int netif_carrier_ok(const struct net_device *dev)
{
return !(dev->state & (1 << __LINK_STATE_NOCARRIER));
}
void *kmem_cache_alloc_node(struct kmem_cache *cache, gfp_t gfp_flags, int arg)
{
return (void*)cache->alloc();
}
int mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
{
ecmd->duplex = DUPLEX_FULL;
return 0;
}
void netif_carrier_on(struct net_device *dev)
{
dev->state &= ~(1 << __LINK_STATE_NOCARRIER);
if (dev->session_component)
reinterpret_cast<Session_component*>(dev->session_component)->link_state(true);
}
int netif_rx(struct sk_buff * skb)
{
if (skb->dev->session_component)
reinterpret_cast<Session_component*>(skb->dev->session_component)->receive(skb);
dev_kfree_skb(skb);
return NET_RX_SUCCESS;
}
int is_valid_ether_addr(const u8 * a)
{
for (unsigned i = 0; i < ETH_ALEN; i++)
if (a[i] != 0 && a[i] != 255) return 1;
return 0;
}
unsigned int mii_check_media (struct mii_if_info *mii, unsigned int ok_to_print, unsigned int init_media)
{
if (mii_link_ok(mii)) netif_carrier_on(mii->dev);
else netif_carrier_off(mii->dev);
return 0;
}
int mii_link_ok (struct mii_if_info *mii)
{
/* first, a dummy read, needed to latch some MII phys */
mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR);
if (mii->mdio_read(mii->dev, mii->phy_id, MII_BMSR) & BMSR_LSTATUS)
return 1;
return 0;
}
static struct page *allocate_pages(gfp_t gfp_mask, unsigned int size)
{
struct page *page = (struct page *)kzalloc(sizeof(struct page), 0);
page->addr = Lx::Malloc::dma().alloc_large(size);
page->size = size;
if (!page->addr) {
Genode::error("alloc_pages: ", size, " failed");
kfree(page);
return 0;
}
Addr_to_page_mapping::insert(page);
atomic_set(&page->_count, 1);
return page;
}
void *page_frag_alloc(struct page_frag_cache *nc, unsigned int fragsz, gfp_t gfp_mask)
{
struct page *page = allocate_pages(gfp_mask, fragsz);
if (!page) return nullptr;
return page->addr;
}
void page_frag_free(void *addr)
{
struct page *page = Addr_to_page_mapping::remove((unsigned long)addr);
if (!atomic_dec_and_test(&page->_count))
Genode::error("page reference count != 0");
Lx::Malloc::dma().free_large(page->addr);
kfree(page);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,65 @@
/*
* \brief Linux emulation code
* \author Josef Soentgen
* \date 2014-03-07
*/
/*
* Copyright (C) 2014-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
/* linux includes */
#include <lx_emul.h>
#include <linux/skbuff.h>
/* local includes */
#include <lxc.h>
struct Skb skb_helper(struct sk_buff *skb)
{
struct Skb helper;
skb_push(skb, ETH_HLEN);
helper.packet = skb->data;
helper.packet_size = ETH_HLEN;
helper.frag = 0;
helper.frag_size = 0;
/**
* If received packets are too large (as of now 128 bytes) the actually
* payload is put into a fragment. Otherwise the payload is stored directly
* in the sk_buff.
*/
if (skb_shinfo(skb)->nr_frags) {
if (skb_shinfo(skb)->nr_frags > 1)
printk("more than 1 fragment in skb: %p nr_frags: %d", skb,
skb_shinfo(skb)->nr_frags);
skb_frag_t *f = &skb_shinfo(skb)->frags[0];
helper.frag = skb_frag_address(f);
helper.frag_size = skb_frag_size(f);
}
else
helper.packet_size += skb->len;
return helper;
}
struct sk_buff *lxc_alloc_skb(size_t len, size_t headroom)
{
struct sk_buff *skb = alloc_skb(len + headroom, GFP_KERNEL | GFP_LX_DMA);
skb_reserve(skb, headroom);
return skb;
}
unsigned char *lxc_skb_put(struct sk_buff *skb, size_t len)
{
return skb_put(skb, len);
}

View File

@ -0,0 +1,40 @@
/*
* \brief Lx C env
* \author Josef Soentgen
* \date 2016-03-04
*/
/*
* Copyright (C) 2016-2017 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#ifndef _LXC_H_
#define _LXC_H_
/*
* The sk_buff struct contains empty array members whose
* size differs between C and C++. Since we want to access
* certain members of the sk_buff from C++ we have to use
* a uniform format useable from both languages.W
*
* Note: we pull struct skb_buff as well as size_t from
* headers included before this one.
*/
struct Skb
{
void *packet;
size_t packet_size;
void *frag;
size_t frag_size;
};
struct Skb skb_helper(struct sk_buff *skb);
bool is_eapol(struct sk_buff *skb);
struct sk_buff *lxc_alloc_skb(size_t len, size_t headroom);
unsigned char *lxc_skb_put(struct sk_buff *skb, size_t len);
#endif /* _LXC_H_ */

View File

@ -0,0 +1,216 @@
/*
* \brief USB net driver
* \author Stefan Kalkowski
* \date 2018-06-07
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is distributed under the terms of the GNU General Public License
* version 2.
*/
#include <base/component.h>
#include <driver.h>
#include <lx_emul.h>
#include <lx_kit/env.h>
#include <lx_kit/malloc.h>
#include <lx_kit/scheduler.h>
#include <lx_kit/timer.h>
#include <lx_kit/work.h>
#include <lx_emul/extern_c_begin.h>
#include <linux/usb.h>
#include <lx_emul/extern_c_end.h>
struct workqueue_struct *tasklet_wq;
void Driver::Device::scan_altsettings(usb_interface * iface,
unsigned iface_idx, unsigned alt_idx)
{
Usb::Interface_descriptor iface_desc;
usb.interface_descriptor(iface_idx, alt_idx, &iface_desc);
Genode::memcpy(&iface->altsetting[alt_idx].desc, &iface_desc,
sizeof(usb_interface_descriptor));
if (iface_desc.active)
iface->cur_altsetting = &iface->altsetting[alt_idx];
iface->altsetting[alt_idx].endpoint = (usb_host_endpoint*)
kzalloc(sizeof(usb_host_endpoint)*iface->altsetting[alt_idx].desc.bNumEndpoints, GFP_KERNEL);
for (unsigned i = 0; i < iface->altsetting[alt_idx].desc.bNumEndpoints; i++) {
Usb::Endpoint_descriptor ep_desc;
usb.endpoint_descriptor(iface_idx, alt_idx, i, &ep_desc);
Genode::memcpy(&iface->altsetting[alt_idx].endpoint[i].desc,
&ep_desc, sizeof(usb_endpoint_descriptor));
int epnum = usb_endpoint_num(&iface->altsetting[alt_idx].endpoint[i].desc);
if (usb_endpoint_dir_out(&iface->altsetting[alt_idx].endpoint[i].desc))
udev->ep_out[epnum] = &iface->altsetting[alt_idx].endpoint[i];
else
udev->ep_in[epnum] = &iface->altsetting[alt_idx].endpoint[i];
}
}
void Driver::Device::scan_interfaces(unsigned iface_idx)
{
struct usb_interface * iface =
(usb_interface*) kzalloc(sizeof(usb_interface), GFP_KERNEL);
iface->num_altsetting = usb.alt_settings(iface_idx);
iface->altsetting = (usb_host_interface*)
kzalloc(sizeof(usb_host_interface)*iface->num_altsetting, GFP_KERNEL);
iface->dev.parent = &udev->dev;
iface->dev.bus = (bus_type*) 0xdeadbeef;
for (unsigned i = 0; i < iface->num_altsetting; i++)
scan_altsettings(iface, iface_idx, i);
struct usb_device_id id;
probe_interface(iface, &id);
udev->config->interface[iface_idx] = iface;
driver.env.parent().announce(driver.ep.manage(driver.root));
};
void Driver::Device::register_device()
{
if (udev) {
Genode::error("device already registered!");
return;
}
Usb::Device_descriptor dev_desc;
Usb::Config_descriptor config_desc;
usb.config_descriptor(&dev_desc, &config_desc);
udev = (usb_device*) kzalloc(sizeof(usb_device), GFP_KERNEL);
udev->bus = (usb_bus*) kzalloc(sizeof(usb_bus), GFP_KERNEL);
udev->config = (usb_host_config*) kzalloc(sizeof(usb_host_config), GFP_KERNEL);
udev->bus->bus_name = "usbbus";
udev->bus->controller = (device*) (&usb);
udev->descriptor.idVendor = dev_desc.vendor_id;
udev->descriptor.idProduct = dev_desc.product_id;
udev->descriptor.bcdDevice = dev_desc.device_release;
for (unsigned i = 0; i < config_desc.num_interfaces; i++)
scan_interfaces(i);
}
void Driver::Device::unregister_device()
{
for (unsigned i = 0; i < USB_MAXINTERFACES; i++) {
if (!udev->config->interface[i]) break;
else remove_interface(udev->config->interface[i]);
}
kfree(udev->bus);
kfree(udev->config);
kfree(udev);
udev = nullptr;
}
void Driver::Device::state_task_entry(void * arg)
{
Device & dev = *reinterpret_cast<Device*>(arg);
for (;;) {
if (dev.usb.plugged() && !dev.udev)
dev.register_device();
if (!dev.usb.plugged() && dev.udev)
dev.unregister_device();
Lx::scheduler().current()->block_and_schedule();
}
}
void Driver::Device::urb_task_entry(void * arg)
{
Device & dev = *reinterpret_cast<Device*>(arg);
for (;;) {
while (dev.udev && dev.usb.source()->ack_avail()) {
Usb::Packet_descriptor p = dev.usb.source()->get_acked_packet();
if (p.completion) p.completion->complete(p);
dev.usb.source()->release_packet(p);
}
Lx::scheduler().current()->block_and_schedule();
}
}
Driver::Device::Device(Driver & driver, Label label)
: label(label),
driver(driver),
env(driver.env),
alloc(driver.alloc),
state_task(env.ep(), state_task_entry, reinterpret_cast<void*>(this),
"usb_state", Lx::Task::PRIORITY_0, Lx::scheduler()),
urb_task(env.ep(), urb_task_entry, reinterpret_cast<void*>(this),
"usb_urb", Lx::Task::PRIORITY_0, Lx::scheduler())
{
usb.tx_channel()->sigh_ack_avail(urb_task.handler);
driver.devices.insert(&le);
}
Driver::Device::~Device()
{
driver.devices.remove(&le);
if (udev) unregister_device();
}
void Driver::main_task_entry(void * arg)
{
Driver * driver = reinterpret_cast<Driver*>(arg);
tasklet_wq = alloc_workqueue("tasklet_wq", 0, 0);
skb_init();
module_usbnet_init();
module_smsc95xx_driver_init();
module_asix_driver_init();
module_ax88179_178a_driver_init();
module_cdc_driver_init();
module_rndis_driver_init();
static Device dev(*driver, Label(""));
for (;;) Lx::scheduler().current()->block_and_schedule();
}
Driver::Driver(Genode::Env &env) : env(env)
{
Genode::log("--- USB net driver ---");
Lx_kit::construct_env(env);
Lx::scheduler(&env);
Lx::malloc_init(env, heap);
Lx::timer(&env, &ep, &heap, &jiffies);
Lx::Work::work_queue(&heap);
main_task.construct(env.ep(), main_task_entry, reinterpret_cast<void*>(this),
"main", Lx::Task::PRIORITY_0, Lx::scheduler());
/* give all task a first kick before returning */
Lx::scheduler().schedule();
}
void Component::construct(Genode::Env &env)
{
env.exec_static_constructors();
static Driver driver(env);
}

View File

@ -0,0 +1,32 @@
TARGET := usb_net_drv
SRC_C := dummies.c lxc.c
SRC_CC := main.cc lx_emul.cc component.cc
SRC_CC += printf.cc timer.cc scheduler.cc malloc.cc env.cc work.cc
LIBS := base usb_net_include lx_kit_setjmp
USB_CONTRIB_DIR := $(call select_from_ports,dde_linux)/src/drivers/usb_net
INC_DIR += $(PRG_DIR)
INC_DIR += $(REP_DIR)/src/include
SRC_C += drivers/net/usb/asix_common.c
SRC_C += drivers/net/usb/asix_devices.c
SRC_C += drivers/net/usb/ax88172a.c
SRC_C += drivers/net/usb/ax88179_178a.c
SRC_C += drivers/net/usb/cdc_ether.c
SRC_C += drivers/net/usb/rndis_host.c
SRC_C += drivers/net/usb/smsc95xx.c
SRC_C += drivers/net/usb/usbnet.c
SRC_C += net/core/skbuff.c
SRC_C += net/ethernet/eth.c
CC_C_OPT += -Wno-comment -Wno-int-conversion -Wno-incompatible-pointer-types \
-Wno-unused-variable -Wno-pointer-sign -Wno-uninitialized \
-Wno-maybe-uninitialized -Wno-format -Wno-discarded-qualifiers \
-Wno-unused-function -Wno-unused-but-set-variable
CC_CXX_WARN_STRICT =
vpath %.c $(USB_CONTRIB_DIR)
vpath %.cc $(REP_DIR)/src/lx_kit

View File

@ -0,0 +1,71 @@
linux-x.x.x/drivers/net/usb/asix_common.c
linux-x.x.x/drivers/net/usb/asix_devices.c
linux-x.x.x/drivers/net/usb/asix.h
linux-x.x.x/drivers/net/usb/ax88172a.c
linux-x.x.x/drivers/net/usb/ax88179_178a.c
linux-x.x.x/drivers/net/usb/cdc_ether.c
linux-x.x.x/drivers/net/usb/rndis_host.c
linux-x.x.x/drivers/net/usb/smsc95xx.h
linux-x.x.x/drivers/net/usb/smsc95xx.c
linux-x.x.x/drivers/net/usb/usbnet.c
linux-x.x.x/net/core/skbuff.c
linux-x.x.x/net/ethernet/eth.c
linux-x.x.x/include/asm-generic/atomic64.h
linux-x.x.x/include/asm-generic/bitops/__ffs.h
linux-x.x.x/include/asm-generic/bitops/__fls.h
linux-x.x.x/include/asm-generic/bitops/ffs.h
linux-x.x.x/include/asm-generic/bitops/fls.h
linux-x.x.x/include/asm-generic/bitops/fls64.h
linux-x.x.x/include/asm-generic/bitops/non-atomic.h
linux-x.x.x/include/linux/cgroup-defs.h
linux-x.x.x/include/linux/errqueue.h
linux-x.x.x/include/linux/ethtool.h
linux-x.x.x/include/linux/if_ether.h
linux-x.x.x/include/linux/kfifo.h
linux-x.x.x/include/linux/list.h
linux-x.x.x/include/linux/list_nulls.h
linux-x.x.x/include/linux/log2.h
linux-x.x.x/include/linux/mii.h
linux-x.x.x/include/linux/mdio.h
linux-x.x.x/include/linux/mod_devicetable.h
linux-x.x.x/include/linux/netdev_features.h
linux-x.x.x/include/linux/net.h
linux-x.x.x/include/linux/phy.h
linux-x.x.x/include/linux/rbtree.h
linux-x.x.x/include/linux/rculist.h
linux-x.x.x/include/linux/rculist_nulls.h
linux-x.x.x/include/linux/refcount.h
linux-x.x.x/include/linux/rndis.h
linux-x.x.x/include/linux/skbuff.h
linux-x.x.x/include/linux/socket.h
linux-x.x.x/include/linux/swab.h
linux-x.x.x/include/linux/usb.h
linux-x.x.x/include/linux/usb/ch9.h
linux-x.x.x/include/linux/usb/cdc.h
linux-x.x.x/include/linux/usb/rndis_host.h
linux-x.x.x/include/linux/usb/usbnet.h
linux-x.x.x/include/net/dst.h
linux-x.x.x/include/net/dst_ops.h
linux-x.x.x/include/net/neighbour.h
linux-x.x.x/include/net/sock.h
linux-x.x.x/include/net/tcp_states.h
linux-x.x.x/include/net/tso.h
linux-x.x.x/include/uapi/linux/byteorder/little_endian.h
linux-x.x.x/include/uapi/linux/capability.h
linux-x.x.x/include/uapi/linux/errqueue.h
linux-x.x.x/include/uapi/linux/ethtool.h
linux-x.x.x/include/uapi/linux/if.h
linux-x.x.x/include/uapi/linux/if_ether.h
linux-x.x.x/include/uapi/linux/if_link.h
linux-x.x.x/include/uapi/linux/if_packet.h
linux-x.x.x/include/uapi/linux/libc-compat.h
linux-x.x.x/include/uapi/linux/mdio.h
linux-x.x.x/include/uapi/linux/mii.h
linux-x.x.x/include/uapi/linux/neighbour.h
linux-x.x.x/include/uapi/linux/net.h
linux-x.x.x/include/uapi/linux/rtnetlink.h
linux-x.x.x/include/uapi/linux/socket.h
linux-x.x.x/include/uapi/linux/swab.h
linux-x.x.x/include/uapi/linux/net_tstamp.h
linux-x.x.x/include/uapi/linux/usb/cdc.h
linux-x.x.x/include/uapi/linux/usb/ch9.h