Merge pull request #908 from lioncash/memory

core/memory: Get rid of 3DS leftovers
master
bunnei 2018-08-03 14:07:49 +07:00 committed by GitHub
commit 40e63ede6d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 27 additions and 557 deletions

@ -63,8 +63,6 @@ add_library(core STATIC
hle/kernel/hle_ipc.h hle/kernel/hle_ipc.h
hle/kernel/kernel.cpp hle/kernel/kernel.cpp
hle/kernel/kernel.h hle/kernel/kernel.h
hle/kernel/memory.cpp
hle/kernel/memory.h
hle/kernel/mutex.cpp hle/kernel/mutex.cpp
hle/kernel/mutex.h hle/kernel/mutex.h
hle/kernel/object.cpp hle/kernel/object.cpp

@ -110,7 +110,7 @@ System::ResultStatus System::Load(EmuWindow& emu_window, const std::string& file
} }
} }
ResultStatus init_result{Init(emu_window, system_mode.first.get())}; ResultStatus init_result{Init(emu_window)};
if (init_result != ResultStatus::Success) { if (init_result != ResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!", LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
static_cast<int>(init_result)); static_cast<int>(init_result));
@ -161,7 +161,7 @@ Cpu& System::CpuCore(size_t core_index) {
return *cpu_cores[core_index]; return *cpu_cores[core_index];
} }
System::ResultStatus System::Init(EmuWindow& emu_window, u32 system_mode) { System::ResultStatus System::Init(EmuWindow& emu_window) {
LOG_DEBUG(HW_Memory, "initialized OK"); LOG_DEBUG(HW_Memory, "initialized OK");
CoreTiming::Init(); CoreTiming::Init();
@ -178,7 +178,7 @@ System::ResultStatus System::Init(EmuWindow& emu_window, u32 system_mode) {
telemetry_session = std::make_unique<Core::TelemetrySession>(); telemetry_session = std::make_unique<Core::TelemetrySession>();
service_manager = std::make_shared<Service::SM::ServiceManager>(); service_manager = std::make_shared<Service::SM::ServiceManager>();
Kernel::Init(system_mode); Kernel::Init();
Service::Init(service_manager); Service::Init(service_manager);
GDBStub::Init(); GDBStub::Init();

@ -189,10 +189,9 @@ private:
* Initialize the emulated system. * Initialize the emulated system.
* @param emu_window Reference to the host-system window used for video output and keyboard * @param emu_window Reference to the host-system window used for video output and keyboard
* input. * input.
* @param system_mode The system mode.
* @return ResultStatus code, indicating if the operation succeeded. * @return ResultStatus code, indicating if the operation succeeded.
*/ */
ResultStatus Init(EmuWindow& emu_window, u32 system_mode); ResultStatus Init(EmuWindow& emu_window);
/// AppLoader used to load the current executing application /// AppLoader used to load the current executing application
std::unique_ptr<Loader::AppLoader> app_loader; std::unique_ptr<Loader::AppLoader> app_loader;

@ -4,7 +4,6 @@
#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/process.h" #include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/resource_limit.h"
#include "core/hle/kernel/thread.h" #include "core/hle/kernel/thread.h"
@ -15,9 +14,7 @@ namespace Kernel {
unsigned int Object::next_object_id; unsigned int Object::next_object_id;
/// Initialize the kernel /// Initialize the kernel
void Init(u32 system_mode) { void Init() {
Kernel::MemoryInit(system_mode);
Kernel::ResourceLimitsInit(); Kernel::ResourceLimitsInit();
Kernel::ThreadingInit(); Kernel::ThreadingInit();
Kernel::TimersInit(); Kernel::TimersInit();
@ -37,7 +34,6 @@ void Shutdown() {
Kernel::TimersShutdown(); Kernel::TimersShutdown();
Kernel::ResourceLimitsShutdown(); Kernel::ResourceLimitsShutdown();
Kernel::MemoryShutdown();
} }
} // namespace Kernel } // namespace Kernel

@ -9,7 +9,7 @@
namespace Kernel { namespace Kernel {
/// Initialize the kernel with the specified system mode. /// Initialize the kernel with the specified system mode.
void Init(u32 system_mode); void Init();
/// Shutdown the kernel /// Shutdown the kernel
void Shutdown(); void Shutdown();

@ -1,90 +0,0 @@
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include <cinttypes>
#include <memory>
#include <utility>
#include <vector>
#include "common/assert.h"
#include "common/common_types.h"
#include "common/logging/log.h"
#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/vm_manager.h"
#include "core/memory.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Kernel {
MemoryRegionInfo memory_regions[3];
/// Size of the APPLICATION, SYSTEM and BASE memory regions (respectively) for each system
/// memory configuration type.
static const u32 memory_region_sizes[8][3] = {
// Old 3DS layouts
{0x04000000, 0x02C00000, 0x01400000}, // 0
{/* This appears to be unused. */}, // 1
{0x06000000, 0x00C00000, 0x01400000}, // 2
{0x05000000, 0x01C00000, 0x01400000}, // 3
{0x04800000, 0x02400000, 0x01400000}, // 4
{0x02000000, 0x04C00000, 0x01400000}, // 5
// New 3DS layouts
{0x07C00000, 0x06400000, 0x02000000}, // 6
{0x0B200000, 0x02E00000, 0x02000000}, // 7
};
void MemoryInit(u32 mem_type) {
// TODO(yuriks): On the n3DS, all o3DS configurations (<=5) are forced to 6 instead.
ASSERT_MSG(mem_type <= 5, "New 3DS memory configuration aren't supported yet!");
ASSERT(mem_type != 1);
// The kernel allocation regions (APPLICATION, SYSTEM and BASE) are laid out in sequence, with
// the sizes specified in the memory_region_sizes table.
VAddr base = 0;
for (int i = 0; i < 3; ++i) {
memory_regions[i].base = base;
memory_regions[i].size = memory_region_sizes[mem_type][i];
memory_regions[i].used = 0;
memory_regions[i].linear_heap_memory = std::make_shared<std::vector<u8>>();
// Reserve enough space for this region of FCRAM.
// We do not want this block of memory to be relocated when allocating from it.
memory_regions[i].linear_heap_memory->reserve(memory_regions[i].size);
base += memory_regions[i].size;
}
// We must've allocated the entire FCRAM by the end
ASSERT(base == Memory::FCRAM_SIZE);
}
void MemoryShutdown() {
for (auto& region : memory_regions) {
region.base = 0;
region.size = 0;
region.used = 0;
region.linear_heap_memory = nullptr;
}
}
MemoryRegionInfo* GetMemoryRegion(MemoryRegion region) {
switch (region) {
case MemoryRegion::APPLICATION:
return &memory_regions[0];
case MemoryRegion::SYSTEM:
return &memory_regions[1];
case MemoryRegion::BASE:
return &memory_regions[2];
default:
UNREACHABLE();
}
}
void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping) {}
void MapSharedPages(VMManager& address_space) {}
} // namespace Kernel

@ -1,34 +0,0 @@
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <memory>
#include <vector>
#include "common/common_types.h"
namespace Kernel {
class VMManager;
enum class MemoryRegion : u16;
struct AddressMapping;
struct MemoryRegionInfo {
u64 base; // Not an address, but offset from start of FCRAM
u64 size;
u64 used;
std::shared_ptr<std::vector<u8>> linear_heap_memory;
};
void MemoryInit(u32 mem_type);
void MemoryShutdown();
MemoryRegionInfo* GetMemoryRegion(MemoryRegion region);
void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping);
void MapSharedPages(VMManager& address_space);
extern MemoryRegionInfo memory_regions[3];
} // namespace Kernel

@ -8,7 +8,6 @@
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/hle/kernel/errors.h" #include "core/hle/kernel/errors.h"
#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/process.h" #include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/resource_limit.h"
#include "core/hle/kernel/thread.h" #include "core/hle/kernel/thread.h"
@ -125,14 +124,6 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size, std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size,
MemoryState::Mapped) MemoryState::Mapped)
.Unwrap(); .Unwrap();
misc_memory_used += stack_size;
memory_region->used += stack_size;
// Map special address mappings
MapSharedPages(vm_manager);
for (const auto& mapping : address_mappings) {
HandleSpecialMapping(vm_manager, mapping);
}
vm_manager.LogLayout(); vm_manager.LogLayout();
status = ProcessStatus::Running; status = ProcessStatus::Running;
@ -141,17 +132,13 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
} }
void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) { void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) {
memory_region = GetMemoryRegion(flags.memory_region); const auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions,
MemoryState memory_state) {
auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions,
MemoryState memory_state) {
auto vma = vm_manager auto vma = vm_manager
.MapMemoryBlock(segment.addr + base_addr, module_->memory, segment.offset, .MapMemoryBlock(segment.addr + base_addr, module_->memory, segment.offset,
segment.size, memory_state) segment.size, memory_state)
.Unwrap(); .Unwrap();
vm_manager.Reprotect(vma, permissions); vm_manager.Reprotect(vma, permissions);
misc_memory_used += segment.size;
memory_region->used += segment.size;
}; };
// Map CodeSet segments // Map CodeSet segments
@ -160,20 +147,6 @@ void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) {
MapSegment(module_->data, VMAPermission::ReadWrite, MemoryState::CodeMutable); MapSegment(module_->data, VMAPermission::ReadWrite, MemoryState::CodeMutable);
} }
VAddr Process::GetLinearHeapAreaAddress() const {
// Starting from system version 8.0.0 a new linear heap layout is supported to allow usage of
// the extra RAM in the n3DS.
return kernel_version < 0x22C ? Memory::LINEAR_HEAP_VADDR : Memory::NEW_LINEAR_HEAP_VADDR;
}
VAddr Process::GetLinearHeapBase() const {
return GetLinearHeapAreaAddress() + memory_region->base;
}
VAddr Process::GetLinearHeapLimit() const {
return GetLinearHeapBase() + memory_region->size;
}
ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) { ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) {
if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END || if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END ||
target + size < target) { target + size < target) {
@ -206,7 +179,6 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission per
vm_manager.Reprotect(vma, perms); vm_manager.Reprotect(vma, perms);
heap_used = size; heap_used = size;
memory_region->used += size;
return MakeResult<VAddr>(heap_end - size); return MakeResult<VAddr>(heap_end - size);
} }
@ -226,52 +198,6 @@ ResultCode Process::HeapFree(VAddr target, u32 size) {
return result; return result;
heap_used -= size; heap_used -= size;
memory_region->used -= size;
return RESULT_SUCCESS;
}
ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission perms) {
UNIMPLEMENTED();
return {};
}
ResultCode Process::LinearFree(VAddr target, u32 size) {
auto& linheap_memory = memory_region->linear_heap_memory;
if (target < GetLinearHeapBase() || target + size > GetLinearHeapLimit() ||
target + size < target) {
return ERR_INVALID_ADDRESS;
}
if (size == 0) {
return RESULT_SUCCESS;
}
VAddr heap_end = GetLinearHeapBase() + (u32)linheap_memory->size();
if (target + size > heap_end) {
return ERR_INVALID_ADDRESS_STATE;
}
ResultCode result = vm_manager.UnmapRange(target, size);
if (result.IsError())
return result;
linear_heap_used -= size;
memory_region->used -= size;
if (target + size == heap_end) {
// End of linear heap has been freed, so check what's the last allocated block in it and
// reduce the size.
auto vma = vm_manager.FindVMA(target);
ASSERT(vma != vm_manager.vma_map.end());
ASSERT(vma->second.type == VMAType::Free);
VAddr new_end = vma->second.base;
if (new_end >= GetLinearHeapBase()) {
linheap_memory->resize(new_end - GetLinearHeapBase());
}
}
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }

