diff --git a/repos/gems/recipes/raw/drivers_nic-pc/drivers.config b/repos/gems/recipes/raw/drivers_nic-pc/drivers.config
index b1e2af5f66..e230df4e84 100644
--- a/repos/gems/recipes/raw/drivers_nic-pc/drivers.config
+++ b/repos/gems/recipes/raw/drivers_nic-pc/drivers.config
@@ -86,8 +86,8 @@
-
-
+
+
diff --git a/repos/os/run/nic_router_flood.run b/repos/os/run/nic_router_flood.run
index 91d0a77f9e..e4fcff4cf1 100644
--- a/repos/os/run/nic_router_flood.run
+++ b/repos/os/run/nic_router_flood.run
@@ -56,7 +56,7 @@ install_config {
-
+
diff --git a/repos/pc/recipes/pkg/pc_nic_drv/README b/repos/pc/recipes/pkg/pc_nic_drv/README
new file mode 100644
index 0000000000..e404087f5d
--- /dev/null
+++ b/repos/pc/recipes/pkg/pc_nic_drv/README
@@ -0,0 +1,2 @@
+
+ Runtime for deploying the PC NIC driver from the depot
diff --git a/repos/pc/recipes/pkg/pc_nic_drv/archives b/repos/pc/recipes/pkg/pc_nic_drv/archives
new file mode 100644
index 0000000000..78bf5a412f
--- /dev/null
+++ b/repos/pc/recipes/pkg/pc_nic_drv/archives
@@ -0,0 +1 @@
+_/src/pc_nic_drv
diff --git a/repos/pc/recipes/pkg/pc_nic_drv/hash b/repos/pc/recipes/pkg/pc_nic_drv/hash
new file mode 100644
index 0000000000..34ff4bed91
--- /dev/null
+++ b/repos/pc/recipes/pkg/pc_nic_drv/hash
@@ -0,0 +1 @@
+2023-06-19 d24305e7a9ad8385854b9971debb689fbcb44a21
diff --git a/repos/pc/recipes/pkg/pc_nic_drv/runtime b/repos/pc/recipes/pkg/pc_nic_drv/runtime
new file mode 100755
index 0000000000..2d2a6c8fa2
--- /dev/null
+++ b/repos/pc/recipes/pkg/pc_nic_drv/runtime
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/repos/pc/recipes/src/pc_nic_drv/content.mk b/repos/pc/recipes/src/pc_nic_drv/content.mk
new file mode 100644
index 0000000000..6ebc3cfe09
--- /dev/null
+++ b/repos/pc/recipes/src/pc_nic_drv/content.mk
@@ -0,0 +1,20 @@
+MIRROR_FROM_REP_DIR := src/drivers/nic/pc \
+ src/lib/pc/lx_emul \
+ src/include
+
+content: $(MIRROR_FROM_REP_DIR)
+$(MIRROR_FROM_REP_DIR):
+ $(mirror_from_rep_dir)
+
+#MIRROR_FROM_OS_DIR := src/lib/genode_c_api/uplink.cc
+#
+#content: $((MIRROR_FROM_OS_DIR)
+#$(MIRROR_FROM_OS_DIR):
+# mkdir -p $(dir $@)
+# cp -r $(GENODE_DIR)/repos/os/$@ $@
+
+PORT_DIR := $(call port_dir,$(GENODE_DIR)/repos/dde_linux/ports/linux)
+
+content: LICENSE
+LICENSE:
+ cp $(PORT_DIR)/src/linux/COPYING $@
diff --git a/repos/pc/recipes/src/pc_nic_drv/hash b/repos/pc/recipes/src/pc_nic_drv/hash
new file mode 100644
index 0000000000..f387cb1e35
--- /dev/null
+++ b/repos/pc/recipes/src/pc_nic_drv/hash
@@ -0,0 +1 @@
+2023-06-19 125d8cc39eb227ca7608d97eaac122600e01e070
diff --git a/repos/pc/recipes/src/pc_nic_drv/used_apis b/repos/pc/recipes/src/pc_nic_drv/used_apis
new file mode 100644
index 0000000000..8443aa6980
--- /dev/null
+++ b/repos/pc/recipes/src/pc_nic_drv/used_apis
@@ -0,0 +1,10 @@
+base
+genode_c_api
+jitterentropy
+nic_session
+os
+pc_linux
+platform_session
+report_session
+timer_session
+uplink_session
diff --git a/repos/pc/src/drivers/nic/pc/dep.list b/repos/pc/src/drivers/nic/pc/dep.list
new file mode 100644
index 0000000000..c14b6d711a
--- /dev/null
+++ b/repos/pc/src/drivers/nic/pc/dep.list
@@ -0,0 +1,181 @@
+arch/x86/include/asm/atomic64_64.h
+arch/x86/include/asm/checksum_32.h
+arch/x86/include/asm/checksum_64.h
+arch/x86/include/asm/cmpxchg_32.h
+arch/x86/include/asm/cmpxchg_64.h
+arch/x86/include/asm/irq_stack.h
+arch/x86/include/asm/kaslr.h
+arch/x86/include/asm/nospec-branch.h
+arch/x86/include/asm/numa_32.h
+arch/x86/include/asm/page_32.h
+arch/x86/include/asm/page_32_types.h
+arch/x86/include/asm/page_64_types.h
+arch/x86/include/asm/pgtable-2level_types.h
+arch/x86/include/asm/pgtable_32_areas.h
+arch/x86/include/asm/pgtable_32_types.h
+arch/x86/include/asm/pgtable_64_types.h
+arch/x86/include/asm/set_memory.h
+arch/x86/include/asm/sparsemem.h
+arch/x86/include/asm/string_64.h
+arch/x86/include/asm/user_32.h
+arch/x86/include/asm/user_64.h
+arch/x86/include/uapi/asm/posix_types_32.h
+arch/x86/include/uapi/asm/posix_types_64.h
+arch/x86/include/uapi/asm/vsyscall.h
+drivers/net/ethernet/intel/e1000/e1000.h
+drivers/net/ethernet/intel/e1000/e1000_hw.h
+drivers/net/ethernet/intel/e1000/e1000_osdep.h
+drivers/net/ethernet/intel/e1000e/80003es2lan.h
+drivers/net/ethernet/intel/e1000e/82571.h
+drivers/net/ethernet/intel/e1000e/defines.h
+drivers/net/ethernet/intel/e1000e/e1000.h
+drivers/net/ethernet/intel/e1000e/hw.h
+drivers/net/ethernet/intel/e1000e/ich8lan.h
+drivers/net/ethernet/intel/e1000e/mac.h
+drivers/net/ethernet/intel/e1000e/manage.h
+drivers/net/ethernet/intel/e1000e/nvm.h
+drivers/net/ethernet/intel/e1000e/phy.h
+drivers/net/ethernet/intel/e1000e/regs.h
+include/asm-generic/asm-prototypes.h
+include/asm-generic/bitops/fls64.h
+include/asm-generic/div64.h
+include/asm-generic/pgtable-nopmd.h
+include/asm-generic/pgtable-nopud.h
+include/asm-generic/set_memory.h
+include/asm-generic/softirq_stack.h
+include/crypto/sha1.h
+include/linux/aer.h
+include/linux/bpf-cgroup.h
+include/linux/bpf.h
+include/linux/bpf_trace.h
+include/linux/bpfptr.h
+include/linux/btf.h
+include/linux/cfi_types.h
+include/linux/cookie.h
+include/linux/cpu_rmap.h
+include/linux/crash_dump.h
+include/linux/dmaengine.h
+include/linux/errqueue.h
+include/linux/etherdevice.h
+include/linux/ethtool_netlink.h
+include/linux/filter.h
+include/linux/firmware.h
+include/linux/icmpv6.h
+include/linux/if_arp.h
+include/linux/if_macvlan.h
+include/linux/if_tunnel.h
+include/linux/if_vlan.h
+include/linux/inet.h
+include/linux/inetdevice.h
+include/linux/ip.h
+include/linux/ipv6_route.h
+include/linux/kcov.h
+include/linux/mpls.h
+include/linux/netfilter.h
+include/linux/netfilter_netdev.h
+include/linux/netpoll.h
+include/linux/nvmem-consumer.h
+include/linux/of_net.h
+include/linux/phylink.h
+include/linux/platform_data/dsa.h
+include/linux/pps_kernel.h
+include/linux/proc_ns.h
+include/linux/ptp_classify.h
+include/linux/ptp_clock_kernel.h
+include/linux/rcupdate_trace.h
+include/linux/rhashtable.h
+include/linux/sctp.h
+include/linux/set_memory.h
+include/linux/skb_array.h
+include/linux/sock_diag.h
+include/linux/wireless.h
+include/net/act_api.h
+include/net/arp.h
+include/net/busy_poll.h
+include/net/devlink.h
+include/net/dsa.h
+include/net/dsfield.h
+include/net/dst_cache.h
+include/net/dst_metadata.h
+include/net/flow_offload.h
+include/net/gen_stats.h
+include/net/gro.h
+include/net/gro_cells.h
+include/net/inet_ecn.h
+include/net/inet_hashtables.h
+include/net/inetpeer.h
+include/net/ip.h
+include/net/ip6_checksum.h
+include/net/ip6_fib.h
+include/net/ip_fib.h
+include/net/ip_tunnels.h
+include/net/ipv6_stubs.h
+include/net/iw_handler.h
+include/net/lwtunnel.h
+include/net/macsec.h
+include/net/mctp.h
+include/net/mpls.h
+include/net/mptcp.h
+include/net/ndisc.h
+include/net/netns/generic.h
+include/net/pkt_cls.h
+include/net/pkt_sched.h
+include/net/protocol.h
+include/net/route.h
+include/net/sch_generic.h
+include/net/sock_reuseport.h
+include/net/switchdev.h
+include/net/tcp.h
+include/net/udp.h
+include/net/udp_tunnel.h
+include/net/xdp_priv.h
+include/net/xdp_sock.h
+include/net/xdp_sock_drv.h
+include/net/xfrm.h
+include/net/xsk_buff_pool.h
+include/trace/events/fib.h
+include/trace/events/napi.h
+include/trace/events/neigh.h
+include/trace/events/net.h
+include/trace/events/net_probe_common.h
+include/trace/events/qdisc.h
+include/trace/events/skb.h
+include/trace/events/sock.h
+include/trace/events/tcp.h
+include/trace/events/udp.h
+include/trace/events/xdp.h
+include/uapi/linux/bpf.h
+include/uapi/linux/bpf_common.h
+include/uapi/linux/btf.h
+include/uapi/linux/devlink.h
+include/uapi/linux/errqueue.h
+include/uapi/linux/ethtool_netlink.h
+include/uapi/linux/filter.h
+include/uapi/linux/gen_stats.h
+include/uapi/linux/if_arp.h
+include/uapi/linux/if_macsec.h
+include/uapi/linux/if_tunnel.h
+include/uapi/linux/if_vlan.h
+include/uapi/linux/if_xdp.h
+include/uapi/linux/in_route.h
+include/uapi/linux/ip.h
+include/uapi/linux/ipsec.h
+include/uapi/linux/ipv6_route.h
+include/uapi/linux/kcov.h
+include/uapi/linux/lwtunnel.h
+include/uapi/linux/mctp.h
+include/uapi/linux/mpls.h
+include/uapi/linux/net_dropmon.h
+include/uapi/linux/net_namespace.h
+include/uapi/linux/pfkeyv2.h
+include/uapi/linux/pps.h
+include/uapi/linux/ptp_clock.h
+include/uapi/linux/route.h
+include/uapi/linux/sctp.h
+include/uapi/linux/sock_diag.h
+include/uapi/linux/vmcore.h
+include/uapi/linux/wireless.h
+net/core/dev.h
+net/core/net-sysfs.h
+net/core/sock_destructor.h
+net/ethtool/common.h
diff --git a/repos/pc/src/drivers/nic/pc/dummies.c b/repos/pc/src/drivers/nic/pc/dummies.c
new file mode 100644
index 0000000000..d7e59f7412
--- /dev/null
+++ b/repos/pc/src/drivers/nic/pc/dummies.c
@@ -0,0 +1,347 @@
+/*
+ * \brief Dummy definitions of Linux Kernel functions - handled manually
+ * \author Christian Helmuth
+ * \date 2023-05-22
+ */
+
+/*
+ * Copyright (C) 2023 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+#include
+
+#include
+#include
+
+struct smp_ops smp_ops = { };
+EXPORT_SYMBOL_GPL(smp_ops);
+
+#include
+
+pteval_t __default_kernel_pte_mask __read_mostly = ~0;
+
+#include
+
+const struct attribute_group dev_attr_physical_location_group = {};
+
+#include
+
+int sysfs_add_file_to_group(struct kobject * kobj,const struct attribute * attr,const char * group)
+{
+ lx_emul_trace(__func__);
+ return 0;
+}
+
+#include
+
+int proc_alloc_inum(unsigned int * inum)
+{
+ *inum = 1; /* according to linux/proc_ns.h without CONFIG_PROC_FS */
+ return 0;
+}
+
+#include
+
+struct ctl_table_header * register_sysctl(const char * path,struct ctl_table * table)
+{
+ lx_emul_trace(__func__);
+ return NULL;
+}
+
+#include
+
+void __init __register_sysctl_init(const char * path,struct ctl_table * table,const char * table_name)
+{
+ lx_emul_trace(__func__);
+}
+
+#include
+
+void register_syscore_ops(struct syscore_ops * ops)
+{
+ lx_emul_trace(__func__);
+}
+
+#include
+
+int get_option(char ** str,int * pint)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+#include
+
+void synchronize_rcu_expedited(void)
+{
+ lx_emul_trace(__func__);
+}
+
+#include
+
+void synchronize_rcu(void)
+{
+ lx_emul_trace(__func__);
+}
+
+#include
+
+void acpi_device_notify(struct device * dev)
+{
+ lx_emul_trace(__func__);
+}
+
+extern bool dev_add_physical_location(struct device * dev);
+bool dev_add_physical_location(struct device * dev)
+{
+ lx_emul_trace(__func__);
+ return false;
+}
+
+#include
+
+int kobject_uevent(struct kobject * kobj,enum kobject_action action)
+{
+ lx_emul_trace(__func__);
+ return 0;
+}
+
+#include
+
+void bpf_prog_change_xdp(struct bpf_prog *prev_prog, struct bpf_prog *prog)
+{
+ lx_emul_trace(__func__);
+}
+
+#include
+
+DEFINE_STATIC_KEY_FALSE(memalloc_socks_key);
+DEFINE_STATIC_KEY_FALSE(bpf_stats_enabled_key);
+DEFINE_STATIC_KEY_FALSE(bpf_master_redirect_enabled_key);
+EXPORT_SYMBOL_GPL(bpf_master_redirect_enabled_key);
+
+#include
+
+DEFINE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_sibling_map);
+EXPORT_PER_CPU_SYMBOL(cpu_sibling_map);
+
+#include
+
+void rtnl_register(int protocol,int msgtype,rtnl_doit_func doit,rtnl_dumpit_func dumpit,unsigned int flags)
+{
+ lx_emul_trace(__func__);
+}
+
+#include
+
+int rtnl_lock_killable(void)
+{
+ lx_emul_trace(__func__);
+ return 0;
+}
+
+#include
+
+int rtnl_is_locked(void)
+{
+ lx_emul_trace(__func__);
+ return 0;
+}
+
+#include
+
+void rtnl_lock(void)
+{
+ lx_emul_trace(__func__);
+}
+
+#include
+
+void rtnl_unlock(void)
+{
+ lx_emul_trace(__func__);
+}
+
+#include
+
+int __init dev_proc_init(void)
+{
+ lx_emul_trace(__func__);
+ return 0;
+}
+
+#include
+
+int iommu_device_use_default_domain(struct device * dev)
+{
+ lx_emul_trace(__func__);
+ return 0;
+}
+
+#include
+
+noinstr void ct_irq_enter(void)
+{
+ lx_emul_trace(__func__);
+}
+
+
+#include
+
+noinstr void ct_irq_exit(void)
+{
+ lx_emul_trace(__func__);
+}
+
+#include
+
+unsigned int full_name_hash(const void * salt,const char * name,unsigned int len)
+{
+ lx_emul_trace(__func__);
+ return 0;
+}
+
+#include
+
+void gnet_stats_basic_sync_init(struct gnet_stats_basic_sync * b)
+{
+ lx_emul_trace(__func__);
+}
+
+#include
+
+void cpu_latency_qos_add_request(struct pm_qos_request * req,s32 value)
+{
+ lx_emul_trace(__func__);
+}
+
+#include
+
+void cpu_latency_qos_update_request(struct pm_qos_request *req, s32 new_value)
+{
+ lx_emul_trace(__func__);
+}
+
+#include
+
+void netdev_rss_key_fill(void * buffer, size_t len)
+{
+ lx_emul_trace(__func__);
+}
+
+#include
+
+int pci_write_config_word(const struct pci_dev *dev, int where, u16 val)
+{
+ lx_emul_trace(__func__);
+ return 0;
+}
+
+#include
+
+int pci_enable_device_mem(struct pci_dev *dev)
+{
+ lx_emul_trace(__func__);
+ return 0;
+}
+
+#include
+
+int pci_select_bars(struct pci_dev *dev, unsigned long flags)
+{
+ lx_emul_trace(__func__);
+ return 0;
+}
+
+#include
+
+int pci_request_selected_regions(struct pci_dev *dev, int, const char *res_name)
+{
+ lx_emul_trace(__func__);
+ return 0;
+}
+
+#include
+
+int pci_request_selected_regions_exclusive(struct pci_dev *dev, int, const char *res_name)
+{
+ lx_emul_trace(__func__);
+ return 0;
+}
+
+#include
+
+int pci_enable_msi(struct pci_dev *dev)
+{
+ lx_emul_trace(__func__);
+ return -ENOSYS;
+}
+
+#include
+
+void pci_restore_state(struct pci_dev *dev)
+{
+ lx_emul_trace(__func__);
+}
+
+#include
+
+int pci_save_state(struct pci_dev *dev)
+{
+ lx_emul_trace(__func__);
+ return 0;
+}
+
+#include
+
+void pci_disable_device(struct pci_dev *dev)
+{
+ lx_emul_trace(__func__);
+}
+
+#include
+
+void pci_disable_msi(struct pci_dev *dev)
+{
+ lx_emul_trace(__func__);
+}
+
+#include
+
+int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries, int minvec, int maxvec)
+{
+ lx_emul_trace(__func__);
+ return -ENOSYS;
+}
+
+#include
+
+void pci_disable_msix(struct pci_dev *dev)
+{
+ lx_emul_trace(__func__);
+}
+
+#include
+
+int pci_disable_link_state_locked(struct pci_dev *dev, int state)
+{
+ lx_emul_trace(__func__);
+ return 0;
+}
+
+#include
+
+int pci_enable_wake(struct pci_dev *pci_dev, pci_power_t state, bool enable)
+{
+ lx_emul_trace(__func__);
+ return -EINVAL;
+}
+
+#include
+
+void pci_clear_master(struct pci_dev *dev)
+{
+ lx_emul_trace(__func__);
+}
diff --git a/repos/pc/src/drivers/nic/pc/lx_emul.c b/repos/pc/src/drivers/nic/pc/lx_emul.c
new file mode 100644
index 0000000000..e0a73cbe9c
--- /dev/null
+++ b/repos/pc/src/drivers/nic/pc/lx_emul.c
@@ -0,0 +1,160 @@
+/*
+ * \brief Linux emulation environment specific to this driver
+ * \author Christian Helmuth
+ * \date 2023-05-22
+ */
+
+/*
+ * Copyright (C) 2023 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+#include
+
+
+unsigned long __FIXADDR_TOP = 0xfffff000;
+
+
+#include
+
+#ifndef INLINE_COPY_FROM_USER
+unsigned long _copy_from_user(void * to, const void __user * from, unsigned long n)
+{
+ memcpy(to, from, n);
+ return 0;
+}
+#endif
+
+unsigned long _copy_to_user(void __user * to,const void * from,unsigned long n)
+{
+ memcpy(to, from, n);
+ return 0;
+}
+
+
+#include
+
+unsigned long get_zeroed_page(gfp_t gfp_mask)
+{
+ return (unsigned long)__alloc_pages(GFP_KERNEL, 0, 0, NULL)->virtual;
+}
+
+void * page_frag_alloc_align(struct page_frag_cache *nc,
+ unsigned int fragsz, gfp_t gfp_mask,
+ unsigned int align_mask)
+{
+ struct page *page;
+
+ if (fragsz > PAGE_SIZE) {
+ printk("no support for fragments larger than PAGE_SIZE\n");
+ lx_emul_trace_and_stop(__func__);
+ }
+
+ page = __alloc_pages(gfp_mask, 0, 0, NULL);
+
+ if (!page)
+ return NULL;
+
+ return page->virtual;
+}
+
+void page_frag_free(void * addr)
+{
+ struct page *page = lx_emul_virt_to_pages(addr, 1ul);
+ if (!page) {
+ printk("BUG %s: page for addr: %p not found\n", __func__, addr);
+ lx_emul_backtrace();
+ }
+
+ __free_pages(page, 0ul);
+}
+
+
+#include
+
+struct kmem_cache * kmem_cache_create_usercopy(const char * name,
+ unsigned int size,
+ unsigned int align,
+ slab_flags_t flags,
+ unsigned int useroffset,
+ unsigned int usersize,
+ void (* ctor)(void *))
+{
+ return kmem_cache_create(name, size, align, flags, ctor);
+}
+
+int kmem_cache_alloc_bulk(struct kmem_cache * s,gfp_t flags, size_t nr,void ** p)
+{
+ size_t i;
+ for (i = 0; i < nr; i++)
+ p[i] = kmem_cache_alloc(s, flags);
+
+ return nr;
+}
+
+
+void kmem_cache_free_bulk(struct kmem_cache * s, size_t size, void ** p)
+{
+ size_t i;
+
+ for (i = 0; i < size; i++)
+ kmem_cache_free(s, p[i]);
+}
+
+
+#include
+
+void ack_bad_irq(unsigned int irq)
+{
+ printk(KERN_CRIT "unexpected IRQ trap at vector %02x\n", irq);
+}
+
+
+#include
+
+void __iomem * pci_ioremap_bar(struct pci_dev * pdev, int bar)
+{
+ struct resource *res = &pdev->resource[bar];
+ return ioremap(res->start, resource_size(res));
+}
+
+int pci_read_config_word(const struct pci_dev *dev, int where, u16 *val)
+{
+ switch (where) {
+ case PCI_COMMAND:
+ *val = 0x7;
+ return 0;
+
+ /*
+ * drivers/net/ethernet/intel/e1000e/ich8lan.c e1000_platform_pm_pch_lpt
+ */
+ case 0xa8:
+ case 0xaa:
+ *val = 0;
+ return 0;
+ /*
+ * drivers/net/ethernet/intel/e1000e/netdev.c e1000_flush_desc_rings
+ *
+ * In i219, the descriptor rings must be emptied before resetting the HW or
+ * before changing the device state to D3 during runtime (runtime PM).
+ *
+ * Failure to do this will cause the HW to enter a unit hang state which
+ * can only be released by PCI reset on the device
+ */
+ case 0xe4:
+ /* XXX report no need to flush */
+ *val = 0;
+ return 0;
+ };
+
+ printk("%s: unexpected read at %x\n", __func__, where);
+ return -1;
+}
+
+int pcie_capability_read_word(struct pci_dev *dev, int pos, u16 *val)
+{
+ printk("%s: unexpected read at %x\n", __func__, pos);
+ return -1;
+}
diff --git a/repos/pc/src/drivers/nic/pc/lx_emul.h b/repos/pc/src/drivers/nic/pc/lx_emul.h
new file mode 100644
index 0000000000..92ca2092ae
--- /dev/null
+++ b/repos/pc/src/drivers/nic/pc/lx_emul.h
@@ -0,0 +1,21 @@
+/**
+ * \brief Dummy definitions of Linux Kernel functions
+ * \author Christian Helmuth
+ * \date 2023-05-22
+ */
+
+/*
+ * Copyright (C) 2023 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+/* Needed to trace and stop */
+#include
+
+/* fix for wait_for_completion_timeout where the __sched include is missing */
+#include
+
+/* fix for missing include in linux/dynamic_debug.h */
+#include
diff --git a/repos/pc/src/drivers/nic/pc/lx_user.c b/repos/pc/src/drivers/nic/pc/lx_user.c
new file mode 100644
index 0000000000..5f9e5998c0
--- /dev/null
+++ b/repos/pc/src/drivers/nic/pc/lx_user.c
@@ -0,0 +1,219 @@
+/*
+ * \brief PC Ethernet driver
+ * \author Christian Helmuth
+ * \date 2023-05-25
+ */
+
+/*
+ * Copyright (C) 2023 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+
+static struct genode_uplink *dev_genode_uplink(struct net_device *dev)
+{
+ return (struct genode_uplink *)dev->ifalias;
+}
+
+
+struct genode_uplink_rx_context
+{
+ struct net_device *dev;
+};
+
+
+struct genode_uplink_tx_packet_context
+{
+ struct sk_buff *skb;
+};
+
+
+static unsigned long uplink_tx_packet_content(struct genode_uplink_tx_packet_context *ctx,
+ char *dst, unsigned long dst_len)
+{
+ struct sk_buff * const skb = ctx->skb;
+
+ skb_push(skb, ETH_HLEN);
+
+ if (dst_len < skb->len) {
+ printk("uplink_tx_packet_content: packet exceeds uplink packet size\n");
+ memset(dst, 0, dst_len);
+ return 0;
+ }
+
+ skb_copy_from_linear_data(skb, dst, skb->len);
+
+ /* clear unused part of the destination buffer */
+ memset(dst + skb->len, 0, dst_len - skb->len);
+
+ return skb->len;
+}
+
+
+static rx_handler_result_t handle_rx(struct sk_buff **pskb)
+{
+ struct sk_buff *skb = *pskb;
+ struct net_device *dev = skb->dev;
+ struct genode_uplink_tx_packet_context ctx = { .skb = skb };
+
+ {
+ bool progress = genode_uplink_tx_packet(dev_genode_uplink(dev),
+ uplink_tx_packet_content,
+ &ctx);
+ if (!progress)
+ printk("handle_rx: uplink saturated, dropping packet\n");
+ }
+
+ kfree_skb(skb);
+ return RX_HANDLER_CONSUMED;
+}
+
+
+/**
+ * Create Genode uplink for given net device
+ *
+ * The uplink is registered at the dev->ifalias pointer.
+ */
+static void handle_create_uplink(struct net_device *dev)
+{
+ struct genode_uplink_args args;
+
+ if (dev_genode_uplink(dev))
+ return;
+
+ if (!netif_carrier_ok(dev))
+ return;
+
+ printk("create uplink for net device %s\n", &dev->name[0]);
+
+ memset(&args, 0, sizeof(args));
+
+ if (dev->addr_len != sizeof(args.mac_address)) {
+ printk("error: net device has unexpected addr_len %u\n", dev->addr_len);
+ return;
+ }
+
+ {
+ unsigned i;
+ for (i = 0; i < dev->addr_len; i++)
+ args.mac_address[i] = dev->dev_addr[i];
+ }
+
+ args.label = &dev->name[0];
+
+ dev->ifalias = (struct dev_ifalias *)genode_uplink_create(&args);
+}
+
+
+static void handle_destroy_uplink(struct net_device *dev)
+{
+ struct genode_uplink *uplink = dev_genode_uplink(dev);
+
+ if (!uplink)
+ return;
+
+ if (netif_carrier_ok(dev))
+ return;
+
+ genode_uplink_destroy(uplink);
+
+ dev->ifalias = NULL;
+}
+
+
+static genode_uplink_rx_result_t uplink_rx_one_packet(struct genode_uplink_rx_context *ctx,
+ char const *ptr, unsigned long len)
+{
+ struct sk_buff *skb = alloc_skb(len, GFP_KERNEL);
+
+ if (!skb) {
+ printk("alloc_skb failed\n");
+ return GENODE_UPLINK_RX_RETRY;
+ }
+
+ skb_copy_to_linear_data(skb, ptr, len);
+ skb_put(skb, len);
+ skb->dev = ctx->dev;
+
+ if (dev_queue_xmit(skb) < 0) {
+ printk("lx_user: failed to xmit packet\n");
+ return GENODE_UPLINK_RX_REJECTED;
+ }
+
+ return GENODE_UPLINK_RX_ACCEPTED;
+}
+
+
+static int user_task_function(void *arg)
+{
+ for (;;) {
+
+ struct net_device *dev;
+
+ for_each_netdev(&init_net, dev) {
+ struct genode_mac_address dev_addr;
+
+ /* enable link sensing, repeated calls are handled by testing IFF_UP */
+ dev_open(dev, 0);
+
+ memcpy(dev_addr.addr, dev->dev_addr, sizeof(dev_addr));
+ genode_mac_address_register(dev->name, dev_addr);
+
+ /* install rx handler once */
+ if (!netdev_is_rx_handler_busy(dev))
+ netdev_rx_handler_register(dev, handle_rx, NULL);
+
+ /* respond to cable plug/unplug */
+ handle_create_uplink(dev);
+ handle_destroy_uplink(dev);
+
+ /* transmit packets received from the uplink session */
+ if (netif_carrier_ok(dev)) {
+
+ struct genode_uplink_rx_context ctx = { .dev = dev };
+
+ while (genode_uplink_rx(dev_genode_uplink(dev),
+ uplink_rx_one_packet,
+ &ctx));
+ }
+ };
+
+ /* block until lx_emul_task_unblock */
+ lx_emul_task_schedule(true);
+ }
+ return 0;
+}
+
+
+struct task_struct *user_task_struct_ptr; /* used by 'Main' for lx_emul_task_unblock */
+
+
+void lx_user_init(void)
+{
+ pid_t pid;
+
+ pid = kernel_thread(user_task_function, NULL, CLONE_FS | CLONE_FILES);
+
+ user_task_struct_ptr = find_task_by_pid_ns(pid, NULL);
+}
+
+
+#include
+
+/*
+ * Called whenever the link state changes
+ */
+void rtmsg_ifinfo(int type, struct net_device * dev, unsigned int change, gfp_t flags)
+{
+ /* trigger handle_create_uplink / handle_destroy_uplink */
+ if (user_task_struct_ptr)
+ lx_emul_task_unblock(user_task_struct_ptr);
+}
diff --git a/repos/pc/src/drivers/nic/pc/main.cc b/repos/pc/src/drivers/nic/pc/main.cc
new file mode 100644
index 0000000000..9755dfb2dd
--- /dev/null
+++ b/repos/pc/src/drivers/nic/pc/main.cc
@@ -0,0 +1,109 @@
+/*
+ * \brief PC Ethernet driver
+ * \author Christian Helmuth
+ * \date 2023-05-24
+ */
+
+/*
+ * Copyright (C) 2023 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+namespace Pc {
+ using namespace Genode;
+ struct Main;
+}
+
+
+extern task_struct *user_task_struct_ptr;
+
+struct Pc::Main : private Entrypoint::Io_progress_handler
+{
+ Env &_env;
+
+ Attached_rom_dataspace _config { _env, "config" };
+
+ /**
+ * Entrypoint::Io_progress_handler
+ */
+ void handle_io_progress() override
+ {
+ genode_uplink_notify_peers();
+ }
+
+ /**
+ * Config update signal handler
+ */
+ Signal_handler _config_handler { _env.ep(), *this, &Main::_handle_config };
+
+ void _handle_config()
+ {
+ _config.update();
+ genode_mac_address_reporter_config(_config.xml());
+ }
+
+ /**
+ * Signal handler triggered by activity of the uplink connection
+ */
+ Io_signal_handler _signal_handler { _env.ep(), *this, &Main::_handle_signal };
+
+ unsigned _signal_handler_nesting_level = 0;
+
+ void _handle_signal()
+ {
+ _signal_handler_nesting_level++;
+
+ {
+ if (!user_task_struct_ptr)
+ return;
+
+ lx_emul_task_unblock(user_task_struct_ptr);
+ Lx_kit::env().scheduler.schedule();
+ }
+
+ /*
+ * Process currently pending I/O signals before leaving the signal
+ * handler to limit the rate of 'handle_io_progress' calls.
+ */
+ if (_signal_handler_nesting_level == 1) {
+ while (_env.ep().dispatch_pending_io_signal());
+ }
+
+ _signal_handler_nesting_level--;
+ }
+
+ Main(Env &env) : _env(env)
+ {
+ Lx_kit::initialize(env);
+
+ env.exec_static_constructors();
+
+ genode_mac_address_reporter_init(env, Lx_kit::env().heap);
+
+ genode_uplink_init(genode_env_ptr(env),
+ genode_allocator_ptr(Lx_kit::env().heap),
+ genode_signal_handler_ptr(_signal_handler));
+
+ /* subscribe to config updates and import initial config */
+ _config.sigh(_config_handler);
+ _handle_config();
+
+ lx_emul_start_kernel(nullptr);
+
+ env.ep().register_io_progress_handler(*this);
+ }
+};
+
+
+void Component::construct(Genode::Env &env) { static Pc::Main main(env); }
diff --git a/repos/pc/src/drivers/nic/pc/spec/x86_32/generated_dummies.c b/repos/pc/src/drivers/nic/pc/spec/x86_32/generated_dummies.c
new file mode 100644
index 0000000000..d2af97c325
--- /dev/null
+++ b/repos/pc/src/drivers/nic/pc/spec/x86_32/generated_dummies.c
@@ -0,0 +1,899 @@
+/*
+ * \brief Dummy definitions of Linux Kernel functions
+ * \author Automatically generated file - do no edit
+ * \date 2023-06-05
+ */
+
+#include
+
+
+#include
+
+int ___ratelimit(struct ratelimit_state * rs,const char * func)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+struct cpumask __cpu_active_mask;
+
+
+#include
+
+int __ethtool_get_link_ksettings(struct net_device * dev,struct ethtool_link_ksettings * link_ksettings)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void __folio_put(struct folio * folio)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int __nla_parse(struct nlattr ** tb,int maxtype,const struct nlattr * head,int len,const struct nla_policy * policy,unsigned int validate,struct netlink_ext_ack * extack)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+struct nlmsghdr * __nlmsg_put(struct sk_buff * skb,u32 portid,u32 seq,int type,int len,int flags)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void __printk_safe_enter(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void __printk_safe_exit(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void __put_task_struct(struct task_struct * tsk)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void __show_mem(unsigned int filter,nodemask_t * nodemask,int max_zone_idx)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void __skb_get_hash(struct sk_buff * skb)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void __srcu_read_unlock(struct srcu_struct * ssp,int idx)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void * __vmalloc_node_range(unsigned long size,unsigned long align,unsigned long start,unsigned long end,gfp_t gfp_mask,pgprot_t prot,unsigned long vm_flags,int node,const void * caller)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int _printk_deferred(const char * fmt,...)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void acpi_device_notify_remove(struct device * dev)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int add_uevent_var(struct kobj_uevent_env * env,const char * format,...)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+extern void arch_trigger_cpumask_backtrace(const cpumask_t * mask,bool exclude_self);
+void arch_trigger_cpumask_backtrace(const cpumask_t * mask,bool exclude_self)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+async_cookie_t async_schedule_node(async_func_t func,void * data,int node)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void async_synchronize_full(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void bpf_warn_invalid_xdp_action(struct net_device * dev,struct bpf_prog * prog,u32 act)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void bust_spinlocks(int yes)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void console_flush_on_panic(enum con_flush_mode mode)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void console_unblank(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void console_verbose(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+const struct cpumask * cpu_clustergroup_mask(int cpu)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void cpu_latency_qos_remove_request(struct pm_qos_request * req)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void do_trace_netlink_extack(const char * msg)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void dst_release(struct dst_entry * dst)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+asmlinkage __visible void dump_stack(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void emergency_restart(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void ethtool_convert_legacy_u32_to_link_mode(unsigned long * dst,u32 legacy_u32)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+bool ethtool_convert_link_mode_to_legacy_u32(u32 * legacy_u32,const unsigned long * src)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+u32 ethtool_op_get_link(struct net_device * dev)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int ethtool_op_get_ts_info(struct net_device * dev,struct ethtool_ts_info * info)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+bool file_ns_capable(const struct file * file,struct user_namespace * ns,int cap)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+struct task_struct * find_task_by_vpid(pid_t vnr)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void finish_rcuwait(struct rcuwait * w)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void gen_kill_estimator(struct net_rate_estimator __rcu ** rate_est)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int generic_mii_ioctl(struct mii_if_info * mii_if,struct mii_ioctl_data * mii_data,int cmd,unsigned int * duplex_chg_out)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+bool gfp_pfmemalloc_allowed(gfp_t gfp_mask)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void gnet_stats_add_basic(struct gnet_stats_basic_sync * bstats,struct gnet_stats_basic_sync __percpu * cpu,struct gnet_stats_basic_sync * b,bool running)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void gnet_stats_add_queue(struct gnet_stats_queue * qstats,const struct gnet_stats_queue __percpu * cpu,const struct gnet_stats_queue * q)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int gnet_stats_copy_basic(struct gnet_dump * d,struct gnet_stats_basic_sync __percpu * cpu,struct gnet_stats_basic_sync * b,bool running)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int gnet_stats_copy_queue(struct gnet_dump * d,struct gnet_stats_queue __percpu * cpu_q,struct gnet_stats_queue * q,__u32 qlen)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void * high_memory;
+
+
+#include
+
+struct pseudo_fs_context * init_pseudo(struct fs_context * fc,unsigned long magic)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+bool initcall_debug;
+
+
+#include
+
+void __sched io_schedule(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void io_schedule_finish(int token)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int io_schedule_prepare(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+long __sched io_schedule_timeout(long timeout)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+struct io_tlb_mem io_tlb_default_mem;
+
+
+#include
+
+void iommu_device_unuse_default_domain(struct device * dev)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void irq_work_tick(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+struct kobject *kernel_kobj;
+
+
+#include
+
+void kill_anon_super(struct super_block * sb)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void * kmem_cache_alloc_lru(struct kmem_cache * cachep,struct list_lru * lru,gfp_t flags)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void kmsg_dump(enum kmsg_dump_reason reason)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int kobject_synth_uevent(struct kobject * kobj,const char * buf,size_t count)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void kvfree_call_rcu(struct rcu_head * head,rcu_callback_t func)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+struct pernet_operations __net_initdata loopback_net_ops;
+
+
+#include
+
+void migrate_disable(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void migrate_enable(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void mii_ethtool_get_link_ksettings(struct mii_if_info * mii,struct ethtool_link_ksettings * cmd)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void mii_ethtool_gset(struct mii_if_info * mii,struct ethtool_cmd * ecmd)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int mii_ethtool_set_link_ksettings(struct mii_if_info * mii,const struct ethtool_link_ksettings * cmd)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int mii_ethtool_sset(struct mii_if_info * mii,struct ethtool_cmd * ecmd)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int mii_link_ok(struct mii_if_info * mii)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int mii_nway_restart(struct mii_if_info * mii)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int net_ratelimit(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+bool netlink_strict_get_check(struct sk_buff * skb)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int nla_put(struct sk_buff * skb,int attrtype,int attrlen,const void * data)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+struct irq_chip no_irq_chip;
+
+
+#include
+
+void note_interrupt(struct irq_desc * desc,irqreturn_t action_ret)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+enum reboot_mode panic_reboot_mode;
+
+
+#include
+
+const struct kernel_param_ops param_ops_int;
+
+
+#include
+
+void pci_clear_mwi(struct pci_dev * dev)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int pci_prepare_to_sleep(struct pci_dev * dev)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void pci_release_selected_regions(struct pci_dev * pdev,int bars)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int pci_set_power_state(struct pci_dev * dev,pci_power_t state)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int pci_wake_from_d3(struct pci_dev * dev,bool enable)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int pcie_capability_clear_and_set_word(struct pci_dev * dev,int pos,u16 clear,u16 set)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int pcie_capability_write_word(struct pci_dev * dev,int pos,u16 val)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int pcix_get_mmrbc(struct pci_dev * dev)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int pcix_set_mmrbc(struct pci_dev * dev,int mmrbc)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int probe_irq_off(unsigned long val)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+unsigned long probe_irq_on(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int proc_dointvec_minmax(struct ctl_table * table,int write,void * buffer,size_t * lenp,loff_t * ppos)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int proc_douintvec(struct ctl_table * table,int write,void * buffer,size_t * lenp,loff_t * ppos)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void proc_free_inum(unsigned int inum)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+enum reboot_mode reboot_mode;
+
+
+#include
+
+struct rhash_lock_head __rcu ** rht_bucket_nested(const struct bucket_table * tbl,unsigned int hash)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+struct sk_buff * rtmsg_ifinfo_build_skb(int type,struct net_device * dev,unsigned int change,u32 event,gfp_t flags,int * new_nsid,int new_ifindex)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void rtmsg_ifinfo_send(struct sk_buff * skb,struct net_device * dev,gfp_t flags)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+struct net * rtnl_get_net_ns_capable(struct sock * sk,int netnsid)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void rtnl_notify(struct sk_buff * skb,struct net * net,u32 pid,u32 group,struct nlmsghdr * nlh,gfp_t flags)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void rtnl_set_sk_err(struct net * net,u32 group,int error)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int rtnl_trylock(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int rtnl_unicast(struct sk_buff * skb,struct net * net,u32 pid)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void seq_printf(struct seq_file * m,const char * f,...)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void show_state_filter(unsigned int state_filter)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void sk_error_report(struct sock * sk)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void smp_call_function_many(const struct cpumask * mask,smp_call_func_t func,void * info,bool wait)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int smp_call_function_single(int cpu,smp_call_func_t func,void * info,int wait)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int smp_call_function_single_async(int cpu,struct __call_single_data * csd)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void sock_efree(struct sk_buff * skb)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+extern void software_node_notify_remove(struct device * dev);
+void software_node_notify_remove(struct device * dev)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+bool static_key_initialized;
+
+
+#include
+
+int suppress_printk;
+
+
+#include
+
+int sysctl_tstamp_allow_data;
+
+
+#include
+
+const int sysctl_vals[] = {};
+
+
+#include
+
+int task_work_add(struct task_struct * task,struct callback_head * work,enum task_work_notify_mode notify)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+struct callback_head * task_work_cancel(struct task_struct * task,task_work_func_t func)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+extern void unregister_handler_proc(unsigned int irq,struct irqaction * action);
+void unregister_handler_proc(unsigned int irq,struct irqaction * action)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void wake_q_add_safe(struct wake_q_head * head,struct task_struct * task)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int xdp_do_generic_redirect(struct net_device * dev,struct sk_buff * skb,struct xdp_buff * xdp,struct bpf_prog * xdp_prog)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+u32 xdp_master_redirect(struct xdp_buff * xdp)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
diff --git a/repos/pc/src/drivers/nic/pc/spec/x86_32/source.list b/repos/pc/src/drivers/nic/pc/spec/x86_32/source.list
new file mode 100644
index 0000000000..8125a3fb7e
--- /dev/null
+++ b/repos/pc/src/drivers/nic/pc/spec/x86_32/source.list
@@ -0,0 +1,109 @@
+arch/x86/lib/checksum_32.S
+arch/x86/lib/hweight.S
+drivers/base/bus.c
+drivers/base/class.c
+drivers/base/component.c
+drivers/base/core.c
+drivers/base/dd.c
+drivers/base/devres.c
+drivers/base/driver.c
+drivers/base/platform.c
+drivers/base/property.c
+drivers/net/ethernet/amd/pcnet32.c
+drivers/net/ethernet/intel/e1000/e1000_ethtool.c
+drivers/net/ethernet/intel/e1000/e1000_hw.c
+drivers/net/ethernet/intel/e1000/e1000_main.c
+drivers/net/ethernet/intel/e1000/e1000_param.c
+drivers/net/ethernet/intel/e1000e/80003es2lan.c
+drivers/net/ethernet/intel/e1000e/82571.c
+drivers/net/ethernet/intel/e1000e/ethtool.c
+drivers/net/ethernet/intel/e1000e/ich8lan.c
+drivers/net/ethernet/intel/e1000e/mac.c
+drivers/net/ethernet/intel/e1000e/manage.c
+drivers/net/ethernet/intel/e1000e/netdev.c
+drivers/net/ethernet/intel/e1000e/nvm.c
+drivers/net/ethernet/intel/e1000e/param.c
+drivers/net/ethernet/intel/e1000e/phy.c
+drivers/net/ethernet/intel/e1000e/ptp.c
+drivers/pci/pci-driver.c
+kernel/irq/chip.c
+kernel/irq/devres.c
+kernel/irq/handle.c
+kernel/irq/irqdesc.c
+kernel/irq/irqdomain.c
+kernel/irq/manage.c
+kernel/irq/resend.c
+kernel/kthread.c
+kernel/locking/mutex.c
+kernel/locking/osq_lock.c
+kernel/locking/rwsem.c
+kernel/notifier.c
+kernel/panic.c
+kernel/resource.c
+kernel/sched/build_utility.c
+kernel/smpboot.c
+kernel/softirq.c
+kernel/time/clockevents.c
+kernel/time/clocksource.c
+kernel/time/hrtimer.c
+kernel/time/jiffies.c
+kernel/time/ntp.c
+kernel/time/tick-broadcast.c
+kernel/time/tick-common.c
+kernel/time/tick-oneshot.c
+kernel/time/tick-sched.c
+kernel/time/time.c
+kernel/time/timeconv.c
+kernel/time/timecounter.c
+kernel/time/timekeeping.c
+kernel/time/timer.c
+kernel/time/timer_list.c
+kernel/workqueue.c
+lib/atomic64.c
+lib/bitmap.c
+lib/crc32.c
+lib/ctype.c
+lib/debug_locks.c
+lib/dec_and_lock.c
+lib/dynamic_queue_limits.c
+lib/find_bit.c
+lib/hexdump.c
+lib/idr.c
+lib/iomap.c
+lib/irq_regs.c
+lib/kasprintf.c
+lib/klist.c
+lib/kobject.c
+lib/kstrtox.c
+lib/list_sort.c
+lib/llist.c
+lib/math/div64.c
+lib/radix-tree.c
+lib/rbtree.c
+lib/refcount.c
+lib/scatterlist.c
+lib/siphash.c
+lib/sort.c
+lib/string.c
+lib/string_helpers.c
+lib/timerqueue.c
+lib/uuid.c
+lib/vsprintf.c
+lib/xarray.c
+mm/mempool.c
+mm/util.c
+net/core/datagram.c
+net/core/dev.c
+net/core/dev_addr_lists.c
+net/core/gro.c
+net/core/link_watch.c
+net/core/net-sysfs.c
+net/core/net-traces.c
+net/core/net_namespace.c
+net/core/skbuff.c
+net/core/xdp.c
+net/devres.c
+net/ethernet/eth.c
+net/ethtool/common.c
+net/sched/sch_generic.c
+net/sched/sch_mq.c
diff --git a/repos/pc/src/drivers/nic/pc/spec/x86_32/target.mk b/repos/pc/src/drivers/nic/pc/spec/x86_32/target.mk
new file mode 100644
index 0000000000..999bd75e93
--- /dev/null
+++ b/repos/pc/src/drivers/nic/pc/spec/x86_32/target.mk
@@ -0,0 +1,6 @@
+REQUIRES := x86_32
+
+SRC_C += lx_emul/spec/x86_32/atomic64_32.c
+SRC_C += lx_emul/shadow/arch/x86/kernel/irq_32.c
+
+include $(PRG_DIR)/../../target.inc
diff --git a/repos/pc/src/drivers/nic/pc/spec/x86_64/generated_dummies.c b/repos/pc/src/drivers/nic/pc/spec/x86_64/generated_dummies.c
new file mode 100644
index 0000000000..d5c53d3f69
--- /dev/null
+++ b/repos/pc/src/drivers/nic/pc/spec/x86_64/generated_dummies.c
@@ -0,0 +1,902 @@
+/*
+ * \brief Dummy definitions of Linux Kernel functions
+ * \author Automatically generated file - do no edit
+ * \date 2023-06-06
+ */
+
+#include
+
+
+#include
+
+int ___ratelimit(struct ratelimit_state * rs,const char * func)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+struct cpumask __cpu_active_mask;
+
+
+#include
+
+int __ethtool_get_link_ksettings(struct net_device * dev,struct ethtool_link_ksettings * link_ksettings)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void __folio_put(struct folio * folio)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int __nla_parse(struct nlattr ** tb,int maxtype,const struct nlattr * head,int len,const struct nla_policy * policy,unsigned int validate,struct netlink_ext_ack * extack)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+struct nlmsghdr * __nlmsg_put(struct sk_buff * skb,u32 portid,u32 seq,int type,int len,int flags)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void __printk_safe_enter(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void __printk_safe_exit(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void __put_task_struct(struct task_struct * tsk)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void __show_mem(unsigned int filter,nodemask_t * nodemask,int max_zone_idx)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void __skb_get_hash(struct sk_buff * skb)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void __srcu_read_unlock(struct srcu_struct * ssp,int idx)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void * __vmalloc_node_range(unsigned long size,unsigned long align,unsigned long start,unsigned long end,gfp_t gfp_mask,pgprot_t prot,unsigned long vm_flags,int node,const void * caller)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int _printk_deferred(const char * fmt,...)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void acpi_device_notify_remove(struct device * dev)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int add_uevent_var(struct kobj_uevent_env * env,const char * format,...)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+extern void arch_trigger_cpumask_backtrace(const cpumask_t * mask,bool exclude_self);
+void arch_trigger_cpumask_backtrace(const cpumask_t * mask,bool exclude_self)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+async_cookie_t async_schedule_node(async_func_t func,void * data,int node)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void async_synchronize_full(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void bpf_warn_invalid_xdp_action(struct net_device * dev,struct bpf_prog * prog,u32 act)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void bust_spinlocks(int yes)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void console_flush_on_panic(enum con_flush_mode mode)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void console_unblank(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void console_verbose(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+const struct cpumask * cpu_clustergroup_mask(int cpu)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void cpu_latency_qos_remove_request(struct pm_qos_request * req)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+__sum16 csum_ipv6_magic(const struct in6_addr * saddr,const struct in6_addr * daddr,__u32 len,__u8 proto,__wsum sum)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void do_trace_netlink_extack(const char * msg)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void dst_release(struct dst_entry * dst)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+asmlinkage __visible void dump_stack(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void emergency_restart(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void ethtool_convert_legacy_u32_to_link_mode(unsigned long * dst,u32 legacy_u32)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+bool ethtool_convert_link_mode_to_legacy_u32(u32 * legacy_u32,const unsigned long * src)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+u32 ethtool_op_get_link(struct net_device * dev)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int ethtool_op_get_ts_info(struct net_device * dev,struct ethtool_ts_info * info)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+bool file_ns_capable(const struct file * file,struct user_namespace * ns,int cap)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+struct task_struct * find_task_by_vpid(pid_t vnr)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void finish_rcuwait(struct rcuwait * w)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void gen_kill_estimator(struct net_rate_estimator __rcu ** rate_est)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int generic_mii_ioctl(struct mii_if_info * mii_if,struct mii_ioctl_data * mii_data,int cmd,unsigned int * duplex_chg_out)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+bool gfp_pfmemalloc_allowed(gfp_t gfp_mask)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void gnet_stats_add_basic(struct gnet_stats_basic_sync * bstats,struct gnet_stats_basic_sync __percpu * cpu,struct gnet_stats_basic_sync * b,bool running)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void gnet_stats_add_queue(struct gnet_stats_queue * qstats,const struct gnet_stats_queue __percpu * cpu,const struct gnet_stats_queue * q)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int gnet_stats_copy_basic(struct gnet_dump * d,struct gnet_stats_basic_sync __percpu * cpu,struct gnet_stats_basic_sync * b,bool running)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int gnet_stats_copy_queue(struct gnet_dump * d,struct gnet_stats_queue __percpu * cpu_q,struct gnet_stats_queue * q,__u32 qlen)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+struct pseudo_fs_context * init_pseudo(struct fs_context * fc,unsigned long magic)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+bool initcall_debug;
+
+
+#include
+
+void __sched io_schedule(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void io_schedule_finish(int token)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int io_schedule_prepare(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+long __sched io_schedule_timeout(long timeout)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+struct io_tlb_mem io_tlb_default_mem;
+
+
+#include
+
+void iommu_device_unuse_default_domain(struct device * dev)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void irq_work_tick(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+struct kobject *kernel_kobj;
+
+
+#include
+
+void kill_anon_super(struct super_block * sb)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void * kmem_cache_alloc_lru(struct kmem_cache * cachep,struct list_lru * lru,gfp_t flags)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void kmsg_dump(enum kmsg_dump_reason reason)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int kobject_synth_uevent(struct kobject * kobj,const char * buf,size_t count)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void kvfree_call_rcu(struct rcu_head * head,rcu_callback_t func)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+struct pernet_operations __net_initdata loopback_net_ops;
+
+
+#include
+
+void migrate_disable(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void migrate_enable(void)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void mii_ethtool_get_link_ksettings(struct mii_if_info * mii,struct ethtool_link_ksettings * cmd)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+void mii_ethtool_gset(struct mii_if_info * mii,struct ethtool_cmd * ecmd)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include
+
+int mii_ethtool_set_link_ksettings(struct mii_if_info * mii,const struct ethtool_link_ksettings * cmd)
+{
+ lx_emul_trace_and_stop(__func__);
+}
+
+
+#include