mirror of
https://github.com/SerenityOS/serenity
synced 2024-07-09 08:37:24 +00:00
As MMIO is placed at fixed physical addressed, and does not need to be backed by real RAM physical pages, there's no need to use PhysicalPage instances to track their pages. This results in slightly reduced allocations, but more importantly makes MMIO addresses which end up after the normal RAM ranges work, like 64-bit PCI BARs usually are.
69 lines
2.2 KiB
C++
69 lines
2.2 KiB
C++
/*
|
|
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/NonnullOwnPtr.h>
|
|
#include <AK/StringView.h>
|
|
#include <AK/Try.h>
|
|
#include <Kernel/Memory/MemoryManager.h>
|
|
|
|
namespace Kernel::Memory {
|
|
|
|
template<typename T>
|
|
struct TypedMapping {
|
|
T const* ptr() const { return reinterpret_cast<T const*>(region->vaddr().offset(offset).as_ptr()); }
|
|
T* ptr() { return reinterpret_cast<T*>(region->vaddr().offset(offset).as_ptr()); }
|
|
VirtualAddress base_address() const { return region->vaddr().offset(offset); }
|
|
T const* operator->() const { return ptr(); }
|
|
T* operator->() { return ptr(); }
|
|
T const& operator*() const { return *ptr(); }
|
|
T& operator*() { return *ptr(); }
|
|
OwnPtr<Region> region;
|
|
PhysicalAddress paddr;
|
|
size_t offset { 0 };
|
|
size_t length { 0 };
|
|
};
|
|
|
|
template<typename T>
|
|
static ErrorOr<NonnullOwnPtr<TypedMapping<T>>> adopt_new_nonnull_own_typed_mapping(PhysicalAddress paddr, size_t length, Region::Access access = Region::Access::Read)
|
|
{
|
|
auto mapping_length = TRY(page_round_up(paddr.offset_in_page() + length));
|
|
auto region = TRY(MM.allocate_mmio_kernel_region(paddr.page_base(), mapping_length, {}, access));
|
|
auto table = TRY(adopt_nonnull_own_or_enomem(new (nothrow) Memory::TypedMapping<T>()));
|
|
table->region = move(region);
|
|
table->offset = paddr.offset_in_page();
|
|
table->paddr = paddr;
|
|
table->length = length;
|
|
return table;
|
|
}
|
|
|
|
template<typename T>
|
|
static ErrorOr<TypedMapping<T>> map_typed(PhysicalAddress paddr, size_t length, Region::Access access = Region::Access::Read)
|
|
{
|
|
TypedMapping<T> table;
|
|
auto mapping_length = TRY(page_round_up(paddr.offset_in_page() + length));
|
|
table.region = TRY(MM.allocate_mmio_kernel_region(paddr.page_base(), mapping_length, {}, access));
|
|
table.offset = paddr.offset_in_page();
|
|
table.paddr = paddr;
|
|
table.length = length;
|
|
return table;
|
|
}
|
|
|
|
template<typename T>
|
|
static ErrorOr<TypedMapping<T>> map_typed(PhysicalAddress paddr)
|
|
{
|
|
return map_typed<T>(paddr, sizeof(T));
|
|
}
|
|
|
|
template<typename T>
|
|
static ErrorOr<TypedMapping<T>> map_typed_writable(PhysicalAddress paddr)
|
|
{
|
|
return map_typed<T>(paddr, sizeof(T), Region::Access::Read | Region::Access::Write);
|
|
}
|
|
|
|
}
|