diff --git a/repos/os/recipes/src/vmm/content.mk b/repos/os/recipes/src/vmm/content.mk
new file mode 100644
index 0000000000..4988150987
--- /dev/null
+++ b/repos/os/recipes/src/vmm/content.mk
@@ -0,0 +1,2 @@
+SRC_DIR = src/server/vmm
+include $(GENODE_DIR)/repos/base/recipes/src/content.inc
diff --git a/repos/os/recipes/src/vmm/hash b/repos/os/recipes/src/vmm/hash
new file mode 100644
index 0000000000..3e529f8cc6
--- /dev/null
+++ b/repos/os/recipes/src/vmm/hash
@@ -0,0 +1 @@
+2021-02-19 d3b2bfd047b47215092d5fad951ab172b3fcb468
diff --git a/repos/os/recipes/src/vmm/used_apis b/repos/os/recipes/src/vmm/used_apis
new file mode 100644
index 0000000000..2e642939a5
--- /dev/null
+++ b/repos/os/recipes/src/vmm/used_apis
@@ -0,0 +1,7 @@
+base-hw
+base
+block_session
+nic_session
+os
+terminal_session
+timer_session
diff --git a/repos/os/run/vmm_arm.run b/repos/os/run/vmm_arm.run
index 83a810c5a5..d5b5e54bbe 100644
--- a/repos/os/run/vmm_arm.run
+++ b/repos/os/run/vmm_arm.run
@@ -12,16 +12,18 @@ if { ![have_board imx7d_sabre] && ![have_board imx8q_evk] &&
exit 0
}
-set build_components {
- core init timer
- server/terminal_crosslink
- test/terminal_expect_send
- server/log_terminal
- server/nic_router
- server/vmm
-}
-build $build_components
create_boot_directory
+import_from_depot [depot_user]/src/[base_src] \
+ [depot_user]/src/init \
+ [depot_user]/src/libc \
+ [depot_user]/src/log_terminal \
+ [depot_user]/src/nic_router \
+ [depot_user]/src/terminal_crosslink \
+ [depot_user]/src/vfs \
+ [depot_user]/src/vfs_block \
+ [depot_user]/src/vmm
+
+build { test/terminal_expect_send }
install_config {
@@ -39,10 +41,12 @@ install_config {
+
+
@@ -57,14 +61,29 @@ install_config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -74,10 +93,11 @@ install_config {
+
-
+
@@ -96,7 +116,7 @@ if { [have_spec arm] } {
if {![file exists bin/dtb]} {
puts "Download device tree blob ..."
- exec >& /dev/null wget -c -O bin/dtb http://genode.org/files/release-20.05/dtb-arm32-virt
+ exec >& /dev/null wget -c -O bin/dtb http://genode.org/files/release-21.02/dtb-arm32-virt
}
if {![file exists bin/initrd]} {
@@ -153,7 +173,7 @@ if { [have_spec arm_64] } {
if {![file exists bin/dtb]} {
puts "Download device tree blob ..."
- exec >& /dev/null wget -c -O bin/dtb http://genode.org/files/release-20.11/dtb-arm64-virt-smp
+ exec >& /dev/null wget -c -O bin/dtb http://genode.org/files/release-21.02/dtb-arm64-virt-smp
}
if {![file exists bin/initrd]} {
@@ -200,23 +220,21 @@ if { [have_spec arm_64] } {
# find . | cpio -H newc -o | gzip > ../initrd
}
-set boot_modules {
- core ld.lib.so init
- timer
- terminal_crosslink
+catch { exec [installed_command dd] if=/dev/zero of=bin/block.img bs=1M count=0 seek=64 }
+exec [installed_command mkfs.vfat] bin/block.img
+
+build_boot_image {
test-terminal_expect_send
- nic_router
- log_terminal
- vmm
linux
dtb
initrd
+ block.img
}
-build_boot_image $boot_modules
#
# Execute test case
#
append qemu_args " -nographic "
-run_genode_until "\[init -> vm\] .*sbin.*" 220
-exec rm bin/linux bin/dtb bin/initrd
+
+run_genode_until "\[init -> vm\] .*resolv.conf.*" 220
+exec rm bin/linux bin/dtb bin/initrd bin/block.img
diff --git a/repos/os/src/server/vmm/spec/arm_v7/board.h b/repos/os/src/server/vmm/spec/arm_v7/board.h
index da0a557848..32d533d72d 100644
--- a/repos/os/src/server/vmm/spec/arm_v7/board.h
+++ b/repos/os/src/server/vmm/spec/arm_v7/board.h
@@ -41,6 +41,10 @@ namespace Vmm {
VIRTIO_NET_MMIO_SIZE = 0x200,
VIRTIO_NET_IRQ = 49,
+ VIRTIO_BLK_MMIO_START = 0xa000400,
+ VIRTIO_BLK_MMIO_SIZE = 0x200,
+ VIRTIO_BLK_IRQ = 50,
+
RAM_START = 0x40000000,
RAM_SIZE = 128 * 1024 *1024,
diff --git a/repos/os/src/server/vmm/spec/arm_v7/virt.dts b/repos/os/src/server/vmm/spec/arm_v7/virt.dts
index 81e3f34f7d..4007ed7cb9 100755
--- a/repos/os/src/server/vmm/spec/arm_v7/virt.dts
+++ b/repos/os/src/server/vmm/spec/arm_v7/virt.dts
@@ -86,4 +86,11 @@
dma-coherent;
reg = <0x00 0xa000200 0x00 0x200>;
};
+
+ virtio_mmio@a000400 {
+ interrupts = <0x00 0x12 0x01>;
+ compatible = "virtio,mmio";
+ dma-coherent;
+ reg = <0x00 0xa000400 0x00 0x200>;
+ };
};
diff --git a/repos/os/src/server/vmm/spec/arm_v8/board.h b/repos/os/src/server/vmm/spec/arm_v8/board.h
index ec9a1993d0..9f17addb85 100644
--- a/repos/os/src/server/vmm/spec/arm_v8/board.h
+++ b/repos/os/src/server/vmm/spec/arm_v8/board.h
@@ -41,6 +41,10 @@ namespace Vmm {
VIRTIO_NET_MMIO_SIZE = 0x200,
VIRTIO_NET_IRQ = 49,
+ VIRTIO_BLK_MMIO_START = 0xa000400,
+ VIRTIO_BLK_MMIO_SIZE = 0x200,
+ VIRTIO_BLK_IRQ = 50,
+
RAM_START = 0x40000000,
RAM_SIZE = 128 * 1024 *1024,
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 c455598d01..7c29c669d0 100755
--- a/repos/os/src/server/vmm/spec/arm_v8/virt.dts
+++ b/repos/os/src/server/vmm/spec/arm_v8/virt.dts
@@ -114,4 +114,11 @@
dma-coherent;
reg = <0x00 0xa000200 0x00 0x200>;
};
+
+ virtio_mmio@a000400 {
+ interrupts = <0x00 0x12 0x01>;
+ compatible = "virtio,mmio";
+ dma-coherent;
+ reg = <0x00 0xa000400 0x00 0x200>;
+ };
};
diff --git a/repos/os/src/server/vmm/virtio_block.h b/repos/os/src/server/vmm/virtio_block.h
new file mode 100644
index 0000000000..e0ec30a69a
--- /dev/null
+++ b/repos/os/src/server/vmm/virtio_block.h
@@ -0,0 +1,284 @@
+/*
+ * \brief Virtio Block implementation
+ * \author Stefan Kalkowski
+ * \date 2020-12-22
+ */
+
+/*
+ * Copyright (C) 2020 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_BLOCK_H_
+#define _VIRTIO_BLOCK_H_
+
+#include
+#include
+
+#include
+
+namespace Vmm
+{
+ class Virtio_block_queue;
+ class Virtio_block_request;
+ class Virtio_block_device;
+
+ using namespace Genode;
+}
+
+
+class Vmm::Virtio_block_queue : public Virtio_split_queue
+{
+ private:
+
+ Ring_index _used_idx;
+
+ friend class Virtio_block_request;
+ friend class Virtio_block_device;
+
+ public:
+
+ using Virtio_split_queue::Virtio_split_queue;
+
+ template
+ bool notify(FUNC func)
+ {
+ memory_barrier();
+ for (Ring_index avail_idx = _avail.current();
+ _cur_idx != avail_idx; _cur_idx.inc()) {
+ func(_avail.get(_cur_idx), _descriptors, _ram);
+ }
+ return false;
+ }
+
+ void ack(Descriptor_index id, size_t written)
+ {
+ _used.add(_used_idx, id, written);
+ _used_idx.inc();
+ _used.write(_used_idx.idx());
+ memory_barrier();
+ }
+};
+
+
+class Vmm::Virtio_block_request
+{
+ public:
+
+ struct Invalid_request : Genode::Exception {};
+
+ private:
+
+ using Index = Virtio_block_queue::Descriptor_index;
+ using Descriptor = Virtio_block_queue::Descriptor;
+ using Descriptor_array = Virtio_block_queue::Descriptor_array;
+
+ struct Request
+ {
+ enum Type {
+ READ = 0,
+ WRITE = 1,
+ FLUSH = 4,
+ DISCARD = 11,
+ WRITE_ZEROES = 13,
+ };
+
+ uint32_t type;
+ uint32_t reserved;
+ uint64_t sector;
+ };
+
+ enum Status { OK, IO_ERROR, UNSUPPORTED };
+
+ Index _next(Descriptor & desc) {
+ if (!Descriptor::Flags::Next::get(desc.flags())) {
+ throw Invalid_request(); }
+ return desc.next();
+ }
+
+ Descriptor_array & _array;
+ Ram & _ram;
+
+ template
+ T * _desc_addr(Descriptor const & desc) const {
+ return (T*) _ram.local_address(desc.address(),
+ desc.length()); }
+
+ Index _request_idx;
+ Descriptor _request { _array.get(_request_idx) };
+ Request & _vbr { *_desc_addr(_request) };
+ Index _data_idx { _next(_request) };
+ Descriptor _data { _array.get(_data_idx) };
+ Index _status_idx { _next(_data) };
+ Descriptor _status { _array.get(_status_idx) };
+ size_t _written { 0 };
+
+ bool _write() const { return _vbr.type == Request::WRITE; }
+
+ public:
+
+ Virtio_block_request(Index id,
+ Descriptor_array & array,
+ Ram & ram)
+ : _array(array), _ram(ram), _request_idx(id)
+ {
+ if (_request.length() != sizeof(Request) ||
+ _status.length() != sizeof(uint8_t)) {
+ throw Invalid_request(); }
+ }
+
+ Block::Operation const operation(Block::Session::Info & info) const
+ {
+ if (_vbr.type != Request::READ && _vbr.type != Request::WRITE) {
+ throw Invalid_request(); }
+
+ size_t sz = _data.length();
+
+ Block::Operation const op {
+ .type = _write() ? Block::Operation::Type::WRITE
+ : Block::Operation::Type::READ,
+ .block_number = (_vbr.sector * 512) / info.block_size,
+ .count = (sz(_data); }
+ size_t size() const { return _data.length(); }
+ void written_to_descriptor(size_t sz) { _written = sz; }
+
+ void done(Virtio_block_queue & queue)
+ {
+ *_desc_addr(_status) = OK;
+ queue.ack(_request_idx, _written);
+ }
+};
+
+
+class Vmm::Virtio_block_device
+: public Virtio_device
+{
+ private:
+
+ using Index = Virtio_block_queue::Descriptor_index;
+ using Descriptor_array = Virtio_block_queue::Descriptor_array;
+
+ enum Queue_idx { REQUEST };
+
+ enum { BLOCK_BUFFER_SIZE = 1024*1024 };
+
+ struct Job : Virtio_block_request,
+ Block::Connection::Job
+ {
+ Job(Block::Connection & con,
+ Block::Session::Info & info,
+ Virtio_block_device::Index id,
+ Virtio_block_device::Descriptor_array & array,
+ Ram & ram)
+ : Virtio_block_request(id, array, ram),
+ Block::Connection::Job(con, Virtio_block_request::operation(info)) {}
+ };
+
+ Heap & _heap;
+ Allocator_avl _block_alloc { &_heap };
+ Block::Connection _block;
+ Block::Session::Info _block_info { _block.info() };
+ Cpu::Signal_handler _handler;
+
+ void _block_signal()
+ {
+ Genode::Mutex::Guard guard(_mutex);
+ _block.update_jobs(*this);
+ }
+
+ void _notify(unsigned idx) override
+ {
+ auto lambda = [&] (Index id,
+ Descriptor_array & array,
+ Ram & ram)
+ {
+ try {
+ new (_heap) Job(_block, _block_info, id, array, ram);
+ _block.update_jobs(*this);
+ } catch(Virtio_block_request::Invalid_request &) {
+ error("Invalid block request ignored!");
+ }
+ return 0;
+ };
+
+ _queue[REQUEST]->notify(lambda);
+ }
+
+ enum Device_id { BLOCK = 2 };
+
+ struct Configuration_area : Mmio_register
+ {
+ uint64_t capacity;
+
+ Register read(Address_range& range, Cpu&) override
+ {
+ if (range.start == 0 && range.size == 4)
+ return capacity & 0xffffffff;
+
+ if (range.start == 4 && range.size == 4)
+ return capacity >> 32;
+
+ throw Exception("Invalid read access of configuration area ",
+ range);
+ }
+
+ Configuration_area(Virtio_block_device & device, uint64_t capacity)
+ : Mmio_register("Configuration_area", Mmio_register::RO, 0x100, 8),
+ capacity(capacity) { device.add(*this); }
+ } _config_area{ *this, _block_info.block_count *
+ (_block_info.block_size / 512) };
+
+ public:
+
+ Virtio_block_device(const char * const name,
+ const uint64_t addr,
+ const uint64_t size,
+ unsigned irq,
+ Cpu & cpu,
+ Mmio_bus & bus,
+ Ram & ram,
+ Env & env,
+ Heap & heap)
+ : Virtio_device(name, addr, size,
+ irq, cpu, bus, ram, BLOCK),
+ _heap(heap),
+ _block(env, &_block_alloc, BLOCK_BUFFER_SIZE),
+ _handler(cpu, env.ep(), *this, &Virtio_block_device::_block_signal) {
+ _block.sigh(_handler); }
+
+
+ /*****************************************************
+ ** Block::Connection::Update_jobs_policy interface **
+ *****************************************************/
+
+ void produce_write_content(Job & job, off_t offset,
+ char *dst, size_t length)
+ {
+ size_t sz = Genode::min(length,job.size());
+ memcpy(dst, job.address(), sz);
+ job.written_to_descriptor(sz);
+ }
+
+ void consume_read_result(Job & job, off_t offset,
+ char const *src, size_t length)
+ {
+ size_t sz = Genode::min(length,job.size());
+ memcpy(job.address(), src, sz);
+ }
+
+ void completed(Job &job, bool success)
+ {
+ job.done(*_queue[REQUEST]);
+ _assert_irq();
+ destroy(_heap, &job);
+ }
+};
+
+#endif /* _VIRTIO_BLOCK_H_ */
diff --git a/repos/os/src/server/vmm/vm.cc b/repos/os/src/server/vmm/vm.cc
index bfd9b31d17..207b7b32f0 100644
--- a/repos/os/src/server/vmm/vm.cc
+++ b/repos/os/src/server/vmm/vm.cc
@@ -55,7 +55,9 @@ Vm::Vm(Genode::Env & env)
_virtio_console("HVC", VIRTIO_CONSOLE_MMIO_START, VIRTIO_CONSOLE_MMIO_SIZE,
VIRTIO_CONSOLE_IRQ, boot_cpu(), _bus, _ram, env),
_virtio_net("Net", VIRTIO_NET_MMIO_START, VIRTIO_NET_MMIO_SIZE,
- VIRTIO_NET_IRQ, boot_cpu(), _bus, _ram, env)
+ VIRTIO_NET_IRQ, boot_cpu(), _bus, _ram, env),
+ _virtio_block("Block", VIRTIO_BLK_MMIO_START, VIRTIO_BLK_MMIO_SIZE,
+ VIRTIO_BLK_IRQ, boot_cpu(), _bus, _ram, env, _heap)
{
_vm.attach(_vm_ram.cap(), RAM_START);
diff --git a/repos/os/src/server/vmm/vm.h b/repos/os/src/server/vmm/vm.h
index 8b2819d811..6e11b97a56 100644
--- a/repos/os/src/server/vmm/vm.h
+++ b/repos/os/src/server/vmm/vm.h
@@ -22,6 +22,7 @@
#include
#include
#include
+#include
#include
#include
@@ -54,6 +55,7 @@ class Vmm::Vm
Pl011 _uart;
Virtio_console _virtio_console;
Virtio_net _virtio_net;
+ Virtio_block_device _virtio_block;
void _load_kernel();
void _load_dtb();