|
|
@@ -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;
|