From adac43ab1c058e30de1db45583ce51cf2f659404 Mon Sep 17 00:00:00 2001 From: Hendiadyoin1 Date: Fri, 12 Jan 2024 00:01:14 +0100 Subject: [PATCH] Kernel: Use new PCI BAR API in IOWindow and correct IO bounds checks The IO bounds checks were on 32 bit instead of the actual limit of 16 bit, which would have caused problems later down the line. --- Kernel/Library/IOWindow.cpp | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/Kernel/Library/IOWindow.cpp b/Kernel/Library/IOWindow.cpp index b89b94148a..de6d5beddf 100644 --- a/Kernel/Library/IOWindow.cpp +++ b/Kernel/Library/IOWindow.cpp @@ -5,6 +5,7 @@ */ #include +#include #include #include @@ -68,24 +69,18 @@ ErrorOr> IOWindow::create_for_pci_device_bar(PCI::Device { u64 pci_bar_value = PCI::get_BAR(pci_device_identifier, pci_bar); auto pci_bar_space_type = PCI::get_BAR_space_type(pci_bar_value); - if (pci_bar_space_type == PCI::BARSpaceType::Memory64BitSpace) { - // FIXME: In theory, BAR5 cannot be assigned to 64 bit as it is the last one... - // however, there might be 64 bit BAR5 for real bare metal hardware, so remove this - // if it makes a problem. - if (pci_bar == PCI::HeaderType0BaseRegister::BAR5) { - return Error::from_errno(EINVAL); - } - u64 next_pci_bar_value = PCI::get_BAR(pci_device_identifier, static_cast(to_underlying(pci_bar) + 1)); - pci_bar_value |= next_pci_bar_value << 32; - } - - auto pci_bar_space_size = PCI::get_BAR_space_size(pci_device_identifier, pci_bar); - if (pci_bar_space_size < space_length) - return Error::from_errno(EIO); if (pci_bar_space_type == PCI::BARSpaceType::IOSpace) { #if ARCH(X86_64) - if (Checked::addition_would_overflow(pci_bar_value, space_length)) + auto pci_bar_space_size = PCI::get_BAR_space_size(pci_device_identifier, pci_bar); + if (pci_bar_space_size < space_length) + return Error::from_errno(EIO); + + // X86 IO instructions use DX -a 16 bit register- as the "address" + // So we need to check against u16's + if (pci_bar_value > AK::NumericLimits::max()) + return Error::from_errno(EOVERFLOW); + if (Checked::addition_would_overflow(static_cast(pci_bar_value), static_cast(space_length))) return Error::from_errno(EOVERFLOW); auto io_address_range = TRY(adopt_nonnull_own_or_enomem(new (nothrow) IOAddressData((pci_bar_value & 0xfffffffc), space_length))); return TRY(adopt_nonnull_own_or_enomem(new (nothrow) IOWindow(move(io_address_range)))); @@ -95,13 +90,7 @@ ErrorOr> IOWindow::create_for_pci_device_bar(PCI::Device #endif } - if (pci_bar_space_type == PCI::BARSpaceType::Memory32BitSpace && Checked::addition_would_overflow(pci_bar_value, space_length)) - return Error::from_errno(EOVERFLOW); - if (pci_bar_space_type == PCI::BARSpaceType::Memory16BitSpace && Checked::addition_would_overflow(pci_bar_value, space_length)) - return Error::from_errno(EOVERFLOW); - if (pci_bar_space_type == PCI::BARSpaceType::Memory64BitSpace && Checked::addition_would_overflow(pci_bar_value, space_length)) - return Error::from_errno(EOVERFLOW); - auto memory_mapped_range = TRY(Memory::adopt_new_nonnull_own_typed_mapping(PhysicalAddress(pci_bar_value & PCI::bar_address_mask), space_length, Memory::Region::Access::ReadWrite)); + auto memory_mapped_range = TRY(PCI::adopt_new_nonnull_own_bar_mapping(pci_device_identifier, pci_bar, space_length)); return TRY(adopt_nonnull_own_or_enomem(new (nothrow) IOWindow(move(memory_mapped_range)))); }