[PATCH 1/2] aarch64: support virtio mmio devices

2 views
Skip to first unread message

Waldemar Kozaczuk

unread,
Jul 14, 2020, 12:54:58 AM7/14/20
to osv...@googlegroups.com, Waldemar Kozaczuk
This is a pretty trivial patch that adds support of
virtio net and block devices over mmio for aarch64 architecture.
It accomplishes it by adding proper factory methods to register relevant
interrupt handlers.

Signed-off-by: Waldemar Kozaczuk <jwkoz...@gmail.com>
---
Makefile | 1 +
drivers/virtio-blk.cc | 10 +++++++++-
drivers/virtio-device.hh | 4 +++-
drivers/virtio-mmio.cc | 4 ++++
drivers/virtio-mmio.hh | 4 ++++
drivers/virtio-net.cc | 10 +++++++++-
6 files changed, 30 insertions(+), 3 deletions(-)

diff --git a/Makefile b/Makefile
index 2896f725..3c609a1c 100644
--- a/Makefile
+++ b/Makefile
@@ -822,6 +822,7 @@ drivers += drivers/pl011.o
drivers += drivers/xenconsole.o
drivers += drivers/virtio.o
drivers += drivers/virtio-pci-device.o
+drivers += drivers/virtio-mmio.o
drivers += drivers/virtio-vring.o
drivers += drivers/virtio-rng.o
drivers += drivers/virtio-blk.o
diff --git a/drivers/virtio-blk.cc b/drivers/virtio-blk.cc
index 87ef70f1..8845a093 100644
--- a/drivers/virtio-blk.cc
+++ b/drivers/virtio-blk.cc
@@ -144,7 +144,15 @@ blk::blk(virtio_device& virtio_dev)
[=] { t->wake(); });
};

-#ifndef AARCH64_PORT_STUB
+#ifdef AARCH64_PORT_STUB
+ int_factory.create_spi_edge_interrupt = [this,t]() {
+ return new spi_interrupt(
+ gic::irq_type::IRQ_TYPE_EDGE,
+ _dev.get_irq(),
+ [=] { return this->ack_irq(); },
+ [=] { t->wake(); });
+ };
+#else
int_factory.create_gsi_edge_interrupt = [this,t]() {
return new gsi_edge_interrupt(
_dev.get_irq(),
diff --git a/drivers/virtio-device.hh b/drivers/virtio-device.hh
index 732f9b18..be6de395 100644
--- a/drivers/virtio-device.hh
+++ b/drivers/virtio-device.hh
@@ -28,7 +28,9 @@ namespace virtio {
struct interrupt_factory {
std::function<void(interrupt_manager &)> register_msi_bindings = nullptr;
std::function<pci_interrupt *(pci::device &)> create_pci_interrupt = nullptr;
-#ifndef AARCH64_PORT_STUB
+#ifdef AARCH64_PORT_STUB
+ std::function<spi_interrupt *()> create_spi_edge_interrupt = nullptr;
+#else
std::function<gsi_edge_interrupt *()> create_gsi_edge_interrupt = nullptr;
#endif /* !AARCH64_PORT_STUB */
};
diff --git a/drivers/virtio-mmio.cc b/drivers/virtio-mmio.cc
index 36088ba1..b2f84d09 100644
--- a/drivers/virtio-mmio.cc
+++ b/drivers/virtio-mmio.cc
@@ -103,7 +103,11 @@ u8 mmio_device::read_config(u32 offset)

void mmio_device::register_interrupt(interrupt_factory irq_factory)
{
+#ifdef AARCH64_PORT_STUB
+ _irq.reset(irq_factory.create_spi_edge_interrupt());
+#else
_irq.reset(irq_factory.create_gsi_edge_interrupt());
+#endif
}

bool mmio_device::parse_config()
diff --git a/drivers/virtio-mmio.hh b/drivers/virtio-mmio.hh
index 0cbf7000..27632971 100644
--- a/drivers/virtio-mmio.hh
+++ b/drivers/virtio-mmio.hh
@@ -144,7 +144,11 @@ private:
u16 _device_id;

mmioaddr_t _addr_mmio;
+#ifdef AARCH64_PORT_STUB
+ std::unique_ptr<spi_interrupt> _irq;
+#else
std::unique_ptr<gsi_edge_interrupt> _irq;
+#endif
};

void parse_mmio_device_configuration(char *cmdline);
diff --git a/drivers/virtio-net.cc b/drivers/virtio-net.cc
index 31a32684..65265ca7 100644
--- a/drivers/virtio-net.cc
+++ b/drivers/virtio-net.cc
@@ -317,7 +317,15 @@ net::net(virtio_device& dev)
[=] { poll_task->wake(); });
};

