summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/audio_core/audio_renderer.cpp2
-rw-r--r--src/audio_core/audio_renderer.h2
-rw-r--r--src/audio_core/stream.cpp4
-rw-r--r--src/audio_core/stream.h14
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic.cpp5
-rw-r--r--src/core/file_sys/program_metadata.cpp4
-rw-r--r--src/core/file_sys/program_metadata.h6
-rw-r--r--src/core/gdbstub/gdbstub.cpp15
-rw-r--r--src/core/hle/kernel/process.cpp28
-rw-r--r--src/core/hle/kernel/process.h12
-rw-r--r--src/core/hle/kernel/shared_memory.cpp4
-rw-r--r--src/core/hle/kernel/svc.cpp45
-rw-r--r--src/core/hle/kernel/thread.cpp3
-rw-r--r--src/core/hle/kernel/vm_manager.cpp180
-rw-r--r--src/core/hle/kernel/vm_manager.h100
-rw-r--r--src/core/hle/service/audio/audren_u.cpp2
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp18
-rw-r--r--src/core/loader/elf.cpp32
-rw-r--r--src/core/loader/nro.cpp12
-rw-r--r--src/core/loader/nso.cpp14
-rw-r--r--src/core/memory.cpp30
-rw-r--r--src/core/memory.h63
-rw-r--r--src/tests/core/arm/arm_test_common.cpp7
-rw-r--r--src/video_core/engines/maxwell_3d.h8
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp7
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h5
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.h3
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp31
-rw-r--r--src/video_core/renderer_opengl/gl_state.h7
-rw-r--r--src/yuzu/game_list.cpp14
-rw-r--r--src/yuzu/game_list.h32
-rw-r--r--src/yuzu/game_list_p.h40
32 files changed, 533 insertions, 216 deletions
diff --git a/src/audio_core/audio_renderer.cpp b/src/audio_core/audio_renderer.cpp
index 521b19ff7..6f0ff953a 100644
--- a/src/audio_core/audio_renderer.cpp
+++ b/src/audio_core/audio_renderer.cpp
@@ -79,7 +79,7 @@ u32 AudioRenderer::GetMixBufferCount() const {
return worker_params.mix_buffer_count;
}
-u32 AudioRenderer::GetState() const {
+Stream::State AudioRenderer::GetStreamState() const {
return stream->GetState();
}
diff --git a/src/audio_core/audio_renderer.h b/src/audio_core/audio_renderer.h
index be923ee65..dfef89e1d 100644
--- a/src/audio_core/audio_renderer.h
+++ b/src/audio_core/audio_renderer.h
@@ -170,7 +170,7 @@ public:
u32 GetSampleRate() const;
u32 GetSampleCount() const;
u32 GetMixBufferCount() const;
- u32 GetState() const;
+ Stream::State GetStreamState() const;
private:
class VoiceState;
diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp
index ee4aa98af..742a5e0a0 100644
--- a/src/audio_core/stream.cpp
+++ b/src/audio_core/stream.cpp
@@ -53,8 +53,8 @@ void Stream::Stop() {
ASSERT_MSG(false, "Unimplemented");
}
-u32 Stream::GetState() const {
- return static_cast<u32>(state);
+Stream::State Stream::GetState() const {
+ return state;
}
s64 Stream::GetBufferReleaseCycles(const Buffer& buffer) const {
diff --git a/src/audio_core/stream.h b/src/audio_core/stream.h
index 43eca74e1..aebfeb51d 100644
--- a/src/audio_core/stream.h
+++ b/src/audio_core/stream.h
@@ -33,6 +33,12 @@ public:
Multi51Channel16,
};
+ /// Current state of the stream
+ enum class State {
+ Stopped,
+ Playing,
+ };
+
/// Callback function type, used to change guest state on a buffer being released
using ReleaseCallback = std::function<void()>;
@@ -73,15 +79,9 @@ public:
u32 GetNumChannels() const;
/// Get the state
- u32 GetState() const;
+ State GetState() const;
private:
- /// Current state of the stream
- enum class State {
- Stopped,
- Playing,
- };
-
/// Plays the next queued buffer in the audio stream, starting playback if necessary
void PlayNextBuffer();
diff --git a/src/core/arm/dynarmic/arm_dynarmic.cpp b/src/core/arm/dynarmic/arm_dynarmic.cpp
index 8760d17a8..8cad070b4 100644
--- a/src/core/arm/dynarmic/arm_dynarmic.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic.cpp
@@ -129,7 +129,8 @@ public:
};
std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const {
- auto** const page_table = Core::CurrentProcess()->vm_manager.page_table.pointers.data();
+ auto& current_process = Core::CurrentProcess();
+ auto** const page_table = current_process->vm_manager.page_table.pointers.data();
Dynarmic::A64::UserConfig config;
@@ -138,7 +139,7 @@ std::unique_ptr<Dynarmic::A64::Jit> ARM_Dynarmic::MakeJit() const {
// Memory
config.page_table = reinterpret_cast<void**>(page_table);
- config.page_table_address_space_bits = Memory::ADDRESS_SPACE_BITS;
+ config.page_table_address_space_bits = current_process->vm_manager.GetAddressSpaceWidth();
config.silently_mirror_page_table = false;
// Multi-process state
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp
index 02319ce0f..8903ed1d3 100644
--- a/src/core/file_sys/program_metadata.cpp
+++ b/src/core/file_sys/program_metadata.cpp
@@ -83,10 +83,12 @@ void ProgramMetadata::Print() const {
auto address_space = "Unknown";
switch (npdm_header.address_space_type) {
- case ProgramAddressSpaceType::Is64Bit:
+ case ProgramAddressSpaceType::Is36Bit:
+ case ProgramAddressSpaceType::Is39Bit:
address_space = "64-bit";
break;
case ProgramAddressSpaceType::Is32Bit:
+ case ProgramAddressSpaceType::Is32BitNoMap:
address_space = "32-bit";
break;
}
diff --git a/src/core/file_sys/program_metadata.h b/src/core/file_sys/program_metadata.h
index 1143e36c4..e4470d6f0 100644
--- a/src/core/file_sys/program_metadata.h
+++ b/src/core/file_sys/program_metadata.h
@@ -17,8 +17,10 @@ enum class ResultStatus : u16;
namespace FileSys {
enum class ProgramAddressSpaceType : u8 {
- Is64Bit = 1,
- Is32Bit = 2,
+ Is32Bit = 0,
+ Is36Bit = 1,
+ Is32BitNoMap = 2,
+ Is39Bit = 3,
};
enum class ProgramFilePermission : u64 {
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp
index 0ecdd9f82..d8c7b3492 100644
--- a/src/core/gdbstub/gdbstub.cpp
+++ b/src/core/gdbstub/gdbstub.cpp
@@ -37,7 +37,9 @@
#include "core/core.h"
#include "core/core_cpu.h"
#include "core/gdbstub/gdbstub.h"
+#include "core/hle/kernel/process.h"
#include "core/hle/kernel/scheduler.h"
+#include "core/hle/kernel/vm_manager.h"
#include "core/loader/loader.h"
#include "core/memory.h"
@@ -585,7 +587,8 @@ static void HandleQuery() {
strlen("Xfer:features:read:target.xml:")) == 0) {
SendReply(target_xml);
} else if (strncmp(query, "Offsets", strlen("Offsets")) == 0) {
- std::string buffer = fmt::format("TextSeg={:0x}", Memory::PROCESS_IMAGE_VADDR);
+ const VAddr base_address = Core::CurrentProcess()->vm_manager.GetCodeRegionBaseAddress();
+ std::string buffer = fmt::format("TextSeg={:0x}", base_address);
SendReply(buffer.c_str());
} else if (strncmp(query, "fThreadInfo", strlen("fThreadInfo")) == 0) {
std::string val = "m";
@@ -893,11 +896,11 @@ static void ReadMemory() {
static u8 reply[GDB_BUFFER_SIZE - 4];
auto start_offset = command_buffer + 1;
- auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
- VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));
+ const auto addr_pos = std::find(start_offset, command_buffer + command_length, ',');
+ const VAddr addr = HexToLong(start_offset, static_cast<u64>(addr_pos - start_offset));
start_offset = addr_pos + 1;
- u64 len =
+ const u64 len =
HexToLong(start_offset, static_cast<u64>((command_buffer + command_length) - start_offset));
LOG_DEBUG(Debug_GDBStub, "gdb: addr: {:016X} len: {:016X}", addr, len);
@@ -906,7 +909,9 @@ static void ReadMemory() {
SendReply("E01");
}
- if (addr < Memory::PROCESS_IMAGE_VADDR || addr >= Memory::MAP_REGION_VADDR_END) {
+ const auto& vm_manager = Core::CurrentProcess()->vm_manager;
+ if (addr < vm_manager.GetCodeRegionBaseAddress() ||
+ addr >= vm_manager.GetMapRegionEndAddress()) {
return SendReply("E00");
}
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 121f741fd..a8e3098ca 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -8,6 +8,7 @@
#include "common/common_funcs.h"
#include "common/logging/log.h"
#include "core/core.h"
+#include "core/file_sys/program_metadata.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
@@ -34,14 +35,21 @@ SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) {
process->name = std::move(name);
process->flags.raw = 0;
process->flags.memory_region.Assign(MemoryRegion::APPLICATION);
+ process->resource_limit = kernel.ResourceLimitForCategory(ResourceLimitCategory::APPLICATION);
process->status = ProcessStatus::Created;
process->program_id = 0;
process->process_id = kernel.CreateNewProcessID();
+ process->svc_access_mask.set();
kernel.AppendNewProcess(process);
return process;
}
+void Process::LoadFromMetadata(const FileSys::ProgramMetadata& metadata) {
+ program_id = metadata.GetTitleID();
+ vm_manager.Reset(metadata.GetAddressSpaceType());
+}
+
void Process::ParseKernelCaps(const u32* kernel_caps, std::size_t len) {
for (std::size_t i = 0; i < len; ++i) {
u32 descriptor = kernel_caps[i];
@@ -119,7 +127,7 @@ void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
// TODO(bunnei): This is heap area that should be allocated by the kernel and not mapped as part
// of the user address space.
vm_manager
- .MapMemoryBlock(Memory::STACK_AREA_VADDR_END - stack_size,
+ .MapMemoryBlock(vm_manager.GetTLSIORegionEndAddress() - stack_size,
std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size,
MemoryState::Mapped)
.Unwrap();
@@ -185,6 +193,7 @@ static std::tuple<std::size_t, std::size_t, bool> FindFreeThreadLocalSlot(
VAddr Process::MarkNextAvailableTLSSlotAsUsed(Thread& thread) {
auto [available_page, available_slot, needs_allocation] = FindFreeThreadLocalSlot(tls_slots);
+ const VAddr tls_begin = vm_manager.GetTLSIORegionBaseAddress();
if (needs_allocation) {
tls_slots.emplace_back(0); // The page is completely available at the start
@@ -197,18 +206,17 @@ VAddr Process::MarkNextAvailableTLSSlotAsUsed(Thread& thread) {
vm_manager.RefreshMemoryBlockMappings(tls_memory.get());
- vm_manager.MapMemoryBlock(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE,
- tls_memory, 0, Memory::PAGE_SIZE, MemoryState::ThreadLocal);
+ vm_manager.MapMemoryBlock(tls_begin + available_page * Memory::PAGE_SIZE, tls_memory, 0,
+ Memory::PAGE_SIZE, MemoryState::ThreadLocal);
}
tls_slots[available_page].set(available_slot);
- return Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE +
- available_slot * Memory::TLS_ENTRY_SIZE;
+ return tls_begin + available_page * Memory::PAGE_SIZE + available_slot * Memory::TLS_ENTRY_SIZE;
}
void Process::FreeTLSSlot(VAddr tls_address) {
- const VAddr tls_base = tls_address - Memory::TLS_AREA_VADDR;
+ const VAddr tls_base = tls_address - vm_manager.GetTLSIORegionBaseAddress();
const VAddr tls_page = tls_base / Memory::PAGE_SIZE;
const VAddr tls_slot = (tls_base % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
@@ -232,8 +240,8 @@ void Process::LoadModule(SharedPtr<CodeSet> module_, VAddr base_addr) {
}
ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) {
- if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END ||
- target + size < target) {
+ if (target < vm_manager.GetHeapRegionBaseAddress() ||
+ target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) {
return ERR_INVALID_ADDRESS;
}
@@ -268,8 +276,8 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission per
}
ResultCode Process::HeapFree(VAddr target, u32 size) {
- if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END ||
- target + size < target) {
+ if (target < vm_manager.GetHeapRegionBaseAddress() ||
+ target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) {
return ERR_INVALID_ADDRESS;
}
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 04d74e572..adb03c228 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -17,6 +17,10 @@
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/vm_manager.h"
+namespace FileSys {
+class ProgramMetadata;
+}
+
namespace Kernel {
class KernelCore;
@@ -141,6 +145,14 @@ public:
return process_id;
}
+ /**
+ * Loads process-specifics configuration info with metadata provided
+ * by an executable.
+ *
+ * @param metadata The provided metadata to load process specific info.
+ */
+ void LoadFromMetadata(const FileSys::ProgramMetadata& metadata);
+
/// Title ID corresponding to the process
u64 program_id;
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index abb1d09cd..9b78c8cb5 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -8,6 +8,7 @@
#include "common/logging/log.h"
#include "core/core.h"
#include "core/hle/kernel/errors.h"
+#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/memory.h"
@@ -71,7 +72,8 @@ SharedPtr<SharedMemory> SharedMemory::CreateForApplet(
shared_memory->other_permissions = other_permissions;
shared_memory->backing_block = std::move(heap_block);
shared_memory->backing_block_offset = offset;
- shared_memory->base_address = Memory::HEAP_VADDR + offset;
+ shared_memory->base_address =
+ kernel.CurrentProcess()->vm_manager.GetHeapRegionBaseAddress() + offset;
return shared_memory;
}
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index c9d212a4c..44bbaf0c8 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -51,8 +51,9 @@ static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) {
}
auto& process = *Core::CurrentProcess();
+ const VAddr heap_base = process.vm_manager.GetHeapRegionBaseAddress();
CASCADE_RESULT(*heap_addr,
- process.HeapAllocate(Memory::HEAP_VADDR, heap_size, VMAPermission::ReadWrite));
+ process.HeapAllocate(heap_base, heap_size, VMAPermission::ReadWrite));
return RESULT_SUCCESS;
}
@@ -325,26 +326,27 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
LOG_TRACE(Kernel_SVC, "called info_id=0x{:X}, info_sub_id=0x{:X}, handle=0x{:08X}", info_id,
info_sub_id, handle);
- const auto& vm_manager = Core::CurrentProcess()->vm_manager;
+ const auto& current_process = Core::CurrentProcess();
+ const auto& vm_manager = current_process->vm_manager;
switch (static_cast<GetInfoType>(info_id)) {
case GetInfoType::AllowedCpuIdBitmask:
- *result = Core::CurrentProcess()->allowed_processor_mask;
+ *result = current_process->allowed_processor_mask;
break;
case GetInfoType::AllowedThreadPrioBitmask:
- *result = Core::CurrentProcess()->allowed_thread_priority_mask;
+ *result = current_process->allowed_thread_priority_mask;
break;
case GetInfoType::MapRegionBaseAddr:
- *result = Memory::MAP_REGION_VADDR;
+ *result = vm_manager.GetMapRegionBaseAddress();
break;
case GetInfoType::MapRegionSize:
- *result = Memory::MAP_REGION_SIZE;
+ *result = vm_manager.GetMapRegionSize();
break;
case GetInfoType::HeapRegionBaseAddr:
- *result = Memory::HEAP_VADDR;
+ *result = vm_manager.GetHeapRegionBaseAddress();
break;
case GetInfoType::HeapRegionSize:
- *result = Memory::HEAP_SIZE;
+ *result = vm_manager.GetHeapRegionSize();
break;
case GetInfoType::TotalMemoryUsage:
*result = vm_manager.GetTotalMemoryUsage();
@@ -359,22 +361,35 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
*result = 0;
break;
case GetInfoType::AddressSpaceBaseAddr:
- *result = vm_manager.GetAddressSpaceBaseAddr();
+ *result = vm_manager.GetCodeRegionBaseAddress();
break;
- case GetInfoType::AddressSpaceSize:
- *result = vm_manager.GetAddressSpaceSize();
+ case GetInfoType::AddressSpaceSize: {
+ const u64 width = vm_manager.GetAddressSpaceWidth();
+
+ switch (width) {
+ case 32:
+ *result = 0xFFE00000;
+ break;
+ case 36:
+ *result = 0xFF8000000;
+ break;
+ case 39:
+ *result = 0x7FF8000000;
+ break;
+ }
break;
+ }
case GetInfoType::NewMapRegionBaseAddr:
- *result = Memory::NEW_MAP_REGION_VADDR;
+ *result = vm_manager.GetNewMapRegionBaseAddress();
break;
case GetInfoType::NewMapRegionSize:
- *result = Memory::NEW_MAP_REGION_SIZE;
+ *result = vm_manager.GetNewMapRegionSize();
break;
case GetInfoType::IsVirtualAddressMemoryEnabled:
- *result = Core::CurrentProcess()->is_virtual_address_memory_enabled;
+ *result = current_process->is_virtual_address_memory_enabled;
break;
case GetInfoType::TitleId:
- *result = Core::CurrentProcess()->program_id;
+ *result = current_process->program_id;
break;
case GetInfoType::PrivilegedProcessId:
LOG_WARNING(Kernel_SVC,
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 315f65338..064ed908d 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -262,8 +262,9 @@ SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 pri
SetCurrentPageTable(&owner_process.vm_manager.page_table);
// Initialize new "main" thread
+ const VAddr stack_top = owner_process.vm_manager.GetTLSIORegionEndAddress();
auto thread_res = Thread::Create(kernel, "main", entry_point, priority, 0, THREADPROCESSORID_0,
- Memory::STACK_AREA_VADDR_END, &owner_process);
+ stack_top, &owner_process);
SharedPtr<Thread> thread = std::move(thread_res).Unwrap();
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index 608cbd57b..e412309fd 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -9,6 +9,7 @@
#include "common/logging/log.h"
#include "core/arm/arm_interface.h"
#include "core/core.h"
+#include "core/file_sys/program_metadata.h"
#include "core/hle/kernel/errors.h"
#include "core/hle/kernel/vm_manager.h"
#include "core/memory.h"
@@ -54,30 +55,32 @@ bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const {
}
VMManager::VMManager() {
- Reset();
+ // Default to assuming a 39-bit address space. This way we have a sane
+ // starting point with executables that don't provide metadata.
+ Reset(FileSys::ProgramAddressSpaceType::Is39Bit);
}
VMManager::~VMManager() {
- Reset();
+ Reset(FileSys::ProgramAddressSpaceType::Is39Bit);
}
-void VMManager::Reset() {
- vma_map.clear();
+void VMManager::Reset(FileSys::ProgramAddressSpaceType type) {
+ Clear();
+
+ InitializeMemoryRegionRanges(type);
+
+ page_table.Resize(address_space_width);
// Initialize the map with a single free region covering the entire managed space.
VirtualMemoryArea initial_vma;
- initial_vma.size = MAX_ADDRESS;
+ initial_vma.size = address_space_end;
vma_map.emplace(initial_vma.base, initial_vma);
- page_table.pointers.fill(nullptr);
- page_table.special_regions.clear();
- page_table.attributes.fill(Memory::PageType::Unmapped);
-
UpdatePageTableForVMA(initial_vma);
}
VMManager::VMAHandle VMManager::FindVMA(VAddr target) const {
- if (target >= MAX_ADDRESS) {
+ if (target >= address_space_end) {
return vma_map.end();
} else {
return std::prev(vma_map.upper_bound(target));
@@ -291,7 +294,7 @@ ResultVal<VMManager::VMAIter> VMManager::CarveVMARange(VAddr target, u64 size) {
const VAddr target_end = target + size;
ASSERT(target_end >= target);
- ASSERT(target_end <= MAX_ADDRESS);
+ ASSERT(target_end <= address_space_end);
ASSERT(size > 0);
VMAIter begin_vma = StripIterConstness(FindVMA(target));
@@ -382,6 +385,85 @@ void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
}
}
+void VMManager::InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType type) {
+ u64 map_region_size = 0;
+ u64 heap_region_size = 0;
+ u64 new_map_region_size = 0;
+ u64 tls_io_region_size = 0;
+
+ switch (type) {
+ case FileSys::ProgramAddressSpaceType::Is32Bit:
+ address_space_width = 32;
+ code_region_base = 0x200000;
+ code_region_end = code_region_base + 0x3FE00000;
+ map_region_size = 0x40000000;
+ heap_region_size = 0x40000000;
+ break;
+ case FileSys::ProgramAddressSpaceType::Is36Bit:
+ address_space_width = 36;
+ code_region_base = 0x8000000;
+ code_region_end = code_region_base + 0x78000000;
+ map_region_size = 0x180000000;
+ heap_region_size = 0x180000000;
+ break;
+ case FileSys::ProgramAddressSpaceType::Is32BitNoMap:
+ address_space_width = 32;
+ code_region_base = 0x200000;
+ code_region_end = code_region_base + 0x3FE00000;
+ map_region_size = 0;
+ heap_region_size = 0x80000000;
+ break;
+ case FileSys::ProgramAddressSpaceType::Is39Bit:
+ address_space_width = 39;
+ code_region_base = 0x8000000;
+ code_region_end = code_region_base + 0x80000000;
+ map_region_size = 0x1000000000;
+ heap_region_size = 0x180000000;
+ new_map_region_size = 0x80000000;
+ tls_io_region_size = 0x1000000000;
+ break;
+ default:
+ UNREACHABLE_MSG("Invalid address space type specified: {}", static_cast<u32>(type));
+ return;
+ }
+
+ address_space_base = 0;
+ address_space_end = 1ULL << address_space_width;
+
+ map_region_base = code_region_end;
+ map_region_end = map_region_base + map_region_size;
+
+ heap_region_base = map_region_end;
+ heap_region_end = heap_region_base + heap_region_size;
+
+ new_map_region_base = heap_region_end;
+ new_map_region_end = new_map_region_base + new_map_region_size;
+
+ tls_io_region_base = new_map_region_end;
+ tls_io_region_end = tls_io_region_base + tls_io_region_size;
+
+ if (new_map_region_size == 0) {
+ new_map_region_base = address_space_base;
+ new_map_region_end = address_space_end;
+ }
+}
+
+void VMManager::Clear() {
+ ClearVMAMap();
+ ClearPageTable();
+}
+
+void VMManager::ClearVMAMap() {
+ vma_map.clear();
+}
+
+void VMManager::ClearPageTable() {
+ std::fill(page_table.pointers.begin(), page_table.pointers.end(), nullptr);
+ page_table.special_regions.clear();
+ std::fill(page_table.attributes.begin(), page_table.attributes.end(),
+ Memory::PageType::Unmapped);
+}
+
u64 VMManager::GetTotalMemoryUsage() const {
LOG_WARNING(Kernel, "(STUBBED) called");
return 0xF8000000;
@@ -392,14 +474,80 @@ u64 VMManager::GetTotalHeapUsage() const {
return 0x0;
}
-VAddr VMManager::GetAddressSpaceBaseAddr() const {
- LOG_WARNING(Kernel, "(STUBBED) called");
- return 0x8000000;
+VAddr VMManager::GetAddressSpaceBaseAddress() const {
+ return address_space_base;
+}
+
+VAddr VMManager::GetAddressSpaceEndAddress() const {
+ return address_space_end;
}
u64 VMManager::GetAddressSpaceSize() const {
- LOG_WARNING(Kernel, "(STUBBED) called");
- return MAX_ADDRESS;
+ return address_space_end - address_space_base;
+}
+
+u64 VMManager::GetAddressSpaceWidth() const {
+ return address_space_width;
+}
+
+VAddr VMManager::GetCodeRegionBaseAddress() const {
+ return code_region_base;
+}
+
+VAddr VMManager::GetCodeRegionEndAddress() const {
+ return code_region_end;
+}
+
+u64 VMManager::GetCodeRegionSize() const {
+ return code_region_end - code_region_base;
+}
+
+VAddr VMManager::GetHeapRegionBaseAddress() const {
+ return heap_region_base;
+}
+
+VAddr VMManager::GetHeapRegionEndAddress() const {
+ return heap_region_end;
+}
+
+u64 VMManager::GetHeapRegionSize() const {
+ return heap_region_end - heap_region_base;
+}
+
+VAddr VMManager::GetMapRegionBaseAddress() const {
+ return map_region_base;
+}
+
+VAddr VMManager::GetMapRegionEndAddress() const {
+ return map_region_end;
+}
+
+u64 VMManager::GetMapRegionSize() const {
+ return map_region_end - map_region_base;
+}
+
+VAddr VMManager::GetNewMapRegionBaseAddress() const {
+ return new_map_region_base;
+}
+
+VAddr VMManager::GetNewMapRegionEndAddress() const {
+ return new_map_region_end;
+}
+
+u64 VMManager::GetNewMapRegionSize() const {
+ return new_map_region_end - new_map_region_base;
+}
+
+VAddr VMManager::GetTLSIORegionBaseAddress() const {
+ return tls_io_region_base;
+}
+
+VAddr VMManager::GetTLSIORegionEndAddress() const {
+ return tls_io_region_end;
+}
+
+u64 VMManager::GetTLSIORegionSize() const {
+ return tls_io_region_end - tls_io_region_base;
}
} // namespace Kernel
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index de75036c0..015559a64 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -12,6 +12,10 @@
#include "core/memory.h"
#include "core/memory_hook.h"
+namespace FileSys {
+enum class ProgramAddressSpaceType : u8;
+}
+
namespace Kernel {
enum class VMAType : u8 {
@@ -111,12 +115,6 @@ struct VirtualMemoryArea {
class VMManager final {
public:
/**
- * The maximum amount of address space managed by the kernel.
- * @todo This was selected arbitrarily, and should be verified for Switch OS.
- */
- static constexpr VAddr MAX_ADDRESS{0x1000000000ULL};
-
- /**
* A map covering the entirety of the managed address space, keyed by the `base` field of each
* VMA. It must always be modified by splitting or merging VMAs, so that the invariant
* `elem.base + elem.size == next.base` is preserved, and mergeable regions must always be
@@ -130,7 +128,7 @@ public:
~VMManager();
/// Clears the address space map, re-initializing with a single free area.
- void Reset();
+ void Reset(FileSys::ProgramAddressSpaceType type);
/// Finds the VMA in which the given address is included in, or `vma_map.end()`.
VMAHandle FindVMA(VAddr target) const;
@@ -195,12 +193,63 @@ public:
/// Gets the total heap usage, used by svcGetInfo
u64 GetTotalHeapUsage() const;
- /// Gets the total address space base address, used by svcGetInfo
- VAddr GetAddressSpaceBaseAddr() const;
+ /// Gets the address space base address
+ VAddr GetAddressSpaceBaseAddress() const;
- /// Gets the total address space address size, used by svcGetInfo
+ /// Gets the address space end address
+ VAddr GetAddressSpaceEndAddress() const;
+
+ /// Gets the total address space address size in bytes
u64 GetAddressSpaceSize() const;
+ /// Gets the address space width in bits.
+ u64 GetAddressSpaceWidth() const;
+
+ /// Gets the base address of the code region.
+ VAddr GetCodeRegionBaseAddress() const;
+
+ /// Gets the end address of the code region.
+ VAddr GetCodeRegionEndAddress() const;
+
+ /// Gets the total size of the code region in bytes.
+ u64 GetCodeRegionSize() const;
+
+ /// Gets the base address of the heap region.
+ VAddr GetHeapRegionBaseAddress() const;
+
+ /// Gets the end address of the heap region;
+ VAddr GetHeapRegionEndAddress() const;
+
+ /// Gets the total size of the heap region in bytes.
+ u64 GetHeapRegionSize() const;
+
+ /// Gets the base address of the map region.
+ VAddr GetMapRegionBaseAddress() const;
+
+ /// Gets the end address of the map region.
+ VAddr GetMapRegionEndAddress() const;
+
+ /// Gets the total size of the map region in bytes.
+ u64 GetMapRegionSize() const;
+
+ /// Gets the base address of the new map region.
+ VAddr GetNewMapRegionBaseAddress() const;
+
+ /// Gets the end address of the new map region.
+ VAddr GetNewMapRegionEndAddress() const;
+
+ /// Gets the total size of the new map region in bytes.
+ u64 GetNewMapRegionSize() const;
+
+ /// Gets the base address of the TLS IO region.
+ VAddr GetTLSIORegionBaseAddress() const;
+
+ /// Gets the end address of the TLS IO region.
+ VAddr GetTLSIORegionEndAddress() const;
+
+ /// Gets the total size of the TLS IO region in bytes.
+ u64 GetTLSIORegionSize() const;
+
/// Each VMManager has its own page table, which is set as the main one when the owning process
/// is scheduled.
Memory::PageTable page_table;
@@ -240,5 +289,36 @@ private:
/// Updates the pages corresponding to this VMA so they match the VMA's attributes.
void UpdatePageTableForVMA(const VirtualMemoryArea& vma);
+
+ /// Initializes memory region ranges to adhere to a given address space type.
+ void InitializeMemoryRegionRanges(FileSys::ProgramAddressSpaceType type);
+
+ /// Clears the underlying map and page table.
+ void Clear();
+
+ /// Clears out the VMA map, unmapping any previously mapped ranges.
+ void ClearVMAMap();
+
+ /// Clears out the page table
+ void ClearPageTable();
+
+ u32 address_space_width = 0;
+ VAddr address_space_base = 0;
+ VAddr address_space_end = 0;
+
+ VAddr code_region_base = 0;
+ VAddr code_region_end = 0;
+
+ VAddr heap_region_base = 0;
+ VAddr heap_region_end = 0;
+
+ VAddr map_region_base = 0;
+ VAddr map_region_end = 0;
+
+ VAddr new_map_region_base = 0;
+ VAddr new_map_region_end = 0;
+
+ VAddr tls_io_region_base = 0;
+ VAddr tls_io_region_end = 0;
};
} // namespace Kernel
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp
index fa15712cf..6073f4ecd 100644
--- a/src/core/hle/service/audio/audren_u.cpp
+++ b/src/core/hle/service/audio/audren_u.cpp
@@ -66,7 +66,7 @@ private:
void GetAudioRendererState(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
- rb.Push<u32>(renderer->GetState());
+ rb.Push<u32>(static_cast<u32>(renderer->GetStreamState()));
LOG_DEBUG(Service_Audio, "called");
}
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index 2b8f78136..7e8035d0f 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -14,11 +14,9 @@
#include "core/gdbstub/gdbstub.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
-#include "core/hle/kernel/resource_limit.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/deconstructed_rom_directory.h"
#include "core/loader/nso.h"
-#include "core/memory.h"
namespace Loader {
@@ -127,12 +125,16 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
metadata.Print();
const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()};
- if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit) {
+ if (arch_bits == FileSys::ProgramAddressSpaceType::Is32Bit ||
+ arch_bits == FileSys::ProgramAddressSpaceType::Is32BitNoMap) {
return ResultStatus::Error32BitISA;
}
+ process->LoadFromMetadata(metadata);
+
// Load NSO modules
- VAddr next_load_addr{Memory::PROCESS_IMAGE_VADDR};
+ const VAddr base_address = process->vm_manager.GetCodeRegionBaseAddress();
+ VAddr next_load_addr = base_address;
for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3",
"subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) {
const FileSys::VirtualFile module_file = dir->GetFile(module);
@@ -145,13 +147,7 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
}
}
- auto& kernel = Core::System::GetInstance().Kernel();
- process->program_id = metadata.GetTitleID();
- process->svc_access_mask.set();
- process->resource_limit =
- kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION);
- process->Run(Memory::PROCESS_IMAGE_VADDR, metadata.GetMainThreadPriority(),
- metadata.GetMainThreadStackSize());
+ process->Run(base_address, metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize());
// Find the RomFS by searching for a ".romfs" file in this directory
const auto& files = dir->GetFiles();
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index 0e2af20b4..ff1221574 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -12,7 +12,7 @@
#include "core/core.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
-#include "core/hle/kernel/resource_limit.h"
+#include "core/hle/kernel/vm_manager.h"
#include "core/loader/elf.h"
#include "core/memory.h"
@@ -189,7 +189,7 @@ private:
u32* sectionAddrs;
bool relocate;
- u32 entryPoint;
+ VAddr entryPoint;
public:
explicit ElfReader(void* ptr);
@@ -205,13 +205,13 @@ public:
ElfMachine GetMachine() const {
return (ElfMachine)(header->e_machine);
}
- u32 GetEntryPoint() const {
+ VAddr GetEntryPoint() const {
return entryPoint;
}
u32 GetFlags() const {
return (u32)(header->e_flags);
}
- SharedPtr<CodeSet> LoadInto(u32 vaddr);
+ SharedPtr<CodeSet> LoadInto(VAddr vaddr);
int GetNumSegments() const {
return (int)(header->e_phnum);
@@ -274,7 +274,7 @@ const char* ElfReader::GetSectionName(int section) const {
return nullptr;
}
-SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) {
+SharedPtr<CodeSet> ElfReader::LoadInto(VAddr vaddr) {
LOG_DEBUG(Loader, "String section: {}", header->e_shstrndx);
// Should we relocate?
@@ -289,11 +289,11 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) {
LOG_DEBUG(Loader, "{} segments:", header->e_phnum);
// First pass : Get the bits into RAM
- u32 base_addr = relocate ? vaddr : 0;
+ const VAddr base_addr = relocate ? vaddr : 0;
- u32 total_image_size = 0;
+ u64 total_image_size = 0;
for (unsigned int i = 0; i < header->e_phnum; ++i) {
- Elf32_Phdr* p = &segments[i];
+ const Elf32_Phdr* p = &segments[i];
if (p->p_type == PT_LOAD) {
total_image_size += (p->p_memsz + 0xFFF) & ~0xFFF;
}
@@ -306,7 +306,7 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) {
SharedPtr<CodeSet> codeset = CodeSet::Create(kernel, "");
for (unsigned int i = 0; i < header->e_phnum; ++i) {
- Elf32_Phdr* p = &segments[i];
+ const Elf32_Phdr* p = &segments[i];
LOG_DEBUG(Loader, "Type: {} Vaddr: {:08X} Filesz: {:08X} Memsz: {:08X} ", p->p_type,
p->p_vaddr, p->p_filesz, p->p_memsz);
@@ -333,8 +333,8 @@ SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) {
continue;
}
- u32 segment_addr = base_addr + p->p_vaddr;
- u32 aligned_size = (p->p_memsz + 0xFFF) & ~0xFFF;
+ const VAddr segment_addr = base_addr + p->p_vaddr;
+ const u32 aligned_size = (p->p_memsz + 0xFFF) & ~0xFFF;
codeset_segment->offset = current_image_position;
codeset_segment->addr = segment_addr;
@@ -395,18 +395,12 @@ ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) {
if (buffer.size() != file->GetSize())
return ResultStatus::ErrorIncorrectELFFileSize;
+ const VAddr base_address = process->vm_manager.GetCodeRegionBaseAddress();
ElfReader elf_reader(&buffer[0]);
- SharedPtr<CodeSet> codeset = elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR);
+ SharedPtr<CodeSet> codeset = elf_reader.LoadInto(base_address);
codeset->name = file->GetName();
process->LoadModule(codeset, codeset->entrypoint);
- process->svc_access_mask.set();
-
- // Attach the default resource limit (APPLICATION) to the process
- auto& kernel = Core::System::GetInstance().Kernel();
- process->resource_limit =
- kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION);
-
process->Run(codeset->entrypoint, 48, Memory::DEFAULT_STACK_SIZE);
is_loaded = true;
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index c49ec34ab..b72871efa 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -16,7 +16,7 @@
#include "core/gdbstub/gdbstub.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
-#include "core/hle/kernel/resource_limit.h"
+#include "core/hle/kernel/vm_manager.h"
#include "core/loader/nro.h"
#include "core/memory.h"
@@ -181,17 +181,13 @@ ResultStatus AppLoader_NRO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
}
// Load NRO
- static constexpr VAddr base_addr{Memory::PROCESS_IMAGE_VADDR};
+ const VAddr base_address = process->vm_manager.GetCodeRegionBaseAddress();
- if (!LoadNro(file, base_addr)) {
+ if (!LoadNro(file, base_address)) {
return ResultStatus::ErrorLoadingNRO;
}
- auto& kernel = Core::System::GetInstance().Kernel();
- process->svc_access_mask.set();
- process->resource_limit =
- kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION);
- process->Run(base_addr, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
+ process->Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
is_loaded = true;
return ResultStatus::Success;
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 78a4438c4..1a6876a22 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -13,7 +13,7 @@
#include "core/gdbstub/gdbstub.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h"
-#include "core/hle/kernel/resource_limit.h"
+#include "core/hle/kernel/vm_manager.h"
#include "core/loader/nso.h"
#include "core/memory.h"
@@ -159,15 +159,11 @@ ResultStatus AppLoader_NSO::Load(Kernel::SharedPtr<Kernel::Process>& process) {
}
// Load module
- LoadModule(file, Memory::PROCESS_IMAGE_VADDR);
- LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), Memory::PROCESS_IMAGE_VADDR);
+ const VAddr base_address = process->vm_manager.GetCodeRegionBaseAddress();
+ LoadModule(file, base_address);
+ LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", file->GetName(), base_address);
- auto& kernel = Core::System::GetInstance().Kernel();
- process->svc_access_mask.set();
- process->resource_limit =
- kernel.ResourceLimitForCategory(Kernel::ResourceLimitCategory::APPLICATION);
- process->Run(Memory::PROCESS_IMAGE_VADDR, Kernel::THREADPRIO_DEFAULT,
- Memory::DEFAULT_STACK_SIZE);
+ process->Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
is_loaded = true;
return ResultStatus::Success;
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 316b46820..6430daad4 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -3,7 +3,6 @@
// Refer to the license.txt file included.
#include <algorithm>
-#include <array>
#include <cstring>
#include <utility>
@@ -15,11 +14,11 @@
#include "core/arm/arm_interface.h"
#include "core/core.h"
#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/vm_manager.h"
#include "core/hle/lock.h"
#include "core/memory.h"
#include "core/memory_setup.h"
#include "video_core/renderer_base.h"
-#include "video_core/video_core.h"
namespace Memory {
@@ -41,6 +40,21 @@ PageTable* GetCurrentPageTable() {
return current_page_table;
}
+PageTable::PageTable() = default;
+
+PageTable::PageTable(std::size_t address_space_width_in_bits) {
+ Resize(address_space_width_in_bits);
+}
+
+PageTable::~PageTable() = default;
+
+void PageTable::Resize(std::size_t address_space_width_in_bits) {
+ const std::size_t num_page_table_entries = 1ULL << (address_space_width_in_bits - PAGE_BITS);
+
+ pointers.resize(num_page_table_entries);
+ attributes.resize(num_page_table_entries);
+}
+
static void MapPages(PageTable& page_table, VAddr base, u64 size, u8* memory, PageType type) {
LOG_DEBUG(HW_Memory, "Mapping {} onto {:016X}-{:016X}", fmt::ptr(memory), base * PAGE_SIZE,
(base + size) * PAGE_SIZE);
@@ -50,7 +64,7 @@ static void MapPages(PageTable& page_table, VAddr base, u64 size, u8* memory, Pa
VAddr end = base + size;
while (base != end) {
- ASSERT_MSG(base < PAGE_TABLE_NUM_ENTRIES, "out of range mapping at {:016X}", base);
+ ASSERT_MSG(base < page_table.pointers.size(), "out of range mapping at {:016X}", base);
page_table.attributes[base] = type;
page_table.pointers[base] = memory;
@@ -323,7 +337,7 @@ void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) {
return;
}
- VAddr end = start + size;
+ const VAddr end = start + size;
const auto CheckRegion = [&](VAddr region_start, VAddr region_end) {
if (start >= region_end || end <= region_start) {
@@ -333,7 +347,7 @@ void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) {
const VAddr overlap_start = std::max(start, region_start);
const VAddr overlap_end = std::min(end, region_end);
- const u64 overlap_size = overlap_end - overlap_start;
+ const VAddr overlap_size = overlap_end - overlap_start;
auto& rasterizer = system_instance.Renderer().Rasterizer();
switch (mode) {
@@ -349,8 +363,10 @@ void RasterizerFlushVirtualRegion(VAddr start, u64 size, FlushMode mode) {
}
};
- CheckRegion(PROCESS_IMAGE_VADDR, PROCESS_IMAGE_VADDR_END);
- CheckRegion(HEAP_VADDR, HEAP_VADDR_END);
+ const auto& vm_manager = Core::CurrentProcess()->vm_manager;
+
+ CheckRegion(vm_manager.GetCodeRegionBaseAddress(), vm_manager.GetCodeRegionEndAddress());
+ CheckRegion(vm_manager.GetHeapRegionBaseAddress(), vm_manager.GetHeapRegionEndAddress());
}
u8 Read8(const VAddr addr) {
diff --git a/src/core/memory.h b/src/core/memory.h
index 2a27c0251..1acf5ce8c 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -4,10 +4,10 @@
#pragma once
-#include <array>
#include <cstddef>
#include <string>
#include <tuple>
+#include <vector>
#include <boost/icl/interval_map.hpp>
#include "common/common_types.h"
#include "core/memory_hook.h"
@@ -23,10 +23,8 @@ namespace Memory {
* be mapped.
*/
constexpr std::size_t PAGE_BITS = 12;
-constexpr u64 PAGE_SIZE = 1 << PAGE_BITS;
+constexpr u64 PAGE_SIZE = 1ULL << PAGE_BITS;
constexpr u64 PAGE_MASK = PAGE_SIZE - 1;
-constexpr std::size_t ADDRESS_SPACE_BITS = 36;
-constexpr std::size_t PAGE_TABLE_NUM_ENTRIES = 1ULL << (ADDRESS_SPACE_BITS - PAGE_BITS);
enum class PageType : u8 {
/// Page is unmapped and should cause an access error.
@@ -62,32 +60,39 @@ struct SpecialRegion {
* mimics the way a real CPU page table works.
*/
struct PageTable {
+ explicit PageTable();
+ explicit PageTable(std::size_t address_space_width_in_bits);
+ ~PageTable();
+
+ /**
+ * Resizes the page table to be able to accomodate enough pages within
+ * a given address space.
+ *
+ * @param address_space_width_in_bits The address size width in bits.
+ */
+ void Resize(std::size_t address_space_width_in_bits);
+
/**
- * Array of memory pointers backing each page. An entry can only be non-null if the
- * corresponding entry in the `attributes` array is of type `Memory`.
+ * Vector of memory pointers backing each page. An entry can only be non-null if the
+ * corresponding entry in the `attributes` vector is of type `Memory`.
*/
- std::array<u8*, PAGE_TABLE_NUM_ENTRIES> pointers;
+ std::vector<u8*> pointers;
/**
- * Contains MMIO handlers that back memory regions whose entries in the `attribute` array is of
- * type `Special`.
+ * Contains MMIO handlers that back memory regions whose entries in the `attribute` vector is
+ * of type `Special`.
*/
boost::icl::interval_map<VAddr, std::set<SpecialRegion>> special_regions;
/**
- * Array of fine grained page attributes. If it is set to any value other than `Memory`, then
+ * Vector of fine grained page attributes. If it is set to any value other than `Memory`, then
* the corresponding entry in `pointers` MUST be set to null.
*/
- std::array<PageType, PAGE_TABLE_NUM_ENTRIES> attributes;
+ std::vector<PageType> attributes;
};
/// Virtual user-space memory regions
enum : VAddr {
- /// Where the application text, data and bss reside.
- PROCESS_IMAGE_VADDR = 0x08000000,
- PROCESS_IMAGE_MAX_SIZE = 0x08000000,
- PROCESS_IMAGE_VADDR_END = PROCESS_IMAGE_VADDR + PROCESS_IMAGE_MAX_SIZE,
-
/// Read-only page containing kernel and system configuration values.
CONFIG_MEMORY_VADDR = 0x1FF80000,
CONFIG_MEMORY_SIZE = 0x00001000,
@@ -98,36 +103,12 @@ enum : VAddr {
SHARED_PAGE_SIZE = 0x00001000,
SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE,
- /// Area where TLS (Thread-Local Storage) buffers are allocated.
- TLS_AREA_VADDR = 0x40000000,
+ /// TLS (Thread-Local Storage) related.
TLS_ENTRY_SIZE = 0x200,
- TLS_AREA_SIZE = 0x10000000,
- TLS_AREA_VADDR_END = TLS_AREA_VADDR + TLS_AREA_SIZE,
/// Application stack
- STACK_AREA_VADDR = TLS_AREA_VADDR_END,
- STACK_AREA_SIZE = 0x10000000,
- STACK_AREA_VADDR_END = STACK_AREA_VADDR + STACK_AREA_SIZE,
DEFAULT_STACK_SIZE = 0x100000,
- /// Application heap
- /// Size is confirmed to be a static value on fw 3.0.0
- HEAP_VADDR = 0x108000000,
- HEAP_SIZE = 0x180000000,
- HEAP_VADDR_END = HEAP_VADDR + HEAP_SIZE,
-
- /// New map region
- /// Size is confirmed to be a static value on fw 3.0.0
- NEW_MAP_REGION_VADDR = HEAP_VADDR_END,
- NEW_MAP_REGION_SIZE = 0x80000000,
- NEW_MAP_REGION_VADDR_END = NEW_MAP_REGION_VADDR + NEW_MAP_REGION_SIZE,
-
- /// Map region
- /// Size is confirmed to be a static value on fw 3.0.0
- MAP_REGION_VADDR = NEW_MAP_REGION_VADDR_END,
- MAP_REGION_SIZE = 0x1000000000,
- MAP_REGION_VADDR_END = MAP_REGION_VADDR + MAP_REGION_SIZE,
-
/// Kernel Virtual Address Range
KERNEL_REGION_VADDR = 0xFFFFFF8000000000,
KERNEL_REGION_SIZE = 0x7FFFE00000,
diff --git a/src/tests/core/arm/arm_test_common.cpp b/src/tests/core/arm/arm_test_common.cpp
index 7c69fc26e..c17a122cd 100644
--- a/src/tests/core/arm/arm_test_common.cpp
+++ b/src/tests/core/arm/arm_test_common.cpp
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <algorithm>
+
#include "core/core.h"
#include "core/hle/kernel/process.h"
#include "core/memory.h"
@@ -16,9 +18,10 @@ TestEnvironment::TestEnvironment(bool mutable_memory_)
Core::CurrentProcess() = Kernel::Process::Create(kernel, "");
page_table = &Core::CurrentProcess()->vm_manager.page_table;
- page_table->pointers.fill(nullptr);
+ std::fill(page_table->pointers.begin(), page_table->pointers.end(), nullptr);
page_table->special_regions.clear();
- page_table->attributes.fill(Memory::PageType::Unmapped);
+ std::fill(page_table->attributes.begin(), page_table->attributes.end(),
+ Memory::PageType::Unmapped);
Memory::MapIoRegion(*page_table, 0x00000000, 0x80000000, test_memory);
Memory::MapIoRegion(*page_table, 0x80000000, 0x80000000, test_memory);
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 16cdfc7e2..9f5581045 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -41,6 +41,7 @@ public:
static constexpr std::size_t NumCBData = 16;
static constexpr std::size_t NumVertexArrays = 32;
static constexpr std::size_t NumVertexAttributes = 32;
+ static constexpr std::size_t NumTextureSamplers = 32;
static constexpr std::size_t MaxShaderProgram = 6;
static constexpr std::size_t MaxShaderStage = 5;
// Maximum number of const buffers per shader stage.
@@ -641,7 +642,11 @@ public:
u32 vb_element_base;
- INSERT_PADDING_WORDS(0x40);
+ INSERT_PADDING_WORDS(0x38);
+
+ float point_size;
+
+ INSERT_PADDING_WORDS(0x7);
u32 zeta_enable;
@@ -1017,6 +1022,7 @@ ASSERT_REG_POSITION(stencil_front_func_mask, 0x4E6);
ASSERT_REG_POSITION(stencil_front_mask, 0x4E7);
ASSERT_REG_POSITION(screen_y_control, 0x4EB);
ASSERT_REG_POSITION(vb_element_base, 0x50D);
+ASSERT_REG_POSITION(point_size, 0x546);
ASSERT_REG_POSITION(zeta_enable, 0x54E);
ASSERT_REG_POSITION(tsc, 0x557);
ASSERT_REG_POSITION(tic, 0x55D);
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 44850d193..1fcd13f04 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -452,6 +452,7 @@ void RasterizerOpenGL::DrawArrays() {
SyncCullMode();
SyncAlphaTest();
SyncTransformFeedback();
+ SyncPointState();
// TODO(bunnei): Sync framebuffer_scale uniform here
// TODO(bunnei): Sync scissorbox uniform(s) here
@@ -905,4 +906,10 @@ void RasterizerOpenGL::SyncTransformFeedback() {
}
}
+void RasterizerOpenGL::SyncPointState() {
+ const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
+
+ state.point.size = regs.point_size;
+}
+
} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index c3f1e14bf..4c8ecbd1c 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -164,6 +164,9 @@ private:
/// Syncs the transform feedback state to match the guest state
void SyncTransformFeedback();
+ /// Syncs the point state to match the guest state
+ void SyncPointState();
+
bool has_ARB_direct_state_access = false;
bool has_ARB_multi_bind = false;
bool has_ARB_separate_shader_objects = false;
@@ -184,7 +187,7 @@ private:
OGLVertexArray>
vertex_array_cache;
- std::array<SamplerInfo, GLShader::NumTextureSamplers> texture_samplers;
+ std::array<SamplerInfo, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> texture_samplers;
static constexpr std::size_t STREAM_BUFFER_SIZE = 128 * 1024 * 1024;
OGLBufferCache buffer_cache;
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h
index b86cd96e8..3de15ba9b 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.h
+++ b/src/video_core/renderer_opengl/gl_shader_manager.h
@@ -11,9 +11,6 @@
namespace OpenGL::GLShader {
-/// Number of OpenGL texture samplers that can be used in the fragment shader
-static constexpr std::size_t NumTextureSamplers = 32;
-
using Tegra::Engines::Maxwell3D;
/// Uniform structure for the Uniform Buffer Object, all vectors must be 16-byte aligned
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index e5173e20a..1fe26a2a9 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -79,6 +79,8 @@ OpenGLState::OpenGLState() {
viewport.height = 0;
clip_distance = {};
+
+ point.size = 1;
}
void OpenGLState::Apply() const {
@@ -205,9 +207,6 @@ void OpenGLState::Apply() const {
glActiveTexture(TextureUnits::MaxwellTexture(static_cast<int>(i)).Enum());
glBindTexture(texture_unit.target, texture_unit.texture);
}
- if (texture_unit.sampler != cur_state_texture_unit.sampler) {
- glBindSampler(static_cast<GLuint>(i), texture_unit.sampler);
- }
// Update the texture swizzle
if (texture_unit.swizzle.r != cur_state_texture_unit.swizzle.r ||
texture_unit.swizzle.g != cur_state_texture_unit.swizzle.g ||
@@ -219,6 +218,27 @@ void OpenGLState::Apply() const {
}
}
+ // Samplers
+ {
+ bool has_delta{};
+ std::size_t first{}, last{};
+ std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> samplers;
+ for (std::size_t i = 0; i < std::size(samplers); ++i) {
+ samplers[i] = texture_units[i].sampler;
+ if (samplers[i] != cur_state.texture_units[i].sampler) {
+ if (!has_delta) {
+ first = i;
+ has_delta = true;
+ }
+ last = i;
+ }
+ }
+ if (has_delta) {
+ glBindSamplers(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1),
+ samplers.data());
+ }
+ }
+
// Framebuffer
if (draw.read_framebuffer != cur_state.draw.read_framebuffer) {
glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer);
@@ -283,6 +303,11 @@ void OpenGLState::Apply() const {
}
}
+ // Point
+ if (point.size != cur_state.point.size) {
+ glPointSize(point.size);
+ }
+
cur_state = *this;
}
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 9a93029d8..dc21a2ee3 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -6,6 +6,7 @@
#include <array>
#include <glad/glad.h>
+#include "video_core/engines/maxwell_3d.h"
namespace OpenGL {
@@ -114,7 +115,7 @@ public:
target = GL_TEXTURE_2D;
}
};
- std::array<TextureUnit, 32> texture_units;
+ std::array<TextureUnit, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> texture_units;
struct {
GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING
@@ -141,6 +142,10 @@ public:
GLsizei height;
} viewport;
+ struct {
+ float size; // GL_POINT_SIZE
+ } point;
+
std::array<bool, 2> clip_distance; // GL_CLIP_DISTANCE
OpenGLState();
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 991ae10cd..67890455a 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -26,10 +26,10 @@
#include "yuzu/main.h"
#include "yuzu/ui_settings.h"
-GameList::SearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist) : gamelist{gamelist} {}
+GameListSearchField::KeyReleaseEater::KeyReleaseEater(GameList* gamelist) : gamelist{gamelist} {}
// EventFilter in order to process systemkeys while editing the searchfield
-bool GameList::SearchField::KeyReleaseEater::eventFilter(QObject* obj, QEvent* event) {
+bool GameListSearchField::KeyReleaseEater::eventFilter(QObject* obj, QEvent* event) {
// If it isn't a KeyRelease event then continue with standard event processing
if (event->type() != QEvent::KeyRelease)
return QObject::eventFilter(obj, event);
@@ -88,21 +88,21 @@ bool GameList::SearchField::KeyReleaseEater::eventFilter(QObject* obj, QEvent* e
return QObject::eventFilter(obj, event);
}
-void GameList::SearchField::setFilterResult(int visible, int total) {
+void GameListSearchField::setFilterResult(int visible, int total) {
label_filter_result->setText(tr("%1 of %n result(s)", "", total).arg(visible));
}
-void GameList::SearchField::clear() {
+void GameListSearchField::clear() {
edit_filter->setText("");
}
-void GameList::SearchField::setFocus() {
+void GameListSearchField::setFocus() {
if (edit_filter->isVisible()) {
edit_filter->setFocus();
}
}
-GameList::SearchField::SearchField(GameList* parent) : QWidget{parent} {
+GameListSearchField::GameListSearchField(GameList* parent) : QWidget{parent} {
KeyReleaseEater* keyReleaseEater = new KeyReleaseEater(parent);
layout_filter = new QHBoxLayout;
layout_filter->setMargin(8);
@@ -202,7 +202,7 @@ GameList::GameList(FileSys::VirtualFilesystem vfs, GMainWindow* parent)
this->main_window = parent;
layout = new QVBoxLayout;
tree_view = new QTreeView;
- search_field = new SearchField(this);
+ search_field = new GameListSearchField(this);
item_model = new QStandardItemModel(tree_view);
tree_view->setModel(item_model);
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h
index 3bf51870e..05e115e19 100644
--- a/src/yuzu/game_list.h
+++ b/src/yuzu/game_list.h
@@ -22,6 +22,7 @@
#include "yuzu/compatibility_list.h"
class GameListWorker;
+class GameListSearchField;
class GMainWindow;
namespace FileSys {
@@ -46,33 +47,6 @@ public:
COLUMN_COUNT, // Number of columns
};
- class SearchField : public QWidget {
- public:
- void setFilterResult(int visible, int total);
- void clear();
- void setFocus();
- explicit SearchField(GameList* parent = nullptr);
-
- private:
- class KeyReleaseEater : public QObject {
- public:
- explicit KeyReleaseEater(GameList* gamelist);
-
- private:
- GameList* gamelist = nullptr;
- QString edit_filter_text_old;
-
- protected:
- bool eventFilter(QObject* obj, QEvent* event) override;
- };
- QHBoxLayout* layout_filter = nullptr;
- QTreeView* tree_view = nullptr;
- QLabel* label_filter = nullptr;
- QLineEdit* edit_filter = nullptr;
- QLabel* label_filter_result = nullptr;
- QToolButton* button_filter_close = nullptr;
- };
-
explicit GameList(std::shared_ptr<FileSys::VfsFilesystem> vfs, GMainWindow* parent = nullptr);
~GameList() override;
@@ -110,7 +84,7 @@ private:
void RefreshGameDirectory();
std::shared_ptr<FileSys::VfsFilesystem> vfs;
- SearchField* search_field;
+ GameListSearchField* search_field;
GMainWindow* main_window = nullptr;
QVBoxLayout* layout = nullptr;
QTreeView* tree_view = nullptr;
@@ -118,6 +92,8 @@ private:
GameListWorker* current_worker = nullptr;
QFileSystemWatcher* watcher = nullptr;
CompatibilityList compatibility_list;
+
+ friend class GameListSearchField;
};
Q_DECLARE_METATYPE(GameListOpenTarget);
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h
index cee109730..3db0e90da 100644
--- a/src/yuzu/game_list_p.h
+++ b/src/yuzu/game_list_p.h
@@ -16,6 +16,7 @@
#include <QObject>
#include <QStandardItem>
#include <QString>
+#include <QWidget>
#include "common/common_types.h"
#include "common/logging/log.h"
@@ -176,3 +177,42 @@ public:
return data(SizeRole).toULongLong() < other.data(SizeRole).toULongLong();
}
};
+
+class GameList;
+class QHBoxLayout;
+class QTreeView;
+class QLabel;
+class QLineEdit;
+class QToolButton;
+
+class GameListSearchField : public QWidget {
+ Q_OBJECT
+
+public:
+ explicit GameListSearchField(GameList* parent = nullptr);
+
+ void setFilterResult(int visible, int total);
+
+ void clear();
+ void setFocus();
+
+private:
+ class KeyReleaseEater : public QObject {
+ public:
+ explicit KeyReleaseEater(GameList* gamelist);
+
+ private:
+ GameList* gamelist = nullptr;
+ QString edit_filter_text_old;
+
+ protected:
+ // EventFilter in order to process systemkeys while editing the searchfield
+ bool eventFilter(QObject* obj, QEvent* event) override;
+ };
+ QHBoxLayout* layout_filter = nullptr;
+ QTreeView* tree_view = nullptr;
+ QLabel* label_filter = nullptr;
+ QLineEdit* edit_filter = nullptr;
+ QLabel* label_filter_result = nullptr;
+ QToolButton* button_filter_close = nullptr;
+};