diff options
| author | Subv <subv2112@gmail.com> | 2016-04-17 21:07:52 -0500 |
|---|---|---|
| committer | Subv <subv2112@gmail.com> | 2016-05-12 20:00:32 -0500 |
| commit | 1bd0cf542ff8db1cda572c4d92462643296af121 (patch) | |
| tree | 8004faa76770c076e2d84d51a64c6419f796a477 /src/core/hle/kernel/shared_memory.cpp | |
| parent | 42a50da76b816fff95ae0e438d3e966f6f991b8a (diff) | |
Kernel/SharedMemory: Properly implemented shared memory support.
Applications can request the kernel to allocate a piece of the linear heap for them when creating a shared memory object.
Shared memory areas are now properly mapped into the target processes when calling svcMapMemoryBlock.
Removed the APT Shared Font hack as it is no longer needed.
Diffstat (limited to 'src/core/hle/kernel/shared_memory.cpp')
| -rw-r--r-- | src/core/hle/kernel/shared_memory.cpp | 116 |
1 files changed, 59 insertions, 57 deletions
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp index d90f0f00f..6f731f317 100644 --- a/src/core/hle/kernel/shared_memory.cpp +++ b/src/core/hle/kernel/shared_memory.cpp @@ -7,6 +7,7 @@ #include "common/logging/log.h" #include "core/memory.h" +#include "core/hle/kernel/memory.h" #include "core/hle/kernel/shared_memory.h" namespace Kernel { @@ -14,93 +15,94 @@ namespace Kernel { SharedMemory::SharedMemory() {} SharedMemory::~SharedMemory() {} -SharedPtr<SharedMemory> SharedMemory::Create(u32 size, MemoryPermission permissions, - MemoryPermission other_permissions, std::string name) { +SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u32 size, MemoryPermission permissions, + MemoryPermission other_permissions, VAddr address, MemoryRegion region, std::string name) { SharedPtr<SharedMemory> shared_memory(new SharedMemory); + shared_memory->owner_process = owner_process; shared_memory->name = std::move(name); - shared_memory->base_address = 0x0; - shared_memory->fixed_address = 0x0; shared_memory->size = size; shared_memory->permissions = permissions; shared_memory->other_permissions = other_permissions; + if (address == 0) { + // We need to allocate a block from the Linear Heap ourselves. + // We'll manually allocate some memory from the linear heap in the specified region. + MemoryRegionInfo* memory_region = GetMemoryRegion(region); + auto& linheap_memory = memory_region->linear_heap_memory; + + ASSERT_MSG(linheap_memory->size() + size <= memory_region->size, "Not enough space in region to allocate shared memory!"); + + shared_memory->backing_block = linheap_memory; + shared_memory->backing_block_offset = linheap_memory->size(); + // Allocate some memory from the end of the linear heap for this region. + linheap_memory->insert(linheap_memory->end(), size, 0); + memory_region->used += size; + + shared_memory->linear_heap_phys_address = Memory::FCRAM_PADDR + memory_region->base + shared_memory->backing_block_offset; + + // Refresh the address mappings for the current process. + if (Kernel::g_current_process != nullptr) { + Kernel::g_current_process->vm_manager.RefreshMemoryBlockMappings(linheap_memory.get()); + } + } else { + auto& vm_manager = shared_memory->owner_process->vm_manager; + // The memory is already available and mapped in the owner process. + auto vma = vm_manager.FindVMA(address)->second; + // Copy it over to our own storage + shared_memory->backing_block = std::make_shared<std::vector<u8>>(vma.backing_block->data() + vma.offset, + vma.backing_block->data() + vma.offset + size); + // Unmap the existing pages + vm_manager.UnmapRange(address, size); + // Map our own block into the address space + vm_manager.MapMemoryBlock(address, shared_memory->backing_block, 0, size, MemoryState::Shared); + } + + shared_memory->base_address = address; return shared_memory; } -ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions, +ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermission permissions, MemoryPermission other_permissions) { - if (base_address != 0) { - LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s: already mapped at 0x%08X!", - GetObjectId(), address, name.c_str(), base_address); - // TODO: Verify error code with hardware - return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, - ErrorSummary::InvalidArgument, ErrorLevel::Permanent); - } - // TODO(Subv): Return E0E01BEE when permissions and other_permissions don't // match what was specified when the memory block was created. - // TODO(Subv): Return E0E01BEE when address should be 0. - // Note: Find out when that's the case. + // TODO(Subv): Check for the Shared Device Mem flag in the creator process. + /*if (was_created_with_shared_device_mem && address != 0) { + return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); + }*/ - if (fixed_address != 0) { - if (address != 0 && address != fixed_address) { - LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s: fixed_addres is 0x%08X!", - GetObjectId(), address, name.c_str(), fixed_address); - // TODO: Verify error code with hardware - return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, - ErrorSummary::InvalidArgument, ErrorLevel::Permanent); - } - - // HACK(yuriks): This is only here to support the APT shared font mapping right now. - // Later, this should actually map the memory block onto the address space. - return RESULT_SUCCESS; - } + // TODO(Subv): The same process that created a SharedMemory object + // can not map it in its own address space unless it was created with addr=0, result 0xD900182C. - if (address < Memory::SHARED_MEMORY_VADDR || address + size >= Memory::SHARED_MEMORY_VADDR_END) { - LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s outside of shared mem bounds!", + if (address < Memory::HEAP_VADDR || address + size >= Memory::SHARED_MEMORY_VADDR_END) { + LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, invalid address", GetObjectId(), address, name.c_str()); - // TODO: Verify error code with hardware - return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, - ErrorSummary::InvalidArgument, ErrorLevel::Permanent); + return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, + ErrorSummary::InvalidArgument, ErrorLevel::Usage); } - // TODO: Test permissions + VAddr target_address = address; - // HACK: Since there's no way to write to the memory block without mapping it onto the game - // process yet, at least initialize memory the first time it's mapped. - if (address != this->base_address) { - std::memset(Memory::GetPointer(address), 0, size); + if (base_address == 0 && target_address == 0) { + // Calculate the address at which to map the memory block. + target_address = Memory::PhysicalToVirtualAddress(linear_heap_phys_address); } - this->base_address = address; + // Map the memory block into the target process + target_process->vm_manager.MapMemoryBlock(target_address, backing_block, backing_block_offset, size, MemoryState::Shared); return RESULT_SUCCESS; } -ResultCode SharedMemory::Unmap(VAddr address) { - if (base_address == 0) { - // TODO(Subv): Verify what actually happens when you want to unmap a memory block that - // was originally mapped with address = 0 - return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); - } - - if (base_address != address) - return ResultCode(ErrorDescription::WrongAddress, ErrorModule::OS, ErrorSummary::InvalidState, ErrorLevel::Usage); - - base_address = 0; - - return RESULT_SUCCESS; +ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) { + // TODO(Subv): Verify what happens if the application tries to unmap an address that is not mapped to a SharedMemory. + return target_process->vm_manager.UnmapRange(address, size); } u8* SharedMemory::GetPointer(u32 offset) { - if (base_address != 0) - return Memory::GetPointer(base_address + offset); - - LOG_ERROR(Kernel_SVC, "memory block id=%u not mapped!", GetObjectId()); - return nullptr; + return backing_block->data() + backing_block_offset + offset; } } // namespace |
