Kernel: Properly implement ControlMemory FREE and COMMIT

This commit is contained in:
Yuri Kunde Schlesner 2015-07-17 23:19:16 -03:00
parent ccab02c723
commit cdeeecf080
6 changed files with 338 additions and 38 deletions

View file

@ -41,32 +41,114 @@ const ResultCode ERR_NOT_FOUND(ErrorDescription::NotFound, ErrorModule::Kernel,
const ResultCode ERR_PORT_NAME_TOO_LONG(ErrorDescription(30), ErrorModule::OS,
ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E0181E
const ResultCode ERR_MISALIGNED_ADDRESS{ // 0xE0E01BF1
ErrorDescription::MisalignedAddress, ErrorModule::OS,
ErrorSummary::InvalidArgument, ErrorLevel::Usage};
const ResultCode ERR_MISALIGNED_SIZE{ // 0xE0E01BF2
ErrorDescription::MisalignedSize, ErrorModule::OS,
ErrorSummary::InvalidArgument, ErrorLevel::Usage};
const ResultCode ERR_INVALID_COMBINATION{ // 0xE0E01BEE
ErrorDescription::InvalidCombination, ErrorModule::OS,
ErrorSummary::InvalidArgument, ErrorLevel::Usage};
enum ControlMemoryOperation {
MEMORY_OPERATION_HEAP = 0x00000003,
MEMORY_OPERATION_GSP_HEAP = 0x00010003,
MEMOP_FREE = 1,
MEMOP_RESERVE = 2, // This operation seems to be unsupported in the kernel
MEMOP_COMMIT = 3,
MEMOP_MAP = 4,
MEMOP_UNMAP = 5,
MEMOP_PROTECT = 6,
MEMOP_OPERATION_MASK = 0xFF,
MEMOP_REGION_APP = 0x100,
MEMOP_REGION_SYSTEM = 0x200,
MEMOP_REGION_BASE = 0x300,
MEMOP_REGION_MASK = 0xF00,
MEMOP_LINEAR = 0x10000,
};
/// Map application or GSP heap memory
static ResultCode ControlMemory(u32* out_addr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) {
LOG_TRACE(Kernel_SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X",
using namespace Kernel;
LOG_DEBUG(Kernel_SVC,"called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=0x%X, permissions=0x%08X",
operation, addr0, addr1, size, permissions);
switch (operation) {
if ((addr0 & Memory::PAGE_MASK) != 0 || (addr1 & Memory::PAGE_MASK) != 0) {
return ERR_MISALIGNED_ADDRESS;
}
if ((size & Memory::PAGE_MASK) != 0) {
return ERR_MISALIGNED_SIZE;
}
// Map normal heap memory
case MEMORY_OPERATION_HEAP:
*out_addr = Memory::MapBlock_Heap(size, operation, permissions);
u32 region = operation & MEMOP_REGION_MASK;
operation &= ~MEMOP_REGION_MASK;
if (region != 0) {
LOG_WARNING(Kernel_SVC, "ControlMemory with specified region not supported, region=%X", region);
}
if ((permissions & (u32)MemoryPermission::ReadWrite) != permissions) {
return ERR_INVALID_COMBINATION;
}
VMAPermission vma_permissions = (VMAPermission)permissions;
auto& process = *g_current_process;
switch (operation & MEMOP_OPERATION_MASK) {
case MEMOP_FREE:
{
if (addr0 >= Memory::HEAP_VADDR && addr0 < Memory::HEAP_VADDR_END) {
ResultCode result = process.HeapFree(addr0, size);
if (result.IsError()) return result;
} else if (addr0 >= Memory::LINEAR_HEAP_VADDR && addr0 < Memory::LINEAR_HEAP_VADDR_END) {
ResultCode result = process.LinearFree(addr0, size);
if (result.IsError()) return result;
} else {
return ERR_INVALID_ADDRESS;
}
*out_addr = addr0;
break;
}
// Map GSP heap memory
case MEMORY_OPERATION_GSP_HEAP:
*out_addr = Memory::MapBlock_HeapLinear(size, operation, permissions);
case MEMOP_COMMIT:
{
if (operation & MEMOP_LINEAR) {
CASCADE_RESULT(*out_addr, process.LinearAllocate(addr0, size, vma_permissions));
} else {
CASCADE_RESULT(*out_addr, process.HeapAllocate(addr0, size, vma_permissions));
}
break;
}
case MEMOP_MAP: // TODO: This is just a hack to avoid regressions until memory aliasing is implemented
{
CASCADE_RESULT(*out_addr, process.HeapAllocate(addr0, size, vma_permissions));
break;
}
case MEMOP_UNMAP: // TODO: This is just a hack to avoid regressions until memory aliasing is implemented
{
ResultCode result = process.HeapFree(addr0, size);
if (result.IsError()) return result;
break;
}
case MEMOP_PROTECT:
{
ResultCode result = process.vm_manager.ReprotectRange(addr0, size, vma_permissions);
if (result.IsError()) return result;
break;
}
// Unknown ControlMemory operation
default:
LOG_ERROR(Kernel_SVC, "unknown operation=0x%08X", operation);
return ERR_INVALID_COMBINATION;
}
process.vm_manager.LogLayout(Log::Level::Trace);
return RESULT_SUCCESS;
}
@ -537,9 +619,9 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_inf
if (process == nullptr)
return ERR_INVALID_HANDLE;
auto vma = process->address_space->FindVMA(addr);
auto vma = process->vm_manager.FindVMA(addr);
if (vma == process->address_space->vma_map.end())
if (vma == Kernel::g_current_process->vm_manager.vma_map.end())
return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
memory_info->base_address = vma->second.base;