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.
This commit is contained in:
Hendiadyoin1 2024-01-12 00:01:14 +01:00 committed by Andrew Kaster
parent bd118f4eb0
commit adac43ab1c

View file

@ -5,6 +5,7 @@
*/
#include <Kernel/Bus/PCI/API.h>
#include <Kernel/Bus/PCI/BarMapping.h>
#include <Kernel/Bus/PCI/Definitions.h>
#include <Kernel/Library/IOWindow.h>
@ -68,24 +69,18 @@ ErrorOr<NonnullOwnPtr<IOWindow>> 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<PCI::HeaderType0BaseRegister>(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<u64>::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<u16>::max())
return Error::from_errno(EOVERFLOW);
if (Checked<u16>::addition_would_overflow(static_cast<u16>(pci_bar_value), static_cast<u16>(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<NonnullOwnPtr<IOWindow>> IOWindow::create_for_pci_device_bar(PCI::Device
#endif
}
if (pci_bar_space_type == PCI::BARSpaceType::Memory32BitSpace && Checked<u32>::addition_would_overflow(pci_bar_value, space_length))
return Error::from_errno(EOVERFLOW);
if (pci_bar_space_type == PCI::BARSpaceType::Memory16BitSpace && Checked<u16>::addition_would_overflow(pci_bar_value, space_length))
return Error::from_errno(EOVERFLOW);
if (pci_bar_space_type == PCI::BARSpaceType::Memory64BitSpace && Checked<u64>::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<u8 volatile>(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<u8 volatile>(pci_device_identifier, pci_bar, space_length));
return TRY(adopt_nonnull_own_or_enomem(new (nothrow) IOWindow(move(memory_mapped_range))));
}