citra-emu
/
citra-canary
Archived
1
0
Fork 0

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.
This commit is contained in:
Subv 2016-04-17 21:07:52 -05:00
parent 42a50da76b
commit 1bd0cf542f
10 changed files with 147 additions and 118 deletions

View File

@ -36,8 +36,8 @@ ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& p
memcpy(&capture_info, parameter.data, sizeof(capture_info)); memcpy(&capture_info, parameter.data, sizeof(capture_info));
using Kernel::MemoryPermission; using Kernel::MemoryPermission;
framebuffer_memory = Kernel::SharedMemory::Create(capture_info.size, MemoryPermission::ReadWrite, framebuffer_memory = Kernel::SharedMemory::Create(nullptr, capture_info.size, MemoryPermission::ReadWrite,
MemoryPermission::ReadWrite, "MiiSelector Memory"); MemoryPermission::ReadWrite, 0, Kernel::MemoryRegion::BASE, "MiiSelector Memory");
// Send the response message with the newly created SharedMemory // Send the response message with the newly created SharedMemory
Service::APT::MessageParameter result; Service::APT::MessageParameter result;

View File

@ -40,8 +40,8 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con
memcpy(&capture_info, parameter.data, sizeof(capture_info)); memcpy(&capture_info, parameter.data, sizeof(capture_info));
using Kernel::MemoryPermission; using Kernel::MemoryPermission;
framebuffer_memory = Kernel::SharedMemory::Create(capture_info.size, MemoryPermission::ReadWrite, framebuffer_memory = Kernel::SharedMemory::Create(nullptr, capture_info.size, MemoryPermission::ReadWrite,
MemoryPermission::ReadWrite, "SoftwareKeyboard Memory"); MemoryPermission::ReadWrite, 0, Kernel::MemoryRegion::BASE, "SoftwareKeyboard Memory");
// Send the response message with the newly created SharedMemory // Send the response message with the newly created SharedMemory
Service::APT::MessageParameter result; Service::APT::MessageParameter result;

View File

@ -7,6 +7,7 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/memory.h" #include "core/memory.h"
#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/shared_memory.h"
namespace Kernel { namespace Kernel {
@ -14,93 +15,94 @@ namespace Kernel {
SharedMemory::SharedMemory() {} SharedMemory::SharedMemory() {}
SharedMemory::~SharedMemory() {} SharedMemory::~SharedMemory() {}
SharedPtr<SharedMemory> SharedMemory::Create(u32 size, MemoryPermission permissions, SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u32 size, MemoryPermission permissions,
MemoryPermission other_permissions, std::string name) { MemoryPermission other_permissions, VAddr address, MemoryRegion region, std::string name) {
SharedPtr<SharedMemory> shared_memory(new SharedMemory); SharedPtr<SharedMemory> shared_memory(new SharedMemory);
shared_memory->owner_process = owner_process;
shared_memory->name = std::move(name); shared_memory->name = std::move(name);
shared_memory->base_address = 0x0;
shared_memory->fixed_address = 0x0;
shared_memory->size = size; shared_memory->size = size;
shared_memory->permissions = permissions; shared_memory->permissions = permissions;
shared_memory->other_permissions = other_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; return shared_memory;
} }
ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions, ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermission permissions,
MemoryPermission other_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 // TODO(Subv): Return E0E01BEE when permissions and other_permissions don't
// match what was specified when the memory block was created. // match what was specified when the memory block was created.
// TODO(Subv): Return E0E01BEE when address should be 0. // TODO(Subv): Check for the Shared Device Mem flag in the creator process.
// Note: Find out when that's the case. /*if (was_created_with_shared_device_mem && address != 0) {
return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
}*/
if (fixed_address != 0) { // TODO(Subv): The same process that created a SharedMemory object
if (address != 0 && address != fixed_address) { // can not map it in its own address space unless it was created with addr=0, result 0xD900182C.
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. if (address < Memory::HEAP_VADDR || address + size >= Memory::SHARED_MEMORY_VADDR_END) {
// Later, this should actually map the memory block onto the address space. LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, invalid address",
return RESULT_SUCCESS;
}
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!",
GetObjectId(), address, name.c_str()); GetObjectId(), address, name.c_str());
// TODO: Verify error code with hardware return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS,
return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
} }
// 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 if (base_address == 0 && target_address == 0) {
// process yet, at least initialize memory the first time it's mapped. // Calculate the address at which to map the memory block.
if (address != this->base_address) { target_address = Memory::PhysicalToVirtualAddress(linear_heap_phys_address);
std::memset(Memory::GetPointer(address), 0, size);
} }
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; return RESULT_SUCCESS;
} }
ResultCode SharedMemory::Unmap(VAddr address) { ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) {
if (base_address == 0) { // TODO(Subv): Verify what happens if the application tries to unmap an address that is not mapped to a SharedMemory.
// TODO(Subv): Verify what actually happens when you want to unmap a memory block that return target_process->vm_manager.UnmapRange(address, size);
// 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;
} }
u8* SharedMemory::GetPointer(u32 offset) { u8* SharedMemory::GetPointer(u32 offset) {
if (base_address != 0) return backing_block->data() + backing_block_offset + offset;
return Memory::GetPointer(base_address + offset);
LOG_ERROR(Kernel_SVC, "memory block id=%u not mapped!", GetObjectId());
return nullptr;
} }
} // namespace } // namespace

