From 102186b0f5acd34ccbbc0960613bd6a916b9ba39 Mon Sep 17 00:00:00 2001 From: Liav A Date: Sat, 17 Dec 2022 21:43:11 +0200 Subject: [PATCH] Kernel/Net: Allocate regions before invoking Intel driver constructors Instead of allocating after the construction point ensure that all Intel drivers are allocating necessary buffer regions and then pass them to the constructors. This could let us fail early in case of OOM, so we don't touch a network adapter before we ensure we have all the appropriate mappings in place. --- Kernel/Net/Intel/E1000ENetworkAdapter.cpp | 27 ++++++++++++++++--- Kernel/Net/Intel/E1000ENetworkAdapter.h | 5 +++- Kernel/Net/Intel/E1000NetworkAdapter.cpp | 32 ++++++++++++++++------- Kernel/Net/Intel/E1000NetworkAdapter.h | 17 ++++++++---- 4 files changed, 62 insertions(+), 19 deletions(-) diff --git a/Kernel/Net/Intel/E1000ENetworkAdapter.cpp b/Kernel/Net/Intel/E1000ENetworkAdapter.cpp index 395416d1a71..c10bad3966c 100644 --- a/Kernel/Net/Intel/E1000ENetworkAdapter.cpp +++ b/Kernel/Net/Intel/E1000ENetworkAdapter.cpp @@ -190,7 +190,20 @@ UNMAP_AFTER_INIT ErrorOr> E1000ENetworkAdapter: u8 irq = pci_device_identifier.interrupt_line().value(); auto interface_name = TRY(NetworkingManagement::generate_interface_name_from_pci_address(pci_device_identifier)); auto registers_io_window = TRY(IOWindow::create_for_pci_device_bar(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR0)); - auto adapter = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) E1000ENetworkAdapter(pci_device_identifier.address(), irq, move(registers_io_window), move(interface_name)))); + + auto rx_buffer_region = TRY(MM.allocate_contiguous_kernel_region(rx_buffer_size * number_of_rx_descriptors, "E1000 RX buffers"sv, Memory::Region::Access::ReadWrite)); + auto tx_buffer_region = MM.allocate_contiguous_kernel_region(tx_buffer_size * number_of_tx_descriptors, "E1000 TX buffers"sv, Memory::Region::Access::ReadWrite).release_value(); + auto rx_descriptors_region = TRY(MM.allocate_contiguous_kernel_region(TRY(Memory::page_round_up(sizeof(e1000_rx_desc) * number_of_rx_descriptors)), "E1000 RX Descriptors"sv, Memory::Region::Access::ReadWrite)); + auto tx_descriptors_region = TRY(MM.allocate_contiguous_kernel_region(TRY(Memory::page_round_up(sizeof(e1000_tx_desc) * number_of_tx_descriptors)), "E1000 TX Descriptors"sv, Memory::Region::Access::ReadWrite)); + + auto adapter = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) E1000ENetworkAdapter(pci_device_identifier.address(), + irq, move(registers_io_window), + move(rx_buffer_region), + move(tx_buffer_region), + move(rx_descriptors_region), + move(tx_descriptors_region), + move(interface_name)))); + if (!adapter->initialize()) return Error::from_string_literal("E1000ENetworkAdapter: Unable to initialize adapter"); return adapter; @@ -217,8 +230,16 @@ UNMAP_AFTER_INIT bool E1000ENetworkAdapter::initialize() return true; } -UNMAP_AFTER_INIT E1000ENetworkAdapter::E1000ENetworkAdapter(PCI::Address address, u8 irq, NonnullOwnPtr registers_io_window, NonnullOwnPtr interface_name) - : E1000NetworkAdapter(address, irq, move(registers_io_window), move(interface_name)) +UNMAP_AFTER_INIT E1000ENetworkAdapter::E1000ENetworkAdapter(PCI::Address address, u8 irq, + NonnullOwnPtr registers_io_window, NonnullOwnPtr rx_buffer_region, + NonnullOwnPtr tx_buffer_region, NonnullOwnPtr rx_descriptors_region, + NonnullOwnPtr tx_descriptors_region, NonnullOwnPtr interface_name) + : E1000NetworkAdapter(address, irq, move(registers_io_window), + move(rx_buffer_region), + move(tx_buffer_region), + move(rx_descriptors_region), + move(tx_descriptors_region), + move(interface_name)) { } diff --git a/Kernel/Net/Intel/E1000ENetworkAdapter.h b/Kernel/Net/Intel/E1000ENetworkAdapter.h index ea62860d1fb..69ae52a6d43 100644 --- a/Kernel/Net/Intel/E1000ENetworkAdapter.h +++ b/Kernel/Net/Intel/E1000ENetworkAdapter.h @@ -30,7 +30,10 @@ public: virtual StringView purpose() const override { return class_name(); } private: - E1000ENetworkAdapter(PCI::Address, u8 irq, NonnullOwnPtr registers_io_window, NonnullOwnPtr); + E1000ENetworkAdapter(PCI::Address, u8 irq, + NonnullOwnPtr registers_io_window, NonnullOwnPtr rx_buffer_region, + NonnullOwnPtr tx_buffer_region, NonnullOwnPtr rx_descriptors_region, + NonnullOwnPtr tx_descriptors_region, NonnullOwnPtr); virtual StringView class_name() const override { return "E1000ENetworkAdapter"sv; } diff --git a/Kernel/Net/Intel/E1000NetworkAdapter.cpp b/Kernel/Net/Intel/E1000NetworkAdapter.cpp index 7b5f4a11da3..1810bd727b3 100644 --- a/Kernel/Net/Intel/E1000NetworkAdapter.cpp +++ b/Kernel/Net/Intel/E1000NetworkAdapter.cpp @@ -168,9 +168,20 @@ UNMAP_AFTER_INIT ErrorOr> E1000NetworkAdapter::t u8 irq = pci_device_identifier.interrupt_line().value(); auto interface_name = TRY(NetworkingManagement::generate_interface_name_from_pci_address(pci_device_identifier)); auto registers_io_window = TRY(IOWindow::create_for_pci_device_bar(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR0)); - auto adapter = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) E1000NetworkAdapter(pci_device_identifier.address(), irq, move(registers_io_window), move(interface_name)))); - adapter->m_rx_descriptors_region = TRY(MM.allocate_contiguous_kernel_region(TRY(Memory::page_round_up(sizeof(e1000_rx_desc) * number_of_rx_descriptors)), "E1000 RX Descriptors"sv, Memory::Region::Access::ReadWrite)); - adapter->m_tx_descriptors_region = TRY(MM.allocate_contiguous_kernel_region(TRY(Memory::page_round_up(sizeof(e1000_tx_desc) * number_of_tx_descriptors)), "E1000 TX Descriptors"sv, Memory::Region::Access::ReadWrite)); + + auto rx_buffer_region = TRY(MM.allocate_contiguous_kernel_region(rx_buffer_size * number_of_rx_descriptors, "E1000 RX buffers"sv, Memory::Region::Access::ReadWrite)); + auto tx_buffer_region = MM.allocate_contiguous_kernel_region(tx_buffer_size * number_of_tx_descriptors, "E1000 TX buffers"sv, Memory::Region::Access::ReadWrite).release_value(); + auto rx_descriptors_region = TRY(MM.allocate_contiguous_kernel_region(TRY(Memory::page_round_up(sizeof(e1000_rx_desc) * number_of_rx_descriptors)), "E1000 RX Descriptors"sv, Memory::Region::Access::ReadWrite)); + auto tx_descriptors_region = TRY(MM.allocate_contiguous_kernel_region(TRY(Memory::page_round_up(sizeof(e1000_tx_desc) * number_of_tx_descriptors)), "E1000 TX Descriptors"sv, Memory::Region::Access::ReadWrite)); + + auto adapter = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) E1000NetworkAdapter(pci_device_identifier.address(), + irq, move(registers_io_window), + move(rx_buffer_region), + move(tx_buffer_region), + move(rx_descriptors_region), + move(tx_descriptors_region), + move(interface_name)))); + if (!adapter->initialize()) return Error::from_string_literal("E1000NetworkAdapter: Unable to initialize adapter"); return adapter; @@ -215,11 +226,18 @@ UNMAP_AFTER_INIT bool E1000NetworkAdapter::initialize() return true; } -UNMAP_AFTER_INIT E1000NetworkAdapter::E1000NetworkAdapter(PCI::Address address, u8 irq, NonnullOwnPtr registers_io_window, NonnullOwnPtr interface_name) +UNMAP_AFTER_INIT E1000NetworkAdapter::E1000NetworkAdapter(PCI::Address address, u8 irq, + NonnullOwnPtr registers_io_window, NonnullOwnPtr rx_buffer_region, + NonnullOwnPtr tx_buffer_region, NonnullOwnPtr rx_descriptors_region, + NonnullOwnPtr tx_descriptors_region, NonnullOwnPtr interface_name) : NetworkAdapter(move(interface_name)) , PCI::Device(address) , IRQHandler(irq) , m_registers_io_window(move(registers_io_window)) + , m_rx_descriptors_region(move(rx_descriptors_region)) + , m_tx_descriptors_region(move(tx_descriptors_region)) + , m_rx_buffer_region(move(rx_buffer_region)) + , m_tx_buffer_region(move(tx_buffer_region)) { } @@ -308,10 +326,7 @@ UNMAP_AFTER_INIT void E1000NetworkAdapter::read_mac_address() UNMAP_AFTER_INIT void E1000NetworkAdapter::initialize_rx_descriptors() { auto* rx_descriptors = (e1000_tx_desc*)m_rx_descriptors_region->vaddr().as_ptr(); - constexpr auto rx_buffer_size = 8192; constexpr auto rx_buffer_page_count = rx_buffer_size / PAGE_SIZE; - - m_rx_buffer_region = MM.allocate_contiguous_kernel_region(rx_buffer_size * number_of_rx_descriptors, "E1000 RX buffers"sv, Memory::Region::Access::ReadWrite).release_value(); for (size_t i = 0; i < number_of_rx_descriptors; ++i) { auto& descriptor = rx_descriptors[i]; m_rx_buffers[i] = m_rx_buffer_region->vaddr().as_ptr() + rx_buffer_size * i; @@ -331,10 +346,7 @@ UNMAP_AFTER_INIT void E1000NetworkAdapter::initialize_rx_descriptors() UNMAP_AFTER_INIT void E1000NetworkAdapter::initialize_tx_descriptors() { auto* tx_descriptors = (e1000_tx_desc*)m_tx_descriptors_region->vaddr().as_ptr(); - - constexpr auto tx_buffer_size = 8192; constexpr auto tx_buffer_page_count = tx_buffer_size / PAGE_SIZE; - m_tx_buffer_region = MM.allocate_contiguous_kernel_region(tx_buffer_size * number_of_tx_descriptors, "E1000 TX buffers"sv, Memory::Region::Access::ReadWrite).release_value(); for (size_t i = 0; i < number_of_tx_descriptors; ++i) { auto& descriptor = tx_descriptors[i]; diff --git a/Kernel/Net/Intel/E1000NetworkAdapter.h b/Kernel/Net/Intel/E1000NetworkAdapter.h index 4869c40c844..c4fa10cb84c 100644 --- a/Kernel/Net/Intel/E1000NetworkAdapter.h +++ b/Kernel/Net/Intel/E1000NetworkAdapter.h @@ -35,10 +35,17 @@ public: virtual StringView device_name() const override { return "E1000"sv; } protected: + static constexpr size_t rx_buffer_size = 8192; + static constexpr size_t tx_buffer_size = 8192; + void setup_interrupts(); void setup_link(); - E1000NetworkAdapter(PCI::Address, u8 irq, NonnullOwnPtr registers_io_window, NonnullOwnPtr); + E1000NetworkAdapter(PCI::Address, u8 irq, + NonnullOwnPtr registers_io_window, NonnullOwnPtr rx_buffer_region, + NonnullOwnPtr tx_buffer_region, NonnullOwnPtr rx_descriptors_region, + NonnullOwnPtr tx_descriptors_region, NonnullOwnPtr); + virtual bool handle_irq(RegisterState const&) override; virtual StringView class_name() const override { return "E1000NetworkAdapter"sv; } @@ -85,10 +92,10 @@ protected: NonnullOwnPtr m_registers_io_window; - OwnPtr m_rx_descriptors_region; - OwnPtr m_tx_descriptors_region; - OwnPtr m_rx_buffer_region; - OwnPtr m_tx_buffer_region; + NonnullOwnPtr m_rx_descriptors_region; + NonnullOwnPtr m_tx_descriptors_region; + NonnullOwnPtr m_rx_buffer_region; + NonnullOwnPtr m_tx_buffer_region; Array m_rx_buffers; Array m_tx_buffers; bool m_has_eeprom { false };