diff --git a/repos/os/run/vmm_arm.run b/repos/os/run/vmm_arm.run
index 6e3e5850ba..c78cea8583 100644
--- a/repos/os/run/vmm_arm.run
+++ b/repos/os/run/vmm_arm.run
@@ -15,6 +15,8 @@ set build_components {
core init timer
server/terminal_crosslink
test/terminal_expect_send
+ server/log_terminal
+ server/nic_router
server/vmm
}
build $build_components
@@ -40,17 +42,42 @@ install_config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
}
@@ -94,17 +121,17 @@ if { [have_spec arm_64] } {
if {![file exists bin/linux]} {
puts "Download linux kernel ..."
- exec >& /dev/null wget -c -O bin/linux http://genode.org/files/release-19.11/linux-arm64-image-5.2
+ exec >& /dev/null wget -c -O bin/linux http://genode.org/files/release-20.02/linux-arm64
}
if {![file exists bin/dtb]} {
puts "Download device tree blob ..."
- exec >& /dev/null wget -c -O bin/dtb http://genode.org/files/release-19.11/dtb-arm64-virt
+ exec >& /dev/null wget -c -O bin/dtb http://genode.org/files/release-20.02/dtb-arm64-virt
}
if {![file exists bin/initrd]} {
puts "Download initramfs ..."
- exec >& /dev/null wget -c -O bin/initrd http://genode.org/files/release-19.11/initrd-arm64
+ exec >& /dev/null wget -c -O bin/initrd http://genode.org/files/release-20.02/initrd-arm64
}
#
@@ -151,6 +178,8 @@ set boot_modules {
timer
terminal_crosslink
test-terminal_expect_send
+ nic_router
+ log_terminal
vmm
linux
dtb
diff --git a/repos/os/src/server/vmm/spec/arm_v8/pl011.cc b/repos/os/src/server/vmm/spec/arm_v8/pl011.cc
index a9cd8f834e..68defd9f5c 100644
--- a/repos/os/src/server/vmm/spec/arm_v8/pl011.cc
+++ b/repos/os/src/server/vmm/spec/arm_v8/pl011.cc
@@ -83,7 +83,7 @@ Pl011::Pl011(const char * const name,
Mmio_bus & bus,
Genode::Env & env)
: Mmio_device(name, addr, size),
- _terminal(env),
+ _terminal(env, "earlycon"),
_handler(cpu, env.ep(), *this, &Pl011::_read),
_irq(cpu.gic().irq(irq))
{
diff --git a/repos/os/src/server/vmm/spec/arm_v8/target.mk b/repos/os/src/server/vmm/spec/arm_v8/target.mk
index 797b883a99..9af3f0a6e9 100644
--- a/repos/os/src/server/vmm/spec/arm_v8/target.mk
+++ b/repos/os/src/server/vmm/spec/arm_v8/target.mk
@@ -8,6 +8,7 @@ SRC_CC += gicv2.cc
SRC_CC += main.cc
SRC_CC += mmio.cc
SRC_CC += pl011.cc
+SRC_CC += virtio_device.cc
SRC_CC += vm.cc
INC_DIR += $(PRG_DIR)
diff --git a/repos/os/src/server/vmm/spec/arm_v8/virt.dts b/repos/os/src/server/vmm/spec/arm_v8/virt.dts
index 92a0110c86..bda1efddd3 100755
--- a/repos/os/src/server/vmm/spec/arm_v8/virt.dts
+++ b/repos/os/src/server/vmm/spec/arm_v8/virt.dts
@@ -45,9 +45,10 @@
};
chosen {
- bootargs = "rdinit=/bin/sh";
+ /* bootargs = "rdinit=/bin/sh console=hvc0 earlycon=pl011,0x9000000"; */
+ bootargs = "init=/sbin/init ip=dhcp console=hvc0";
linux,initrd-start = <0x42000000>;
- linux,initrd-end = <0x42113b86>;
+ linux,initrd-end = <0x420aa539>;
stdout-path = "/pl011@9000000";
};
@@ -62,4 +63,19 @@
#interrupt-cells = <0x03>;
#size-cells = <0x02>;
};
+
+
+ virtio_mmio@a000000 {
+ interrupts = <0x00 0x10 0x01>;
+ compatible = "virtio,mmio";
+ dma-coherent;
+ reg = <0x00 0xa000000 0x00 0x200>;
+ };
+
+ virtio_mmio@a000200 {
+ interrupts = <0x00 0x11 0x01>;
+ compatible = "virtio,mmio";
+ dma-coherent;
+ reg = <0x00 0xa000200 0x00 0x200>;
+ };
};
diff --git a/repos/os/src/server/vmm/spec/arm_v8/virtio_console.h b/repos/os/src/server/vmm/spec/arm_v8/virtio_console.h
new file mode 100644
index 0000000000..3c4cd01b19
--- /dev/null
+++ b/repos/os/src/server/vmm/spec/arm_v8/virtio_console.h
@@ -0,0 +1,82 @@
+/*
+ * \brief Virtio console implementation
+ * \author Sebastian Sumpf
+ * \date 2019-10-10
+ */
+
+/*
+ * Copyright (C) 2019 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef _VIRTIO_CONSOLE_H_
+#define _VIRTIO_CONSOLE_H_
+
+#include
+
+#include
+
+namespace Vmm
+{
+ class Virtio_console;
+}
+
+class Vmm::Virtio_console : public Virtio_device
+{
+ private:
+
+ Terminal::Connection _terminal;
+ Cpu::Signal_handler _handler;
+
+ void _read()
+ {
+ auto read = [&] (addr_t data, size_t size)
+ {
+ size_t length = _terminal.read((void *)data, size);
+ return length;
+ };
+
+ if (!_terminal.avail() || !_queue[RX].constructed()) return;
+
+ _queue[RX]->notify(read);
+ _assert_irq();
+ }
+
+ void _notify(unsigned idx) override
+ {
+ if (idx != TX) return;
+
+ auto write = [&] (addr_t data, size_t size)
+ {
+ _terminal.write((void *)data, size);
+ return size;
+ };
+
+ if (_queue[TX]->notify(write))
+ _assert_irq();
+ }
+
+ public:
+
+ Virtio_console(const char * const name,
+ const uint64_t addr,
+ const uint64_t size,
+ unsigned irq,
+ Cpu &cpu,
+ Mmio_bus &bus,
+ Ram &ram,
+ Genode::Env &env)
+ : Virtio_device(name, addr, size, irq, cpu, bus, ram),
+ _terminal(env, "console"),
+ _handler(cpu, env.ep(), *this, &Virtio_console::_read)
+ {
+ /* set device ID to console */
+ _device_id(0x3);
+
+ _terminal.read_avail_sigh(_handler);
+ }
+};
+
+#endif /* _VIRTIO_CONSOLE_H_ */
diff --git a/repos/os/src/server/vmm/spec/arm_v8/virtio_device.cc b/repos/os/src/server/vmm/spec/arm_v8/virtio_device.cc
new file mode 100644
index 0000000000..a780e4c1ba
--- /dev/null
+++ b/repos/os/src/server/vmm/spec/arm_v8/virtio_device.cc
@@ -0,0 +1,57 @@
+/*
+ * \brief Generic and simple virtio device
+ * \author Sebastian Sumpf
+ * \date 2019-10-10
+ */
+
+/*
+ * Copyright (C) 2019 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#include
+#include
+
+#include
+
+using Vmm::Virtio_device;
+using Register = Vmm::Mmio_register::Register;
+
+Virtio_device::Virtio_device(const char * const name,
+ const Genode::uint64_t addr,
+ const Genode::uint64_t size,
+ unsigned irq,
+ Cpu &cpu,
+ Mmio_bus &bus,
+ Ram &ram,
+ unsigned queue_size)
+: Mmio_device(name, addr, size),
+ _irq(cpu.gic().irq(irq)),
+ _ram(ram)
+{
+ for (unsigned i = 0; i < (sizeof(Dummy::regs) / sizeof(Mmio_register)); i++)
+ add(_reg_container.regs[i]);
+
+ add(_device_features);
+ add(_driver_features);
+ add(_queue_sel);
+ add(_queue_ready);
+ add(_queue_num);
+ add(_queue_notify);
+ add(_queue_descr_low);
+ add(_queue_descr_high);
+ add(_queue_driver_low);
+ add(_queue_driver_high);
+ add(_queue_device_low);
+ add(_queue_device_high);
+ add(_interrupt_status);
+ add(_interrupt_ack);
+ add(_status);
+
+ /* set queue size */
+ _reg_container.regs[6].set(queue_size);
+
+ bus.add(*this);
+}
diff --git a/repos/os/src/server/vmm/spec/arm_v8/virtio_device.h b/repos/os/src/server/vmm/spec/arm_v8/virtio_device.h
new file mode 100644
index 0000000000..67a7c59671
--- /dev/null
+++ b/repos/os/src/server/vmm/spec/arm_v8/virtio_device.h
@@ -0,0 +1,501 @@
+/*
+ * \brief Generic and simple virtio device
+ * \author Sebastian Sumpf
+ * \date 2019-10-10
+ */
+
+/*
+ * Copyright (C) 2019 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef _VIRTIO_DEVICE_H_
+#define _VIRTIO_DEVICE_H_
+
+#include
+#include
+
+#include
+#include
+#include
+
+namespace Vmm {
+ class Virtio_device;
+ class Virtio_queue;
+ struct Virtio_queue_data;
+ class Virtio_descriptor;
+ class Virtio_avail;
+ class Virtio_used;
+}
+
+using uint16_t = Genode::uint16_t;
+using uint32_t = Genode::uint32_t;
+using uint64_t = Genode::uint64_t;
+using addr_t = Genode::addr_t;
+using size_t = Genode::size_t;
+
+struct Vmm::Virtio_queue_data
+{
+ uint32_t descr_low { 0 };
+ uint32_t descr_high { 0 };
+ uint32_t driver_low { 0 };
+ uint32_t driver_high { 0 };
+ uint32_t device_low { 0 };
+ uint32_t device_high { 0 };
+ uint32_t num { 0 };
+ uint32_t ready { 0 };
+ bool tx { false };
+
+ addr_t descr() const { return ((addr_t)descr_high << 32) | descr_low; }
+ addr_t driver() const { return ((addr_t)driver_high << 32) | driver_low; }
+ addr_t device() const { return ((addr_t)device_high << 32) | device_low; }
+
+ enum { MAX_QUEUE_SIZE = 1 << 15 };
+};
+
+
+class Vmm::Virtio_descriptor : Genode::Mmio
+{
+ public:
+
+ Virtio_descriptor(addr_t base)
+ : Mmio(base) { }
+
+
+ struct Address : Register<0x0, 64> { };
+ struct Length : Register<0x8, 32> { };
+
+ struct Flags : Register<0xc, 16>
+ {
+ struct Next : Bitfield<0, 1> { };
+ struct Write : Bitfield<1, 1> { };
+ struct Indirect : Bitfield<2, 1> { };
+ };
+
+ struct Next : Register<0xe, 16> { };
+
+ static constexpr size_t size() { return 16; }
+
+ Virtio_descriptor index(unsigned idx)
+ {
+ return Virtio_descriptor(base() + (size() * idx));
+ }
+
+ addr_t address() const { return read(); }
+ size_t length () const { return read(); }
+ uint16_t flags() const { return read(); }
+ uint16_t next() const { return read(); }
+};
+
+
+class Vmm::Virtio_avail : public Genode::Mmio
+{
+ public:
+
+ Virtio_avail(addr_t base)
+ : Mmio(base) { };
+
+ struct Flags : Register<0x0, 16> { };
+ struct Idx : Register<0x2, 16> { };
+ struct Ring : Register_array<0x4, 16, Virtio_queue_data::MAX_QUEUE_SIZE, 16> { };
+};
+
+
+class Vmm::Virtio_used : public Genode::Mmio
+{
+ public:
+
+ Virtio_used(addr_t base)
+ : Mmio(base) { };
+
+ struct Flags : Register<0x0, 16> { };
+ struct Idx : Register<0x2, 16> { };
+
+ struct Elem : Register_array<0x4, 64, Virtio_queue_data::MAX_QUEUE_SIZE, 64>
+ {
+ struct Id : Bitfield<0, 32> { };
+ struct Length : Bitfield<32,32> { };
+ };
+};
+
+/**
+ * Split queue implementation
+ */
+class Vmm::Virtio_queue
+{
+ private:
+
+ Virtio_queue_data &_data;
+ Ram &_ram;
+
+ Virtio_descriptor _descr { _ram.local_address(_data.descr(),
+ Virtio_descriptor::size() * _data.num ) };
+ Virtio_avail _avail { _ram.local_address(_data.driver(), 6 + 2 * _data.num) };
+ Virtio_used _used { _ram.local_address(_data.device(), 6 + 8 * _data.num) };
+
+ uint16_t _idx { 0 };
+ uint32_t _length { _data.num };
+ bool _tx { _data.tx };
+
+ public:
+
+ Virtio_queue(Virtio_queue_data &data, Ram &ram)
+ : _data(data), _ram(ram) { }
+
+ template
+ bool notify(FUNC func)
+ {
+ uint16_t used_idx = _used.read();
+ uint16_t avail_idx = _avail.read();
+ uint16_t queue_idx = _tx ? avail_idx : used_idx + 1;
+
+ uint16_t written = 0;
+ while (_idx != queue_idx && written < _length) {
+ uint16_t id = _avail.read(_idx % _length);
+
+ /* make sure id stays in ring */
+ id %= _length;
+
+ Virtio_descriptor descr = _descr.index(id);
+ addr_t address = descr.address();
+ size_t length = descr.length();
+ if (!address || !length) break;
+
+ addr_t data = 0;
+ try {
+ data = _ram.local_address(address, length);
+ length = func(data, length);
+ } catch (...) { break; }
+
+ if (length == 0) break;
+
+ _used.write(0);
+ Virtio_used::Elem::access_t elem = 0;
+ Virtio_used::Elem::Id::set(elem, id);
+ Virtio_used::Elem::Length::set(elem, length);
+ _used.write(elem, id);
+ written++; _idx++;
+
+ if (used_idx + written == avail_idx) break;
+ }
+
+ _used.write(used_idx + written);
+
+ return written > 0;
+ }
+};
+
+
+class Vmm::Virtio_device : public Vmm::Mmio_device
+{
+ protected:
+
+ enum { RX = 0, TX = 1, NUM = 2 };
+ Virtio_queue_data _data[NUM];
+ uint32_t _current { RX };
+
+ Genode::Constructible _queue[NUM];
+ Gic::Irq &_irq;
+ Ram &_ram;
+
+ struct Dummy {
+ Mmio_register regs[7];
+ } _reg_container { .regs = {
+ { "MagicValue", Mmio_register::RO, 0x0, 4, 0x74726976 },
+ { "Version", Mmio_register::RO, 0x4, 4, 0x2 },
+ { "DeviceID", Mmio_register::RO, 0x8, 4, 0x0 },
+ { "VendorID", Mmio_register::RO, 0xc, 4, 0x554d4551 /* QEMU */ },
+ { "DeviceFeatureSel", Mmio_register::RW, 0x14, 4, 0 },
+ { "DriverFeatureSel", Mmio_register::RW, 0x24, 4, 0 },
+ { "QueueNumMax", Mmio_register::RO, 0x34, 4, 8 }
+ }};
+
+
+ void _device_id(unsigned id)
+ {
+ _reg_container.regs[2].set(id);
+ }
+
+ void _queue_select(uint32_t sel) { _current = sel; }
+ Virtio_queue_data &_queue_data() { return _data[_current]; }
+
+ void _queue_state(bool const construct)
+ {
+ if (construct && !_queue[_current].constructed() && _queue_data().num > 0) {
+ _queue_data().tx = (_current == TX);
+ _queue[_current].construct(_queue_data(), _ram);
+ }
+
+ if (!construct && _queue[_current].constructed())
+ _queue[_current].destruct();
+ }
+
+ void _assert_irq()
+ {
+ _interrupt_status.set(0x1);
+ _irq.assert();
+ }
+
+ void _deassert_irq()
+ {
+ _interrupt_status.set(0);
+ _irq.deassert();
+ }
+
+ virtual void _notify(unsigned idx) = 0;
+
+
+ /***************
+ ** Registers **
+ ***************/
+
+ struct DeviceFeatures : Mmio_register
+ {
+ enum {
+ VIRTIO_F_VERSION_1 = 1,
+ };
+
+ Mmio_register &_selector;
+
+ Register read(Address_range&, Cpu&) override
+ {
+ /* lower 32 bit */
+ if (_selector.value() == 0) return 0;
+
+ /* upper 32 bit */
+ return VIRTIO_F_VERSION_1;
+ }
+
+ DeviceFeatures(Mmio_register &selector)
+ : Mmio_register("DeviceFeatures", Mmio_register::RO, 0x10, 4),
+ _selector(selector)
+ { }
+ } _device_features { _reg_container.regs[4] };
+
+ struct DriverFeatures : Mmio_register
+ {
+ Mmio_register &_selector;
+ uint32_t _lower { 0 };
+ uint32_t _upper { 0 };
+
+ void write(Address_range&, Cpu&, Register reg) override
+ {
+ if (_selector.value() == 0) _lower = reg;
+ _upper = reg;
+ }
+
+ DriverFeatures(Mmio_register &selector)
+ : Mmio_register("DriverFeatures", Mmio_register::WO, 0x20, 4),
+ _selector(selector)
+ { }
+ } _driver_features { _reg_container.regs[5] };
+
+ struct Status : Mmio_register
+ {
+ Register read(Address_range&, Cpu&) override
+ {
+ return value();
+ }
+
+ void write(Address_range&, Cpu&, Register reg) override
+ {
+ set(reg);
+ }
+
+ Status()
+ : Mmio_register("Status", Mmio_register::RW, 0x70, 4, 0)
+ { }
+ } _status;
+
+ struct QueueSel : Mmio_register
+ {
+ Virtio_device &device;
+
+ void write(Address_range&, Cpu&, Register reg) override
+ {
+ if (reg >= device.NUM) return;
+ device._queue_select(reg);
+ }
+
+ QueueSel(Virtio_device &device)
+ : Mmio_register("QueueSel", Mmio_register::WO, 0x30, 4),
+ device(device) { }
+ } _queue_sel { *this };
+
+ struct QueueNum : Mmio_register
+ {
+ Virtio_device &device;
+
+ void write(Address_range&, Cpu&, Register reg) override
+ {
+ device._queue_data().num = Genode::min(reg,
+ device._reg_container.regs[6].value());
+ }
+
+ QueueNum(Virtio_device &device)
+ : Mmio_register("QueueNum", Mmio_register::WO, 0x38, 4),
+ device(device) { }
+ } _queue_num { *this };
+
+ struct QueueReady : Mmio_register
+ {
+ Virtio_device &device;
+
+ Register read(Address_range&, Cpu&) override
+ {
+ return device._queue_data().ready;
+ }
+
+ void write(Address_range&, Cpu&, Register reg) override
+ {
+ bool construct = reg == 1 ? true : false;
+ device._queue_data().ready = reg;
+ device._queue_state(construct);
+ }
+
+ QueueReady(Virtio_device &device)
+ : Mmio_register("QueueReady", Mmio_register::RW, 0x44, 4),
+ device(device) { }
+ } _queue_ready { *this };
+
+ struct QueueNotify : Mmio_register
+ {
+ Virtio_device &device;
+
+ void write(Address_range&, Cpu&, Register reg) override
+ {
+ if (!device._queue[reg].constructed()) return;
+
+ device._notify(reg);
+ }
+
+ QueueNotify(Virtio_device &device)
+ : Mmio_register("QueueNotify", Mmio_register::WO, 0x50, 4),
+ device(device) { }
+ } _queue_notify { *this };
+
+ struct QueueDescrLow : Mmio_register
+ {
+ Virtio_device &device;
+
+ void write(Address_range&, Cpu&, Register reg) override
+ {
+ device._queue_data().descr_low = reg;
+ }
+
+ QueueDescrLow(Virtio_device &device)
+ : Mmio_register("QueuDescrLow", Mmio_register::WO, 0x80, 4),
+ device(device) { }
+ } _queue_descr_low { *this };
+
+ struct QueueDescrHigh : Mmio_register
+ {
+ Virtio_device &device;
+
+ void write(Address_range&, Cpu&, Register reg) override
+ {
+ device._queue_data().descr_high = reg;
+ }
+
+ QueueDescrHigh(Virtio_device &device)
+ : Mmio_register("QueuDescrHigh", Mmio_register::WO, 0x84, 4),
+ device(device) { }
+ } _queue_descr_high { *this };
+
+ struct QueueDriverLow : Mmio_register
+ {
+ Virtio_device &device;
+
+ void write(Address_range&, Cpu&, Register reg) override
+ {
+ device._queue_data().driver_low = reg;
+ }
+
+ QueueDriverLow(Virtio_device &device)
+ : Mmio_register("QueuDriverLow", Mmio_register::WO, 0x90, 4),
+ device(device) { }
+ } _queue_driver_low { *this };
+
+ struct QueueDriverHigh : Mmio_register
+ {
+ Virtio_device &device;
+
+ void write(Address_range&, Cpu&, Register reg) override
+ {
+ device._queue_data().driver_high = reg;
+ }
+
+ QueueDriverHigh(Virtio_device &device)
+ : Mmio_register("QueuDriverHigh", Mmio_register::WO, 0x94, 4),
+ device(device) { }
+ } _queue_driver_high { *this };
+
+ struct QueueDeviceLow : Mmio_register
+ {
+ Virtio_device &device;
+
+ void write(Address_range&, Cpu&, Register reg) override
+ {
+ device._queue_data().device_low = reg;
+ }
+
+ QueueDeviceLow(Virtio_device &device)
+ : Mmio_register("QueuDeviceLow", Mmio_register::WO, 0xa0, 4),
+ device(device) { }
+ } _queue_device_low { *this };
+
+ struct QueueDeviceHigh : Mmio_register
+ {
+ Virtio_device &device;
+
+ void write(Address_range&, Cpu&, Register reg) override
+ {
+ device._queue_data().device_high = reg;
+ }
+
+ QueueDeviceHigh(Virtio_device &device)
+ : Mmio_register("QueuDeviceHigh", Mmio_register::WO, 0xa4, 4),
+ device(device) { }
+ } _queue_device_high { *this };
+
+ struct InterruptStatus : Mmio_register
+ {
+ Register read(Address_range&, Cpu&) override
+ {
+ return value();
+ }
+
+ InterruptStatus()
+ : Mmio_register("InterruptStatus", Mmio_register::RO, 0x60, 4)
+ { }
+ } _interrupt_status;
+
+ struct InterruptAck : Mmio_register
+ {
+ Virtio_device &device;
+
+ void write(Address_range&, Cpu&, Register reg) override
+ {
+ device._deassert_irq();
+ }
+
+ InterruptAck(Virtio_device &device)
+ : Mmio_register("InterruptAck", Mmio_register::WO, 0x64, 4),
+ device(device) { }
+ } _interrupt_ack { *this };
+
+ public:
+
+ Virtio_device(const char * const name,
+ const uint64_t addr,
+ const uint64_t size,
+ unsigned irq,
+ Cpu &cpu,
+ Mmio_bus &bus,
+ Ram &ram,
+ unsigned queue_size = 8);
+};
+
+#endif /* _VIRTIO_DEVICE_H_ */
diff --git a/repos/os/src/server/vmm/spec/arm_v8/virtio_net.h b/repos/os/src/server/vmm/spec/arm_v8/virtio_net.h
new file mode 100644
index 0000000000..9ee1a7c981
--- /dev/null
+++ b/repos/os/src/server/vmm/spec/arm_v8/virtio_net.h
@@ -0,0 +1,138 @@
+/*
+ * \brief Virtio networking implementation
+ * \author Sebastian Sumpf
+ * \date 2019-10-10
+ */
+
+/*
+ * Copyright (C) 2019 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+#ifndef _VIRTIO_NET_H_
+#define _VIRTIO_NET_H_
+
+#include
+#include
+
+#include
+
+namespace Vmm
+{
+ class Virtio_net;
+}
+
+class Vmm::Virtio_net : public Virtio_device
+{
+ private:
+
+ Genode::Env &_env;
+
+ Genode::Heap _heap { _env.ram(), _env.rm() };
+ Genode::Allocator_avl _tx_alloc { &_heap };
+
+ enum { BUF_SIZE = Nic::Packet_allocator::DEFAULT_PACKET_SIZE * 128,
+ NIC_HEADER_SIZE = 12 };
+
+ Nic::Connection _nic { _env, &_tx_alloc, BUF_SIZE, BUF_SIZE };
+
+ Cpu::Signal_handler _handler;
+
+ void _free_packets()
+ {
+ while (_nic.tx()->ack_avail()) {
+ Nic::Packet_descriptor packet = _nic.tx()->get_acked_packet();
+ _nic.tx()->release_packet(packet);
+ }
+ }
+
+ void _rx()
+ {
+ /* RX */
+ auto recv = [&] (addr_t data, size_t size)
+ {
+ Nic::Packet_descriptor const rx_packet = _nic.rx()->get_packet();
+
+ size_t sz = Genode::min(size, rx_packet.size() + NIC_HEADER_SIZE);
+ Genode::memcpy((void *)(data + NIC_HEADER_SIZE),
+ _nic.rx()->packet_content(rx_packet),
+ sz);
+ _nic.rx()->acknowledge_packet(rx_packet);
+
+ return sz;
+ };
+
+ if (!_queue[RX].constructed()) return;
+
+ bool progress = false;
+ while (_nic.rx()->packet_avail() && _nic.rx()->ready_to_ack()) {
+ if (!_queue[RX]->notify(recv)) break;
+ progress = true;
+ }
+
+ if (progress) _assert_irq();
+ }
+
+ void _tx()
+ {
+ auto send = [&] (addr_t data, size_t size)
+ {
+ if (!_nic.tx()->ready_to_submit()) return 0lu;
+
+ data += NIC_HEADER_SIZE; size -= NIC_HEADER_SIZE;
+
+ Nic::Packet_descriptor tx_packet;
+ try {
+ tx_packet = _nic.tx()->alloc_packet(size); }
+ catch (Nic::Session::Tx::Source::Packet_alloc_failed) {
+ return 0lu; }
+
+ Genode::memcpy(_nic.tx()->packet_content(tx_packet),
+ (void *)data, size);
+ _nic.tx()->submit_packet(tx_packet);
+ return size;
+ };
+
+ if (!_queue[TX].constructed()) return;
+
+ if (_queue[TX]->notify(send)) _assert_irq();
+ _free_packets();
+ }
+
+ void _handle()
+ {
+ _rx();
+ _tx();
+ }
+
+ void _notify(unsigned /* idx */) override
+ {
+ _rx();
+ _tx();
+ }
+
+ public:
+
+ Virtio_net(const char * const name,
+ const uint64_t addr,
+ const uint64_t size,
+ unsigned irq,
+ Cpu &cpu,
+ Mmio_bus &bus,
+ Ram &ram,
+ Genode::Env &env)
+ : Virtio_device(name, addr, size, irq, cpu, bus, ram, 128),
+ _env(env),
+ _handler(cpu, _env.ep(), *this, &Virtio_net::_handle)
+ {
+ /* set device ID to network */
+ _device_id(0x1);
+
+ _nic.tx_channel()->sigh_ready_to_submit(_handler);
+ _nic.tx_channel()->sigh_ack_avail (_handler);
+ _nic.rx_channel()->sigh_ready_to_ack (_handler);
+ _nic.rx_channel()->sigh_packet_avail (_handler);
+ }
+};
+#endif /* _VIRTIO_NET_H_ */
diff --git a/repos/os/src/server/vmm/spec/arm_v8/vm.cc b/repos/os/src/server/vmm/spec/arm_v8/vm.cc
index abe2e8e358..26093ddfc6 100644
--- a/repos/os/src/server/vmm/spec/arm_v8/vm.cc
+++ b/repos/os/src/server/vmm/spec/arm_v8/vm.cc
@@ -49,7 +49,9 @@ Vmm::Cpu & Vm::boot_cpu()
Vm::Vm(Genode::Env & env)
: _env(env),
_gic("Gicv3", 0x8000000, 0x10000, _bus, env),
- _uart("Pl011", 0x9000000, 0x1000, 33, boot_cpu(), _bus, env)
+ _uart("Pl011", 0x9000000, 0x1000, 33, boot_cpu(), _bus, env),
+ _virtio_console("HVC", 0xa000000, 0x200, 48, boot_cpu(), _bus, _ram, env),
+ _virtio_net("Net", 0xa000200, 0x200, 49, boot_cpu(), _bus, _ram, env)
{
_vm.attach(_vm_ram.cap(), RAM_ADDRESS);
diff --git a/repos/os/src/server/vmm/spec/arm_v8/vm.h b/repos/os/src/server/vmm/spec/arm_v8/vm.h
index b1b78cbafa..29c76523cd 100644
--- a/repos/os/src/server/vmm/spec/arm_v8/vm.h
+++ b/repos/os/src/server/vmm/spec/arm_v8/vm.h
@@ -19,6 +19,8 @@
#include
#include
#include
+#include
+#include
#include
#include
@@ -48,7 +50,7 @@ class Vmm::Vm
Genode::Attached_rom_dataspace _dtb_rom { _env, "dtb" };
Genode::Attached_rom_dataspace _initrd_rom { _env, "initrd" };
Genode::Attached_ram_dataspace _vm_ram { _env.ram(), _env.rm(),
- RAM_SIZE, Genode::UNCACHED };
+ RAM_SIZE, Genode::CACHED };
Ram _ram { RAM_ADDRESS, RAM_SIZE,
(Genode::addr_t)_vm_ram.local_addr()};
Genode::Heap _heap { _env.ram(), _env.rm() };
@@ -57,6 +59,8 @@ class Vmm::Vm
Genode::Constructible _eps[MAX_CPUS];
Genode::Constructible _cpus[MAX_CPUS];
Pl011 _uart;
+ Virtio_console _virtio_console;
+ Virtio_net _virtio_net;
void _load_kernel();
void _load_dtb();