diff --git a/repos/os/run/vmm_arm.run b/repos/os/run/vmm_arm.run index cd4bc69b72..ed6298b782 100644 --- a/repos/os/run/vmm_arm.run +++ b/repos/os/run/vmm_arm.run @@ -150,7 +150,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.02/dtb-arm64-virt + exec >& /dev/null wget -c -O bin/dtb http://genode.org/files/release-20.11/dtb-arm64-virt-smp } if {![file exists bin/initrd]} { @@ -216,4 +216,4 @@ build_boot_image $boot_modules # append qemu_args " -nographic " run_genode_until "\[init -> vm\] .*sbin.*" 220 -exec rm bin/linux bin/dtb +exec rm bin/linux bin/dtb bin/initrd diff --git a/repos/os/src/server/vmm/cpu_base.cc b/repos/os/src/server/vmm/cpu_base.cc index 4ca063caaa..78a6d6440d 100644 --- a/repos/os/src/server/vmm/cpu_base.cc +++ b/repos/os/src/server/vmm/cpu_base.cc @@ -90,6 +90,7 @@ void Cpu_base::_handle_sync() { /* check device number*/ switch (Esr::Ec::get(_state.esr_el2)) { + case Esr::Ec::HVC_32: [[fallthrough]]; case Esr::Ec::HVC: _handle_hyper_call(); break; @@ -137,6 +138,7 @@ void Cpu_base::_handle_hyper_call() case Psci::PSCI_FEATURES: _state.reg(0, Psci::NOT_SUPPORTED); return; + case Psci::CPU_ON_32: [[fallthrough]]; case Psci::CPU_ON: _vm.cpu((unsigned)_state.reg(1), [&] (Cpu & cpu) { cpu.state().ip = _state.reg(2); diff --git a/repos/os/src/server/vmm/cpu_base.h b/repos/os/src/server/vmm/cpu_base.h index 1a4411dd8e..cfb5c0bff6 100644 --- a/repos/os/src/server/vmm/cpu_base.h +++ b/repos/os/src/server/vmm/cpu_base.h @@ -45,6 +45,7 @@ class Vmm::Cpu_base enum { WFI = 0x1, MRC_MCR = 0x3, + HVC_32 = 0x12, HVC = 0x16, MRS_MSR = 0x18, DA = 0x24, @@ -219,6 +220,10 @@ class Vmm::Cpu_base void _handle_data_abort(); void _handle_hyper_call(); void _update_state(); + + public: + + Vm & vm() { return _vm; } }; #endif /* _SRC__SERVER__VMM__CPU_BASE_H_ */ diff --git a/repos/os/src/server/vmm/generic_timer.cc b/repos/os/src/server/vmm/generic_timer.cc index c2eb4377ab..f0e77fbaa5 100644 --- a/repos/os/src/server/vmm/generic_timer.cc +++ b/repos/os/src/server/vmm/generic_timer.cc @@ -58,8 +58,9 @@ void Generic_timer::schedule_timeout() } if (_enabled()) { - if (_usecs_left()) { - _timeout.schedule(Genode::Microseconds(_usecs_left())); + Genode::uint64_t usecs = _usecs_left(); + if (usecs) { + _timeout.schedule(Genode::Microseconds(usecs)); } else _handle_timeout(Genode::Duration(Genode::Microseconds(0))); } } @@ -67,7 +68,7 @@ void Generic_timer::schedule_timeout() void Generic_timer::cancel_timeout() { - if (_timeout.scheduled()) _timeout.discard(); + if (_timeout.scheduled()) { _timeout.discard(); } } diff --git a/repos/os/src/server/vmm/gic.cc b/repos/os/src/server/vmm/gic.cc index a8671de8fc..25e67e5128 100644 --- a/repos/os/src/server/vmm/gic.cc +++ b/repos/os/src/server/vmm/gic.cc @@ -18,6 +18,13 @@ using Vmm::Gic; using Register = Vmm::Mmio_register::Register; +static Genode::Mutex & big_gic_lock() +{ + static Genode::Mutex mutex; + return mutex; +} + + bool Gic::Irq::enabled() const { return _enabled; } bool Gic::Irq::active() const { @@ -52,10 +59,10 @@ void Gic::Irq::disable() void Gic::Irq::activate() { switch (_state) { - case INACTIVE: return; - case PENDING: return; - case ACTIVE_PENDING: _state = PENDING; return; - case ACTIVE: _state = INACTIVE; return; + case INACTIVE: _state = ACTIVE; return; + case PENDING: _state = ACTIVE_PENDING; return; + case ACTIVE_PENDING: return; + case ACTIVE: return; }; } @@ -75,6 +82,8 @@ void Gic::Irq::assert() { if (pending()) return; + Genode::Mutex::Guard guard(big_gic_lock()); + _state = PENDING; _pending_list.insert(*this); } @@ -84,6 +93,8 @@ void Gic::Irq::deassert() { if (_state == INACTIVE) return; + Genode::Mutex::Guard guard(big_gic_lock()); + _state = INACTIVE; _pending_list.remove(this); if (_handler) _handler->eoi(); @@ -124,17 +135,17 @@ Gic::Irq::Irq(unsigned num, Type t, Irq::List & l) void Gic::Irq::List::insert(Irq & irq) { Irq * i = first(); - while (i && i->priority() < irq.priority() && i->next()) i = i->next(); + while (i && i->priority() <= irq.priority() && i->next()) i = i->next(); Genode::List::insert(&irq, i); } -Gic::Irq * Gic::Irq::List::highest_enabled() +Gic::Irq * Gic::Irq::List::highest_enabled(unsigned cpu_id) { - Irq * i = first(); - while(i) { - if (i->enabled()) return i; - i = i->next(); + for (Irq * i = first(); i; i = i->next()) { + if (!i->enabled() || i->active()) { continue; } + if (cpu_id < ~0U && (i->target() != cpu_id)) { continue; } + return i; } return nullptr; } @@ -165,6 +176,8 @@ void Gic::Gicd_banked::handle_irq() bool Gic::Gicd_banked::pending_irq() { + Genode::Mutex::Guard guard(big_gic_lock()); + if (_cpu.state().irqs.virtual_irq != SPURIOUS) return true; Irq * i = _gic._pending_list.highest_enabled(); @@ -202,6 +215,8 @@ Gic::Gicd_banked::Gicd_banked(Cpu_base & cpu, Gic & gic, Mmio_bus & bus) Register Gic::Irq_reg::read(Address_range & access, Cpu & cpu) { + Genode::Mutex::Guard guard(big_gic_lock()); + Register ret = 0; Register bits_per_irq = size * 8 / irq_count; @@ -214,6 +229,8 @@ Register Gic::Irq_reg::read(Address_range & access, Cpu & cpu) void Gic::Irq_reg::write(Address_range & access, Cpu & cpu, Register value) { + Genode::Mutex::Guard guard(big_gic_lock()); + Register bits_per_irq = size * 8 / irq_count; Register irq_value_mask = (1<= 0x20) { Irq_reg::write(access, cpu, value); } +} + + Gic::Gic(const char * const name, const Genode::uint64_t addr, const Genode::uint64_t size, diff --git a/repos/os/src/server/vmm/gic.h b/repos/os/src/server/vmm/gic.h index c7487d5583..1eec032795 100644 --- a/repos/os/src/server/vmm/gic.h +++ b/repos/os/src/server/vmm/gic.h @@ -47,7 +47,7 @@ class Vmm::Gic : public Vmm::Mmio_device struct List : Genode::List { void insert(Irq & irq); - Irq * highest_enabled(); + Irq * highest_enabled(unsigned cpu_id = ~0U); }; struct Irq_handler { @@ -92,7 +92,7 @@ class Vmm::Gic : public Vmm::Mmio_device Config _config { LEVEL }; unsigned _num { 0 }; Genode::uint8_t _prio { 0 }; - Genode::uint8_t _target { 1 }; + Genode::uint8_t _target { 0 }; List & _pending_list; Irq_handler * _handler { nullptr }; }; @@ -382,6 +382,9 @@ class Vmm::Gic : public Vmm::Mmio_device Register read(Irq & irq) { return irq.target(); } void write(Irq & irq, Register v) { irq.target(v); } + Register read(Address_range & access, Cpu&) override; + void write(Address_range & access, Cpu&, Register value) override; + Gicd_itargetr() : Irq_reg("GICD_ITARGETSR", Mmio_register::RW, 0x800, 8, 1024) {} } _itargetr; @@ -398,14 +401,14 @@ class Vmm::Gic : public Vmm::Mmio_device struct Gicd_sgir : Genode::Register<32>, Mmio_register { - struct Enable : Bitfield<0, 1> {}; - struct Disable : Bitfield<6, 1> {}; + struct Int_id : Bitfield<0, 4> {}; + struct Target_list : Bitfield<16, 8> {}; + struct Target_filter : Bitfield<24, 2> { + enum Target_type { LIST, ALL, MYSELF, INVALID }; + }; void write(Address_range & access, Cpu & cpu, - Mmio_register::Register value) override - { - Genode::error("SGIR WRITE ", value); - } + Mmio_register::Register value) override; Gicd_sgir() : Mmio_register("GICD_SGIR", Mmio_register::WO, 0xf00, 4, 0) {} @@ -414,8 +417,10 @@ class Vmm::Gic : public Vmm::Mmio_device struct Gicd_irouter : Irq_reg { - Register read(Irq &) { return 0x0; } // FIXME smp - void write(Irq &, Register) { } + Register read(Irq &) { return 0x0; } /* FIXME affinity routing support */ + + void write(Irq & i, Register v) { + if (v) Genode::error("Affinity routing not supported ", i.number()); } Gicd_irouter() : Irq_reg("GICD_IROUTER", Mmio_register::RW, 0x6100, 64, 1024) {} diff --git a/repos/os/src/server/vmm/psci.h b/repos/os/src/server/vmm/psci.h index ead06b8e34..04e93ac779 100644 --- a/repos/os/src/server/vmm/psci.h +++ b/repos/os/src/server/vmm/psci.h @@ -21,6 +21,7 @@ namespace Vmm { PSCI_VERSION = 0x84000000, MIGRATE_INFO_TYPE = 0x84000006, PSCI_FEATURES = 0x8400000a, + CPU_ON_32 = 0x84000003, CPU_ON = 0xc4000003, }; diff --git a/repos/os/src/server/vmm/spec/arm_v7/cpu.cc b/repos/os/src/server/vmm/spec/arm_v7/cpu.cc index 7b3f80fa5c..d441cd939c 100644 --- a/repos/os/src/server/vmm/spec/arm_v7/cpu.cc +++ b/repos/os/src/server/vmm/spec/arm_v7/cpu.cc @@ -186,4 +186,5 @@ Cpu::Cpu(Vm & vm, { _state.cpsr = 0x93; /* el1 mode and IRQs disabled */ _state.sctrl = 0xc50078; + _state.vmpidr = (1UL << 31) | cpu_id(); } 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 4701073e7a..81e3f34f7d 100755 --- a/repos/os/src/server/vmm/spec/arm_v7/virt.dts +++ b/repos/os/src/server/vmm/spec/arm_v7/virt.dts @@ -14,9 +14,18 @@ compatible = "arm,cortex-a15"; reg = <0x00>; device_type = "cpu"; + enable-method = "psci"; }; }; + psci { + compatible = "arm,psci-1.0"; + method = "hvc"; + cpu_suspend = <0xc4000001>; + cpu_off = <0xc4000002>; + cpu_on = <0xc4000003>; + }; + timer { interrupts = <0x01 0x0d 0x04 0x01 0x0e 0x04 0x01 0x0b 0x04 0x01 0x0a 0x04>; compatible = "arm,armv7-timer"; 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 96be06a496..ec9a1993d0 100644 --- a/repos/os/src/server/vmm/spec/arm_v8/board.h +++ b/repos/os/src/server/vmm/spec/arm_v8/board.h @@ -46,7 +46,7 @@ namespace Vmm { VTIMER_IRQ = 27, - MAX_CPUS = 1, + MAX_CPUS = 4, }; } 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 bda1efddd3..c455598d01 100755 --- a/repos/os/src/server/vmm/spec/arm_v8/virt.dts +++ b/repos/os/src/server/vmm/spec/arm_v8/virt.dts @@ -4,39 +4,75 @@ compatible = "linux,dummy-virt"; #address-cells = <0x02>; #size-cells = <0x02>; - interrupt-parent = <0x8001>; + interrupt-parent = <&gic>; cpus { #address-cells = <0x01>; #size-cells = <0x00>; cpu@0 { - compatible = "arm,cortex-a53"; - reg = <0x00>; - device_type = "cpu"; + compatible = "arm,cortex-a53"; + reg = <0x00>; + device_type = "cpu"; + enable-method = "psci"; }; + + cpu@1 { + compatible = "arm,cortex-a53"; + reg = <0x01>; + device_type = "cpu"; + enable-method = "psci"; + }; + + cpu@2 { + compatible = "arm,cortex-a53"; + reg = <0x02>; + device_type = "cpu"; + enable-method = "psci"; + }; + + cpu@3 { + compatible = "arm,cortex-a53"; + reg = <0x03>; + device_type = "cpu"; + enable-method = "psci"; + }; + }; + + psci { + compatible = "arm,psci-1.0"; + method = "hvc"; + cpu_suspend = <0xc4000001>; + cpu_off = <0xc4000002>; + cpu_on = <0xc4000003>; }; timer { interrupts = <0x01 0x0d 0x04 0x01 0x0e 0x04 0x01 0x0b 0x04 0x01 0x0a 0x04>; - compatible = "arm,armv8-timer\0arm,armv7-timer"; + compatible = "arm,armv8-timer", "arm,armv7-timer"; always-on; }; - apb-pclk { - compatible = "fixed-clock"; - phandle = <0x8000>; - clock-output-names = "clk24mhz"; - clock-frequency = <0x16e3600>; - #clock-cells = <0x00>; + clocks { + + #address-cells = <1>; + #size-cells = <0>; + + clk_24mhz: clk@0 { + compatible = "fixed-clock"; + clock-output-names = "clk24mhz"; + clock-frequency = <0x16e3600>; + #clock-cells = <0x00>; + reg = <0>; + }; }; pl011@9000000 { interrupts = <0x00 0x01 0x04>; - compatible = "arm,pl011\0arm,primecell"; - clock-names = "uartclk\0apb_pclk"; + compatible = "arm,pl011", "arm,primecell"; + clock-names = "uartclk", "apb_pclk"; reg = <0x00 0x9000000 0x00 0x1000>; - clocks = <0x8000 0x8000>; + clocks = <&clk_24mhz>, <&clk_24mhz>; }; memory@40000000 { @@ -45,17 +81,17 @@ }; chosen { - /* bootargs = "rdinit=/bin/sh console=hvc0 earlycon=pl011,0x9000000"; */ + /*bootargs = "rdinit=/bin/sh console=hvc0 earlycon=pl011,0x9000000";*/ bootargs = "init=/sbin/init ip=dhcp console=hvc0"; linux,initrd-start = <0x42000000>; linux,initrd-end = <0x420aa539>; stdout-path = "/pl011@9000000"; }; - intc@8000000 { + gic: intc@8000000 { compatible = "arm,gic-v3"; - phandle = <0x8001>; - reg = <0x00 0x8000000 0x00 0x10000 0x00 0x80a0000 0x00 0xf60000>; + reg = <0x00 0x8000000 0x00 0x10000>, + <0x00 0x80a0000 0x00 0xf60000>; ranges; #address-cells = <0x02>; #redistributor-regions = <0x01>; diff --git a/repos/os/src/server/vmm/virtio_console.h b/repos/os/src/server/vmm/virtio_console.h index 6cc5139fb5..c5f014fbf7 100644 --- a/repos/os/src/server/vmm/virtio_console.h +++ b/repos/os/src/server/vmm/virtio_console.h @@ -32,6 +32,8 @@ class Vmm::Virtio_console : public Virtio_device void _read() { + Genode::Mutex::Guard guard(_mutex); + auto read = [&] (addr_t data, size_t size) { if (!_terminal.avail()) return 0ul; @@ -61,6 +63,7 @@ class Vmm::Virtio_console : public Virtio_device } Register _device_specific_features() { return 0; } + public: Virtio_console(const char * const name, diff --git a/repos/os/src/server/vmm/virtio_device.h b/repos/os/src/server/vmm/virtio_device.h index 5ec1327db8..63fd3b0d0b 100644 --- a/repos/os/src/server/vmm/virtio_device.h +++ b/repos/os/src/server/vmm/virtio_device.h @@ -225,6 +225,7 @@ class Vmm::Virtio_device : public Vmm::Mmio_device Genode::Constructible _queue[NUM]; Gic::Irq &_irq; Ram &_ram; + Genode::Mutex _mutex; struct Dummy { Mmio_register regs[7]; @@ -344,6 +345,7 @@ class Vmm::Virtio_device : public Vmm::Mmio_device void write(Address_range&, Cpu&, Register reg) override { + Genode::Mutex::Guard guard(device.mutex()); if (reg >= device.NUM) return; device._queue_select(reg); } @@ -359,6 +361,7 @@ class Vmm::Virtio_device : public Vmm::Mmio_device void write(Address_range&, Cpu&, Register reg) override { + Genode::Mutex::Guard guard(device.mutex()); device._queue_data().num = Genode::min(reg, device._reg_container.regs[6].value()); } @@ -374,11 +377,13 @@ class Vmm::Virtio_device : public Vmm::Mmio_device Register read(Address_range&, Cpu&) override { + Genode::Mutex::Guard guard(device.mutex()); return device._queue_data().ready; } void write(Address_range&, Cpu&, Register reg) override { + Genode::Mutex::Guard guard(device.mutex()); bool construct = reg == 1 ? true : false; device._queue_data().ready = reg; device._queue_state(construct); @@ -395,6 +400,7 @@ class Vmm::Virtio_device : public Vmm::Mmio_device void write(Address_range&, Cpu&, Register reg) override { + Genode::Mutex::Guard guard(device.mutex()); if (!device._queue[reg].constructed()) return; device._notify(reg); @@ -411,6 +417,7 @@ class Vmm::Virtio_device : public Vmm::Mmio_device void write(Address_range&, Cpu&, Register reg) override { + Genode::Mutex::Guard guard(device.mutex()); device._queue_data().descr_low = reg; } @@ -425,6 +432,7 @@ class Vmm::Virtio_device : public Vmm::Mmio_device void write(Address_range&, Cpu&, Register reg) override { + Genode::Mutex::Guard guard(device.mutex()); device._queue_data().descr_high = reg; } @@ -439,6 +447,7 @@ class Vmm::Virtio_device : public Vmm::Mmio_device void write(Address_range&, Cpu&, Register reg) override { + Genode::Mutex::Guard guard(device.mutex()); device._queue_data().driver_low = reg; } @@ -453,6 +462,7 @@ class Vmm::Virtio_device : public Vmm::Mmio_device void write(Address_range&, Cpu&, Register reg) override { + Genode::Mutex::Guard guard(device.mutex()); device._queue_data().driver_high = reg; } @@ -467,6 +477,7 @@ class Vmm::Virtio_device : public Vmm::Mmio_device void write(Address_range&, Cpu&, Register reg) override { + Genode::Mutex::Guard guard(device.mutex()); device._queue_data().device_low = reg; } @@ -481,6 +492,7 @@ class Vmm::Virtio_device : public Vmm::Mmio_device void write(Address_range&, Cpu&, Register reg) override { + Genode::Mutex::Guard guard(device.mutex()); device._queue_data().device_high = reg; } @@ -507,6 +519,7 @@ class Vmm::Virtio_device : public Vmm::Mmio_device void write(Address_range&, Cpu&, Register reg) override { + Genode::Mutex::Guard guard(device.mutex()); device._deassert_irq(); } @@ -525,6 +538,8 @@ class Vmm::Virtio_device : public Vmm::Mmio_device Mmio_bus &bus, Ram &ram, unsigned queue_size = 8); + + Genode::Mutex & mutex() { return _mutex; } }; #endif /* _VIRTIO_DEVICE_H_ */ diff --git a/repos/os/src/server/vmm/virtio_net.h b/repos/os/src/server/vmm/virtio_net.h index d25ee2b991..c411093447 100644 --- a/repos/os/src/server/vmm/virtio_net.h +++ b/repos/os/src/server/vmm/virtio_net.h @@ -109,6 +109,8 @@ class Vmm::Virtio_net : public Virtio_device void _handle() { + Genode::Mutex::Guard guard(_mutex); + _rx(); _tx(); }