-#ifndef AARCH64_PORT_STUB
+#ifdef AARCH64_PORT_STUB
+ int_factory.create_spi_edge_interrupt = [this,poll_task]() {
+ return new spi_interrupt(
+ gic::irq_type::IRQ_TYPE_EDGE,
+ _dev.get_irq(),
+ [=] { return this->ack_irq(); },
+ [=] { poll_task->wake(); });
+ };
+#else
int_factory.create_gsi_edge_interrupt = [this,poll_task]() {
return new gsi_edge_interrupt(
_dev.get_irq(),
--
2.26.2

Waldemar Kozaczuk

unread,
Jul 14, 2020, 12:55:07 AM7/14/20
to osv...@googlegroups.com, Waldemar Kozaczuk
The aarch64 version of firecracker (unlike the x64 one) passes
the configuration information of virtio devices using dtb.
This patch adds necessary logic to parse this information from dtb
and activate the relevant devices.

This patch effectively enables support of virtio net and block
devices on aarch64 version of firecracker.

Signed-off-by: Waldemar Kozaczuk <jwkoz...@gmail.com>
---
arch/aarch64/arch-dtb.cc | 46 ++++++++++++++++++++++++++++++++++++++
arch/aarch64/arch-dtb.hh | 7 ++++++
arch/aarch64/arch-setup.cc | 10 +++++++--
drivers/virtio-mmio.cc | 16 ++++++++++++-
drivers/virtio-mmio.hh | 5 +++++
5 files changed, 81 insertions(+), 3 deletions(-)

diff --git a/arch/aarch64/arch-dtb.cc b/arch/aarch64/arch-dtb.cc
index a0ec2acf..462d2fb9 100644
--- a/arch/aarch64/arch-dtb.cc
+++ b/arch/aarch64/arch-dtb.cc
@@ -16,6 +16,7 @@
#include <osv/mempool.hh>
#include <osv/commands.hh>
#include <osv/elf.hh>
+#include "drivers/virtio-mmio.hh"

#define DTB_INTERRUPT_CELLS 3

@@ -219,6 +220,49 @@ u64 dtb_get_mmio_serial_console(int *irqid)
return address;
}

+#define VIRTIO_MMIO_DEV_COMPAT "virtio,mmio"
+#define DTB_MAX_VIRTIO_MMIO_DEV_COUNT 8
+static virtio::mmio_device_info dtb_dtb_virtio_mmio_devices_infos[DTB_MAX_VIRTIO_MMIO_DEV_COUNT];
+static unsigned int dtb_virtio_mmio_dev_count;
+static void dtb_parse_mmio_virtio_devices()
+{
+ int node;
+ struct dtb_int_spec int_spec[1];
+
+ if (!dtb)
+ return;
+
+ dtb_virtio_mmio_dev_count = 0;
+ node = fdt_node_offset_by_compatible(dtb, -1, VIRTIO_MMIO_DEV_COMPAT);
+ while (node != -FDT_ERR_NOTFOUND && dtb_virtio_mmio_dev_count < DTB_MAX_VIRTIO_MMIO_DEV_COUNT) {
+ int value_size;
+ int required = 2 * sizeof(u64); // We expect two fields - address and length, each u64 size
+ u64 *reg = (u64 *)fdt_getprop(dtb, node, "reg", &value_size);
+ if (!reg || value_size < required) {
+ break;
+ }
+
+ dtb_dtb_virtio_mmio_devices_infos[dtb_virtio_mmio_dev_count]._address = fdt64_to_cpu(reg[0]);
+ dtb_dtb_virtio_mmio_devices_infos[dtb_virtio_mmio_dev_count]._size = fdt64_to_cpu(reg[1]);
+
+ if( !dtb_get_int_spec(node, int_spec, 1)) {
+ break;
+ };
+
+ dtb_dtb_virtio_mmio_devices_infos[dtb_virtio_mmio_dev_count++]._irq_no = int_spec[0].irq_id;
+
+ // Move to the next node
+ node = fdt_node_offset_by_compatible(dtb, node, VIRTIO_MMIO_DEV_COMPAT);
+ }
+}
+
+void dtb_collect_parsed_mmio_virtio_devices()
+{
+ for( unsigned int idx = 0; idx < dtb_virtio_mmio_dev_count; idx++) {
+ virtio::add_mmio_device_configuration(dtb_dtb_virtio_mmio_devices_infos[idx]);
+ }
+}
+
/* this gets the virtual timer irq, we are not interested
* about the other timers.
*/
@@ -653,6 +697,8 @@ void __attribute__((constructor(init_prio::dtb))) dtb_setup()
abort("dtb_setup: failed to parse pci_irq_map.\n");
}

