Merge pull request #1907 from lioncash/attribute
kernel/svc: Implement svcSetMemoryAttribute
This commit is contained in:
		
						commit
						e73dd39413
					
				@ -254,11 +254,52 @@ static ResultCode SetMemoryPermission(VAddr addr, u64 size, u32 prot) {
 | 
			
		||||
    return vm_manager.ReprotectRange(addr, size, converted_permissions);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ResultCode SetMemoryAttribute(VAddr addr, u64 size, u32 state0, u32 state1) {
 | 
			
		||||
    LOG_WARNING(Kernel_SVC,
 | 
			
		||||
                "(STUBBED) called, addr=0x{:X}, size=0x{:X}, state0=0x{:X}, state1=0x{:X}", addr,
 | 
			
		||||
                size, state0, state1);
 | 
			
		||||
    return RESULT_SUCCESS;
 | 
			
		||||
static ResultCode SetMemoryAttribute(VAddr address, u64 size, u32 mask, u32 attribute) {
 | 
			
		||||
    LOG_DEBUG(Kernel_SVC,
 | 
			
		||||
              "called, address=0x{:016X}, size=0x{:X}, mask=0x{:08X}, attribute=0x{:08X}", address,
 | 
			
		||||
              size, mask, attribute);
 | 
			
		||||
 | 
			
		||||
    if (!Common::Is4KBAligned(address)) {
 | 
			
		||||
        LOG_ERROR(Kernel_SVC, "Address not page aligned (0x{:016X})", address);
 | 
			
		||||
        return ERR_INVALID_ADDRESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (size == 0 || !Common::Is4KBAligned(size)) {
 | 
			
		||||
        LOG_ERROR(Kernel_SVC, "Invalid size (0x{:X}). Size must be non-zero and page aligned.",
 | 
			
		||||
                  size);
 | 
			
		||||
        return ERR_INVALID_ADDRESS;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!IsValidAddressRange(address, size)) {
 | 
			
		||||
        LOG_ERROR(Kernel_SVC, "Address range overflowed (Address: 0x{:016X}, Size: 0x{:016X})",
 | 
			
		||||
                  address, size);
 | 
			
		||||
        return ERR_INVALID_ADDRESS_STATE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const auto mem_attribute = static_cast<MemoryAttribute>(attribute);
 | 
			
		||||
    const auto mem_mask = static_cast<MemoryAttribute>(mask);
 | 
			
		||||
    const auto attribute_with_mask = mem_attribute | mem_mask;
 | 
			
		||||
 | 
			
		||||
    if (attribute_with_mask != mem_mask) {
 | 
			
		||||
        LOG_ERROR(Kernel_SVC,
 | 
			
		||||
                  "Memory attribute doesn't match the given mask (Attribute: 0x{:X}, Mask: {:X}",
 | 
			
		||||
                  attribute, mask);
 | 
			
		||||
        return ERR_INVALID_COMBINATION;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ((attribute_with_mask | MemoryAttribute::Uncached) != MemoryAttribute::Uncached) {
 | 
			
		||||
        LOG_ERROR(Kernel_SVC, "Specified attribute isn't equal to MemoryAttributeUncached (8).");
 | 
			
		||||
        return ERR_INVALID_COMBINATION;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto& vm_manager = Core::CurrentProcess()->VMManager();
 | 
			
		||||
    if (!IsInsideAddressSpace(vm_manager, address, size)) {
 | 
			
		||||
        LOG_ERROR(Kernel_SVC,
 | 
			
		||||
                  "Given address (0x{:016X}) is outside the bounds of the address space.", address);
 | 
			
		||||
        return ERR_INVALID_ADDRESS_STATE;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return vm_manager.SetMemoryAttribute(address, size, mem_mask, mem_attribute);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Maps a memory range into a different range.
 | 
			
		||||
 | 
			
		||||
@ -37,7 +37,7 @@ static const char* GetMemoryStateName(MemoryState state) {
 | 
			
		||||
 | 
			
		||||
bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const {
 | 
			
		||||
    ASSERT(base + size == next.base);
 | 
			
		||||
    if (permissions != next.permissions || meminfo_state != next.meminfo_state ||
 | 
			
		||||
    if (permissions != next.permissions || state != next.state || attribute != next.attribute ||
 | 
			
		||||
        type != next.type) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
@ -115,7 +115,7 @@ ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target,
 | 
			
		||||
 | 
			
		||||
    final_vma.type = VMAType::AllocatedMemoryBlock;
 | 
			
		||||
    final_vma.permissions = VMAPermission::ReadWrite;
 | 
			
		||||
    final_vma.meminfo_state = state;
 | 
			
		||||
    final_vma.state = state;
 | 
			
		||||
    final_vma.backing_block = std::move(block);
 | 
			
		||||
    final_vma.offset = offset;
 | 
			
		||||
    UpdatePageTableForVMA(final_vma);
 | 
			
		||||
@ -140,7 +140,7 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* me
 | 
			
		||||
 | 
			
		||||
    final_vma.type = VMAType::BackingMemory;
 | 
			
		||||
    final_vma.permissions = VMAPermission::ReadWrite;
 | 
			
		||||
    final_vma.meminfo_state = state;
 | 
			
		||||
    final_vma.state = state;
 | 
			
		||||
    final_vma.backing_memory = memory;
 | 
			
		||||
    UpdatePageTableForVMA(final_vma);
 | 
			
		||||
 | 
			
		||||
@ -177,7 +177,7 @@ ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u6
 | 
			
		||||
 | 
			
		||||
    final_vma.type = VMAType::MMIO;
 | 
			
		||||
    final_vma.permissions = VMAPermission::ReadWrite;
 | 
			
		||||
    final_vma.meminfo_state = state;
 | 
			
		||||
    final_vma.state = state;
 | 
			
		||||
    final_vma.paddr = paddr;
 | 
			
		||||
    final_vma.mmio_handler = std::move(mmio_handler);
 | 
			
		||||
    UpdatePageTableForVMA(final_vma);
 | 
			
		||||
@ -189,7 +189,7 @@ VMManager::VMAIter VMManager::Unmap(VMAIter vma_handle) {
 | 
			
		||||
    VirtualMemoryArea& vma = vma_handle->second;
 | 
			
		||||
    vma.type = VMAType::Free;
 | 
			
		||||
    vma.permissions = VMAPermission::None;
 | 
			
		||||
    vma.meminfo_state = MemoryState::Unmapped;
 | 
			
		||||
    vma.state = MemoryState::Unmapped;
 | 
			
		||||
 | 
			
		||||
    vma.backing_block = nullptr;
 | 
			
		||||
    vma.offset = 0;
 | 
			
		||||
@ -308,9 +308,10 @@ MemoryInfo VMManager::QueryMemory(VAddr address) const {
 | 
			
		||||
 | 
			
		||||
    if (IsValidHandle(vma)) {
 | 
			
		||||
        memory_info.base_address = vma->second.base;
 | 
			
		||||
        memory_info.attributes = ToSvcMemoryAttribute(vma->second.attribute);
 | 
			
		||||
        memory_info.permission = static_cast<u32>(vma->second.permissions);
 | 
			
		||||
        memory_info.size = vma->second.size;
 | 
			
		||||
        memory_info.state = ToSvcMemoryState(vma->second.meminfo_state);
 | 
			
		||||
        memory_info.state = ToSvcMemoryState(vma->second.state);
 | 
			
		||||
    } else {
 | 
			
		||||
        memory_info.base_address = address_space_end;
 | 
			
		||||
        memory_info.permission = static_cast<u32>(VMAPermission::None);
 | 
			
		||||
@ -321,6 +322,34 @@ MemoryInfo VMManager::QueryMemory(VAddr address) const {
 | 
			
		||||
    return memory_info;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ResultCode VMManager::SetMemoryAttribute(VAddr address, u64 size, MemoryAttribute mask,
 | 
			
		||||
                                         MemoryAttribute attribute) {
 | 
			
		||||
    constexpr auto ignore_mask = MemoryAttribute::Uncached | MemoryAttribute::DeviceMapped;
 | 
			
		||||
    constexpr auto attribute_mask = ~ignore_mask;
 | 
			
		||||
 | 
			
		||||
    const auto result = CheckRangeState(
 | 
			
		||||
        address, size, MemoryState::FlagUncached, MemoryState::FlagUncached, VMAPermission::None,
 | 
			
		||||
        VMAPermission::None, attribute_mask, MemoryAttribute::None, ignore_mask);
 | 
			
		||||
 | 
			
		||||
    if (result.Failed()) {
 | 
			
		||||
        return result.Code();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const auto [prev_state, prev_permissions, prev_attributes] = *result;
 | 
			
		||||
    const auto new_attribute = (prev_attributes & ~mask) | (mask & attribute);
 | 
			
		||||
 | 
			
		||||
    const auto carve_result = CarveVMARange(address, size);
 | 
			
		||||
    if (carve_result.Failed()) {
 | 
			
		||||
        return carve_result.Code();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    auto vma_iter = *carve_result;
 | 
			
		||||
    vma_iter->second.attribute = new_attribute;
 | 
			
		||||
 | 
			
		||||
    MergeAdjacent(vma_iter);
 | 
			
		||||
    return RESULT_SUCCESS;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ResultCode VMManager::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size, MemoryState state) {
 | 
			
		||||
    const auto vma = FindVMA(src_addr);
 | 
			
		||||
 | 
			
		||||
@ -364,7 +393,7 @@ void VMManager::LogLayout() const {
 | 
			
		||||
                  (u8)vma.permissions & (u8)VMAPermission::Read ? 'R' : '-',
 | 
			
		||||
                  (u8)vma.permissions & (u8)VMAPermission::Write ? 'W' : '-',
 | 
			
		||||
                  (u8)vma.permissions & (u8)VMAPermission::Execute ? 'X' : '-',
 | 
			
		||||
                  GetMemoryStateName(vma.meminfo_state));
 | 
			
		||||
                  GetMemoryStateName(vma.state));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -591,6 +620,66 @@ void VMManager::ClearPageTable() {
 | 
			
		||||
              Memory::PageType::Unmapped);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VMManager::CheckResults VMManager::CheckRangeState(VAddr address, u64 size, MemoryState state_mask,
 | 
			
		||||
                                                   MemoryState state, VMAPermission permission_mask,
 | 
			
		||||
                                                   VMAPermission permissions,
 | 
			
		||||
                                                   MemoryAttribute attribute_mask,
 | 
			
		||||
                                                   MemoryAttribute attribute,
 | 
			
		||||
                                                   MemoryAttribute ignore_mask) const {
 | 
			
		||||
    auto iter = FindVMA(address);
 | 
			
		||||
 | 
			
		||||
    // If we don't have a valid VMA handle at this point, then it means this is
 | 
			
		||||
    // being called with an address outside of the address space, which is definitely
 | 
			
		||||
    // indicative of a bug, as this function only operates on mapped memory regions.
 | 
			
		||||
    DEBUG_ASSERT(IsValidHandle(iter));
 | 
			
		||||
 | 
			
		||||
    const VAddr end_address = address + size - 1;
 | 
			
		||||
    const MemoryAttribute initial_attributes = iter->second.attribute;
 | 
			
		||||
    const VMAPermission initial_permissions = iter->second.permissions;
 | 
			
		||||
    const MemoryState initial_state = iter->second.state;
 | 
			
		||||
 | 
			
		||||
    while (true) {
 | 
			
		||||
        // The iterator should be valid throughout the traversal. Hitting the end of
 | 
			
		||||
        // the mapped VMA regions is unquestionably indicative of a bug.
 | 
			
		||||
        DEBUG_ASSERT(IsValidHandle(iter));
 | 
			
		||||
 | 
			
		||||
        const auto& vma = iter->second;
 | 
			
		||||
 | 
			
		||||
        if (vma.state != initial_state) {
 | 
			
		||||
            return ERR_INVALID_ADDRESS_STATE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ((vma.state & state_mask) != state) {
 | 
			
		||||
            return ERR_INVALID_ADDRESS_STATE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (vma.permissions != initial_permissions) {
 | 
			
		||||
            return ERR_INVALID_ADDRESS_STATE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ((vma.permissions & permission_mask) != permissions) {
 | 
			
		||||
            return ERR_INVALID_ADDRESS_STATE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ((vma.attribute | ignore_mask) != (initial_attributes | ignore_mask)) {
 | 
			
		||||
            return ERR_INVALID_ADDRESS_STATE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if ((vma.attribute & attribute_mask) != attribute) {
 | 
			
		||||
            return ERR_INVALID_ADDRESS_STATE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (end_address <= vma.EndAddress()) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ++iter;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return MakeResult(
 | 
			
		||||
        std::make_tuple(initial_state, initial_permissions, initial_attributes & ~ignore_mask));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
u64 VMManager::GetTotalMemoryUsage() const {
 | 
			
		||||
    LOG_WARNING(Kernel, "(STUBBED) called");
 | 
			
		||||
    return 0xF8000000;
 | 
			
		||||
 | 
			
		||||
@ -6,6 +6,7 @@
 | 
			
		||||
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <tuple>
 | 
			
		||||
#include <vector>
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "core/hle/result.h"
 | 
			
		||||
@ -43,6 +44,88 @@ enum class VMAPermission : u8 {
 | 
			
		||||
    ReadWriteExecute = Read | Write | Execute,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
constexpr VMAPermission operator|(VMAPermission lhs, VMAPermission rhs) {
 | 
			
		||||
    return static_cast<VMAPermission>(u32(lhs) | u32(rhs));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr VMAPermission operator&(VMAPermission lhs, VMAPermission rhs) {
 | 
			
		||||
    return static_cast<VMAPermission>(u32(lhs) & u32(rhs));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr VMAPermission operator^(VMAPermission lhs, VMAPermission rhs) {
 | 
			
		||||
    return static_cast<VMAPermission>(u32(lhs) ^ u32(rhs));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr VMAPermission operator~(VMAPermission permission) {
 | 
			
		||||
    return static_cast<VMAPermission>(~u32(permission));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr VMAPermission& operator|=(VMAPermission& lhs, VMAPermission rhs) {
 | 
			
		||||
    lhs = lhs | rhs;
 | 
			
		||||
    return lhs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr VMAPermission& operator&=(VMAPermission& lhs, VMAPermission rhs) {
 | 
			
		||||
    lhs = lhs & rhs;
 | 
			
		||||
    return lhs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr VMAPermission& operator^=(VMAPermission& lhs, VMAPermission rhs) {
 | 
			
		||||
    lhs = lhs ^ rhs;
 | 
			
		||||
    return lhs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Attribute flags that can be applied to a VMA
 | 
			
		||||
enum class MemoryAttribute : u32 {
 | 
			
		||||
    Mask = 0xFF,
 | 
			
		||||
 | 
			
		||||
    /// No particular qualities
 | 
			
		||||
    None = 0,
 | 
			
		||||
    /// Memory locked/borrowed for use. e.g. This would be used by transfer memory.
 | 
			
		||||
    Locked = 1,
 | 
			
		||||
    /// Memory locked for use by IPC-related internals.
 | 
			
		||||
    LockedForIPC = 2,
 | 
			
		||||
    /// Mapped as part of the device address space.
 | 
			
		||||
    DeviceMapped = 4,
 | 
			
		||||
    /// Uncached memory
 | 
			
		||||
    Uncached = 8,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
constexpr MemoryAttribute operator|(MemoryAttribute lhs, MemoryAttribute rhs) {
 | 
			
		||||
    return static_cast<MemoryAttribute>(u32(lhs) | u32(rhs));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr MemoryAttribute operator&(MemoryAttribute lhs, MemoryAttribute rhs) {
 | 
			
		||||
    return static_cast<MemoryAttribute>(u32(lhs) & u32(rhs));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr MemoryAttribute operator^(MemoryAttribute lhs, MemoryAttribute rhs) {
 | 
			
		||||
    return static_cast<MemoryAttribute>(u32(lhs) ^ u32(rhs));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr MemoryAttribute operator~(MemoryAttribute attribute) {
 | 
			
		||||
    return static_cast<MemoryAttribute>(~u32(attribute));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr MemoryAttribute& operator|=(MemoryAttribute& lhs, MemoryAttribute rhs) {
 | 
			
		||||
    lhs = lhs | rhs;
 | 
			
		||||
    return lhs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr MemoryAttribute& operator&=(MemoryAttribute& lhs, MemoryAttribute rhs) {
 | 
			
		||||
    lhs = lhs & rhs;
 | 
			
		||||
    return lhs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr MemoryAttribute& operator^=(MemoryAttribute& lhs, MemoryAttribute rhs) {
 | 
			
		||||
    lhs = lhs ^ rhs;
 | 
			
		||||
    return lhs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constexpr u32 ToSvcMemoryAttribute(MemoryAttribute attribute) {
 | 
			
		||||
    return static_cast<u32>(attribute & MemoryAttribute::Mask);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// clang-format off
 | 
			
		||||
/// Represents memory states and any relevant flags, as used by the kernel.
 | 
			
		||||
/// svcQueryMemory interprets these by masking away all but the first eight
 | 
			
		||||
@ -174,6 +257,16 @@ struct PageInfo {
 | 
			
		||||
 * also backed by a single host memory allocation.
 | 
			
		||||
 */
 | 
			
		||||
struct VirtualMemoryArea {
 | 
			
		||||
    /// Gets the starting (base) address of this VMA.
 | 
			
		||||
    VAddr StartAddress() const {
 | 
			
		||||
        return base;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Gets the ending address of this VMA.
 | 
			
		||||
    VAddr EndAddress() const {
 | 
			
		||||
        return base + size - 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Virtual base address of the region.
 | 
			
		||||
    VAddr base = 0;
 | 
			
		||||
    /// Size of the region.
 | 
			
		||||
@ -181,8 +274,8 @@ struct VirtualMemoryArea {
 | 
			
		||||
 | 
			
		||||
    VMAType type = VMAType::Free;
 | 
			
		||||
    VMAPermission permissions = VMAPermission::None;
 | 
			
		||||
    /// Tag returned by svcQueryMemory. Not otherwise used.
 | 
			
		||||
    MemoryState meminfo_state = MemoryState::Unmapped;
 | 
			
		||||
    MemoryState state = MemoryState::Unmapped;
 | 
			
		||||
    MemoryAttribute attribute = MemoryAttribute::None;
 | 
			
		||||
 | 
			
		||||
    // Settings for type = AllocatedMemoryBlock
 | 
			
		||||
    /// Memory block backing this VMA.
 | 
			
		||||
@ -299,6 +392,19 @@ public:
 | 
			
		||||
    ///
 | 
			
		||||
    MemoryInfo QueryMemory(VAddr address) const;
 | 
			
		||||
 | 
			
		||||
    /// Sets an attribute across the given address range.
 | 
			
		||||
    ///
 | 
			
		||||
    /// @param address   The starting address
 | 
			
		||||
    /// @param size      The size of the range to set the attribute on.
 | 
			
		||||
    /// @param mask      The attribute mask
 | 
			
		||||
    /// @param attribute The attribute to set across the given address range
 | 
			
		||||
    ///
 | 
			
		||||
    /// @returns RESULT_SUCCESS if successful
 | 
			
		||||
    /// @returns ERR_INVALID_ADDRESS_STATE if the attribute could not be set.
 | 
			
		||||
    ///
 | 
			
		||||
    ResultCode SetMemoryAttribute(VAddr address, u64 size, MemoryAttribute mask,
 | 
			
		||||
                                  MemoryAttribute attribute);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Scans all VMAs and updates the page table range of any that use the given vector as backing
 | 
			
		||||
     * memory. This should be called after any operation that causes reallocation of the vector.
 | 
			
		||||
@ -435,6 +541,35 @@ private:
 | 
			
		||||
    /// Clears out the page table
 | 
			
		||||
    void ClearPageTable();
 | 
			
		||||
 | 
			
		||||
    using CheckResults = ResultVal<std::tuple<MemoryState, VMAPermission, MemoryAttribute>>;
 | 
			
		||||
 | 
			
		||||
    /// Checks if an address range adheres to the specified states provided.
 | 
			
		||||
    ///
 | 
			
		||||
    /// @param address         The starting address of the address range.
 | 
			
		||||
    /// @param size            The size of the address range.
 | 
			
		||||
    /// @param state_mask      The memory state mask.
 | 
			
		||||
    /// @param state           The state to compare the individual VMA states against,
 | 
			
		||||
    ///                        which is done in the form of: (vma.state & state_mask) != state.
 | 
			
		||||
    /// @param permission_mask The memory permissions mask.
 | 
			
		||||
    /// @param permissions     The permission to compare the individual VMA permissions against,
 | 
			
		||||
    ///                        which is done in the form of:
 | 
			
		||||
    ///                        (vma.permission & permission_mask) != permission.
 | 
			
		||||
    /// @param attribute_mask  The memory attribute mask.
 | 
			
		||||
    /// @param attribute       The memory attributes to compare the individual VMA attributes
 | 
			
		||||
    ///                        against, which is done in the form of:
 | 
			
		||||
    ///                        (vma.attributes & attribute_mask) != attribute.
 | 
			
		||||
    /// @param ignore_mask     The memory attributes to ignore during the check.
 | 
			
		||||
    ///
 | 
			
		||||
    /// @returns If successful, returns a tuple containing the memory attributes
 | 
			
		||||
    ///          (with ignored bits specified by ignore_mask unset), memory permissions, and
 | 
			
		||||
    ///          memory state across the memory range.
 | 
			
		||||
    /// @returns If not successful, returns ERR_INVALID_ADDRESS_STATE.
 | 
			
		||||
    ///
 | 
			
		||||
    CheckResults CheckRangeState(VAddr address, u64 size, MemoryState state_mask, MemoryState state,
 | 
			
		||||
                                 VMAPermission permission_mask, VMAPermission permissions,
 | 
			
		||||
                                 MemoryAttribute attribute_mask, MemoryAttribute attribute,
 | 
			
		||||
                                 MemoryAttribute ignore_mask) const;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A map covering the entirety of the managed address space, keyed by the `base` field of each
 | 
			
		||||
     * VMA. It must always be modified by splitting or merging VMAs, so that the invariant
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user