mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-13 01:40:36 +00:00
Kernel: Add convenience helpers for mapping PCI BAR spaces
This commit is contained in:
parent
55cd89aea8
commit
2f98c7d470
Notes:
sideshowbarker
2024-07-17 22:41:14 +09:00
Author: https://github.com/Hendiadyoin1 Commit: https://github.com/SerenityOS/serenity/commit/2f98c7d470 Pull-request: https://github.com/SerenityOS/serenity/pull/22710 Reviewed-by: https://github.com/ADKaster ✅
1 changed files with 71 additions and 0 deletions
71
Kernel/Bus/PCI/BarMapping.h
Normal file
71
Kernel/Bus/PCI/BarMapping.h
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright (c) 2024, Leon Albrecht <leon.a@serenityos.org>
|
||||
* Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/StdLibExtras.h>
|
||||
#include <Kernel/Bus/PCI/API.h>
|
||||
#include <Kernel/Memory/TypedMapping.h>
|
||||
|
||||
namespace Kernel::PCI {
|
||||
|
||||
inline ErrorOr<PhysicalAddress> get_bar_address(DeviceIdentifier const& device, HeaderType0BaseRegister bar)
|
||||
{
|
||||
u64 pci_bar_value = get_BAR(device, bar);
|
||||
auto pci_bar_space_type = get_BAR_space_type(pci_bar_value);
|
||||
|
||||
if (pci_bar_space_type == BARSpaceType::IOSpace)
|
||||
return EIO;
|
||||
|
||||
if (pci_bar_space_type == 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 (bar == HeaderType0BaseRegister::BAR5) {
|
||||
return Error::from_errno(EINVAL);
|
||||
}
|
||||
u64 next_pci_bar_value = get_BAR(device, static_cast<PCI::HeaderType0BaseRegister>(to_underlying(bar) + 1));
|
||||
pci_bar_value |= next_pci_bar_value << 32;
|
||||
|
||||
return PhysicalAddress { pci_bar_value & bar_address_mask };
|
||||
}
|
||||
|
||||
return PhysicalAddress { pci_bar_value & bar_address_mask };
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline ErrorOr<Memory::TypedMapping<T>> map_bar(DeviceIdentifier const& device, HeaderType0BaseRegister bar, size_t size = sizeof(T), Memory::Region::Access access = IsConst<T> ? Memory::Region::Access::Read : Memory::Region::Access::ReadWrite)
|
||||
{
|
||||
u64 pci_bar_value = get_BAR(device, bar);
|
||||
auto pci_bar_space_type = get_BAR_space_type(pci_bar_value);
|
||||
|
||||
if (pci_bar_space_type == PCI::BARSpaceType::IOSpace)
|
||||
return EIO;
|
||||
|
||||
auto bar_address = TRY(get_bar_address(device, bar));
|
||||
|
||||
auto pci_bar_space_size = PCI::get_BAR_space_size(device, bar);
|
||||
if (pci_bar_space_size < size)
|
||||
return Error::from_errno(EIO);
|
||||
|
||||
if (pci_bar_space_type == PCI::BARSpaceType::Memory32BitSpace && Checked<u32>::addition_would_overflow(bar_address.get(), size))
|
||||
return Error::from_errno(EOVERFLOW);
|
||||
if (pci_bar_space_type == PCI::BARSpaceType::Memory16BitSpace && Checked<u16>::addition_would_overflow(bar_address.get(), size))
|
||||
return Error::from_errno(EOVERFLOW);
|
||||
if (pci_bar_space_type == PCI::BARSpaceType::Memory64BitSpace && Checked<u64>::addition_would_overflow(bar_address.get(), size))
|
||||
return Error::from_errno(EOVERFLOW);
|
||||
|
||||
return Memory::map_typed<T>(bar_address, size, access);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline ErrorOr<NonnullOwnPtr<Memory::TypedMapping<T>>> adopt_new_nonnull_own_bar_mapping(DeviceIdentifier const& device, HeaderType0BaseRegister bar, size_t size = sizeof(T), Memory::Region::Access access = IsConst<T> ? Memory::Region::Access::Read : Memory::Region::Access::ReadWrite)
|
||||
{
|
||||
return adopt_nonnull_own_or_enomem(new (nothrow) Memory::TypedMapping<T>(TRY(map_bar<T>(device, bar, size, access))));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue