summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2017-09-29 14:58:42 -0400
committerGravatar GitHub2017-09-29 14:58:42 -0400
commitb07af7dda822898e9c8f231c5ddcd1741d93dbef (patch)
treed41c9221d6065b8cf9e6a2405565b675a9c83c51 /src
parentMerge pull request #2907 from Subv/warnings3 (diff)
parentLoaders: Don't automatically set the current process every time we load an ap... (diff)
downloadyuzu-b07af7dda822898e9c8f231c5ddcd1741d93dbef.tar.gz
yuzu-b07af7dda822898e9c8f231c5ddcd1741d93dbef.tar.xz
yuzu-b07af7dda822898e9c8f231c5ddcd1741d93dbef.zip
Merge pull request #2961 from Subv/load_titles
Loaders: Don't automatically set the current process every time we load an application.
Diffstat (limited to 'src')
-rw-r--r--src/core/core.cpp6
-rw-r--r--src/core/hle/kernel/process.cpp2
-rw-r--r--src/core/hle/kernel/thread.cpp17
-rw-r--r--src/core/hle/kernel/thread.h15
-rw-r--r--src/core/hle/svc.cpp5
-rw-r--r--src/core/loader/3dsx.cpp15
-rw-r--r--src/core/loader/3dsx.h2
-rw-r--r--src/core/loader/elf.cpp15
-rw-r--r--src/core/loader/elf.h2
-rw-r--r--src/core/loader/loader.h13
-rw-r--r--src/core/loader/ncch.cpp19
-rw-r--r--src/core/loader/ncch.h5
-rw-r--r--src/core/memory.cpp25
-rw-r--r--src/core/memory.h7
-rw-r--r--src/tests/CMakeLists.txt1
-rw-r--r--src/tests/core/arm/arm_test_common.cpp22
-rw-r--r--src/tests/core/memory/memory.cpp56
17 files changed, 157 insertions, 70 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 59b8768e7..0c7a72987 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -13,6 +13,7 @@
13#include "core/core_timing.h" 13#include "core/core_timing.h"
14#include "core/gdbstub/gdbstub.h" 14#include "core/gdbstub/gdbstub.h"
15#include "core/hle/kernel/kernel.h" 15#include "core/hle/kernel/kernel.h"
16#include "core/hle/kernel/process.h"
16#include "core/hle/kernel/thread.h" 17#include "core/hle/kernel/thread.h"
17#include "core/hle/service/service.h" 18#include "core/hle/service/service.h"
18#include "core/hw/hw.h" 19#include "core/hw/hw.h"
@@ -100,7 +101,7 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
100 return init_result; 101 return init_result;
101 } 102 }
102 103
103 const Loader::ResultStatus load_result{app_loader->Load()}; 104 const Loader::ResultStatus load_result{app_loader->Load(Kernel::g_current_process)};
104 if (Loader::ResultStatus::Success != load_result) { 105 if (Loader::ResultStatus::Success != load_result) {
105 LOG_CRITICAL(Core, "Failed to load ROM (Error %i)!", load_result); 106 LOG_CRITICAL(Core, "Failed to load ROM (Error %i)!", load_result);
106 System::Shutdown(); 107 System::Shutdown();
@@ -114,6 +115,7 @@ System::ResultStatus System::Load(EmuWindow* emu_window, const std::string& file
114 return ResultStatus::ErrorLoader; 115 return ResultStatus::ErrorLoader;
115 } 116 }
116 } 117 }
118 Memory::SetCurrentPageTable(&Kernel::g_current_process->vm_manager.page_table);
117 status = ResultStatus::Success; 119 status = ResultStatus::Success;
118 return status; 120 return status;
119} 121}
@@ -196,4 +198,4 @@ void System::Shutdown() {
196 LOG_DEBUG(Core, "Shutdown OK"); 198 LOG_DEBUG(Core, "Shutdown OK");
197} 199}
198 200
199} // namespace 201} // namespace Core
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index 522ad2333..cf3163e0f 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -147,7 +147,7 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) {
147 } 147 }
148 148
149 vm_manager.LogLayout(Log::Level::Debug); 149 vm_manager.LogLayout(Log::Level::Debug);
150 Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority); 150 Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority, this);
151} 151}
152 152
153VAddr Process::GetLinearHeapAreaAddress() const { 153VAddr Process::GetLinearHeapAreaAddress() const {
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 61378211f..1033f8552 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -361,7 +361,8 @@ static void ResetThreadContext(ARM_Interface::ThreadContext& context, u32 stack_
361} 361}
362 362
363ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, u32 priority, 363ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, u32 priority,
364 u32 arg, s32 processor_id, VAddr stack_top) { 364 u32 arg, s32 processor_id, VAddr stack_top,
365 SharedPtr<Process> owner_process) {
365 // Check if priority is in ranged. Lowest priority -> highest priority id. 366 // Check if priority is in ranged. Lowest priority -> highest priority id.
366 if (priority > THREADPRIO_LOWEST) { 367 if (priority > THREADPRIO_LOWEST) {
367 LOG_ERROR(Kernel_SVC, "Invalid thread priority: %d", priority); 368 LOG_ERROR(Kernel_SVC, "Invalid thread priority: %d", priority);
@@ -375,7 +376,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
375 376
376 // TODO(yuriks): Other checks, returning 0xD9001BEA 377 // TODO(yuriks): Other checks, returning 0xD9001BEA
377 378
378 if (!Memory::IsValidVirtualAddress(entry_point)) { 379 if (!Memory::IsValidVirtualAddress(*owner_process, entry_point)) {
379 LOG_ERROR(Kernel_SVC, "(name=%s): invalid entry %08x", name.c_str(), entry_point); 380 LOG_ERROR(Kernel_SVC, "(name=%s): invalid entry %08x", name.c_str(), entry_point);
380 // TODO: Verify error 381 // TODO: Verify error
381 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel, 382 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
@@ -399,10 +400,10 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
399 thread->wait_address = 0; 400 thread->wait_address = 0;
400 thread->name = std::move(name); 401 thread->name = std::move(name);
401 thread->callback_handle = wakeup_callback_handle_table.Create(thread).Unwrap(); 402 thread->callback_handle = wakeup_callback_handle_table.Create(thread).Unwrap();
402 thread->owner_process = g_current_process; 403 thread->owner_process = owner_process;
403 404
404 // Find the next available TLS index, and mark it as used 405 // Find the next available TLS index, and mark it as used
405 auto& tls_slots = Kernel::g_current_process->tls_slots; 406 auto& tls_slots = owner_process->tls_slots;
406 bool needs_allocation = true; 407 bool needs_allocation = true;
407 u32 available_page; // Which allocated page has free space 408 u32 available_page; // Which allocated page has free space
408 u32 available_slot; // Which slot within the page is free 409 u32 available_slot; // Which slot within the page is free
@@ -426,13 +427,13 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
426 // Allocate some memory from the end of the linear heap for this region. 427 // Allocate some memory from the end of the linear heap for this region.
427 linheap_memory->insert(linheap_memory->end(), Memory::PAGE_SIZE, 0); 428 linheap_memory->insert(linheap_memory->end(), Memory::PAGE_SIZE, 0);
428 memory_region->used += Memory::PAGE_SIZE; 429 memory_region->used += Memory::PAGE_SIZE;
429 Kernel::g_current_process->linear_heap_used += Memory::PAGE_SIZE; 430 owner_process->linear_heap_used += Memory::PAGE_SIZE;
430 431
431 tls_slots.emplace_back(0); // The page is completely available at the start 432 tls_slots.emplace_back(0); // The page is completely available at the start
432 available_page = tls_slots.size() - 1; 433 available_page = tls_slots.size() - 1;
433 available_slot = 0; // Use the first slot in the new page 434 available_slot = 0; // Use the first slot in the new page
434 435
435 auto& vm_manager = Kernel::g_current_process->vm_manager; 436 auto& vm_manager = owner_process->vm_manager;
436 vm_manager.RefreshMemoryBlockMappings(linheap_memory.get()); 437 vm_manager.RefreshMemoryBlockMappings(linheap_memory.get());
437 438
438 // Map the page to the current process' address space. 439 // Map the page to the current process' address space.
@@ -486,10 +487,10 @@ void Thread::BoostPriority(s32 priority) {
486 current_priority = priority; 487 current_priority = priority;
487} 488}
488 489
489SharedPtr<Thread> SetupMainThread(u32 entry_point, s32 priority) { 490SharedPtr<Thread> SetupMainThread(u32 entry_point, s32 priority, SharedPtr<Process> owner_process) {
490 // Initialize new "main" thread 491 // Initialize new "main" thread
491 auto thread_res = Thread::Create("main", entry_point, priority, 0, THREADPROCESSORID_0, 492 auto thread_res = Thread::Create("main", entry_point, priority, 0, THREADPROCESSORID_0,
492 Memory::HEAP_VADDR_END); 493 Memory::HEAP_VADDR_END, owner_process);
493 494
494 SharedPtr<Thread> thread = std::move(thread_res).Unwrap(); 495 SharedPtr<Thread> thread = std::move(thread_res).Unwrap();
495 496
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 6a3566f15..ddc0d15c5 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -56,10 +56,12 @@ public:
56 * @param arg User data to pass to the thread 56 * @param arg User data to pass to the thread
57 * @param processor_id The ID(s) of the processors on which the thread is desired to be run 57 * @param processor_id The ID(s) of the processors on which the thread is desired to be run
58 * @param stack_top The address of the thread's stack top 58 * @param stack_top The address of the thread's stack top
59 * @param owner_process The parent process for the thread
59 * @return A shared pointer to the newly created thread 60 * @return A shared pointer to the newly created thread
60 */ 61 */
61 static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, u32 priority, 62 static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, u32 priority,
62 u32 arg, s32 processor_id, VAddr stack_top); 63 u32 arg, s32 processor_id, VAddr stack_top,
64 SharedPtr<Process> owner_process);
63 65
64 std::string GetName() const override { 66 std::string GetName() const override {
65 return name; 67 return name;
@@ -116,9 +118,9 @@ public:
116 void ResumeFromWait(); 118 void ResumeFromWait();
117 119
118 /** 120 /**
119 * Schedules an event to wake up the specified thread after the specified delay 121 * Schedules an event to wake up the specified thread after the specified delay
120 * @param nanoseconds The time this thread will be allowed to sleep for 122 * @param nanoseconds The time this thread will be allowed to sleep for
121 */ 123 */
122 void WakeAfterDelay(s64 nanoseconds); 124 void WakeAfterDelay(s64 nanoseconds);
123 125
124 /** 126 /**
@@ -214,9 +216,10 @@ private:
214 * Sets up the primary application thread 216 * Sets up the primary application thread
215 * @param entry_point The address at which the thread should start execution 217 * @param entry_point The address at which the thread should start execution
216 * @param priority The priority to give the main thread 218 * @param priority The priority to give the main thread
219 * @param owner_process The parent process for the main thread
217 * @return A shared pointer to the main thread 220 * @return A shared pointer to the main thread
218 */ 221 */
219SharedPtr<Thread> SetupMainThread(u32 entry_point, s32 priority); 222SharedPtr<Thread> SetupMainThread(u32 entry_point, s32 priority, SharedPtr<Process> owner_process);
220 223
221/** 224/**
222 * Returns whether there are any threads that are ready to run. 225 * Returns whether there are any threads that are ready to run.
@@ -276,4 +279,4 @@ void ThreadingShutdown();
276 */ 279 */
277const std::vector<SharedPtr<Thread>>& GetThreadList(); 280const std::vector<SharedPtr<Thread>>& GetThreadList();
278 281
279} // namespace 282} // namespace Kernel
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index dfc36748c..05c6897bf 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -656,8 +656,9 @@ static ResultCode CreateThread(Kernel::Handle* out_handle, u32 priority, u32 ent
656 "Newly created thread must run in the SysCore (Core1), unimplemented."); 656 "Newly created thread must run in the SysCore (Core1), unimplemented.");
657 } 657 }
658 658
659 CASCADE_RESULT(SharedPtr<Thread> thread, Kernel::Thread::Create(name, entry_point, priority, 659 CASCADE_RESULT(SharedPtr<Thread> thread,
660 arg, processor_id, stack_top)); 660 Kernel::Thread::Create(name, entry_point, priority, arg, processor_id, stack_top,
661 Kernel::g_current_process));
661 662
662 thread->context.fpscr = 663 thread->context.fpscr =
663 FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO; // 0x03C00000 664 FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO; // 0x03C00000
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp
index 5ad5c5287..918038f1e 100644
--- a/src/core/loader/3dsx.cpp
+++ b/src/core/loader/3dsx.cpp
@@ -91,8 +91,8 @@ static u32 TranslateAddr(u32 addr, const THREEloadinfo* loadinfo, u32* offsets)
91 return loadinfo->seg_addrs[2] + addr - offsets[1]; 91 return loadinfo->seg_addrs[2] + addr - offsets[1];
92} 92}
93 93
94using Kernel::SharedPtr;
95using Kernel::CodeSet; 94using Kernel::CodeSet;
95using Kernel::SharedPtr;
96 96
97static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr, 97static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr,
98 SharedPtr<CodeSet>* out_codeset) { 98 SharedPtr<CodeSet>* out_codeset) {
@@ -255,7 +255,7 @@ FileType AppLoader_THREEDSX::IdentifyType(FileUtil::IOFile& file) {
255 return FileType::Error; 255 return FileType::Error;
256} 256}
257 257
258ResultStatus AppLoader_THREEDSX::Load() { 258ResultStatus AppLoader_THREEDSX::Load(Kernel::SharedPtr<Kernel::Process>& process) {
259 if (is_loaded) 259 if (is_loaded)
260 return ResultStatus::ErrorAlreadyLoaded; 260 return ResultStatus::ErrorAlreadyLoaded;
261 261
@@ -267,16 +267,15 @@ ResultStatus AppLoader_THREEDSX::Load() {
267 return ResultStatus::Error; 267 return ResultStatus::Error;
268 codeset->name = filename; 268 codeset->name = filename;
269 269
270 Kernel::g_current_process = Kernel::Process::Create(std::move(codeset)); 270 process = Kernel::Process::Create(std::move(codeset));
271 Kernel::g_current_process->svc_access_mask.set(); 271 process->svc_access_mask.set();
272 Kernel::g_current_process->address_mappings = default_address_mappings; 272 process->address_mappings = default_address_mappings;
273 Memory::SetCurrentPageTable(&Kernel::g_current_process->vm_manager.page_table);
274 273
275 // Attach the default resource limit (APPLICATION) to the process 274 // Attach the default resource limit (APPLICATION) to the process
276 Kernel::g_current_process->resource_limit = 275 process->resource_limit =
277 Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); 276 Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
278 277
279 Kernel::g_current_process->Run(48, Kernel::DEFAULT_STACK_SIZE); 278 process->Run(48, Kernel::DEFAULT_STACK_SIZE);
280 279
281 Service::FS::RegisterSelfNCCH(*this); 280 Service::FS::RegisterSelfNCCH(*this);
282 281
diff --git a/src/core/loader/3dsx.h b/src/core/loader/3dsx.h
index 3f376778a..1e59bbb9d 100644
--- a/src/core/loader/3dsx.h
+++ b/src/core/loader/3dsx.h
@@ -31,7 +31,7 @@ public:
31 return IdentifyType(file); 31 return IdentifyType(file);
32 } 32 }
33 33
34 ResultStatus Load() override; 34 ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
35 35
36 ResultStatus ReadIcon(std::vector<u8>& buffer) override; 36 ResultStatus ReadIcon(std::vector<u8>& buffer) override;
37 37
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index 2de1f4e81..e36e42120 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -13,8 +13,8 @@
13#include "core/loader/elf.h" 13#include "core/loader/elf.h"
14#include "core/memory.h" 14#include "core/memory.h"
15 15
16using Kernel::SharedPtr;
17using Kernel::CodeSet; 16using Kernel::CodeSet;
17using Kernel::SharedPtr;
18 18
19//////////////////////////////////////////////////////////////////////////////////////////////////// 19////////////////////////////////////////////////////////////////////////////////////////////////////
20// ELF Header Constants 20// ELF Header Constants
@@ -375,7 +375,7 @@ FileType AppLoader_ELF::IdentifyType(FileUtil::IOFile& file) {
375 return FileType::Error; 375 return FileType::Error;
376} 376}
377 377
378ResultStatus AppLoader_ELF::Load() { 378ResultStatus AppLoader_ELF::Load(Kernel::SharedPtr<Kernel::Process>& process) {
379 if (is_loaded) 379 if (is_loaded)
380 return ResultStatus::ErrorAlreadyLoaded; 380 return ResultStatus::ErrorAlreadyLoaded;
381 381
@@ -394,16 +394,15 @@ ResultStatus AppLoader_ELF::Load() {
394 SharedPtr<CodeSet> codeset = elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR); 394 SharedPtr<CodeSet> codeset = elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR);
395 codeset->name = filename; 395 codeset->name = filename;
396 396
397 Kernel::g_current_process = Kernel::Process::Create(std::move(codeset)); 397 process = Kernel::Process::Create(std::move(codeset));
398 Kernel::g_current_process->svc_access_mask.set(); 398 process->svc_access_mask.set();
399 Kernel::g_current_process->address_mappings = default_address_mappings; 399 process->address_mappings = default_address_mappings;
400 Memory::SetCurrentPageTable(&Kernel::g_current_process->vm_manager.page_table);
401 400
402 // Attach the default resource limit (APPLICATION) to the process 401 // Attach the default resource limit (APPLICATION) to the process
403 Kernel::g_current_process->resource_limit = 402 process->resource_limit =
404 Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); 403 Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
405 404
406 Kernel::g_current_process->Run(48, Kernel::DEFAULT_STACK_SIZE); 405 process->Run(48, Kernel::DEFAULT_STACK_SIZE);
407 406
408 is_loaded = true; 407 is_loaded = true;
409 return ResultStatus::Success; 408 return ResultStatus::Success;
diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h
index 862aa90d8..113da5917 100644
--- a/src/core/loader/elf.h
+++ b/src/core/loader/elf.h
@@ -30,7 +30,7 @@ public:
30 return IdentifyType(file); 30 return IdentifyType(file);
31 } 31 }
32 32
33 ResultStatus Load() override; 33 ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
34 34
35private: 35private:
36 std::string filename; 36 std::string filename;
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 3160fd2fd..82b2be6a3 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -13,10 +13,12 @@
13#include <boost/optional.hpp> 13#include <boost/optional.hpp>
14#include "common/common_types.h" 14#include "common/common_types.h"
15#include "common/file_util.h" 15#include "common/file_util.h"
16#include "core/hle/kernel/kernel.h"
16 17
17namespace Kernel { 18namespace Kernel {
18struct AddressMapping; 19struct AddressMapping;
19} 20class Process;
21} // namespace Kernel
20 22
21//////////////////////////////////////////////////////////////////////////////////////////////////// 23////////////////////////////////////////////////////////////////////////////////////////////////////
22// Loader namespace 24// Loader namespace
@@ -92,10 +94,11 @@ public:
92 virtual FileType GetFileType() = 0; 94 virtual FileType GetFileType() = 0;
93 95
94 /** 96 /**
95 * Load the application 97 * Load the application and return the created Process instance
96 * @return ResultStatus result of function 98 * @param process The newly created process.
99 * @return The status result of the operation.
97 */ 100 */
98 virtual ResultStatus Load() = 0; 101 virtual ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) = 0;
99 102
100 /** 103 /**
101 * Loads the system mode that this application needs. 104 * Loads the system mode that this application needs.
@@ -206,4 +209,4 @@ extern const std::initializer_list<Kernel::AddressMapping> default_address_mappi
206 */ 209 */
207std::unique_ptr<AppLoader> GetLoader(const std::string& filename); 210std::unique_ptr<AppLoader> GetLoader(const std::string& filename);
208 211
209} // namespace 212} // namespace Loader
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index 5107135f9..66bc5823d 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -67,9 +67,9 @@ std::pair<boost::optional<u32>, ResultStatus> AppLoader_NCCH::LoadKernelSystemMo
67 ResultStatus::Success); 67 ResultStatus::Success);
68} 68}
69 69
70ResultStatus AppLoader_NCCH::LoadExec() { 70ResultStatus AppLoader_NCCH::LoadExec(Kernel::SharedPtr<Kernel::Process>& process) {
71 using Kernel::SharedPtr;
72 using Kernel::CodeSet; 71 using Kernel::CodeSet;
72 using Kernel::SharedPtr;
73 73
74 if (!is_loaded) 74 if (!is_loaded)
75 return ResultStatus::ErrorNotLoaded; 75 return ResultStatus::ErrorNotLoaded;
@@ -107,16 +107,15 @@ ResultStatus AppLoader_NCCH::LoadExec() {
107 codeset->entrypoint = codeset->code.addr; 107 codeset->entrypoint = codeset->code.addr;
108 codeset->memory = std::make_shared<std::vector<u8>>(std::move(code)); 108 codeset->memory = std::make_shared<std::vector<u8>>(std::move(code));
109 109
110 Kernel::g_current_process = Kernel::Process::Create(std::move(codeset)); 110 process = Kernel::Process::Create(std::move(codeset));
111 Memory::SetCurrentPageTable(&Kernel::g_current_process->vm_manager.page_table);
112 111
113 // Attach a resource limit to the process based on the resource limit category 112 // Attach a resource limit to the process based on the resource limit category
114 Kernel::g_current_process->resource_limit = 113 process->resource_limit =
115 Kernel::ResourceLimit::GetForCategory(static_cast<Kernel::ResourceLimitCategory>( 114 Kernel::ResourceLimit::GetForCategory(static_cast<Kernel::ResourceLimitCategory>(
116 overlay_ncch->exheader_header.arm11_system_local_caps.resource_limit_category)); 115 overlay_ncch->exheader_header.arm11_system_local_caps.resource_limit_category));
117 116
118 // Set the default CPU core for this process 117 // Set the default CPU core for this process
119 Kernel::g_current_process->ideal_processor = 118 process->ideal_processor =
120 overlay_ncch->exheader_header.arm11_system_local_caps.ideal_processor; 119 overlay_ncch->exheader_header.arm11_system_local_caps.ideal_processor;
121 120
122 // Copy data while converting endianness 121 // Copy data while converting endianness
@@ -124,11 +123,11 @@ ResultStatus AppLoader_NCCH::LoadExec() {
124 kernel_caps; 123 kernel_caps;
125 std::copy_n(overlay_ncch->exheader_header.arm11_kernel_caps.descriptors, kernel_caps.size(), 124 std::copy_n(overlay_ncch->exheader_header.arm11_kernel_caps.descriptors, kernel_caps.size(),
126 begin(kernel_caps)); 125 begin(kernel_caps));
127 Kernel::g_current_process->ParseKernelCaps(kernel_caps.data(), kernel_caps.size()); 126 process->ParseKernelCaps(kernel_caps.data(), kernel_caps.size());
128 127
129 s32 priority = overlay_ncch->exheader_header.arm11_system_local_caps.priority; 128 s32 priority = overlay_ncch->exheader_header.arm11_system_local_caps.priority;
130 u32 stack_size = overlay_ncch->exheader_header.codeset_info.stack_size; 129 u32 stack_size = overlay_ncch->exheader_header.codeset_info.stack_size;
131 Kernel::g_current_process->Run(priority, stack_size); 130 process->Run(priority, stack_size);
132 return ResultStatus::Success; 131 return ResultStatus::Success;
133 } 132 }
134 return ResultStatus::Error; 133 return ResultStatus::Error;
@@ -151,7 +150,7 @@ void AppLoader_NCCH::ParseRegionLockoutInfo() {
151 } 150 }
152} 151}
153 152
154ResultStatus AppLoader_NCCH::Load() { 153ResultStatus AppLoader_NCCH::Load(Kernel::SharedPtr<Kernel::Process>& process) {
155 u64_le ncch_program_id; 154 u64_le ncch_program_id;
156 155
157 if (is_loaded) 156 if (is_loaded)
@@ -183,7 +182,7 @@ ResultStatus AppLoader_NCCH::Load() {
183 182
184 is_loaded = true; // Set state to loaded 183 is_loaded = true; // Set state to loaded
185 184
186 result = LoadExec(); // Load the executable into memory for booting 185 result = LoadExec(process); // Load the executable into memory for booting
187 if (ResultStatus::Success != result) 186 if (ResultStatus::Success != result)
188 return result; 187 return result;
189 188
diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h
index 9b56465cb..09230ae33 100644
--- a/src/core/loader/ncch.h
+++ b/src/core/loader/ncch.h
@@ -33,7 +33,7 @@ public:
33 return IdentifyType(file); 33 return IdentifyType(file);
34 } 34 }
35 35
36 ResultStatus Load() override; 36 ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override;
37 37
38 /** 38 /**
39 * Loads the Exheader and returns the system mode for this application. 39 * Loads the Exheader and returns the system mode for this application.
@@ -62,9 +62,10 @@ public:
62private: 62private:
63 /** 63 /**
64 * Loads .code section into memory for booting 64 * Loads .code section into memory for booting
65 * @param process The newly created process
65 * @return ResultStatus result of function 66 * @return ResultStatus result of function
66 */ 67 */
67 ResultStatus LoadExec(); 68 ResultStatus LoadExec(Kernel::SharedPtr<Kernel::Process>& process);
68 69
69 /// Reads the region lockout info in the SMDH and send it to CFG service 70 /// Reads the region lockout info in the SMDH and send it to CFG service
70 void ParseRegionLockoutInfo(); 71 void ParseRegionLockoutInfo();
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 9b394f84b..5ea0694a9 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -110,8 +110,8 @@ static u8* GetPointerFromVMA(VAddr vaddr) {
110/** 110/**
111 * This function should only be called for virtual addreses with attribute `PageType::Special`. 111 * This function should only be called for virtual addreses with attribute `PageType::Special`.
112 */ 112 */
113static MMIORegionPointer GetMMIOHandler(VAddr vaddr) { 113static MMIORegionPointer GetMMIOHandler(const PageTable& page_table, VAddr vaddr) {
114 for (const auto& region : current_page_table->special_regions) { 114 for (const auto& region : page_table.special_regions) {
115 if (vaddr >= region.base && vaddr < (region.base + region.size)) { 115 if (vaddr >= region.base && vaddr < (region.base + region.size)) {
116 return region.handler; 116 return region.handler;
117 } 117 }
@@ -120,6 +120,11 @@ static MMIORegionPointer GetMMIOHandler(VAddr vaddr) {
120 return nullptr; // Should never happen 120 return nullptr; // Should never happen
121} 121}
122 122
123static MMIORegionPointer GetMMIOHandler(VAddr vaddr) {
124 const PageTable& page_table = Kernel::g_current_process->vm_manager.page_table;
125 return GetMMIOHandler(page_table, vaddr);
126}
127
123template <typename T> 128template <typename T>
124T ReadMMIO(MMIORegionPointer mmio_handler, VAddr addr); 129T ReadMMIO(MMIORegionPointer mmio_handler, VAddr addr);
125 130
@@ -204,18 +209,20 @@ void Write(const VAddr vaddr, const T data) {
204 } 209 }
205} 210}
206 211
207bool IsValidVirtualAddress(const VAddr vaddr) { 212bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) {
208 const u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; 213 auto& page_table = process.vm_manager.page_table;
214
215 const u8* page_pointer = page_table.pointers[vaddr >> PAGE_BITS];
209 if (page_pointer) 216 if (page_pointer)
210 return true; 217 return true;
211 218
212 if (current_page_table->attributes[vaddr >> PAGE_BITS] == PageType::RasterizerCachedMemory) 219 if (page_table.attributes[vaddr >> PAGE_BITS] == PageType::RasterizerCachedMemory)
213 return true; 220 return true;
214 221
215 if (current_page_table->attributes[vaddr >> PAGE_BITS] != PageType::Special) 222 if (page_table.attributes[vaddr >> PAGE_BITS] != PageType::Special)
216 return false; 223 return false;
217 224
218 MMIORegionPointer mmio_region = GetMMIOHandler(vaddr); 225 MMIORegionPointer mmio_region = GetMMIOHandler(page_table, vaddr);
219 if (mmio_region) { 226 if (mmio_region) {
220 return mmio_region->IsValidAddress(vaddr); 227 return mmio_region->IsValidAddress(vaddr);
221 } 228 }
@@ -223,6 +230,10 @@ bool IsValidVirtualAddress(const VAddr vaddr) {
223 return false; 230 return false;
224} 231}
225 232
233bool IsValidVirtualAddress(const VAddr vaddr) {
234 return IsValidVirtualAddress(*Kernel::g_current_process, vaddr);
235}
236
226bool IsValidPhysicalAddress(const PAddr paddr) { 237bool IsValidPhysicalAddress(const PAddr paddr) {
227 return GetPhysicalPointer(paddr) != nullptr; 238 return GetPhysicalPointer(paddr) != nullptr;
228} 239}
diff --git a/src/core/memory.h b/src/core/memory.h
index 1865bfea0..347c08c78 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -12,6 +12,10 @@
12#include "common/common_types.h" 12#include "common/common_types.h"
13#include "core/mmio.h" 13#include "core/mmio.h"
14 14
15namespace Kernel {
16class Process;
17}
18
15namespace Memory { 19namespace Memory {
16 20
17/** 21/**
@@ -185,7 +189,10 @@ enum : VAddr {
185void SetCurrentPageTable(PageTable* page_table); 189void SetCurrentPageTable(PageTable* page_table);
186PageTable* GetCurrentPageTable(); 190PageTable* GetCurrentPageTable();
187 191
192/// Determines if the given VAddr is valid for the specified process.
193bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr);
188bool IsValidVirtualAddress(const VAddr addr); 194bool IsValidVirtualAddress(const VAddr addr);
195
189bool IsValidPhysicalAddress(const PAddr addr); 196bool IsValidPhysicalAddress(const PAddr addr);
190 197
191u8 Read8(VAddr addr); 198u8 Read8(VAddr addr);
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index 5e9c4c2bf..1aac0daa2 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -4,6 +4,7 @@ set(SRCS
4 core/arm/dyncom/arm_dyncom_vfp_tests.cpp 4 core/arm/dyncom/arm_dyncom_vfp_tests.cpp
5 core/file_sys/path_parser.cpp 5 core/file_sys/path_parser.cpp
6 core/hle/kernel/hle_ipc.cpp 6 core/hle/kernel/hle_ipc.cpp
7 core/memory/memory.cpp
7 glad.cpp 8 glad.cpp
8 tests.cpp 9 tests.cpp
9 ) 10 )
diff --git a/src/tests/core/arm/arm_test_common.cpp b/src/tests/core/arm/arm_test_common.cpp
index cfe0d503a..484713a92 100644
--- a/src/tests/core/arm/arm_test_common.cpp
+++ b/src/tests/core/arm/arm_test_common.cpp
@@ -3,30 +3,34 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "core/core.h" 5#include "core/core.h"
6#include "core/hle/kernel/process.h"
6#include "core/memory.h" 7#include "core/memory.h"
7#include "core/memory_setup.h" 8#include "core/memory_setup.h"
8#include "tests/core/arm/arm_test_common.h" 9#include "tests/core/arm/arm_test_common.h"
9 10
10namespace ArmTests { 11namespace ArmTests {
11 12
12static Memory::PageTable page_table; 13static Memory::PageTable* page_table = nullptr;
13 14
14TestEnvironment::TestEnvironment(bool mutable_memory_) 15TestEnvironment::TestEnvironment(bool mutable_memory_)
15 : mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) { 16 : mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) {
16 17
17 page_table.pointers.fill(nullptr); 18 Kernel::g_current_process = Kernel::Process::Create(Kernel::CodeSet::Create("", 0));
18 page_table.attributes.fill(Memory::PageType::Unmapped); 19 page_table = &Kernel::g_current_process->vm_manager.page_table;
19 page_table.cached_res_count.fill(0);
20 20
21 Memory::MapIoRegion(page_table, 0x00000000, 0x80000000, test_memory); 21 page_table->pointers.fill(nullptr);
22 Memory::MapIoRegion(page_table, 0x80000000, 0x80000000, test_memory); 22 page_table->attributes.fill(Memory::PageType::Unmapped);
23 page_table->cached_res_count.fill(0);
23 24
24 Memory::SetCurrentPageTable(&page_table); 25 Memory::MapIoRegion(*page_table, 0x00000000, 0x80000000, test_memory);
26 Memory::MapIoRegion(*page_table, 0x80000000, 0x80000000, test_memory);
27
28 Memory::SetCurrentPageTable(page_table);
25} 29}
26 30
27TestEnvironment::~TestEnvironment() { 31TestEnvironment::~TestEnvironment() {
28 Memory::UnmapRegion(page_table, 0x80000000, 0x80000000); 32 Memory::UnmapRegion(*page_table, 0x80000000, 0x80000000);
29 Memory::UnmapRegion(page_table, 0x00000000, 0x80000000); 33 Memory::UnmapRegion(*page_table, 0x00000000, 0x80000000);
30} 34}
31 35
32void TestEnvironment::SetMemory64(VAddr vaddr, u64 value) { 36void TestEnvironment::SetMemory64(VAddr vaddr, u64 value) {
diff --git a/src/tests/core/memory/memory.cpp b/src/tests/core/memory/memory.cpp
new file mode 100644
index 000000000..a01b896f7
--- /dev/null
+++ b/src/tests/core/memory/memory.cpp
@@ -0,0 +1,56 @@
1// Copyright 2017 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <catch.hpp>
6#include "core/hle/kernel/memory.h"
7#include "core/hle/kernel/process.h"
8#include "core/memory.h"
9
10TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") {
11 SECTION("these regions should not be mapped on an empty process") {
12 auto process = Kernel::Process::Create(Kernel::CodeSet::Create("", 0));
13 CHECK(Memory::IsValidVirtualAddress(*process, Memory::PROCESS_IMAGE_VADDR) == false);
14 CHECK(Memory::IsValidVirtualAddress(*process, Memory::HEAP_VADDR) == false);
15 CHECK(Memory::IsValidVirtualAddress(*process, Memory::LINEAR_HEAP_VADDR) == false);
16 CHECK(Memory::IsValidVirtualAddress(*process, Memory::VRAM_VADDR) == false);
17 CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == false);
18 CHECK(Memory::IsValidVirtualAddress(*process, Memory::SHARED_PAGE_VADDR) == false);
19 CHECK(Memory::IsValidVirtualAddress(*process, Memory::TLS_AREA_VADDR) == false);
20 }
21
22 SECTION("CONFIG_MEMORY_VADDR and SHARED_PAGE_VADDR should be valid after mapping them") {
23 auto process = Kernel::Process::Create(Kernel::CodeSet::Create("", 0));
24 Kernel::MapSharedPages(process->vm_manager);
25 CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == true);
26 CHECK(Memory::IsValidVirtualAddress(*process, Memory::SHARED_PAGE_VADDR) == true);
27 }
28
29 SECTION("special regions should be valid after mapping them") {
30 auto process = Kernel::Process::Create(Kernel::CodeSet::Create("", 0));
31 SECTION("VRAM") {
32 Kernel::HandleSpecialMapping(process->vm_manager,
33 {Memory::VRAM_VADDR, Memory::VRAM_SIZE, false, false});
34 CHECK(Memory::IsValidVirtualAddress(*process, Memory::VRAM_VADDR) == true);
35 }
36
37 SECTION("IO (Not yet implemented)") {
38 Kernel::HandleSpecialMapping(
39 process->vm_manager, {Memory::IO_AREA_VADDR, Memory::IO_AREA_SIZE, false, false});
40 CHECK_FALSE(Memory::IsValidVirtualAddress(*process, Memory::IO_AREA_VADDR) == true);
41 }
42
43 SECTION("DSP") {
44 Kernel::HandleSpecialMapping(
45 process->vm_manager, {Memory::DSP_RAM_VADDR, Memory::DSP_RAM_SIZE, false, false});
46 CHECK(Memory::IsValidVirtualAddress(*process, Memory::DSP_RAM_VADDR) == true);
47 }
48 }
49
50 SECTION("Unmapping a VAddr should make it invalid") {
51 auto process = Kernel::Process::Create(Kernel::CodeSet::Create("", 0));
52 Kernel::MapSharedPages(process->vm_manager);
53 process->vm_manager.UnmapRange(Memory::CONFIG_MEMORY_VADDR, Memory::CONFIG_MEMORY_SIZE);
54 CHECK(Memory::IsValidVirtualAddress(*process, Memory::CONFIG_MEMORY_VADDR) == false);
55 }
56}