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