View File

@ -9,6 +9,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
#include "core/hle/result.h" #include "core/hle/result.h"
namespace Kernel { namespace Kernel {
@ -30,13 +31,16 @@ class SharedMemory final : public Object {
public: public:
/** /**
* Creates a shared memory object * Creates a shared memory object
* @param owner_process Process that created this shared memory object.
* @param size Size of the memory block. Must be page-aligned. * @param size Size of the memory block. Must be page-aligned.
* @param permissions Permission restrictions applied to the process which created the block. * @param permissions Permission restrictions applied to the process which created the block.
* @param other_permissions Permission restrictions applied to other processes mapping the block. * @param other_permissions Permission restrictions applied to other processes mapping the block.
* @param address The address from which to map the Shared Memory.
* @param region If the address is 0, the shared memory will be allocated in this region of the linear heap.
* @param name Optional object name, used for debugging purposes. * @param name Optional object name, used for debugging purposes.
*/ */
static SharedPtr<SharedMemory> Create(u32 size, MemoryPermission permissions, static SharedPtr<SharedMemory> Create(SharedPtr<Process> owner_process, u32 size, MemoryPermission permissions,
MemoryPermission other_permissions, std::string name = "Unknown"); MemoryPermission other_permissions, VAddr address = 0, MemoryRegion region = MemoryRegion::BASE, std::string name = "Unknown");
std::string GetTypeName() const override { return "SharedMemory"; } std::string GetTypeName() const override { return "SharedMemory"; }
std::string GetName() const override { return name; } std::string GetName() const override { return name; }
@ -45,19 +49,21 @@ public:
HandleType GetHandleType() const override { return HANDLE_TYPE; } HandleType GetHandleType() const override { return HANDLE_TYPE; }
/** /**
* Maps a shared memory block to an address in system memory * Maps a shared memory block to an address in the target process' address space
* @param target_process Process on which to map the memory block.
* @param address Address in system memory to map shared memory block to * @param address Address in system memory to map shared memory block to
* @param permissions Memory block map permissions (specified by SVC field) * @param permissions Memory block map permissions (specified by SVC field)
* @param other_permissions Memory block map other permissions (specified by SVC field) * @param other_permissions Memory block map other permissions (specified by SVC field)
*/ */
ResultCode Map(VAddr address, MemoryPermission permissions, MemoryPermission other_permissions); ResultCode Map(Process* target_process, VAddr address, MemoryPermission permissions, MemoryPermission other_permissions);
/** /**
* Unmaps a shared memory block from the specified address in system memory * Unmaps a shared memory block from the specified address in system memory
* @param target_process Process from which to umap the memory block.
* @param address Address in system memory where the shared memory block is mapped * @param address Address in system memory where the shared memory block is mapped
* @return Result code of the unmap operation * @return Result code of the unmap operation
*/ */
ResultCode Unmap(VAddr address); ResultCode Unmap(Process* target_process, VAddr address);
/** /**
* Gets a pointer to the shared memory block * Gets a pointer to the shared memory block
@ -66,10 +72,16 @@ public:
*/ */
u8* GetPointer(u32 offset = 0); u8* GetPointer(u32 offset = 0);
/// Address of shared memory block in the process. /// Process that created this shared memory block.
SharedPtr<Process> owner_process;
/// Address of shared memory block in the owner process if specified.
VAddr base_address; VAddr base_address;
/// Fixed address to allow mapping to. Used for blocks created from the linear heap. /// Physical address of the shared memory block in the linear heap if no address was specified during creation.
VAddr fixed_address; PAddr linear_heap_phys_address;
/// Backing memory for this shared memory block.
std::shared_ptr<std::vector<u8>> backing_block;
/// Offset into the backing block for this shared memory.
u32 backing_block_offset;
/// Size of the memory block. Page-aligned. /// Size of the memory block. Page-aligned.
u32 size; u32 size;
/// Permission restrictions applied to the process which created the block. /// Permission restrictions applied to the process which created the block.

View File

@ -37,8 +37,6 @@ static Kernel::SharedPtr<Kernel::Mutex> lock;
static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event
static Kernel::SharedPtr<Kernel::Event> parameter_event; ///< APT parameter event static Kernel::SharedPtr<Kernel::Event> parameter_event; ///< APT parameter event
static std::shared_ptr<std::vector<u8>> shared_font;
static u32 cpu_percent; ///< CPU time available to the running application static u32 cpu_percent; ///< CPU time available to the running application
/// Parameter data to be returned in the next call to Glance/ReceiveParameter /// Parameter data to be returned in the next call to Glance/ReceiveParameter
@ -74,23 +72,14 @@ void Initialize(Service::Interface* self) {
void GetSharedFont(Service::Interface* self) { void GetSharedFont(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); u32* cmd_buff = Kernel::GetCommandBuffer();
if (shared_font != nullptr) {
// TODO(yuriks): This is a hack to keep this working right now even with our completely
// broken shared memory system.
shared_font_mem->fixed_address = SHARED_FONT_VADDR;
Kernel::g_current_process->vm_manager.MapMemoryBlock(shared_font_mem->fixed_address,
shared_font, 0, shared_font_mem->size, Kernel::MemoryState::Shared);
cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2); cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2);
cmd_buff[1] = RESULT_SUCCESS.raw; // No error cmd_buff[1] = RESULT_SUCCESS.raw; // No error
cmd_buff[2] = SHARED_FONT_VADDR; // Since the SharedMemory interface doesn't provide the address at which the memory was allocated,
// the APT service calculates this address by scanning the entire address space (using svcQueryMemory)
// and searches for an allocation of the same size as the Shared Font.
cmd_buff[2] = Memory::PhysicalToVirtualAddress(shared_font_mem->linear_heap_phys_address);
cmd_buff[3] = IPC::MoveHandleDesc(); cmd_buff[3] = IPC::MoveHandleDesc();
cmd_buff[4] = Kernel::g_handle_table.Create(shared_font_mem).MoveFrom(); cmd_buff[4] = Kernel::g_handle_table.Create(shared_font_mem).MoveFrom();
} else {
cmd_buff[0] = IPC::MakeHeader(0x44, 1, 0);
cmd_buff[1] = -1; // Generic error (not really possible to verify this on hardware)
LOG_ERROR(Kernel_SVC, "called, but %s has not been loaded!", SHARED_FONT);
}
} }
void NotifyToWait(Service::Interface* self) { void NotifyToWait(Service::Interface* self) {
@ -433,14 +422,12 @@ void Init() {
FileUtil::IOFile file(filepath, "rb"); FileUtil::IOFile file(filepath, "rb");
if (file.IsOpen()) { if (file.IsOpen()) {
// Read shared font data
shared_font = std::make_shared<std::vector<u8>>((size_t)file.GetSize());
file.ReadBytes(shared_font->data(), shared_font->size());
// Create shared font memory object // Create shared font memory object
using Kernel::MemoryPermission; using Kernel::MemoryPermission;
shared_font_mem = Kernel::SharedMemory::Create(3 * 1024 * 1024, // 3MB shared_font_mem = Kernel::SharedMemory::Create(nullptr, 0x332000, // 3272 KB
MemoryPermission::ReadWrite, MemoryPermission::Read, "APT_U:shared_font_mem"); MemoryPermission::ReadWrite, MemoryPermission::Read, 0, Kernel::MemoryRegion::SYSTEM, "APT:SharedFont");
// Read shared font data
file.ReadBytes(shared_font_mem->GetPointer(), file.GetSize());
} else { } else {
LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str()); LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str());
shared_font_mem = nullptr; shared_font_mem = nullptr;
@ -459,7 +446,6 @@ void Init() {
} }
void Shutdown() { void Shutdown() {
shared_font = nullptr;
shared_font_mem = nullptr; shared_font_mem = nullptr;
lock = nullptr; lock = nullptr;
notification_event = nullptr; notification_event = nullptr;

View File

@ -3,6 +3,7 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <cstring> #include <cstring>
#include "common/alignment.h"
#include "core/hle/hle.h" #include "core/hle/hle.h"
#include "core/hle/kernel/mutex.h" #include "core/hle/kernel/mutex.h"
#include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/shared_memory.h"
@ -41,14 +42,16 @@ static Kernel::SharedPtr<Kernel::Mutex> mutex = nullptr;
void Initialize(Service::Interface* self) { void Initialize(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer(); u32* cmd_buff = Kernel::GetCommandBuffer();
shared_memory = Kernel::SharedMemory::Create(cmd_buff[1], u32 size = Common::AlignUp(cmd_buff[1], Memory::PAGE_SIZE);
Kernel::MemoryPermission::ReadWrite, using Kernel::MemoryPermission;
Kernel::MemoryPermission::ReadWrite, "CSNDSharedMem"); shared_memory = Kernel::SharedMemory::Create(nullptr, size,
MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
0, Kernel::MemoryRegion::BASE, "CSND:SharedMemory");
mutex = Kernel::Mutex::Create(false); mutex = Kernel::Mutex::Create(false);
cmd_buff[1] = 0; cmd_buff[1] = RESULT_SUCCESS.raw;
cmd_buff[2] = 0x4000000; cmd_buff[2] = IPC::MoveHandleDesc(2);
cmd_buff[3] = Kernel::g_handle_table.Create(mutex).MoveFrom(); cmd_buff[3] = Kernel::g_handle_table.Create(mutex).MoveFrom();
cmd_buff[4] = Kernel::g_handle_table.Create(shared_memory).MoveFrom(); cmd_buff[4] = Kernel::g_handle_table.Create(shared_memory).MoveFrom();
} }

View File

@ -335,8 +335,9 @@ static void RegisterInterruptRelayQueue(Service::Interface* self) {
g_interrupt_event->name = "GSP_GPU::interrupt_event"; g_interrupt_event->name = "GSP_GPU::interrupt_event";
using Kernel::MemoryPermission; using Kernel::MemoryPermission;
g_shared_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite, g_shared_memory = Kernel::SharedMemory::Create(nullptr, 0x1000,
MemoryPermission::ReadWrite, "GSPSharedMem"); MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
0, Kernel::MemoryRegion::BASE, "GSP:SharedMemory");
Handle shmem_handle = Kernel::g_handle_table.Create(g_shared_memory).MoveFrom(); Handle shmem_handle = Kernel::g_handle_table.Create(g_shared_memory).MoveFrom();

View File

@ -280,8 +280,9 @@ void Init() {
AddService(new HID_SPVR_Interface); AddService(new HID_SPVR_Interface);
using Kernel::MemoryPermission; using Kernel::MemoryPermission;
shared_mem = SharedMemory::Create(0x1000, MemoryPermission::ReadWrite, shared_mem = SharedMemory::Create(nullptr, 0x1000,
MemoryPermission::Read, "HID:SharedMem"); MemoryPermission::ReadWrite, MemoryPermission::Read,
0, Kernel::MemoryRegion::BASE, "HID:SharedMemory");
next_pad_index = 0; next_pad_index = 0;
next_touch_index = 0; next_touch_index = 0;

View File

@ -94,8 +94,9 @@ void Init() {
AddService(new IR_User_Interface); AddService(new IR_User_Interface);
using Kernel::MemoryPermission; using Kernel::MemoryPermission;
shared_memory = SharedMemory::Create(0x1000, Kernel::MemoryPermission::ReadWrite, shared_memory = SharedMemory::Create(nullptr, 0x1000,
Kernel::MemoryPermission::ReadWrite, "IR:SharedMemory"); Kernel::MemoryPermission::ReadWrite, Kernel::MemoryPermission::ReadWrite,
0, Kernel::MemoryRegion::BASE, "IR:SharedMemory");
transfer_shared_memory = nullptr; transfer_shared_memory = nullptr;
// Create event handle(s) // Create event handle(s)

View File

@ -160,8 +160,6 @@ static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 o
LOG_TRACE(Kernel_SVC, "called memblock=0x%08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", LOG_TRACE(Kernel_SVC, "called memblock=0x%08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d",
handle, addr, permissions, other_permissions); handle, addr, permissions, other_permissions);
// TODO(Subv): The same process that created a SharedMemory object can not map it in its own address space
SharedPtr<SharedMemory> shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle); SharedPtr<SharedMemory> shared_memory = Kernel::g_handle_table.Get<SharedMemory>(handle);
if (shared_memory == nullptr) if (shared_memory == nullptr)
return ERR_INVALID_HANDLE; return ERR_INVALID_HANDLE;
@ -176,7 +174,7 @@ static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 o
case MemoryPermission::WriteExecute: case MemoryPermission::WriteExecute:
case MemoryPermission::ReadWriteExecute: case MemoryPermission::ReadWriteExecute:
case MemoryPermission::DontCare: case MemoryPermission::DontCare:
return shared_memory->Map(addr, permissions_type, return shared_memory->Map(Kernel::g_current_process.get(), addr, permissions_type,
static_cast<MemoryPermission>(other_permissions)); static_cast<MemoryPermission>(other_permissions));
default: default:
LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions); LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions);
@ -196,7 +194,7 @@ static ResultCode UnmapMemoryBlock(Handle handle, u32 addr) {
if (shared_memory == nullptr) if (shared_memory == nullptr)
return ERR_INVALID_HANDLE; return ERR_INVALID_HANDLE;
return shared_memory->Unmap(addr); return shared_memory->Unmap(Kernel::g_current_process.get(), addr);
} }
/// Connect to an OS service given the port name, returns the handle to the port to out /// Connect to an OS service given the port name, returns the handle to the port to out
@ -790,18 +788,43 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32
if (size % Memory::PAGE_SIZE != 0) if (size % Memory::PAGE_SIZE != 0)
return ResultCode(ErrorDescription::MisalignedSize, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); return ResultCode(ErrorDescription::MisalignedSize, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
// TODO(Subv): Return E0A01BF5 if the address is not in the application's heap SharedPtr<SharedMemory> shared_memory = nullptr;
// TODO(Subv): Implement this function properly
using Kernel::MemoryPermission; using Kernel::MemoryPermission;
SharedPtr<SharedMemory> shared_memory = SharedMemory::Create(size, auto VerifyPermissions = [](MemoryPermission permission) {
(MemoryPermission)my_permission, (MemoryPermission)other_permission); // SharedMemory blocks can not be created with Execute permissions
// Map the SharedMemory to the specified address switch (permission) {
shared_memory->base_address = addr; case MemoryPermission::None:
case MemoryPermission::Read:
case MemoryPermission::Write:
case MemoryPermission::ReadWrite:
return true;
default:
return false;
}
};
if (!VerifyPermissions(static_cast<MemoryPermission>(my_permission)) ||
!VerifyPermissions(static_cast<MemoryPermission>(other_permission)))
return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS,
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
if (addr < Memory::PROCESS_IMAGE_VADDR || addr + size > Memory::SHARED_MEMORY_VADDR_END) {
return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
}
// When trying to create a memory block with address = 0,
// if the process has the Shared Device Memory flag in the exheader,
// then we have to allocate from the same region as the caller process instead of the BASE region.
Kernel::MemoryRegion region = Kernel::MemoryRegion::BASE;
if (addr == 0 && Kernel::g_current_process->flags.shared_device_mem)
region = Kernel::g_current_process->flags.memory_region;
shared_memory = SharedMemory::Create(Kernel::g_current_process, size,
static_cast<MemoryPermission>(my_permission), static_cast<MemoryPermission>(other_permission), addr, region);
CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory))); CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory)));
LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr); LOG_WARNING(Kernel_SVC, "called addr=0x%08X", addr);
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }