20#ifndef PEDIGREE_MODULES_DRIVERS_COMMON_DMABUFFER_H
21#define PEDIGREE_MODULES_DRIVERS_COMMON_DMABUFFER_H
22#include "pedigree/kernel/TargetInfo.h"
29 return byteCount ? ((byteCount - 1) / pageSize) + 1 : 0;
32constexpr bool physicalRangeFits(physical_uintptr_t address,
size_t byteCount,
33 physical_uintptr_t highestAddress) {
34 return !byteCount || (address <= highestAddress && (byteCount - 1) <= (highestAddress - address));
37constexpr bool physicalEndpointsAreContiguous(physical_uintptr_t first, physical_uintptr_t last,
38 size_t byteCount, physical_uintptr_t highestAddress) {
39 return byteCount && physicalRangeFits(first, byteCount, highestAddress) &&
40 last == first + (byteCount - 1);
44template <
size_t PageBytes = TargetInfo::getPageSize(),
typename AddressSpace>
45bool virtualToPhysical(AddressSpace& addressSpace, uintptr_t virtualAddress,
47 static_assert(PageBytes && !(PageBytes & (PageBytes - 1)),
48 "DMA mapping pages must be a power of two");
50 void* address =
reinterpret_cast<void*
>(virtualAddress);
51 if (!addressSpace.isMapped(address))
54 physical_uintptr_t physicalPage = 0;
56 addressSpace.getMapping(address, physicalPage, flags);
58 const size_t pageOffset = virtualAddress & (PageBytes - 1);
59 const physical_uintptr_t highestPhysical =
static_cast<physical_uintptr_t
>(-1);
60 if (physicalPage > highestPhysical - pageOffset)
73template <
size_t PageBytes = TargetInfo::getPageSize(),
typename AddressSpace>
74bool contiguousVirtualRangeToPhysical(AddressSpace& addressSpace, uintptr_t virtualAddress,
76 static_assert(PageBytes && !(PageBytes & (PageBytes - 1)),
77 "DMA mapping pages must be a power of two");
82 const uintptr_t highestVirtual =
static_cast<uintptr_t
>(-1);
83 if ((byteCount - 1) > highestVirtual - virtualAddress)
86 if (!virtualToPhysical<PageBytes>(addressSpace, virtualAddress,
physicalAddress))
89 const physical_uintptr_t highestPhysical =
static_cast<physical_uintptr_t
>(-1);
93 size_t consumed = PageBytes - (virtualAddress & (PageBytes - 1));
94 if (consumed >= byteCount)
97 while (consumed < byteCount) {
98 physical_uintptr_t nextPhysical = 0;
99 if (!virtualToPhysical<PageBytes>(addressSpace, virtualAddress + consumed, nextPhysical) ||
104 const size_t remaining = byteCount - consumed;
105 consumed += remaining < PageBytes ? remaining : PageBytes;
111static_assert(pageCountForBytes(0, 4096) == 0);
112static_assert(pageCountForBytes(4096, 4096) == 1);
113static_assert(pageCountForBytes(4097, 4096) == 2);
114static_assert(pageCountForBytes(16384, 16384) == 1);
115static_assert(pageCountForBytes(20480, 16384) == 2);
116static_assert(physicalRangeFits(0xfffff000, 4096, 0xffffffff));
117static_assert(!physicalRangeFits(0xfffff001, 4096, 0xffffffff));
118static_assert(physicalEndpointsAreContiguous(0x1000, 0x1fff, 4096, 0xffffffff));
119static_assert(!physicalEndpointsAreContiguous(0x1000, 0x2fff, 4096, 0xffffffff));
120static_assert(!physicalEndpointsAreContiguous(0xfffff001, 0xffffffff, 4096, 0xffffffff));
static constexpr size_t getPageSize() noexcept
uintptr_t physicalAddress(physical_uintptr_t address) PURE