@ -53,7 +53,6 @@ union ProcessFlags {
enum class ProcessStatus { Created, Running, Exited }; enum class ProcessStatus { Created, Running, Exited };
class ResourceLimit; class ResourceLimit;
struct MemoryRegionInfo;
struct CodeSet final : public Object { struct CodeSet final : public Object {
static SharedPtr<CodeSet> Create(std::string name); static SharedPtr<CodeSet> Create(std::string name);
@ -163,12 +162,11 @@ public:
// This makes deallocation and reallocation of holes fast and keeps process memory contiguous // This makes deallocation and reallocation of holes fast and keeps process memory contiguous
// in the emulator address space, allowing Memory::GetPointer to be reasonably safe. // in the emulator address space, allowing Memory::GetPointer to be reasonably safe.
std::shared_ptr<std::vector<u8>> heap_memory; std::shared_ptr<std::vector<u8>> heap_memory;
// The left/right bounds of the address space covered by heap_memory. // The left/right bounds of the address space covered by heap_memory.
VAddr heap_start = 0, heap_end = 0; VAddr heap_start = 0;
VAddr heap_end = 0;
u64 heap_used = 0, linear_heap_used = 0, misc_memory_used = 0; u64 heap_used = 0;
MemoryRegionInfo* memory_region = nullptr;
/// The Thread Local Storage area is allocated as processes create threads, /// The Thread Local Storage area is allocated as processes create threads,
/// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part /// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part
@ -179,16 +177,9 @@ public:
std::string name; std::string name;
VAddr GetLinearHeapAreaAddress() const;
VAddr GetLinearHeapBase() const;
VAddr GetLinearHeapLimit() const;
ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms); ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms);
ResultCode HeapFree(VAddr target, u32 size); ResultCode HeapFree(VAddr target, u32 size);
ResultVal<VAddr> LinearAllocate(VAddr target, u32 size, VMAPermission perms);
ResultCode LinearFree(VAddr target, u32 size);
ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size); ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size);
ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size); ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size);