+ dtb_parse_mmio_virtio_devices();
+
register u64 edata;
asm volatile ("adrp %0, .edata" : "=r"(edata));

diff --git a/arch/aarch64/arch-dtb.hh b/arch/aarch64/arch-dtb.hh
index a52c5160..7f2eb18d 100644
--- a/arch/aarch64/arch-dtb.hh
+++ b/arch/aarch64/arch-dtb.hh
@@ -57,6 +57,13 @@ u64 dtb_get_uart(int *irqid);
*/
u64 dtb_get_mmio_serial_console(int *irqid);

+/* dtb_collect_parsed_mmio_virtio_devices()
+ *
+ * collect and add any parsed mmio devices
+ * to be recognized and potentially recognized
+ */
+void dtb_collect_parsed_mmio_virtio_devices();
+
/* int gdb_get_timer_irq()
*
* returns the irqid of the virtual timer from the dtb,
diff --git a/arch/aarch64/arch-setup.cc b/arch/aarch64/arch-setup.cc
index 90eff282..351ac0da 100644
--- a/arch/aarch64/arch-setup.cc
+++ b/arch/aarch64/arch-setup.cc
@@ -118,6 +118,8 @@ void arch_setup_free_memory()
console::mmio_isa_serial_console::clean_cmdline(cmdline);
osv::parse_cmdline(cmdline);

+ dtb_collect_parsed_mmio_virtio_devices();
+
mmu::switch_to_runtime_page_tables();

console::mmio_isa_serial_console::memory_map();
@@ -147,6 +149,7 @@ void arch_init_premain()
#include "drivers/virtio-rng.hh"
#include "drivers/virtio-blk.hh"
#include "drivers/virtio-net.hh"
+#include "drivers/virtio-mmio.hh"

void arch_init_drivers()
{
@@ -168,10 +171,13 @@ void arch_init_drivers()
// Enumerate PCI devices
size_t pci_cfg_len;
if (pci::get_pci_cfg(&pci_cfg_len)) {
- pci::pci_device_enumeration();
- boot_time.event("pci enumerated");
+ pci::pci_device_enumeration();
+ boot_time.event("pci enumerated");
}

+ // Register any parsed virtio-mmio devices
+ virtio::register_mmio_devices(device_manager::instance());
+
// Initialize all drivers
hw::driver_manager* drvman = hw::driver_manager::instance();
drvman->register_driver(virtio::rng::probe);
diff --git a/drivers/virtio-mmio.cc b/drivers/virtio-mmio.cc
index b2f84d09..43db8130 100644
--- a/drivers/virtio-mmio.cc
+++ b/drivers/virtio-mmio.cc
@@ -140,6 +140,7 @@ bool mmio_device::parse_config()
return true;
}

+#ifndef AARCH64_PORT_STUB
#define VIRTIO_MMIO_DEVICE_CMDLINE_PREFIX "virtio_mmio.device="
static mmio_device_info* parse_mmio_device_info(char *cmdline)
{ //
@@ -190,18 +191,31 @@ static mmio_device_info* parse_mmio_device_info(char *cmdline)

return new mmio_device_info(address, size, irq);
}
+#endif

static std::vector<struct mmio_device_info> *mmio_device_info_entries = 0;

+#ifndef AARCH64_PORT_STUB
void parse_mmio_device_configuration(char *cmdline)
{ //
// We are assuming the mmio devices information is appended to the
// command line (at least it is the case with the firecracker) so
// once we parse those we strip it away so only plain OSv command line is left
- mmio_device_info_entries = new std::vector<struct mmio_device_info>();
+ if (!mmio_device_info_entries) {
+ mmio_device_info_entries = new std::vector<struct mmio_device_info>();
+ }
for( auto device_info = parse_mmio_device_info(cmdline); device_info != nullptr; device_info = parse_mmio_device_info(cmdline))
mmio_device_info_entries->push_back(*device_info);
}
+#else
+void add_mmio_device_configuration(mmio_device_info device_info)
+{
+ if (!mmio_device_info_entries) {
+ mmio_device_info_entries = new std::vector<struct mmio_device_info>();
+ }
+ mmio_device_info_entries->push_back(device_info);
+}
+#endif

void register_mmio_devices(hw::device_manager *dev_manager)
{
diff --git a/drivers/virtio-mmio.hh b/drivers/virtio-mmio.hh
index 27632971..98f8ad5b 100644
--- a/drivers/virtio-mmio.hh
+++ b/drivers/virtio-mmio.hh
@@ -92,6 +92,7 @@ namespace virtio {
struct mmio_device_info {
mmio_device_info(u64 address, u64 size, unsigned int irq) :
_address(address), _size(size), _irq_no(irq) {}
+ mmio_device_info() : mmio_device_info(0, 0, 0) {}

u64 _address;
u64 _size;
@@ -151,7 +152,11 @@ private:
#endif
};

+#ifndef AARCH64_PORT_STUB
void parse_mmio_device_configuration(char *cmdline);
+#else
+void add_mmio_device_configuration(mmio_device_info device_info);
+#endif
void register_mmio_devices(hw::device_manager *dev_manager);

}
--
2.26.2

Commit Bot

unread,
Jul 17, 2020, 4:54:12 PM7/17/20
to osv...@googlegroups.com, Waldemar Kozaczuk
From: Waldemar Kozaczuk <jwkoz...@gmail.com>
Committer: Waldemar Kozaczuk <jwkoz...@gmail.com>
Branch: master

aarch64: support virtio mmio devices

This is a pretty trivial patch that adds support of
virtio net and block devices over mmio for aarch64 architecture.
It accomplishes it by adding proper factory methods to register relevant
interrupt handlers.

Signed-off-by: Waldemar Kozaczuk <jwkoz...@gmail.com>

---
diff --git a/Makefile b/Makefile
--- a/Makefile
+++ b/Makefile
@@ -822,6 +822,7 @@ drivers += drivers/pl011.o
drivers += drivers/xenconsole.o
drivers += drivers/virtio.o
drivers += drivers/virtio-pci-device.o
+drivers += drivers/virtio-mmio.o
drivers += drivers/virtio-vring.o
drivers += drivers/virtio-rng.o
drivers += drivers/virtio-blk.o
diff --git a/drivers/virtio-blk.cc b/drivers/virtio-blk.cc
--- a/drivers/virtio-blk.cc
+++ b/drivers/virtio-blk.cc
@@ -144,7 +144,15 @@ blk::blk(virtio_device& virtio_dev)
[=] { t->wake(); });
};

-#ifndef AARCH64_PORT_STUB
+#ifdef AARCH64_PORT_STUB
+ int_factory.create_spi_edge_interrupt = [this,t]() {
+ return new spi_interrupt(
+ gic::irq_type::IRQ_TYPE_EDGE,
+ _dev.get_irq(),
+ [=] { return this->ack_irq(); },
+ [=] { t->wake(); });
+ };
+#else
int_factory.create_gsi_edge_interrupt = [this,t]() {
return new gsi_edge_interrupt(
_dev.get_irq(),
diff --git a/drivers/virtio-device.hh b/drivers/virtio-device.hh
--- a/drivers/virtio-device.hh
+++ b/drivers/virtio-device.hh
@@ -28,7 +28,9 @@ namespace virtio {
struct interrupt_factory {
std::function<void(interrupt_manager &)> register_msi_bindings = nullptr;
std::function<pci_interrupt *(pci::device &)> create_pci_interrupt = nullptr;
-#ifndef AARCH64_PORT_STUB
+#ifdef AARCH64_PORT_STUB
+ std::function<spi_interrupt *()> create_spi_edge_interrupt = nullptr;
+#else
std::function<gsi_edge_interrupt *()> create_gsi_edge_interrupt = nullptr;
#endif /* !AARCH64_PORT_STUB */
};
diff --git a/drivers/virtio-mmio.cc b/drivers/virtio-mmio.cc
--- a/drivers/virtio-mmio.cc
+++ b/drivers/virtio-mmio.cc
@@ -103,7 +103,11 @@ u8 mmio_device::read_config(u32 offset)

