|
|
@@ -39,6 +39,73 @@ namespace {
|
|
|
constexpr bool Is4KBAligned(VAddr address) {
|
|
|
return (address & 0xFFF) == 0;
|
|
|
}
|
|
|
+
|
|
|
+// Checks if address + size is greater than the given address
|
|
|
+// This can return false if the size causes an overflow of a 64-bit type
|
|
|
+// or if the given size is zero.
|
|
|
+constexpr bool IsValidAddressRange(VAddr address, u64 size) {
|
|
|
+ return address + size > address;
|
|
|
+}
|
|
|
+
|
|
|
+// Checks if a given address range lies within a larger address range.
|
|
|
+constexpr bool IsInsideAddressRange(VAddr address, u64 size, VAddr address_range_begin,
|
|
|
+ VAddr address_range_end) {
|
|
|
+ const VAddr end_address = address + size - 1;
|
|
|
+ return address_range_begin <= address && end_address <= address_range_end - 1;
|
|
|
+}
|
|
|
+
|
|
|
+bool IsInsideAddressSpace(const VMManager& vm, VAddr address, u64 size) {
|
|
|
+ return IsInsideAddressRange(address, size, vm.GetAddressSpaceBaseAddress(),
|
|
|
+ vm.GetAddressSpaceEndAddress());
|
|
|
+}
|
|
|
+
|
|
|
+bool IsInsideNewMapRegion(const VMManager& vm, VAddr address, u64 size) {
|
|
|
+ return IsInsideAddressRange(address, size, vm.GetNewMapRegionBaseAddress(),
|
|
|
+ vm.GetNewMapRegionEndAddress());
|
|
|
+}
|
|
|
+
|
|
|
+// Helper function that performs the common sanity checks for svcMapMemory
|
|
|
+// and svcUnmapMemory. This is doable, as both functions perform their sanitizing
|
|
|
+// in the same order.
|
|
|
+ResultCode MapUnmapMemorySanityChecks(const VMManager& vm_manager, VAddr dst_addr, VAddr src_addr,
|
|
|
+ u64 size) {
|
|
|
+ if (!Is4KBAligned(dst_addr) || !Is4KBAligned(src_addr)) {
|
|
|
+ return ERR_INVALID_ADDRESS;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (size == 0 || !Is4KBAligned(size)) {
|
|
|
+ return ERR_INVALID_SIZE;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!IsValidAddressRange(dst_addr, size)) {
|
|
|
+ return ERR_INVALID_ADDRESS_STATE;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!IsValidAddressRange(src_addr, size)) {
|
|
|
+ return ERR_INVALID_ADDRESS_STATE;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!IsInsideAddressSpace(vm_manager, src_addr, size)) {
|
|
|
+ return ERR_INVALID_ADDRESS_STATE;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!IsInsideNewMapRegion(vm_manager, dst_addr, size)) {
|
|
|
+ return ERR_INVALID_MEMORY_RANGE;
|
|
|
+ }
|
|
|
+
|
|
|
+ const VAddr dst_end_address = dst_addr + size;
|
|
|
+ if (dst_end_address > vm_manager.GetHeapRegionBaseAddress() &&
|
|
|
+ dst_addr < vm_manager.GetHeapRegionEndAddress()) {
|
|
|
+ return ERR_INVALID_MEMORY_RANGE;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dst_end_address > vm_manager.GetNewMapRegionBaseAddress() &&
|
|
|
+ dst_addr < vm_manager.GetMapRegionEndAddress()) {
|
|
|
+ return ERR_INVALID_MEMORY_RANGE;
|
|
|
+ }
|
|
|
+
|
|
|
+ return RESULT_SUCCESS;
|
|
|
+}
|
|
|
} // Anonymous namespace
|
|
|
|
|
|
/// Set the process heap to a given Size. It can both extend and shrink the heap.
|
|
|
@@ -69,15 +136,15 @@ static ResultCode MapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
|
|
|
LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
|
|
|
src_addr, size);
|
|
|
|
|
|
- if (!Is4KBAligned(dst_addr) || !Is4KBAligned(src_addr)) {
|
|
|
- return ERR_INVALID_ADDRESS;
|
|
|
- }
|
|
|
+ auto* const current_process = Core::CurrentProcess();
|
|
|
+ const auto& vm_manager = current_process->VMManager();
|
|
|
|
|
|
- if (size == 0 || !Is4KBAligned(size)) {
|
|
|
- return ERR_INVALID_SIZE;
|
|
|
+ const auto result = MapUnmapMemorySanityChecks(vm_manager, dst_addr, src_addr, size);
|
|
|
+ if (result != RESULT_SUCCESS) {
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
- return Core::CurrentProcess()->MirrorMemory(dst_addr, src_addr, size);
|
|
|
+ return current_process->MirrorMemory(dst_addr, src_addr, size);
|
|
|
}
|
|
|
|
|
|
/// Unmaps a region that was previously mapped with svcMapMemory
|
|
|
@@ -85,15 +152,15 @@ static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
|
|
|
LOG_TRACE(Kernel_SVC, "called, dst_addr=0x{:X}, src_addr=0x{:X}, size=0x{:X}", dst_addr,
|
|
|
src_addr, size);
|
|
|
|
|
|
- if (!Is4KBAligned(dst_addr) || !Is4KBAligned(src_addr)) {
|
|
|
- return ERR_INVALID_ADDRESS;
|
|
|
- }
|
|
|
+ auto* const current_process = Core::CurrentProcess();
|
|
|
+ const auto& vm_manager = current_process->VMManager();
|
|
|
|
|
|
- if (size == 0 || !Is4KBAligned(size)) {
|
|
|
- return ERR_INVALID_SIZE;
|
|
|
+ const auto result = MapUnmapMemorySanityChecks(vm_manager, dst_addr, src_addr, size);
|
|
|
+ if (result != RESULT_SUCCESS) {
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
- return Core::CurrentProcess()->UnmapMemory(dst_addr, src_addr, size);
|
|
|
+ return current_process->UnmapMemory(dst_addr, src_addr, size);
|
|
|
}
|
|
|
|
|
|
/// Connect to an OS service given the port name, returns the handle to the port to out
|