diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 53bd50eb2..662030782 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -59,6 +59,7 @@ set(SRCS hle/kernel/timer.cpp hle/kernel/vm_manager.cpp hle/kernel/wait_object.cpp + hle/lock.cpp hle/romfs.cpp hle/service/ac/ac.cpp hle/service/ac/ac_i.cpp @@ -256,6 +257,7 @@ set(HEADERS hle/kernel/timer.h hle/kernel/vm_manager.h hle/kernel/wait_object.h + hle/lock.h hle/result.h hle/romfs.h hle/service/ac/ac.h diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 142bb84b2..73fab3981 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -132,4 +132,4 @@ void Init(u32 system_mode); /// Shutdown the kernel void Shutdown(); -} // namespace +} // namespace Kernel diff --git a/src/core/hle/lock.cpp b/src/core/hle/lock.cpp new file mode 100644 index 000000000..082f689c8 --- /dev/null +++ b/src/core/hle/lock.cpp @@ -0,0 +1,11 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +namespace HLE { +std::mutex g_hle_lock; +} diff --git a/src/core/hle/lock.h b/src/core/hle/lock.h new file mode 100644 index 000000000..8265621e1 --- /dev/null +++ b/src/core/hle/lock.h @@ -0,0 +1,18 @@ +// Copyright 2017 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +namespace HLE { +/* + * Synchronizes access to the internal HLE kernel structures, it is acquired when a guest + * application thread performs a syscall. It should be acquired by any host threads that read or + * modify the HLE kernel state. Note: Any operation that directly or indirectly reads from or writes + * to the emulated memory is not protected by this mutex, and should be avoided in any threads other + * than the CPU thread. + */ +extern std::mutex g_hle_lock; +} // namespace HLE diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index e4b803046..b98938cb4 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -31,6 +31,7 @@ #include "core/hle/kernel/timer.h" #include "core/hle/kernel/vm_manager.h" #include "core/hle/kernel/wait_object.h" +#include "core/hle/lock.h" #include "core/hle/result.h" #include "core/hle/service/service.h" @@ -1188,7 +1189,7 @@ struct FunctionDef { Func* func; const char* name; }; -} +} // namespace static const FunctionDef SVC_Table[] = { {0x00, nullptr, "Unknown"}, @@ -1332,6 +1333,9 @@ MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70)); void CallSVC(u32 immediate) { MICROPROFILE_SCOPE(Kernel_SVC); + // Lock the global kernel mutex when we enter the kernel HLE. + std::lock_guard lock(HLE::g_hle_lock); + const FunctionDef* info = GetSVCInfo(immediate); if (info) { if (info->func) { @@ -1342,4 +1346,4 @@ void CallSVC(u32 immediate) { } } -} // namespace +} // namespace SVC diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 65649d9d7..a3c5f4a9d 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -9,6 +9,7 @@ #include "common/logging/log.h" #include "common/swap.h" #include "core/hle/kernel/process.h" +#include "core/hle/lock.h" #include "core/memory.h" #include "core/memory_setup.h" #include "core/mmio.h" @@ -181,6 +182,9 @@ T Read(const VAddr vaddr) { return value; } + // The memory access might do an MMIO or cached access, so we have to lock the HLE kernel state + std::lock_guard lock(HLE::g_hle_lock); + PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; switch (type) { case PageType::Unmapped: @@ -219,6 +223,9 @@ void Write(const VAddr vaddr, const T data) { return; } + // The memory access might do an MMIO or cached access, so we have to lock the HLE kernel state + std::lock_guard lock(HLE::g_hle_lock); + PageType type = current_page_table->attributes[vaddr >> PAGE_BITS]; switch (type) { case PageType::Unmapped: @@ -746,4 +753,4 @@ boost::optional PhysicalToVirtualAddress(const PAddr addr) { return boost::none; } -} // namespace +} // namespace Memory