mirror of
https://github.com/citra-emu/citra.git
synced 2024-12-18 13:20:04 +00:00
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:
parent
42a50da76b
commit
1bd0cf542f
@ -36,8 +36,8 @@ ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& p
|
||||
|
||||
memcpy(&capture_info, parameter.data, sizeof(capture_info));
|
||||
using Kernel::MemoryPermission;
|
||||
framebuffer_memory = Kernel::SharedMemory::Create(capture_info.size, MemoryPermission::ReadWrite,
|
||||
MemoryPermission::ReadWrite, "MiiSelector Memory");
|
||||
framebuffer_memory = Kernel::SharedMemory::Create(nullptr, capture_info.size, MemoryPermission::ReadWrite,
|
||||
MemoryPermission::ReadWrite, 0, Kernel::MemoryRegion::BASE, "MiiSelector Memory");
|
||||
|
||||
// Send the response message with the newly created SharedMemory
|
||||
Service::APT::MessageParameter result;
|
||||
|
@ -40,8 +40,8 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con
|
||||
memcpy(&capture_info, parameter.data, sizeof(capture_info));
|
||||
|
||||
using Kernel::MemoryPermission;
|
||||
framebuffer_memory = Kernel::SharedMemory::Create(capture_info.size, MemoryPermission::ReadWrite,
|
||||
MemoryPermission::ReadWrite, "SoftwareKeyboard Memory");
|
||||
framebuffer_memory = Kernel::SharedMemory::Create(nullptr, capture_info.size, MemoryPermission::ReadWrite,
|
||||
MemoryPermission::ReadWrite, 0, Kernel::MemoryRegion::BASE, "SoftwareKeyboard Memory");
|
||||
|
||||
// Send the response message with the newly created SharedMemory
|
||||
Service::APT::MessageParameter result;
|
||||
|
@ -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);
|
||||
}
|
||||
// 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.
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "common/common_types.h"
|
||||
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Kernel {
|
||||
@ -30,13 +31,16 @@ class SharedMemory final : public Object {
|
||||
public:
|
||||
/**
|
||||
* 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 permissions Permission restrictions applied to the process which created 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.
|
||||
*/
|
||||
static SharedPtr<SharedMemory> Create(u32 size, MemoryPermission permissions,
|
||||
MemoryPermission other_permissions, std::string name = "Unknown");
|
||||
static SharedPtr<SharedMemory> Create(SharedPtr<Process> owner_process, u32 size, MemoryPermission permissions,
|
||||
MemoryPermission other_permissions, VAddr address = 0, MemoryRegion region = MemoryRegion::BASE, std::string name = "Unknown");
|
||||
|
||||
std::string GetTypeName() const override { return "SharedMemory"; }
|
||||
std::string GetName() const override { return name; }
|
||||
@ -45,19 +49,21 @@ public:
|
||||
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 permissions Memory block map 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
|
||||
* @param target_process Process from which to umap the memory block.
|
||||
* @param address Address in system memory where the shared memory block is mapped
|
||||
* @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
|
||||
@ -66,10 +72,16 @@ public:
|
||||
*/
|
||||
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;
|
||||
/// Fixed address to allow mapping to. Used for blocks created from the linear heap.
|
||||
VAddr fixed_address;
|
||||
/// Physical address of the shared memory block in the linear heap if no address was specified during creation.
|
||||
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.
|
||||
u32 size;
|
||||
/// Permission restrictions applied to the process which created the block.
|
||||
|
@ -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> 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
|
||||
|
||||
/// 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) {
|
||||
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[1] = RESULT_SUCCESS.raw; // No error
|
||||
cmd_buff[2] = SHARED_FONT_VADDR;
|
||||
cmd_buff[3] = IPC::MoveHandleDesc();
|
||||
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);
|
||||
}
|
||||
cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2);
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
// 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[4] = Kernel::g_handle_table.Create(shared_font_mem).MoveFrom();
|
||||
}
|
||||
|
||||
void NotifyToWait(Service::Interface* self) {
|
||||
@ -433,14 +422,12 @@ void Init() {
|
||||
FileUtil::IOFile file(filepath, "rb");
|
||||
|
||||
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
|
||||
using Kernel::MemoryPermission;
|
||||
shared_font_mem = Kernel::SharedMemory::Create(3 * 1024 * 1024, // 3MB
|
||||
MemoryPermission::ReadWrite, MemoryPermission::Read, "APT_U:shared_font_mem");
|
||||
shared_font_mem = Kernel::SharedMemory::Create(nullptr, 0x332000, // 3272 KB
|
||||
MemoryPermission::ReadWrite, MemoryPermission::Read, 0, Kernel::MemoryRegion::SYSTEM, "APT:SharedFont");
|
||||
// Read shared font data
|
||||
file.ReadBytes(shared_font_mem->GetPointer(), file.GetSize());
|
||||
} else {
|
||||
LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str());
|
||||
shared_font_mem = nullptr;
|
||||
@ -459,7 +446,6 @@ void Init() {
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
shared_font = nullptr;
|
||||
shared_font_mem = nullptr;
|
||||
lock = nullptr;
|
||||
notification_event = nullptr;
|
||||
|
@ -3,6 +3,7 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstring>
|
||||
#include "common/alignment.h"
|
||||
#include "core/hle/hle.h"
|
||||
#include "core/hle/kernel/mutex.h"
|
||||
#include "core/hle/kernel/shared_memory.h"
|
||||
@ -41,14 +42,16 @@ static Kernel::SharedPtr<Kernel::Mutex> mutex = nullptr;
|
||||
void Initialize(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
|
||||
shared_memory = Kernel::SharedMemory::Create(cmd_buff[1],
|
||||
Kernel::MemoryPermission::ReadWrite,
|
||||
Kernel::MemoryPermission::ReadWrite, "CSNDSharedMem");
|
||||
u32 size = Common::AlignUp(cmd_buff[1], Memory::PAGE_SIZE);
|
||||
using Kernel::MemoryPermission;
|
||||
shared_memory = Kernel::SharedMemory::Create(nullptr, size,
|
||||
MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
|
||||
0, Kernel::MemoryRegion::BASE, "CSND:SharedMemory");
|
||||
|
||||
mutex = Kernel::Mutex::Create(false);
|
||||
|
||||
cmd_buff[1] = 0;
|
||||
cmd_buff[2] = 0x4000000;
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
cmd_buff[2] = IPC::MoveHandleDesc(2);
|
||||
cmd_buff[3] = Kernel::g_handle_table.Create(mutex).MoveFrom();
|
||||
cmd_buff[4] = Kernel::g_handle_table.Create(shared_memory).MoveFrom();
|
||||
}
|
||||
|
@ -335,8 +335,9 @@ static void RegisterInterruptRelayQueue(Service::Interface* self) {
|
||||
g_interrupt_event->name = "GSP_GPU::interrupt_event";
|
||||
|
||||
using Kernel::MemoryPermission;
|
||||
g_shared_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite,
|
||||
MemoryPermission::ReadWrite, "GSPSharedMem");
|
||||
g_shared_memory = Kernel::SharedMemory::Create(nullptr, 0x1000,
|
||||
MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
|
||||
0, Kernel::MemoryRegion::BASE, "GSP:SharedMemory");
|
||||
|
||||
Handle shmem_handle = Kernel::g_handle_table.Create(g_shared_memory).MoveFrom();
|
||||
|
||||
|
@ -280,8 +280,9 @@ void Init() {
|
||||
AddService(new HID_SPVR_Interface);
|
||||
|
||||
using Kernel::MemoryPermission;
|
||||
shared_mem = SharedMemory::Create(0x1000, MemoryPermission::ReadWrite,
|
||||
MemoryPermission::Read, "HID:SharedMem");
|
||||
shared_mem = SharedMemory::Create(nullptr, 0x1000,
|
||||
MemoryPermission::ReadWrite, MemoryPermission::Read,
|
||||
0, Kernel::MemoryRegion::BASE, "HID:SharedMemory");
|
||||
|
||||
next_pad_index = 0;
|
||||
next_touch_index = 0;
|
||||
|
@ -94,8 +94,9 @@ void Init() {
|
||||
AddService(new IR_User_Interface);
|
||||
|
||||
using Kernel::MemoryPermission;
|
||||
shared_memory = SharedMemory::Create(0x1000, Kernel::MemoryPermission::ReadWrite,
|
||||
Kernel::MemoryPermission::ReadWrite, "IR:SharedMemory");
|
||||
shared_memory = SharedMemory::Create(nullptr, 0x1000,
|
||||
Kernel::MemoryPermission::ReadWrite, Kernel::MemoryPermission::ReadWrite,
|
||||
0, Kernel::MemoryRegion::BASE, "IR:SharedMemory");
|
||||
transfer_shared_memory = nullptr;
|
||||
|
||||
// Create event handle(s)
|
||||
|
@ -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",
|
||||
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);
|
||||
if (shared_memory == nullptr)
|
||||
return ERR_INVALID_HANDLE;
|
||||
@ -176,7 +174,7 @@ static ResultCode MapMemoryBlock(Handle handle, u32 addr, u32 permissions, u32 o
|
||||
case MemoryPermission::WriteExecute:
|
||||
case MemoryPermission::ReadWriteExecute:
|
||||
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));
|
||||
default:
|
||||
LOG_ERROR(Kernel_SVC, "unknown permissions=0x%08X", permissions);
|
||||
@ -196,7 +194,7 @@ static ResultCode UnmapMemoryBlock(Handle handle, u32 addr) {
|
||||
if (shared_memory == nullptr)
|
||||
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
|
||||
@ -790,18 +788,43 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32
|
||||
if (size % Memory::PAGE_SIZE != 0)
|
||||
return ResultCode(ErrorDescription::MisalignedSize, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
||||
|
||||
// TODO(Subv): Return E0A01BF5 if the address is not in the application's heap
|
||||
|
||||
// TODO(Subv): Implement this function properly
|
||||
SharedPtr<SharedMemory> shared_memory = nullptr;
|
||||
|
||||
using Kernel::MemoryPermission;
|
||||
SharedPtr<SharedMemory> shared_memory = SharedMemory::Create(size,
|
||||
(MemoryPermission)my_permission, (MemoryPermission)other_permission);
|
||||
// Map the SharedMemory to the specified address
|
||||
shared_memory->base_address = addr;
|
||||
auto VerifyPermissions = [](MemoryPermission permission) {
|
||||
// SharedMemory blocks can not be created with Execute permissions
|
||||
switch (permission) {
|
||||
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)));
|
||||
|
||||
LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr);
|
||||
LOG_WARNING(Kernel_SVC, "called addr=0x%08X", addr);
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user