void mmio_device::register_interrupt(interrupt_factory irq_factory)
{
+#ifdef AARCH64_PORT_STUB
+ _irq.reset(irq_factory.create_spi_edge_interrupt());
+#else
_irq.reset(irq_factory.create_gsi_edge_interrupt());
+#endif
}

bool mmio_device::parse_config()
diff --git a/drivers/virtio-mmio.hh b/drivers/virtio-mmio.hh
--- a/drivers/virtio-mmio.hh
+++ b/drivers/virtio-mmio.hh
@@ -144,7 +144,11 @@ private:
u16 _device_id;

mmioaddr_t _addr_mmio;
+#ifdef AARCH64_PORT_STUB
+ std::unique_ptr<spi_interrupt> _irq;
+#else
std::unique_ptr<gsi_edge_interrupt> _irq;
+#endif
};

void parse_mmio_device_configuration(char *cmdline);
diff --git a/drivers/virtio-net.cc b/drivers/virtio-net.cc

Commit Bot

unread,
Jul 17, 2020, 4:54:14 PM7/17/20
to osv...@googlegroups.com, Waldemar Kozaczuk
From: Waldemar Kozaczuk <jwkoz...@gmail.com>
Committer: Waldemar Kozaczuk <jwkoz...@gmail.com>
Branch: master

aarch64: parse and activate virtio mmio devices

The aarch64 version of firecracker (unlike the x64 one) passes
the configuration information of virtio devices using dtb.
This patch adds necessary logic to parse this information from dtb
and activate the relevant devices.

This patch effectively enables support of virtio net and block
devices on aarch64 version of firecracker.

Signed-off-by: Waldemar Kozaczuk <jwkoz...@gmail.com>

---
diff --git a/arch/aarch64/arch-dtb.cc b/arch/aarch64/arch-dtb.cc
--- a/arch/aarch64/arch-dtb.hh
+++ b/arch/aarch64/arch-dtb.hh
@@ -57,6 +57,13 @@ u64 dtb_get_uart(int *irqid);
*/
u64 dtb_get_mmio_serial_console(int *irqid);

+/* dtb_collect_parsed_mmio_virtio_devices()
+ *
+ * collect and add any parsed mmio devices
+ * to be recognized and potentially recognized
+ */
+void dtb_collect_parsed_mmio_virtio_devices();
+
/* int gdb_get_timer_irq()
*
* returns the irqid of the virtual timer from the dtb,
diff --git a/arch/aarch64/arch-setup.cc b/arch/aarch64/arch-setup.cc
diff --git a/drivers/virtio-mmio.cc b/drivers/virtio-mmio.cc
--- a/drivers/virtio-mmio.cc
+++ b/drivers/virtio-mmio.cc
diff --git a/drivers/virtio-mmio.hh b/drivers/virtio-mmio.hh
--- a/drivers/virtio-mmio.hh
+++ b/drivers/virtio-mmio.hh
Reply all
Reply to author
Forward
0 new messages