@ -8,7 +8,6 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/core.h" #include "core/core.h"
#include "core/hle/kernel/errors.h" #include "core/hle/kernel/errors.h"
#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/shared_memory.h"
#include "core/memory.h" #include "core/memory.h"
@ -29,51 +28,22 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u
shared_memory->permissions = permissions; shared_memory->permissions = permissions;
shared_memory->other_permissions = other_permissions; shared_memory->other_permissions = other_permissions;
if (address == 0) { auto& vm_manager = shared_memory->owner_process->vm_manager;
// 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, // The memory is already available and mapped in the owner process.
"Not enough space in region to allocate shared memory!"); auto vma = vm_manager.FindVMA(address);
ASSERT_MSG(vma != vm_manager.vma_map.end(), "Invalid memory address");
ASSERT_MSG(vma->second.backing_block, "Backing block doesn't exist for address");
shared_memory->backing_block = linheap_memory; // The returned VMA might be a bigger one encompassing the desired address.
shared_memory->backing_block_offset = linheap_memory->size(); auto vma_offset = address - vma->first;
// Allocate some memory from the end of the linear heap for this region. ASSERT_MSG(vma_offset + size <= vma->second.size,
linheap_memory->insert(linheap_memory->end(), size, 0); "Shared memory exceeds bounds of mapped block");
memory_region->used += size;
shared_memory->linear_heap_phys_address =
Memory::FCRAM_PADDR + memory_region->base +
static_cast<PAddr>(shared_memory->backing_block_offset);
// Increase the amount of used linear heap memory for the owner process.
if (shared_memory->owner_process != nullptr) {
shared_memory->owner_process->linear_heap_used += size;
}
// Refresh the address mappings for the current process.
if (Core::CurrentProcess() != nullptr) {
Core::CurrentProcess()->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);
ASSERT_MSG(vma != vm_manager.vma_map.end(), "Invalid memory address");
ASSERT_MSG(vma->second.backing_block, "Backing block doesn't exist for address");
// The returned VMA might be a bigger one encompassing the desired address.
auto vma_offset = address - vma->first;
ASSERT_MSG(vma_offset + size <= vma->second.size,
"Shared memory exceeds bounds of mapped block");
shared_memory->backing_block = vma->second.backing_block;
shared_memory->backing_block_offset = vma->second.offset + vma_offset;
}
shared_memory->backing_block = vma->second.backing_block;
shared_memory->backing_block_offset = vma->second.offset + vma_offset;
shared_memory->base_address = address; shared_memory->base_address = address;
return shared_memory; return shared_memory;
} }
@ -124,11 +94,6 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi
VAddr target_address = address; VAddr target_address = address;
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).value();
}
// Map the memory block into the target process // Map the memory block into the target process
auto result = target_process->vm_manager.MapMemoryBlock( auto result = target_process->vm_manager.MapMemoryBlock(
target_address, backing_block, backing_block_offset, size, MemoryState::Shared); target_address, backing_block, backing_block_offset, size, MemoryState::Shared);

