diff options
author | Liav A <liavalb@gmail.com> | 2021-09-04 08:42:31 +0300 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-09-04 16:36:02 +0200 |
commit | ed6c1f53afbb6207450045b07552effa5335ceb1 (patch) | |
tree | db576e877f69cafedd27e5da4ada89e8c531058f /Kernel | |
parent | e490c17bdedf48ea252a1f9fe04b748e63cbd9b7 (diff) | |
download | serenity-ed6c1f53afbb6207450045b07552effa5335ceb1.zip |
Kernel/VirtIO: Defer initialization of device out of the constructor
This ensures we safely handle interrupts (which can call virtual
functions), so they don't happen in the constructor - this pattern can
lead to a crash, if we are still in the constructor context because
not all methods are available for usage (some are pure virtual,
so it's possible to call __cxa_pure_virtual).
Also, under some conditions like adding a PCI device via PCI-passthrough
mechanism in QEMU, it became exposed to the eye that the code asserts on
RNG::handle_device_config_change(). That device has no configuration but
if the hypervisor still misbehaves and tries to configure it, we should
simply return false to indicate nothing happened.
Diffstat (limited to 'Kernel')
-rw-r--r-- | Kernel/Bus/VirtIO/Console.cpp | 11 | ||||
-rw-r--r-- | Kernel/Bus/VirtIO/Console.h | 2 | ||||
-rw-r--r-- | Kernel/Bus/VirtIO/Device.cpp | 22 | ||||
-rw-r--r-- | Kernel/Bus/VirtIO/Device.h | 2 | ||||
-rw-r--r-- | Kernel/Bus/VirtIO/RNG.cpp | 11 | ||||
-rw-r--r-- | Kernel/Bus/VirtIO/RNG.h | 2 | ||||
-rw-r--r-- | Kernel/Graphics/VirtIOGPU/GPU.cpp | 11 | ||||
-rw-r--r-- | Kernel/Graphics/VirtIOGPU/GPU.h | 2 | ||||
-rw-r--r-- | Kernel/Graphics/VirtIOGPU/GraphicsAdapter.cpp | 1 |
9 files changed, 47 insertions, 17 deletions
diff --git a/Kernel/Bus/VirtIO/Console.cpp b/Kernel/Bus/VirtIO/Console.cpp index 1dc38fc1f9..38e695a07d 100644 --- a/Kernel/Bus/VirtIO/Console.cpp +++ b/Kernel/Bus/VirtIO/Console.cpp @@ -17,10 +17,9 @@ UNMAP_AFTER_INIT NonnullRefPtr<Console> Console::must_create(PCI::Address addres return adopt_ref_if_nonnull(new Console(address)).release_nonnull(); } -UNMAP_AFTER_INIT Console::Console(PCI::Address address) - : VirtIO::Device(address) - , m_device_id(next_device_id++) +UNMAP_AFTER_INIT void Console::initialize() { + Device::initialize(); if (auto cfg = get_config(ConfigurationType::Device)) { bool success = negotiate_features([&](u64 supported_features) { u64 negotiated = 0; @@ -58,6 +57,12 @@ UNMAP_AFTER_INIT Console::Console(PCI::Address address) } } +UNMAP_AFTER_INIT Console::Console(PCI::Address address) + : VirtIO::Device(address) + , m_device_id(next_device_id++) +{ +} + bool Console::handle_device_config_change() { dbgln("VirtIO::Console: Handle device config change"); diff --git a/Kernel/Bus/VirtIO/Console.h b/Kernel/Bus/VirtIO/Console.h index 3a303166ff..77d0b1c285 100644 --- a/Kernel/Bus/VirtIO/Console.h +++ b/Kernel/Bus/VirtIO/Console.h @@ -28,6 +28,8 @@ public: return m_device_id; } + virtual void initialize() override; + private: virtual StringView class_name() const override { return "VirtIOConsole"; } explicit Console(PCI::Address); diff --git a/Kernel/Bus/VirtIO/Device.cpp b/Kernel/Bus/VirtIO/Device.cpp index 9ea6ca2b65..fad217e65e 100644 --- a/Kernel/Bus/VirtIO/Device.cpp +++ b/Kernel/Bus/VirtIO/Device.cpp @@ -25,11 +25,13 @@ UNMAP_AFTER_INIT void detect() return; switch (id.device_id) { case PCI::DeviceID::VirtIOConsole: { - [[maybe_unused]] auto& unused = Console::must_create(address).leak_ref(); + auto& console = Console::must_create(address).leak_ref(); + console.initialize(); break; } case PCI::DeviceID::VirtIOEntropy: { - [[maybe_unused]] auto& unused = RNG::must_create(address).leak_ref(); + auto& rng = RNG::must_create(address).leak_ref(); + rng.initialize(); break; } case PCI::DeviceID::VirtIOGPU: { @@ -60,13 +62,9 @@ StringView determine_device_class(const PCI::Address& address) VERIFY_NOT_REACHED(); } -UNMAP_AFTER_INIT VirtIO::Device::Device(PCI::Address address) - : PCI::Device(address) - , IRQHandler(PCI::get_interrupt_line(address)) - , m_io_base(IOAddress(PCI::get_BAR0(pci_address()) & ~1)) +UNMAP_AFTER_INIT void Device::initialize() { - dbgln("{}: Found @ {}", VirtIO::determine_device_class(address), pci_address()); - + auto address = pci_address(); enable_bus_mastering(pci_address()); PCI::enable_interrupt_line(pci_address()); enable_irq(); @@ -116,6 +114,14 @@ UNMAP_AFTER_INIT VirtIO::Device::Device(PCI::Address address) set_status_bit(DEVICE_STATUS_DRIVER); } +UNMAP_AFTER_INIT VirtIO::Device::Device(PCI::Address address) + : PCI::Device(address) + , IRQHandler(PCI::get_interrupt_line(address)) + , m_io_base(IOAddress(PCI::get_BAR0(pci_address()) & ~1)) +{ + dbgln("{}: Found @ {}", VirtIO::determine_device_class(address), pci_address()); +} + auto Device::mapping_for_bar(u8 bar) -> MappedMMIO& { VERIFY(m_use_mmio); diff --git a/Kernel/Bus/VirtIO/Device.h b/Kernel/Bus/VirtIO/Device.h index 54d9964ef0..6a2d6b3e0e 100644 --- a/Kernel/Bus/VirtIO/Device.h +++ b/Kernel/Bus/VirtIO/Device.h @@ -90,6 +90,8 @@ class Device public: virtual ~Device() override = default; + virtual void initialize(); + protected: virtual StringView class_name() const = 0; explicit Device(PCI::Address); diff --git a/Kernel/Bus/VirtIO/RNG.cpp b/Kernel/Bus/VirtIO/RNG.cpp index bccf375949..c98bdb5316 100644 --- a/Kernel/Bus/VirtIO/RNG.cpp +++ b/Kernel/Bus/VirtIO/RNG.cpp @@ -14,9 +14,9 @@ UNMAP_AFTER_INIT NonnullRefPtr<RNG> RNG::must_create(PCI::Address address) return adopt_ref_if_nonnull(new RNG(address)).release_nonnull(); } -UNMAP_AFTER_INIT RNG::RNG(PCI::Address address) - : VirtIO::Device(address) +UNMAP_AFTER_INIT void RNG::initialize() { + Device::initialize(); bool success = negotiate_features([&](auto) { return 0; }); @@ -33,9 +33,14 @@ UNMAP_AFTER_INIT RNG::RNG(PCI::Address address) } } +UNMAP_AFTER_INIT RNG::RNG(PCI::Address address) + : VirtIO::Device(address) +{ +} + bool RNG::handle_device_config_change() { - VERIFY_NOT_REACHED(); // Device has no config + return false; // Device has no config } void RNG::handle_queue_update(u16 queue_index) diff --git a/Kernel/Bus/VirtIO/RNG.h b/Kernel/Bus/VirtIO/RNG.h index ac0c92d719..c1e6d3c440 100644 --- a/Kernel/Bus/VirtIO/RNG.h +++ b/Kernel/Bus/VirtIO/RNG.h @@ -23,6 +23,8 @@ public: virtual StringView purpose() const override { return class_name(); } virtual ~RNG() override = default; + virtual void initialize() override; + private: virtual StringView class_name() const override { return "VirtIOConsole"; } explicit RNG(PCI::Address); diff --git a/Kernel/Graphics/VirtIOGPU/GPU.cpp b/Kernel/Graphics/VirtIOGPU/GPU.cpp index cf79a438b1..3513b38067 100644 --- a/Kernel/Graphics/VirtIOGPU/GPU.cpp +++ b/Kernel/Graphics/VirtIOGPU/GPU.cpp @@ -15,10 +15,9 @@ namespace Kernel::Graphics::VirtIOGPU { -GPU::GPU(PCI::Address address) - : VirtIO::Device(address) - , m_scratch_space(MM.allocate_contiguous_kernel_region(32 * PAGE_SIZE, "VirtGPU Scratch Space", Memory::Region::Access::ReadWrite)) +void GPU::initialize() { + Device::initialize(); VERIFY(!!m_scratch_space); if (auto cfg = get_config(VirtIO::ConfigurationType::Device)) { m_device_configuration = cfg; @@ -47,6 +46,12 @@ GPU::GPU(PCI::Address address) } } +GPU::GPU(PCI::Address address) + : VirtIO::Device(address) + , m_scratch_space(MM.allocate_contiguous_kernel_region(32 * PAGE_SIZE, "VirtGPU Scratch Space", Memory::Region::Access::ReadWrite)) +{ +} + GPU::~GPU() { } diff --git a/Kernel/Graphics/VirtIOGPU/GPU.h b/Kernel/Graphics/VirtIOGPU/GPU.h index de56a8fa8a..0427eba006 100644 --- a/Kernel/Graphics/VirtIOGPU/GPU.h +++ b/Kernel/Graphics/VirtIOGPU/GPU.h @@ -57,6 +57,8 @@ public: return IterationDecision::Continue; } + virtual void initialize() override; + RefPtr<Console> default_console() { if (m_default_scanout.has_value()) diff --git a/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.cpp b/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.cpp index 6fcecdf973..7e17d83304 100644 --- a/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.cpp +++ b/Kernel/Graphics/VirtIOGPU/GraphicsAdapter.cpp @@ -22,6 +22,7 @@ GraphicsAdapter::GraphicsAdapter(PCI::Address base_address) : PCI::Device(base_address) { m_gpu_device = adopt_ref(*new GPU(base_address)).leak_ref(); + m_gpu_device->initialize(); } void GraphicsAdapter::initialize_framebuffer_devices() |