Merge pull request #908 from lioncash/memory
core/memory: Get rid of 3DS leftovers
This commit is contained in:
commit
40e63ede6d
@ -63,8 +63,6 @@ add_library(core STATIC
|
||||
hle/kernel/hle_ipc.h
|
||||
hle/kernel/kernel.cpp
|
||||
hle/kernel/kernel.h
|
||||
hle/kernel/memory.cpp
|
||||
hle/kernel/memory.h
|
||||
hle/kernel/mutex.cpp
|
||||
hle/kernel/mutex.h
|
||||
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) {
|
||||
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
|
||||
static_cast<int>(init_result));
|
||||
@ -161,7 +161,7 @@ Cpu& System::CpuCore(size_t 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");
|
||||
|
||||
CoreTiming::Init();
|
||||
@ -178,7 +178,7 @@ System::ResultStatus System::Init(EmuWindow& emu_window, u32 system_mode) {
|
||||
telemetry_session = std::make_unique<Core::TelemetrySession>();
|
||||
service_manager = std::make_shared<Service::SM::ServiceManager>();
|
||||
|
||||
Kernel::Init(system_mode);
|
||||
Kernel::Init();
|
||||
Service::Init(service_manager);
|
||||
GDBStub::Init();
|
||||
|
||||
|
@ -189,10 +189,9 @@ private:
|
||||
* Initialize the emulated system.
|
||||
* @param emu_window Reference to the host-system window used for video output and keyboard
|
||||
* input.
|
||||
* @param system_mode The system mode.
|
||||
* @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
|
||||
std::unique_ptr<Loader::AppLoader> app_loader;
|
||||
|
@ -4,7 +4,6 @@
|
||||
|
||||
#include "core/hle/kernel/handle_table.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/memory.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/resource_limit.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
@ -15,9 +14,7 @@ namespace Kernel {
|
||||
unsigned int Object::next_object_id;
|
||||
|
||||
/// Initialize the kernel
|
||||
void Init(u32 system_mode) {
|
||||
Kernel::MemoryInit(system_mode);
|
||||
|
||||
void Init() {
|
||||
Kernel::ResourceLimitsInit();
|
||||
Kernel::ThreadingInit();
|
||||
Kernel::TimersInit();
|
||||
@ -37,7 +34,6 @@ void Shutdown() {
|
||||
|
||||
Kernel::TimersShutdown();
|
||||
Kernel::ResourceLimitsShutdown();
|
||||
Kernel::MemoryShutdown();
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
|
@ -9,7 +9,7 @@
|
||||
namespace Kernel {
|
||||
|
||||
/// Initialize the kernel with the specified system mode.
|
||||
void Init(u32 system_mode);
|
||||
void Init();
|
||||
|
||||
/// Shutdown the kernel
|
||||
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/logging/log.h"
|
||||
#include "core/hle/kernel/errors.h"
|
||||
#include "core/hle/kernel/memory.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/resource_limit.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,
|
||||
MemoryState::Mapped)
|
||||
.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();
|
||||
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) {
|
||||
memory_region = GetMemoryRegion(flags.memory_region);
|
||||
|
||||
auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions,
|
||||
MemoryState memory_state) {
|
||||
const auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions,
|
||||
MemoryState memory_state) {
|
||||
auto vma = vm_manager
|
||||
.MapMemoryBlock(segment.addr + base_addr, module_->memory, segment.offset,
|
||||
segment.size, memory_state)
|
||||
.Unwrap();
|
||||
vm_manager.Reprotect(vma, permissions);
|
||||
misc_memory_used += segment.size;
|
||||
memory_region->used += segment.size;
|
||||
};
|
||||
|
||||
// Map CodeSet segments
|
||||
@ -160,20 +147,6 @@ void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) {
|
||||
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) {
|
||||
if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END ||
|
||||
target + size < target) {
|
||||
@ -206,7 +179,6 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission per
|
||||
vm_manager.Reprotect(vma, perms);
|
||||
|
||||
heap_used = size;
|
||||
memory_region->used += size;
|
||||
|
||||
return MakeResult<VAddr>(heap_end - size);
|
||||
}
|
||||
@ -226,52 +198,6 @@ ResultCode Process::HeapFree(VAddr target, u32 size) {
|
||||
return result;
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -53,7 +53,6 @@ union ProcessFlags {
|
||||
enum class ProcessStatus { Created, Running, Exited };
|
||||
|
||||
class ResourceLimit;
|
||||
struct MemoryRegionInfo;
|
||||
|
||||
struct CodeSet final : public Object {
|
||||
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
|
||||
// in the emulator address space, allowing Memory::GetPointer to be reasonably safe.
|
||||
std::shared_ptr<std::vector<u8>> heap_memory;
|
||||
|
||||
// The left/right bounds of the address space covered by heap_memory.
|
||||
VAddr heap_start = 0, heap_end = 0;
|
||||
|
||||
u64 heap_used = 0, linear_heap_used = 0, misc_memory_used = 0;
|
||||
|
||||
MemoryRegionInfo* memory_region = nullptr;
|
||||
VAddr heap_start = 0;
|
||||
VAddr heap_end = 0;
|
||||
u64 heap_used = 0;
|
||||
|
||||
/// 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
|
||||
@ -179,16 +177,9 @@ public:
|
||||
|
||||
std::string name;
|
||||
|
||||
VAddr GetLinearHeapAreaAddress() const;
|
||||
VAddr GetLinearHeapBase() const;
|
||||
VAddr GetLinearHeapLimit() const;
|
||||
|
||||
ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms);
|
||||
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 UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size);
|
||||
|
@ -8,7 +8,6 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/errors.h"
|
||||
#include "core/hle/kernel/memory.h"
|
||||
#include "core/hle/kernel/shared_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->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;
|
||||
auto& vm_manager = shared_memory->owner_process->vm_manager;
|
||||
|
||||
ASSERT_MSG(linheap_memory->size() + size <= memory_region->size,
|
||||
"Not enough space in region to allocate shared memory!");
|
||||
// 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");
|
||||
|
||||
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 +
|
||||
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;
|
||||
}
|
||||
// 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->base_address = address;
|
||||
|
||||
return shared_memory;
|
||||
}
|
||||
|
||||
@ -124,11 +94,6 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi
|
||||
|
||||
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
|
||||
auto result = target_process->vm_manager.MapMemoryBlock(
|
||||
target_address, backing_block, backing_block_offset, size, MemoryState::Shared);
|
||||
|
@ -111,9 +111,6 @@ public:
|
||||
SharedPtr<Process> owner_process;
|
||||
/// Address of shared memory block in the owner process if specified.
|
||||
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.
|
||||
std::shared_ptr<std::vector<u8>> backing_block;
|
||||
/// Offset into the backing block for this shared memory.
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include "core/core_timing_util.h"
|
||||
#include "core/hle/kernel/errors.h"
|
||||
#include "core/hle/kernel/handle_table.h"
|
||||
#include "core/hle/kernel/memory.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
@ -81,8 +80,8 @@ void Thread::Stop() {
|
||||
wait_objects.clear();
|
||||
|
||||
// Mark the TLS slot in the thread's page as free.
|
||||
u64 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE;
|
||||
u64 tls_slot =
|
||||
const u64 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE;
|
||||
const u64 tls_slot =
|
||||
((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
|
||||
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 [available_page, available_slot, needs_allocation] = GetFreeThreadLocalSlot(tls_slots);
|
||||
|
||||
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
|
||||
available_page = tls_slots.size() - 1;
|
||||
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
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include "common/swap.h"
|
||||
#include "core/arm/arm_interface.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/memory.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/lock.h"
|
||||
#include "core/memory.h"
|
||||
@ -24,8 +23,6 @@
|
||||
|
||||
namespace Memory {
|
||||
|
||||
static std::array<u8, Memory::VRAM_SIZE> vram;
|
||||
|
||||
static PageTable* current_page_table = nullptr;
|
||||
|
||||
void SetCurrentPageTable(PageTable* page_table) {
|
||||
@ -242,10 +239,6 @@ bool IsKernelVirtualAddress(const VAddr vaddr) {
|
||||
return KERNEL_REGION_VADDR <= vaddr && vaddr < KERNEL_REGION_END;
|
||||
}
|
||||
|
||||
bool IsValidPhysicalAddress(const PAddr paddr) {
|
||||
return GetPhysicalPointer(paddr) != nullptr;
|
||||
}
|
||||
|
||||
u8* GetPointer(const VAddr vaddr) {
|
||||
u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
|
||||
if (page_pointer) {
|
||||
@ -274,61 +267,6 @@ std::string ReadCString(VAddr vaddr, std::size_t max_length) {
|
||||
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) {
|
||||
if (gpu_addr == 0) {
|
||||
return;
|
||||
@ -666,48 +604,4 @@ void CopyBlock(VAddr dest_addr, VAddr src_addr, size_t 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
|
||||
|
@ -6,12 +6,9 @@
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
#include <boost/icl/interval_map.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "core/memory_hook.h"
|
||||
#include "video_core/memory_manager.h"
|
||||
@ -85,40 +82,6 @@ struct PageTable {
|
||||
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
|
||||
enum : VAddr {
|
||||
/// Where the application text, data and bss reside.
|
||||
@ -126,24 +89,6 @@ enum : VAddr {
|
||||
PROCESS_IMAGE_MAX_SIZE = 0x08000000,
|
||||
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.
|
||||
CONFIG_MEMORY_VADDR = 0x1FF80000,
|
||||
CONFIG_MEMORY_SIZE = 0x00001000,
|
||||
@ -154,13 +99,8 @@ enum : VAddr {
|
||||
SHARED_PAGE_SIZE = 0x00001000,
|
||||
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.
|
||||
TLS_AREA_VADDR = NEW_LINEAR_HEAP_VADDR_END,
|
||||
TLS_AREA_VADDR = 0x40000000,
|
||||
TLS_ENTRY_SIZE = 0x200,
|
||||
TLS_AREA_SIZE = 0x10000000,
|
||||
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
|
||||
bool IsKernelVirtualAddress(const VAddr addr);
|
||||
|
||||
bool IsValidPhysicalAddress(const PAddr addr);
|
||||
|
||||
u8 Read8(VAddr addr);
|
||||
u16 Read16(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);
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
/// Write back modified surfaces to RAM
|
||||
Flush,
|
||||
|
@ -3,7 +3,6 @@ add_executable(tests
|
||||
core/arm/arm_test_common.cpp
|
||||
core/arm/arm_test_common.h
|
||||
core/core_timing.cpp
|
||||
core/memory/memory.cpp
|
||||
glad.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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user