@ -111,9 +111,6 @@ public:
SharedPtr<Process> owner_process; SharedPtr<Process> owner_process;
/// Address of shared memory block in the owner process if specified. /// Address of shared memory block in the owner process if specified.
VAddr base_address; VAddr base_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. /// Backing memory for this shared memory block.
std::shared_ptr<std::vector<u8>> backing_block; std::shared_ptr<std::vector<u8>> backing_block;
/// Offset into the backing block for this shared memory. /// Offset into the backing block for this shared memory.

@ -20,7 +20,6 @@
#include "core/core_timing_util.h" #include "core/core_timing_util.h"
#include "core/hle/kernel/errors.h" #include "core/hle/kernel/errors.h"
#include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/handle_table.h"
#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/object.h" #include "core/hle/kernel/object.h"
#include "core/hle/kernel/process.h" #include "core/hle/kernel/process.h"
#include "core/hle/kernel/thread.h" #include "core/hle/kernel/thread.h"
@ -81,8 +80,8 @@ void Thread::Stop() {
wait_objects.clear(); wait_objects.clear();
// Mark the TLS slot in the thread's page as free. // Mark the TLS slot in the thread's page as free.
u64 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE; const u64 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE;
u64 tls_slot = const u64 tls_slot =
((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE; ((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
Core::CurrentProcess()->tls_slots[tls_page].reset(tls_slot); Core::CurrentProcess()->tls_slots[tls_page].reset(tls_slot);
} }
@ -336,38 +335,10 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
auto& tls_slots = owner_process->tls_slots; auto& tls_slots = owner_process->tls_slots;
auto [available_page, available_slot, needs_allocation] = GetFreeThreadLocalSlot(tls_slots); auto [available_page, available_slot, needs_allocation] = GetFreeThreadLocalSlot(tls_slots);
if (needs_allocation) { if (needs_allocation) {
// There are no already-allocated pages with free slots, lets allocate a new one.
// TLS pages are allocated from the BASE region in the linear heap.
MemoryRegionInfo* memory_region = GetMemoryRegion(MemoryRegion::BASE);
auto& linheap_memory = memory_region->linear_heap_memory;
if (linheap_memory->size() + Memory::PAGE_SIZE > memory_region->size) {
LOG_ERROR(Kernel_SVC,
"Not enough space in region to allocate a new TLS page for thread");
return ERR_OUT_OF_MEMORY;
}
size_t offset = linheap_memory->size();
// Allocate some memory from the end of the linear heap for this region.
linheap_memory->insert(linheap_memory->end(), Memory::PAGE_SIZE, 0);
memory_region->used += Memory::PAGE_SIZE;
owner_process->linear_heap_used += Memory::PAGE_SIZE;
tls_slots.emplace_back(0); // The page is completely available at the start tls_slots.emplace_back(0); // The page is completely available at the start
available_page = tls_slots.size() - 1; available_page = tls_slots.size() - 1;
available_slot = 0; // Use the first slot in the new page available_slot = 0; // Use the first slot in the new page
auto& vm_manager = owner_process->vm_manager;
vm_manager.RefreshMemoryBlockMappings(linheap_memory.get());
// Map the page to the current process' address space.
// TODO(Subv): Find the correct MemoryState for this region.
vm_manager.MapMemoryBlock(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE,
linheap_memory, offset, Memory::PAGE_SIZE,
MemoryState::ThreadLocal);
} }
// Mark the slot as used // Mark the slot as used

@ -14,7 +14,6 @@
#include "common/swap.h" #include "common/swap.h"
#include "core/arm/arm_interface.h" #include "core/arm/arm_interface.h"
#include "core/core.h" #include "core/core.h"
#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/process.h" #include "core/hle/kernel/process.h"
#include "core/hle/lock.h" #include "core/hle/lock.h"
#include "core/memory.h" #include "core/memory.h"
@ -24,8 +23,6 @@
namespace Memory { namespace Memory {
static std::array<u8, Memory::VRAM_SIZE> vram;
static PageTable* current_page_table = nullptr; static PageTable* current_page_table = nullptr;
void SetCurrentPageTable(PageTable* page_table) { void SetCurrentPageTable(PageTable* page_table) {
@ -242,10 +239,6 @@ bool IsKernelVirtualAddress(const VAddr vaddr) {
return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END; return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END;
} }
bool IsValidPhysicalAddress(const PAddr paddr) {
return GetPhysicalPointer(paddr) != nullptr;
}
u8* GetPointer(const VAddr vaddr) { u8* GetPointer(const VAddr vaddr) {
u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
if (page_pointer) { if (page_pointer) {
@ -274,61 +267,6 @@ std::string ReadCString(VAddr vaddr, std::size_t max_length) {
return string; return string;
} }
u8* GetPhysicalPointer(PAddr address) {
struct MemoryArea {
PAddr paddr_base;
u32 size;
};
static constexpr MemoryArea memory_areas[] = {
{VRAM_PADDR, VRAM_SIZE},
{IO_AREA_PADDR, IO_AREA_SIZE},
{DSP_RAM_PADDR, DSP_RAM_SIZE},
{FCRAM_PADDR, FCRAM_N3DS_SIZE},
};
const auto area =
std::find_if(std::begin(memory_areas), std::end(memory_areas), [&](const auto& area) {
return address >= area.paddr_base && address < area.paddr_base + area.size;
});
if (area == std::end(memory_areas)) {
LOG_ERROR(HW_Memory, "Unknown GetPhysicalPointer @ 0x{:016X}", address);
return nullptr;
}
if (area->paddr_base == IO_AREA_PADDR) {
LOG_ERROR(HW_Memory, "MMIO mappings are not supported yet. phys_addr={:016X}", address);
return nullptr;
}
u64 offset_into_region = address - area->paddr_base;
u8* target_pointer = nullptr;
switch (area->paddr_base) {
case VRAM_PADDR:
target_pointer = vram.data() + offset_into_region;
break;
case DSP_RAM_PADDR:
break;
case FCRAM_PADDR:
for (const auto& region : Kernel::memory_regions) {
if (offset_into_region >= region.base &&
offset_into_region < region.base + region.size) {
target_pointer =
region.linear_heap_memory->data() + offset_into_region - region.base;
break;
}
}
ASSERT_MSG(target_pointer != nullptr, "Invalid FCRAM address");
break;
default:
UNREACHABLE();
}
return target_pointer;
}
void RasterizerMarkRegionCached(Tegra::GPUVAddr gpu_addr, u64 size, bool cached) { void RasterizerMarkRegionCached(Tegra::GPUVAddr gpu_addr, u64 size, bool cached) {
if (gpu_addr == 0) { if (gpu_addr == 0) {
return; return;
@ -666,48 +604,4 @@ void CopyBlock(VAddr dest_addr, VAddr src_addr, size_t size) {
CopyBlock(*Core::CurrentProcess(), dest_addr, src_addr, size); CopyBlock(*Core::CurrentProcess(), dest_addr, src_addr, size);
} }
boost::optional<PAddr> TryVirtualToPhysicalAddress(const VAddr addr) {
if (addr == 0) {
return 0;
} else if (addr >= VRAM_VADDR && addr < VRAM_VADDR_END) {
return addr - VRAM_VADDR + VRAM_PADDR;
} else if (addr >= LINEAR_HEAP_VADDR && addr < LINEAR_HEAP_VADDR_END) {
return addr - LINEAR_HEAP_VADDR + FCRAM_PADDR;
} else if (addr >= NEW_LINEAR_HEAP_VADDR && addr < NEW_LINEAR_HEAP_VADDR_END) {
return addr - NEW_LINEAR_HEAP_VADDR + FCRAM_PADDR;
} else if (addr >= DSP_RAM_VADDR && addr < DSP_RAM_VADDR_END) {
return addr - DSP_RAM_VADDR + DSP_RAM_PADDR;
} else if (addr >= IO_AREA_VADDR && addr < IO_AREA_VADDR_END) {
return addr - IO_AREA_VADDR + IO_AREA_PADDR;
}
return boost::none;
}
PAddr VirtualToPhysicalAddress(const VAddr addr) {
auto paddr = TryVirtualToPhysicalAddress(addr);
if (!paddr) {
LOG_ERROR(HW_Memory, "Unknown virtual address @ 0x{:016X}", addr);
// To help with debugging, set bit on address so that it's obviously invalid.
return addr | 0x80000000;
}
return *paddr;
}
boost::optional<VAddr> PhysicalToVirtualAddress(const PAddr addr) {
if (addr == 0) {
return 0;
} else if (addr >= VRAM_PADDR && addr < VRAM_PADDR_END) {
return addr - VRAM_PADDR + VRAM_VADDR;
} else if (addr >= FCRAM_PADDR && addr < FCRAM_PADDR_END) {
return addr - FCRAM_PADDR + Core::CurrentProcess()->GetLinearHeapAreaAddress();
} else if (addr >= DSP_RAM_PADDR && addr < DSP_RAM_PADDR_END) {
return addr - DSP_RAM_PADDR + DSP_RAM_VADDR;
} else if (addr >= IO_AREA_PADDR && addr < IO_AREA_PADDR_END) {
return addr - IO_AREA_PADDR + IO_AREA_VADDR;
}
return boost::none;
}
} // namespace Memory } // namespace Memory

@ -6,12 +6,9 @@
#include <array> #include <array>
#include <cstddef> #include <cstddef>
#include <map>
#include <string> #include <string>
#include <tuple> #include <tuple>
#include <vector>
#include <boost/icl/interval_map.hpp> #include <boost/icl/interval_map.hpp>
#include <boost/optional.hpp>
#include "common/common_types.h" #include "common/common_types.h"
#include "core/memory_hook.h" #include "core/memory_hook.h"
#include "video_core/memory_manager.h" #include "video_core/memory_manager.h"
@ -85,40 +82,6 @@ struct PageTable {
std::array<PageType, PAGE_TABLE_NUM_ENTRIES> attributes; std::array<PageType, PAGE_TABLE_NUM_ENTRIES> attributes;
}; };
/// Physical memory regions as seen from the ARM11
enum : PAddr {
/// IO register area
IO_AREA_PADDR = 0x10100000,
IO_AREA_SIZE = 0x01000000, ///< IO area size (16MB)
IO_AREA_PADDR_END = IO_AREA_PADDR + IO_AREA_SIZE,
/// MPCore internal memory region
MPCORE_RAM_PADDR = 0x17E00000,
MPCORE_RAM_SIZE = 0x00002000, ///< MPCore internal memory size (8KB)
MPCORE_RAM_PADDR_END = MPCORE_RAM_PADDR + MPCORE_RAM_SIZE,
/// Video memory
VRAM_PADDR = 0x18000000,
VRAM_SIZE = 0x00600000, ///< VRAM size (6MB)
VRAM_PADDR_END = VRAM_PADDR + VRAM_SIZE,
/// DSP memory
DSP_RAM_PADDR = 0x1FF00000,
DSP_RAM_SIZE = 0x00080000, ///< DSP memory size (512KB)
DSP_RAM_PADDR_END = DSP_RAM_PADDR + DSP_RAM_SIZE,
/// AXI WRAM
AXI_WRAM_PADDR = 0x1FF80000,
AXI_WRAM_SIZE = 0x00080000, ///< AXI WRAM size (512KB)
AXI_WRAM_PADDR_END = AXI_WRAM_PADDR + AXI_WRAM_SIZE,
/// Main FCRAM
FCRAM_PADDR = 0x20000000,
FCRAM_SIZE = 0x08000000, ///< FCRAM size on the Old 3DS (128MB)
FCRAM_N3DS_SIZE = 0x10000000, ///< FCRAM size on the New 3DS (256MB)
FCRAM_PADDR_END = FCRAM_PADDR + FCRAM_SIZE,
};
/// Virtual user-space memory regions /// Virtual user-space memory regions
enum : VAddr { enum : VAddr {
/// Where the application text, data and bss reside. /// Where the application text, data and bss reside.
@ -126,24 +89,6 @@ enum : VAddr {
PROCESS_IMAGE_MAX_SIZE = 0x08000000, PROCESS_IMAGE_MAX_SIZE = 0x08000000,
PROCESS_IMAGE_VADDR_END = PROCESS_IMAGE_VADDR + PROCESS_IMAGE_MAX_SIZE, PROCESS_IMAGE_VADDR_END = PROCESS_IMAGE_VADDR + PROCESS_IMAGE_MAX_SIZE,
/// Maps 1:1 to an offset in FCRAM. Used for HW allocations that need to be linear in physical
/// memory.
LINEAR_HEAP_VADDR = 0x14000000,
LINEAR_HEAP_SIZE = 0x08000000,
LINEAR_HEAP_VADDR_END = LINEAR_HEAP_VADDR + LINEAR_HEAP_SIZE,
/// Maps 1:1 to the IO register area.
IO_AREA_VADDR = 0x1EC00000,
IO_AREA_VADDR_END = IO_AREA_VADDR + IO_AREA_SIZE,
/// Maps 1:1 to VRAM.
VRAM_VADDR = 0x1F000000,
VRAM_VADDR_END = VRAM_VADDR + VRAM_SIZE,
/// Maps 1:1 to DSP memory.
DSP_RAM_VADDR = 0x1FF00000,
DSP_RAM_VADDR_END = DSP_RAM_VADDR + DSP_RAM_SIZE,
/// Read-only page containing kernel and system configuration values. /// Read-only page containing kernel and system configuration values.
CONFIG_MEMORY_VADDR = 0x1FF80000, CONFIG_MEMORY_VADDR = 0x1FF80000,
CONFIG_MEMORY_SIZE = 0x00001000, CONFIG_MEMORY_SIZE = 0x00001000,
@ -154,13 +99,8 @@ enum : VAddr {
SHARED_PAGE_SIZE = 0x00001000, SHARED_PAGE_SIZE = 0x00001000,
SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE, SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE,
/// Equivalent to LINEAR_HEAP_VADDR, but expanded to cover the extra memory in the New 3DS.
NEW_LINEAR_HEAP_VADDR = 0x30000000,
NEW_LINEAR_HEAP_SIZE = 0x10000000,
NEW_LINEAR_HEAP_VADDR_END = NEW_LINEAR_HEAP_VADDR + NEW_LINEAR_HEAP_SIZE,
/// Area where TLS (Thread-Local Storage) buffers are allocated. /// Area where TLS (Thread-Local Storage) buffers are allocated.
TLS_AREA_VADDR = NEW_LINEAR_HEAP_VADDR_END, TLS_AREA_VADDR = 0x40000000,
TLS_ENTRY_SIZE = 0x200, TLS_ENTRY_SIZE = 0x200,
TLS_AREA_SIZE = 0x10000000, TLS_AREA_SIZE = 0x10000000,
TLS_AREA_VADDR_END = TLS_AREA_VADDR + TLS_AREA_SIZE, TLS_AREA_VADDR_END = TLS_AREA_VADDR + TLS_AREA_SIZE,
@ -205,8 +145,6 @@ bool IsValidVirtualAddress(const VAddr addr);
/// Determines if the given VAddr is a kernel address /// Determines if the given VAddr is a kernel address
bool IsKernelVirtualAddress(const VAddr addr); bool IsKernelVirtualAddress(const VAddr addr);
bool IsValidPhysicalAddress(const PAddr addr);
u8 Read8(VAddr addr); u8 Read8(VAddr addr);
u16 Read16(VAddr addr); u16 Read16(VAddr addr);
u32 Read32(VAddr addr); u32 Read32(VAddr addr);
@ -230,30 +168,6 @@ u8* GetPointer(VAddr virtual_address);
std::string ReadCString(VAddr virtual_address, std::size_t max_length); std::string ReadCString(VAddr virtual_address, std::size_t max_length);
/**
* Converts a virtual address inside a region with 1:1 mapping to physical memory to a physical
* address. This should be used by services to translate addresses for use by the hardware.
*/
boost::optional<PAddr> TryVirtualToPhysicalAddress(VAddr addr);
/**
* Converts a virtual address inside a region with 1:1 mapping to physical memory to a physical
* address. This should be used by services to translate addresses for use by the hardware.
*
* @deprecated Use TryVirtualToPhysicalAddress(), which reports failure.
*/
PAddr VirtualToPhysicalAddress(VAddr addr);
/**
* Undoes a mapping performed by VirtualToPhysicalAddress().
*/
boost::optional<VAddr> PhysicalToVirtualAddress(PAddr addr);
/**
* Gets a pointer to the memory region beginning at the specified physical address.
*/
u8* GetPhysicalPointer(PAddr address);
enum class FlushMode { enum class FlushMode {
/// Write back modified surfaces to RAM /// Write back modified surfaces to RAM
Flush, Flush,

@ -3,7 +3,6 @@ add_executable(tests
core/arm/arm_test_common.cpp core/arm/arm_test_common.cpp
core/arm/arm_test_common.h core/arm/arm_test_common.h
core/core_timing.cpp core/core_timing.cpp
core/memory/memory.cpp
glad.cpp glad.cpp
tests.cpp tests.cpp
) )

@ -1,56 +0,0 @@
// Copyright 2017 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <catch.hpp>
#include "core/hle/kernel/memory.h"
#include "core/hle/kernel/process.h"
#include "core/memory.h"
TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory][!hide]") {
SECTION("these regions should not be mapped on an empty process") {
auto process = Kernel::Process::Create("");
CHECK(Memory::IsValidVirtualAddress(*process, Memory::PROCESS_IMAGE_VADDR) == false);
CHECK(Memory::IsValidVirtualAddress(*process, Memory::HEAP_VADDR) == false);
CHECK(Memory::IsValidVirtualAddress(*process, Memory::LINEAR_HEAP_VADDR) == false);
CHECK(Memory::IsValidVirtualAddress(*process, Memory::VRAM_VADDR) == false);
CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == false);
CHECK(Memory::IsValidVirtualAddress(*process, Memory::SHARED_PAGE_VADDR) == false);
CHECK(Memory::IsValidVirtualAddress(*process, Memory::TLS_AREA_VADDR) == false);
}
SECTION("CONFIG_MEMORY_VADDR and SHARED_PAGE_VADDR should be valid after mapping them") {
auto process = Kernel::Process::Create("");
Kernel::MapSharedPages(process->vm_manager);
CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == true);
CHECK(Memory::IsValidVirtualAddress(*process, Memory::SHARED_PAGE_VADDR) == true);
}
SECTION("special regions should be valid after mapping them") {
auto process = Kernel::Process::Create("");
SECTION("VRAM") {
Kernel::HandleSpecialMapping(process->vm_manager,
{Memory::VRAM_VADDR, Memory::VRAM_SIZE, false, false});
CHECK(Memory::IsValidVirtualAddress(*process, Memory::VRAM_VADDR) == true);
}
SECTION("IO (Not yet implemented)") {
Kernel::HandleSpecialMapping(
process->vm_manager, {Memory::IO_AREA_VADDR, Memory::IO_AREA_SIZE, false, false});
CHECK_FALSE(Memory::IsValidVirtualAddress(*process, Memory::IO_AREA_VADDR) == true);
}
SECTION("DSP") {
Kernel::HandleSpecialMapping(
process->vm_manager, {Memory::DSP_RAM_VADDR, Memory::DSP_RAM_SIZE, false, false});
CHECK(Memory::IsValidVirtualAddress(*process, Memory::DSP_RAM_VADDR) == true);
}
}
SECTION("Unmapping a VAddr should make it invalid") {
auto process = Kernel::Process::Create("");
Kernel::MapSharedPages(process->vm_manager);
process->vm_manager.UnmapRange(Memory::CONFIG_MEMORY_VADDR, Memory::CONFIG_MEMORY_SIZE);
CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == false);
}
}