aboutsummaryrefslogtreecommitdiff
path: root/src/core/hle
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle')
-rw-r--r--src/core/hle/config_mem.cpp58
-rw-r--r--src/core/hle/config_mem.h38
-rw-r--r--src/core/hle/function_wrappers.h13
-rw-r--r--src/core/hle/hle.cpp55
-rw-r--r--src/core/hle/hle.h28
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp7
-rw-r--r--src/core/hle/kernel/event.cpp2
-rw-r--r--src/core/hle/kernel/kernel.cpp30
-rw-r--r--src/core/hle/kernel/kernel.h33
-rw-r--r--src/core/hle/kernel/mutex.cpp12
-rw-r--r--src/core/hle/kernel/process.cpp98
-rw-r--r--src/core/hle/kernel/process.h98
-rw-r--r--src/core/hle/kernel/semaphore.cpp2
-rw-r--r--src/core/hle/kernel/session.h12
-rw-r--r--src/core/hle/kernel/shared_memory.cpp33
-rw-r--r--src/core/hle/kernel/shared_memory.h25
-rw-r--r--src/core/hle/kernel/thread.cpp131
-rw-r--r--src/core/hle/kernel/thread.h65
-rw-r--r--src/core/hle/kernel/timer.cpp8
-rw-r--r--src/core/hle/result.h1
-rw-r--r--src/core/hle/service/am_sys.cpp2
-rw-r--r--src/core/hle/service/apt/apt.cpp92
-rw-r--r--src/core/hle/service/apt/apt.h49
-rw-r--r--src/core/hle/service/apt/apt_a.cpp6
-rw-r--r--src/core/hle/service/apt/apt_s.cpp3
-rw-r--r--src/core/hle/service/apt/apt_u.cpp1
-rw-r--r--src/core/hle/service/cfg/cfg.cpp18
-rw-r--r--src/core/hle/service/cfg/cfg.h4
-rw-r--r--src/core/hle/service/cfg/cfg_u.cpp2
-rw-r--r--src/core/hle/service/dsp_dsp.cpp61
-rw-r--r--src/core/hle/service/err_f.cpp2
-rw-r--r--src/core/hle/service/fs/archive.cpp11
-rw-r--r--src/core/hle/service/fs/archive.h16
-rw-r--r--src/core/hle/service/fs/fs_user.cpp85
-rw-r--r--src/core/hle/service/gsp_gpu.cpp44
-rw-r--r--src/core/hle/service/hid/hid.cpp36
-rw-r--r--src/core/hle/service/hid/hid.h6
-rw-r--r--src/core/hle/service/ir/ir.cpp52
-rw-r--r--src/core/hle/service/ir/ir.h30
-rw-r--r--src/core/hle/service/ir/ir_rst.cpp24
-rw-r--r--src/core/hle/service/ir/ir_rst.h (renamed from src/core/hle/service/ir_rst.h)13
-rw-r--r--src/core/hle/service/ir/ir_u.cpp (renamed from src/core/hle/service/ir_u.cpp)17
-rw-r--r--src/core/hle/service/ir/ir_u.h22
-rw-r--r--src/core/hle/service/ir/ir_user.cpp34
-rw-r--r--src/core/hle/service/ir/ir_user.h22
-rw-r--r--src/core/hle/service/ir_rst.cpp27
-rw-r--r--src/core/hle/service/ldr_ro.cpp2
-rw-r--r--src/core/hle/service/nim_u.cpp48
-rw-r--r--src/core/hle/service/nim_u.h (renamed from src/core/hle/service/ir_u.h)8
-rw-r--r--src/core/hle/service/ns_s.cpp2
-rw-r--r--src/core/hle/service/nwm_uds.cpp113
-rw-r--r--src/core/hle/service/nwm_uds.h2
-rw-r--r--src/core/hle/service/ptm/ptm.cpp64
-rw-r--r--src/core/hle/service/ptm/ptm.h46
-rw-r--r--src/core/hle/service/ptm/ptm_play.cpp8
-rw-r--r--src/core/hle/service/ptm/ptm_sysm.cpp75
-rw-r--r--src/core/hle/service/ptm/ptm_u.cpp64
-rw-r--r--src/core/hle/service/service.cpp70
-rw-r--r--src/core/hle/service/service.h57
-rw-r--r--src/core/hle/service/soc_u.cpp1
-rw-r--r--src/core/hle/service/srv.cpp2
-rw-r--r--src/core/hle/service/y2r_u.cpp4
-rw-r--r--src/core/hle/shared_page.cpp60
-rw-r--r--src/core/hle/shared_page.h38
-rw-r--r--src/core/hle/svc.cpp131
-rw-r--r--src/core/hle/svc.h2
66 files changed, 1517 insertions, 708 deletions
diff --git a/src/core/hle/config_mem.cpp b/src/core/hle/config_mem.cpp
index 40bae9346..aea936d2d 100644
--- a/src/core/hle/config_mem.cpp
+++ b/src/core/hle/config_mem.cpp
@@ -2,71 +2,30 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <cstring>
+
+#include "common/assert.h"
#include "common/common_types.h"
#include "common/common_funcs.h"
#include "core/core.h"
-#include "core/mem_map.h"
+#include "core/memory.h"
#include "core/hle/config_mem.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace ConfigMem {
-struct ConfigMemDef {
- u8 kernel_unk; // 0
- u8 kernel_version_rev; // 1
- u8 kernel_version_min; // 2
- u8 kernel_version_maj; // 3
- u32 update_flag; // 4
- u64 ns_tid; // 8
- u32 sys_core_ver; // 10
- u8 unit_info; // 14
- u8 boot_firm; // 15
- u8 prev_firm; // 16
- INSERT_PADDING_BYTES(0x1); // 17
- u32 ctr_sdk_ver; // 18
- INSERT_PADDING_BYTES(0x30 - 0x1C); // 1C
- u32 app_mem_type; // 30
- INSERT_PADDING_BYTES(0x40 - 0x34); // 34
- u32 app_mem_alloc; // 40
- u32 sys_mem_alloc; // 44
- u32 base_mem_alloc; // 48
- INSERT_PADDING_BYTES(0x60 - 0x4C); // 4C
- u8 firm_unk; // 60
- u8 firm_version_rev; // 61
- u8 firm_version_min; // 62
- u8 firm_version_maj; // 63
- u32 firm_sys_core_ver; // 64
- u32 firm_ctr_sdk_ver; // 68
- INSERT_PADDING_BYTES(0x1000 - 0x6C); // 6C
-};
-
-static_assert(sizeof(ConfigMemDef) == Memory::CONFIG_MEMORY_SIZE, "Config Memory structure size is wrong");
-
-static ConfigMemDef config_mem;
-
-template <typename T>
-inline void Read(T &var, const u32 addr) {
- u32 offset = addr - Memory::CONFIG_MEMORY_VADDR;
- ASSERT(offset < Memory::CONFIG_MEMORY_SIZE);
- var = *(reinterpret_cast<T*>(((uintptr_t)&config_mem) + offset));
-}
-
-// Explicitly instantiate template functions because we aren't defining this in the header:
-
-template void Read<u64>(u64 &var, const u32 addr);
-template void Read<u32>(u32 &var, const u32 addr);
-template void Read<u16>(u16 &var, const u32 addr);
-template void Read<u8>(u8 &var, const u32 addr);
+ConfigMemDef config_mem;
void Init() {
+ std::memset(&config_mem, 0, sizeof(config_mem));
+
config_mem.update_flag = 0; // No update
config_mem.sys_core_ver = 0x2;
config_mem.unit_info = 0x1; // Bit 0 set for Retail
config_mem.prev_firm = 0;
config_mem.app_mem_type = 0x2; // Default app mem type is 0
- config_mem.unit_info = 0x1; // Bit 0 set for Retail
config_mem.app_mem_alloc = 0x06000000; // Set to 96MB, since some games use more than the default (64MB)
config_mem.base_mem_alloc = 0x01400000; // Default base memory is 20MB
config_mem.sys_mem_alloc = Memory::FCRAM_SIZE - (config_mem.app_mem_alloc + config_mem.base_mem_alloc);
@@ -77,4 +36,7 @@ void Init() {
config_mem.firm_sys_core_ver = 0x2;
}
+void Shutdown() {
+}
+
} // namespace
diff --git a/src/core/hle/config_mem.h b/src/core/hle/config_mem.h
index 94853901a..9825a09e8 100644
--- a/src/core/hle/config_mem.h
+++ b/src/core/hle/config_mem.h
@@ -9,15 +9,49 @@
// bootrom. Because we're not emulating this, and essentially just "stubbing" the functionality, I'm
// putting this as a subset of HLE for now.
+#include "common/common_funcs.h"
#include "common/common_types.h"
+#include "common/swap.h"
+
+#include "core/memory.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace ConfigMem {
-template <typename T>
-void Read(T &var, const u32 addr);
+struct ConfigMemDef {
+ u8 kernel_unk; // 0
+ u8 kernel_version_rev; // 1
+ u8 kernel_version_min; // 2
+ u8 kernel_version_maj; // 3
+ u32_le update_flag; // 4
+ u64_le ns_tid; // 8
+ u32_le sys_core_ver; // 10
+ u8 unit_info; // 14
+ u8 boot_firm; // 15
+ u8 prev_firm; // 16
+ INSERT_PADDING_BYTES(0x1); // 17
+ u32_le ctr_sdk_ver; // 18
+ INSERT_PADDING_BYTES(0x30 - 0x1C); // 1C
+ u32_le app_mem_type; // 30
+ INSERT_PADDING_BYTES(0x40 - 0x34); // 34
+ u32_le app_mem_alloc; // 40
+ u32_le sys_mem_alloc; // 44
+ u32_le base_mem_alloc; // 48
+ INSERT_PADDING_BYTES(0x60 - 0x4C); // 4C
+ u8 firm_unk; // 60
+ u8 firm_version_rev; // 61
+ u8 firm_version_min; // 62
+ u8 firm_version_maj; // 63
+ u32_le firm_sys_core_ver; // 64
+ u32_le firm_ctr_sdk_ver; // 68
+ INSERT_PADDING_BYTES(0x1000 - 0x6C); // 6C
+};
+static_assert(sizeof(ConfigMemDef) == Memory::CONFIG_MEMORY_SIZE, "Config Memory structure size is wrong");
+
+extern ConfigMemDef config_mem;
void Init();
+void Shutdown();
} // namespace
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h
index 0b6b6f518..eb52c8fb1 100644
--- a/src/core/hle/function_wrappers.h
+++ b/src/core/hle/function_wrappers.h
@@ -7,7 +7,7 @@
#include "common/common_types.h"
#include "core/arm/arm_interface.h"
-#include "core/mem_map.h"
+#include "core/memory.h"
#include "core/hle/hle.h"
namespace HLE {
@@ -46,6 +46,13 @@ template<ResultCode func(u32*, u32, u32, u32, u32, u32)> void Wrap(){
FuncReturn(retval);
}
+template<ResultCode func(u32*, s32, u32, u32, u32, s32)> void Wrap() {
+ u32 param_1 = 0;
+ u32 retval = func(&param_1, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)).raw;
+ Core::g_app_core->SetReg(1, param_1);
+ FuncReturn(retval);
+}
+
template<ResultCode func(s32*, u32*, s32, bool, s64)> void Wrap() {
s32 param_1 = 0;
s32 retval = func(&param_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2),
@@ -102,7 +109,7 @@ template<ResultCode func(s64*, u32, void*, s32)> void Wrap(){
template<ResultCode func(u32*, const char*)> void Wrap() {
u32 param_1 = 0;
- u32 retval = func(&param_1, Memory::GetCharPointer(PARAM(1))).raw;
+ u32 retval = func(&param_1, (char*)Memory::GetPointer(PARAM(1))).raw;
Core::g_app_core->SetReg(1, param_1);
FuncReturn(retval);
}
@@ -156,7 +163,7 @@ template<void func(s64)> void Wrap() {
}
template<void func(const char*)> void Wrap() {
- func(Memory::GetCharPointer(PARAM(0)));
+ func((char*)Memory::GetPointer(PARAM(0)));
}
#undef PARAM
diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp
index 1aaeaa9c9..fdeb9a028 100644
--- a/src/core/hle/hle.cpp
+++ b/src/core/hle/hle.cpp
@@ -2,12 +2,11 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include <vector>
-
-#include "common/profiler.h"
+#include "common/assert.h"
+#include "common/logging/log.h"
#include "core/arm/arm_interface.h"
-#include "core/mem_map.h"
+#include "core/core.h"
#include "core/hle/hle.h"
#include "core/hle/config_mem.h"
#include "core/hle/shared_page.h"
@@ -18,35 +17,7 @@
namespace HLE {
-Common::Profiling::TimingCategory profiler_svc("SVC Calls");
-
-static std::vector<ModuleDef> g_module_db;
-
-bool g_reschedule = false; ///< If true, immediately reschedules the CPU to a new thread
-
-static const FunctionDef* GetSVCInfo(u32 opcode) {
- u32 func_num = opcode & 0xFFFFFF; // 8 bits
- if (func_num > 0xFF) {
- LOG_ERROR(Kernel_SVC,"unknown svc=0x%02X", func_num);
- return nullptr;
- }
- return &g_module_db[0].func_table[func_num];
-}
-
-void CallSVC(u32 opcode) {
- Common::Profiling::ScopeTimer timer_svc(profiler_svc);
-
- const FunctionDef *info = GetSVCInfo(opcode);
-
- if (!info) {
- return;
- }
- if (info->func) {
- info->func();
- } else {
- LOG_ERROR(Kernel_SVC, "unimplemented SVC function %s(..)", info->name.c_str());
- }
-}
+bool g_reschedule; ///< If true, immediately reschedules the CPU to a new thread
void Reschedule(const char *reason) {
DEBUG_ASSERT_MSG(reason != nullptr && strlen(reason) < 256, "Reschedule: Invalid or too long reason.");
@@ -62,31 +33,21 @@ void Reschedule(const char *reason) {
g_reschedule = true;
}
-void RegisterModule(std::string name, int num_functions, const FunctionDef* func_table) {
- ModuleDef module = {name, num_functions, func_table};
- g_module_db.push_back(module);
-}
-
-static void RegisterAllModules() {
- SVC::Register();
-}
-
void Init() {
Service::Init();
-
- RegisterAllModules();
-
ConfigMem::Init();
SharedPage::Init();
+ g_reschedule = false;
+
LOG_DEBUG(Kernel, "initialized OK");
}
void Shutdown() {
+ ConfigMem::Shutdown();
+ SharedPage::Shutdown();
Service::Shutdown();
- g_module_db.clear();
-
LOG_DEBUG(Kernel, "shutdown OK");
}
diff --git a/src/core/hle/hle.h b/src/core/hle/hle.h
index 3f6f9a4b5..e0b97797c 100644
--- a/src/core/hle/hle.h
+++ b/src/core/hle/hle.h
@@ -4,40 +4,20 @@
#pragma once
-#include <string>
-
#include "common/common_types.h"
-#include "core/core.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
+typedef u32 Handle;
+typedef s32 Result;
+
+const Handle INVALID_HANDLE = 0;
namespace HLE {
extern bool g_reschedule; ///< If true, immediately reschedules the CPU to a new thread
-typedef u32 Addr;
-typedef void (*Func)();
-
-struct FunctionDef {
- u32 id;
- Func func;
- std::string name;
-};
-
-struct ModuleDef {
- std::string name;
- int num_funcs;
- const FunctionDef* func_table;
-};
-
-void RegisterModule(std::string name, int num_functions, const FunctionDef *func_table);
-
-void CallSVC(u32 opcode);
-
void Reschedule(const char *reason);
void Init();
-
void Shutdown();
} // namespace
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index 42f8ce2d9..a1221766e 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -3,8 +3,9 @@
// Refer to the license.txt file included.
#include "common/common_types.h"
+#include "common/logging/log.h"
-#include "core/mem_map.h"
+#include "core/memory.h"
#include "core/hle/hle.h"
#include "core/hle/kernel/address_arbiter.h"
@@ -46,14 +47,12 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address,
case ArbitrationType::WaitIfLessThan:
if ((s32)Memory::Read32(address) <= value) {
Kernel::WaitCurrentThread_ArbitrateAddress(address);
- HLE::Reschedule(__func__);
}
break;
case ArbitrationType::WaitIfLessThanWithTimeout:
if ((s32)Memory::Read32(address) <= value) {
Kernel::WaitCurrentThread_ArbitrateAddress(address);
GetCurrentThread()->WakeAfterDelay(nanoseconds);
- HLE::Reschedule(__func__);
}
break;
case ArbitrationType::DecrementAndWaitIfLessThan:
@@ -62,7 +61,6 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address,
Memory::Write32(address, memory_value);
if (memory_value <= value) {
Kernel::WaitCurrentThread_ArbitrateAddress(address);
- HLE::Reschedule(__func__);
}
break;
}
@@ -73,7 +71,6 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address,
if (memory_value <= value) {
Kernel::WaitCurrentThread_ArbitrateAddress(address);
GetCurrentThread()->WakeAfterDelay(nanoseconds);
- HLE::Reschedule(__func__);
}
break;
}
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp
index 420906ec0..f338f3266 100644
--- a/src/core/hle/kernel/event.cpp
+++ b/src/core/hle/kernel/event.cpp
@@ -6,7 +6,7 @@
#include <algorithm>
#include <vector>
-#include "common/common.h"
+#include "common/assert.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/event.h"
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 498b2ec98..b5c98b249 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -4,21 +4,20 @@
#include <algorithm>
-#include "common/common.h"
+#include "common/assert.h"
+#include "common/logging/log.h"
#include "core/arm/arm_interface.h"
#include "core/core.h"
#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/process.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/timer.h"
namespace Kernel {
-unsigned int Object::next_object_id = 0;
-
-SharedPtr<Thread> g_main_thread = nullptr;
+unsigned int Object::next_object_id;
HandleTable g_handle_table;
-u64 g_program_id = 0;
void WaitObject::AddWaitingThread(SharedPtr<Thread> thread) {
auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
@@ -116,8 +115,7 @@ SharedPtr<Object> HandleTable::GetGeneric(Handle handle) const {
if (handle == CurrentThread) {
return GetCurrentThread();
} else if (handle == CurrentProcess) {
- LOG_ERROR(Kernel, "Current process (%08X) pseudo-handle not supported", CurrentProcess);
- return nullptr;
+ return g_current_process;
}
if (!IsValid(handle)) {
@@ -138,6 +136,11 @@ void HandleTable::Clear() {
void Init() {
Kernel::ThreadingInit();
Kernel::TimersInit();
+
+ Object::next_object_id = 0;
+ // TODO(Subv): Start the process ids from 10 for now, as lower PIDs are
+ // reserved for low-level services
+ Process::next_process_id = 10;
}
/// Shutdown the kernel
@@ -145,18 +148,7 @@ void Shutdown() {
Kernel::ThreadingShutdown();
Kernel::TimersShutdown();
g_handle_table.Clear(); // Free all kernel objects
-}
-
-/**
- * Loads executable stored at specified address
- * @entry_point Entry point in memory of loaded executable
- * @return True on success, otherwise false
- */
-bool LoadExec(u32 entry_point) {
- // 0x30 is the typical main thread priority I've seen used so far
- g_main_thread = Kernel::SetupMainThread(Kernel::DEFAULT_STACK_SIZE, entry_point, 0x30);
-
- return true;
+ g_current_process = nullptr;
}
} // namespace
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 2d295ea00..7c106d37c 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -7,21 +7,16 @@
#include <boost/intrusive_ptr.hpp>
#include <array>
+#include <memory>
#include <string>
#include <vector>
-#include "common/common.h"
-#include "core/hle/result.h"
-
-typedef u32 Handle;
-typedef s32 Result;
+#include "common/common_types.h"
-// TODO: It would be nice to eventually replace these with strong types that prevent accidental
-// conversion between each other.
-typedef u32 VAddr; ///< Represents a pointer in the userspace virtual address space.
-typedef u32 PAddr; ///< Represents a pointer in the ARM11 physical address space.
+#include "core/hle/hle.h"
+#include "core/hle/result.h"
-const Handle INVALID_HANDLE = 0;
+struct ApplicationInfo;
namespace Kernel {
@@ -95,12 +90,13 @@ public:
return false;
}
+public:
+ static unsigned int next_object_id;
+
private:
friend void intrusive_ptr_add_ref(Object*);
friend void intrusive_ptr_release(Object*);
- static unsigned int next_object_id;
-
unsigned int ref_count = 0;
unsigned int object_id = next_object_id++;
};
@@ -277,23 +273,10 @@ private:
extern HandleTable g_handle_table;
-/// The ID code of the currently running game
-/// TODO(Subv): This variable should not be here,
-/// we need a way to store information about the currently loaded application
-/// for later query during runtime, maybe using the LDR service?
-extern u64 g_program_id;
-
/// Initialize the kernel
void Init();
/// Shutdown the kernel
void Shutdown();
-/**
- * Loads executable stored at specified address
- * @entry_point Entry point in memory of loaded executable
- * @return True on success, otherwise false
- */
-bool LoadExec(u32 entry_point);
-
} // namespace
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index be2c49706..f530217fd 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -7,7 +7,7 @@
#include <boost/range/algorithm_ext/erase.hpp>
-#include "common/common.h"
+#include "common/assert.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/mutex.h"
@@ -56,7 +56,15 @@ SharedPtr<Mutex> Mutex::Create(bool initial_locked, std::string name) {
}
bool Mutex::ShouldWait() {
- return lock_count > 0 && holding_thread != GetCurrentThread();;
+ auto thread = GetCurrentThread();
+ bool wait = lock_count > 0 && holding_thread != thread;
+
+ // If the holding thread of the mutex is lower priority than this thread, that thread should
+ // temporarily inherit this thread's priority
+ if (wait && thread->current_priority < holding_thread->current_priority)
+ holding_thread->BoostPriority(thread->current_priority);
+
+ return wait;
}
void Mutex::Acquire() {
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
new file mode 100644
index 000000000..0cdfa58d7
--- /dev/null
+++ b/src/core/hle/kernel/process.cpp
@@ -0,0 +1,98 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+#include "common/common_funcs.h"
+#include "common/logging/log.h"
+
+#include "core/hle/kernel/process.h"
+#include "core/hle/kernel/thread.h"
+#include "core/memory.h"
+
+namespace Kernel {
+
+u32 Process::next_process_id;
+
+SharedPtr<Process> Process::Create(std::string name, u64 program_id) {
+ SharedPtr<Process> process(new Process);
+
+ process->name = std::move(name);
+ process->program_id = program_id;
+
+ process->flags.raw = 0;
+ process->flags.memory_region = MemoryRegion::APPLICATION;
+
+ return process;
+}
+
+void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) {
+ for (int i = 0; i < len; ++i) {
+ u32 descriptor = kernel_caps[i];
+ u32 type = descriptor >> 20;
+
+ if (descriptor == 0xFFFFFFFF) {
+ // Unused descriptor entry
+ continue;
+ } else if ((type & 0xF00) == 0xE00) { // 0x0FFF
+ // Allowed interrupts list
+ LOG_WARNING(Loader, "ExHeader allowed interrupts list ignored");
+ } else if ((type & 0xF80) == 0xF00) { // 0x07FF
+ // Allowed syscalls mask
+ unsigned int index = ((descriptor >> 24) & 7) * 24;
+ u32 bits = descriptor & 0xFFFFFF;
+
+ while (bits && index < svc_access_mask.size()) {
+ svc_access_mask.set(index, bits & 1);
+ ++index; bits >>= 1;
+ }
+ } else if ((type & 0xFF0) == 0xFE0) { // 0x00FF
+ // Handle table size
+ handle_table_size = descriptor & 0x3FF;
+ } else if ((type & 0xFF8) == 0xFF0) { // 0x007F
+ // Misc. flags
+ flags.raw = descriptor & 0xFFFF;
+ } else if ((type & 0xFFE) == 0xFF8) { // 0x001F
+ // Mapped memory range
+ if (i+1 >= len || ((kernel_caps[i+1] >> 20) & 0xFFE) != 0xFF8) {
+ LOG_WARNING(Loader, "Incomplete exheader memory range descriptor ignored.");
+ continue;
+ }
+ u32 end_desc = kernel_caps[i+1];
+ ++i; // Skip over the second descriptor on the next iteration
+
+ AddressMapping mapping;
+ mapping.address = descriptor << 12;
+ mapping.size = (end_desc << 12) - mapping.address;
+ mapping.writable = descriptor & (1 << 20);
+ mapping.unk_flag = end_desc & (1 << 20);
+
+ address_mappings.push_back(mapping);
+ } else if ((type & 0xFFF) == 0xFFE) { // 0x000F
+ // Mapped memory page
+ AddressMapping mapping;
+ mapping.address = descriptor << 12;
+ mapping.size = Memory::PAGE_SIZE;
+ mapping.writable = true; // TODO: Not sure if correct
+ mapping.unk_flag = false;
+ } else if ((type & 0xFE0) == 0xFC0) { // 0x01FF
+ // Kernel version
+ int minor = descriptor & 0xFF;
+ int major = (descriptor >> 8) & 0xFF;
+ LOG_INFO(Loader, "ExHeader kernel version ignored: %d.%d", major, minor);
+ } else {
+ LOG_ERROR(Loader, "Unhandled kernel caps descriptor: 0x%08X", descriptor);
+ }
+ }
+}
+
+void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) {
+ Kernel::SetupMainThread(entry_point, main_thread_priority);
+}
+
+Kernel::Process::Process() {}
+Kernel::Process::~Process() {}
+
+SharedPtr<Process> g_current_process;
+
+}
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
new file mode 100644
index 000000000..90881054c
--- /dev/null
+++ b/src/core/hle/kernel/process.h
@@ -0,0 +1,98 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <bitset>
+
+#include <boost/container/static_vector.hpp>
+
+#include "common/bit_field.h"
+#include "common/common_types.h"
+
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/result.h"
+
+namespace Kernel {
+
+struct AddressMapping {
+ // Address and size must be page-aligned
+ VAddr address;
+ u32 size;
+ bool writable;
+ bool unk_flag;
+};
+
+enum class MemoryRegion : u16 {
+ APPLICATION = 1,
+ SYSTEM = 2,
+ BASE = 3,
+};
+
+union ProcessFlags {
+ u16 raw;
+
+ BitField< 0, 1, u16> allow_debug; ///< Allows other processes to attach to and debug this process.
+ BitField< 1, 1, u16> force_debug; ///< Allows this process to attach to processes even if they don't have allow_debug set.
+ BitField< 2, 1, u16> allow_nonalphanum;
+ BitField< 3, 1, u16> shared_page_writable; ///< Shared page is mapped with write permissions.
+ BitField< 4, 1, u16> privileged_priority; ///< Can use priority levels higher than 24.
+ BitField< 5, 1, u16> allow_main_args;
+ BitField< 6, 1, u16> shared_device_mem;
+ BitField< 7, 1, u16> runnable_on_sleep;
+ BitField< 8, 4, MemoryRegion> memory_region; ///< Default region for memory allocations for this process
+ BitField<12, 1, u16> loaded_high; ///< Application loaded high (not at 0x00100000).
+};
+
+class Process final : public Object {
+public:
+ static SharedPtr<Process> Create(std::string name, u64 program_id);
+
+ std::string GetTypeName() const override { return "Process"; }
+ std::string GetName() const override { return name; }
+
+ static const HandleType HANDLE_TYPE = HandleType::Process;
+ HandleType GetHandleType() const override { return HANDLE_TYPE; }
+
+ static u32 next_process_id;
+
+ /// Name of the process
+ std::string name;
+ /// Title ID corresponding to the process
+ u64 program_id;
+
+ /// The process may only call SVCs which have the corresponding bit set.
+ std::bitset<0x80> svc_access_mask;
+ /// Maximum size of the handle table for the process.
+ unsigned int handle_table_size = 0x200;
+ /// Special memory ranges mapped into this processes address space. This is used to give
+ /// processes access to specific I/O regions and device memory.
+ boost::container::static_vector<AddressMapping, 8> address_mappings;
+ ProcessFlags flags;
+
+ /// The id of this process
+ u32 process_id = next_process_id++;
+
+ /// Bitmask of the used TLS slots
+ std::bitset<300> used_tls_slots;
+
+ /**
+ * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them
+ * to this process.
+ */
+ void ParseKernelCaps(const u32* kernel_caps, size_t len);
+
+ /**
+ * Applies address space changes and launches the process main thread.
+ */
+ void Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size);
+
+private:
+ Process();
+ ~Process() override;
+};
+
+extern SharedPtr<Process> g_current_process;
+
+}
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp
index 6aecc24aa..5d6543ef4 100644
--- a/src/core/hle/kernel/semaphore.cpp
+++ b/src/core/hle/kernel/semaphore.cpp
@@ -2,7 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "common/common.h"
+#include "common/assert.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/semaphore.h"
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h
index 9e9288e0f..54a062971 100644
--- a/src/core/hle/kernel/session.h
+++ b/src/core/hle/kernel/session.h
@@ -5,19 +5,23 @@
#pragma once
#include "core/hle/kernel/kernel.h"
-#include "core/mem_map.h"
+#include "core/hle/kernel/thread.h"
+#include "core/memory.h"
namespace Kernel {
static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header
/**
- * Returns a pointer to the command buffer in kernel memory
+ * Returns a pointer to the command buffer in the current thread's TLS
+ * TODO(Subv): This is not entirely correct, the command buffer should be copied from
+ * the thread's TLS to an intermediate buffer in kernel memory, and then copied again to
+ * the service handler process' memory.
* @param offset Optional offset into command buffer
* @return Pointer to command buffer
*/
-inline static u32* GetCommandBuffer(const int offset=0) {
- return (u32*)Memory::GetPointer(Memory::KERNEL_MEMORY_VADDR + kCommandHeaderOffset + offset);
+inline static u32* GetCommandBuffer(const int offset = 0) {
+ return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset + offset);
}
/**
diff --git a/src/core/hle/kernel/shared_memory.cpp b/src/core/hle/kernel/shared_memory.cpp
index 4211fcf04..4137683b5 100644
--- a/src/core/hle/kernel/shared_memory.cpp
+++ b/src/core/hle/kernel/shared_memory.cpp
@@ -2,9 +2,11 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "common/common.h"
+#include <cstring>
-#include "core/mem_map.h"
+#include "common/logging/log.h"
+
+#include "core/memory.h"
#include "core/hle/kernel/shared_memory.h"
namespace Kernel {
@@ -12,10 +14,15 @@ namespace Kernel {
SharedMemory::SharedMemory() {}
SharedMemory::~SharedMemory() {}
-SharedPtr<SharedMemory> SharedMemory::Create(std::string name) {
+SharedPtr<SharedMemory> SharedMemory::Create(u32 size, MemoryPermission permissions,
+ MemoryPermission other_permissions, std::string name) {
SharedPtr<SharedMemory> shared_memory(new SharedMemory);
shared_memory->name = std::move(name);
+ shared_memory->base_address = 0x0;
+ shared_memory->size = size;
+ shared_memory->permissions = permissions;
+ shared_memory->other_permissions = other_permissions;
return shared_memory;
}
@@ -23,7 +30,7 @@ SharedPtr<SharedMemory> SharedMemory::Create(std::string name) {
ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions,
MemoryPermission other_permissions) {
- if (address < Memory::SHARED_MEMORY_VADDR || address >= Memory::SHARED_MEMORY_VADDR_END) {
+ if (address < Memory::SHARED_MEMORY_VADDR || address + size >= Memory::SHARED_MEMORY_VADDR_END) {
LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X outside of shared mem bounds!",
GetObjectId(), address);
// TODO: Verify error code with hardware
@@ -31,21 +38,25 @@ ResultCode SharedMemory::Map(VAddr address, MemoryPermission permissions,
ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
}
+ // TODO: Test permissions
+
+ // HACK: Since there's no way to write to the memory block without mapping it onto the game
+ // process yet, at least initialize memory the first time it's mapped.
+ if (address != this->base_address) {
+ std::memset(Memory::GetPointer(address), 0, size);
+ }
+
this->base_address = address;
- this->permissions = permissions;
- this->other_permissions = other_permissions;
return RESULT_SUCCESS;
}
-ResultVal<u8*> SharedMemory::GetPointer(u32 offset) {
+u8* SharedMemory::GetPointer(u32 offset) {
if (base_address != 0)
- return MakeResult<u8*>(Memory::GetPointer(base_address + offset));
+ return Memory::GetPointer(base_address + offset);
LOG_ERROR(Kernel_SVC, "memory block id=%u not mapped!", GetObjectId());
- // TODO(yuriks): Verify error code.
- return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
- ErrorSummary::InvalidState, ErrorLevel::Permanent);
+ return nullptr;
}
} // namespace
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 5833b411c..204266896 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -27,11 +27,16 @@ class SharedMemory final : public Object {
public:
/**
* Creates a shared memory object
- * @param name Optional object name, used only for debugging purposes.
+ * @param size Size of the memory block. Must be page-aligned.
+ * @param permissions Permission restrictions applied to the process which created the block.
+ * @param other_permissions Permission restrictions applied to other processes mapping the block.
+ * @param name Optional object name, used for debugging purposes.
*/
- static SharedPtr<SharedMemory> Create(std::string name = "Unknown");
+ static SharedPtr<SharedMemory> Create(u32 size, MemoryPermission permissions,
+ MemoryPermission other_permissions, std::string name = "Unknown");
std::string GetTypeName() const override { return "SharedMemory"; }
+ std::string GetName() const override { return name; }
static const HandleType HANDLE_TYPE = HandleType::SharedMemory;
HandleType GetHandleType() const override { return HANDLE_TYPE; }
@@ -49,12 +54,18 @@ public:
* @param offset Offset from the start of the shared memory block to get pointer
* @return Pointer to the shared memory block from the specified offset
*/
- ResultVal<u8*> GetPointer(u32 offset = 0);
+ u8* GetPointer(u32 offset = 0);
- VAddr base_address; ///< Address of shared memory block in RAM
- MemoryPermission permissions; ///< Permissions of shared memory block (SVC field)
- MemoryPermission other_permissions; ///< Other permissions of shared memory block (SVC field)
- std::string name; ///< Name of shared memory object (optional)
+ /// Address of shared memory block in the process.
+ VAddr base_address;
+ /// Size of the memory block. Page-aligned.
+ u32 size;
+ /// Permission restrictions applied to the process which created the block.
+ MemoryPermission permissions;
+ /// Permission restrictions applied to other processes mapping the block.
+ MemoryPermission other_permissions;
+ /// Name of shared memory object.
+ std::string name;
private:
SharedMemory();
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index be1aed615..a5f1904d7 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -6,7 +6,9 @@
#include <list>
#include <vector>
-#include "common/common.h"
+#include "common/assert.h"
+#include "common/common_types.h"
+#include "common/logging/log.h"
#include "common/math_util.h"
#include "common/thread_queue_list.h"
@@ -15,15 +17,16 @@
#include "core/core_timing.h"
#include "core/hle/hle.h"
#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/process.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/kernel/mutex.h"
#include "core/hle/result.h"
-#include "core/mem_map.h"
+#include "core/memory.h"
namespace Kernel {
/// Event type for the thread wake up event
-static int ThreadWakeupEventType = -1;
+static int ThreadWakeupEventType;
bool Thread::ShouldWait() {
return status != THREADSTATUS_DEAD;
@@ -42,7 +45,7 @@ static Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST+1> ready_queue;
static Thread* current_thread;
// The first available thread id at startup
-static u32 next_thread_id = 1;
+static u32 next_thread_id;
/**
* Creates a new thread ID
@@ -104,6 +107,8 @@ void Thread::Stop() {
for (auto& wait_object : wait_objects) {
wait_object->RemoveWaitingThread(this);
}
+
+ Kernel::g_current_process->used_tls_slots[tls_index] = false;
}
Thread* ArbitrateHighestPriorityThread(u32 address) {
@@ -140,17 +145,38 @@ void ArbitrateAllThreads(u32 address) {
}
}
+/// Boost low priority threads (temporarily) that have been starved
+static void PriorityBoostStarvedThreads() {
+ u64 current_ticks = CoreTiming::GetTicks();
+
+ for (auto& thread : thread_list) {
+ // TODO(bunnei): Threads that have been waiting to be scheduled for `boost_ticks` (or
+ // longer) will have their priority temporarily adjusted to 1 higher than the highest
+ // priority thread to prevent thread starvation. This general behavior has been verified
+ // on hardware. However, this is almost certainly not perfect, and the real CTR OS scheduler
+ // should probably be reversed to verify this.
+
+ const u64 boost_timeout = 2000000; // Boost threads that have been ready for > this long
+
+ u64 delta = current_ticks - thread->last_running_ticks;
+
+ if (thread->status == THREADSTATUS_READY && delta > boost_timeout) {
+ const s32 priority = std::max(ready_queue.get_first()->current_priority - 1, 0);
+ thread->BoostPriority(priority);
+ }
+ }
+}
+
/**
* Switches the CPU's active thread context to that of the specified thread
* @param new_thread The thread to switch to
*/
static void SwitchContext(Thread* new_thread) {
- DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY, "Thread must be ready to become running.");
-
Thread* previous_thread = GetCurrentThread();
// Save context for previous thread
if (previous_thread) {
+ previous_thread->last_running_ticks = CoreTiming::GetTicks();
Core::g_app_core->SaveContext(previous_thread->context);
if (previous_thread->status == THREADSTATUS_RUNNING) {
@@ -163,12 +189,18 @@ static void SwitchContext(Thread* new_thread) {
// Load context of new thread
if (new_thread) {
+ DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY, "Thread must be ready to become running.");
+
current_thread = new_thread;
ready_queue.remove(new_thread->current_priority, new_thread);
new_thread->status = THREADSTATUS_RUNNING;
+ // Restores thread to its nominal priority if it has been temporarily changed
+ new_thread->current_priority = new_thread->nominal_priority;
+
Core::g_app_core->LoadContext(new_thread->context);
+ Core::g_app_core->SetCP15Register(CP15_THREAD_URO, new_thread->GetTLSAddress());
} else {
current_thread = nullptr;
}
@@ -186,6 +218,10 @@ static Thread* PopNextReadyThread() {
// We have to do better than the current thread.
// This call returns null when that's not possible.
next = ready_queue.pop_first_better(thread->current_priority);
+ if (!next) {
+ // Otherwise just keep going with the current thread
+ next = thread;
+ }
} else {
next = ready_queue.pop_first();
}
@@ -364,7 +400,8 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
thread->status = THREADSTATUS_DORMANT;
thread->entry_point = entry_point;
thread->stack_top = stack_top;
- thread->initial_priority = thread->current_priority = priority;
+ thread->nominal_priority = thread->current_priority = priority;
+ thread->last_running_ticks = CoreTiming::GetTicks();
thread->processor_id = processor_id;
thread->wait_set_output = false;
thread->wait_all = false;
@@ -372,6 +409,20 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
thread->wait_address = 0;
thread->name = std::move(name);
thread->callback_handle = wakeup_callback_handle_table.Create(thread).MoveFrom();
+ thread->owner_process = g_current_process;
+ thread->tls_index = -1;
+
+ // Find the next available TLS index, and mark it as used
+ auto& used_tls_slots = Kernel::g_current_process->used_tls_slots;
+ for (unsigned int i = 0; i < used_tls_slots.size(); ++i) {
+ if (used_tls_slots[i] == false) {
+ thread->tls_index = i;
+ used_tls_slots[i] = true;
+ break;
+ }
+ }
+
+ ASSERT_MSG(thread->tls_index != -1, "Out of TLS space");
// TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
// to initialize the context
@@ -400,35 +451,26 @@ static void ClampPriority(const Thread* thread, s32* priority) {
void Thread::SetPriority(s32 priority) {
ClampPriority(this, &priority);
- if (current_priority == priority) {
- return;
- }
-
- if (status == THREADSTATUS_READY) {
- // If thread was ready, adjust queues
- ready_queue.remove(current_priority, this);
+ // If thread was ready, adjust queues
+ if (status == THREADSTATUS_READY)
+ ready_queue.move(this, current_priority, priority);
+ else
ready_queue.prepare(priority);
- ready_queue.push_back(priority, this);
- }
-
- current_priority = priority;
-}
-SharedPtr<Thread> SetupIdleThread() {
- // We need to pass a few valid values to get around parameter checking in Thread::Create.
- auto thread = Thread::Create("idle", Memory::KERNEL_MEMORY_VADDR, THREADPRIO_LOWEST, 0,
- THREADPROCESSORID_0, 0).MoveFrom();
+ nominal_priority = current_priority = priority;
+}
- thread->idle = true;
- return thread;
+void Thread::BoostPriority(s32 priority) {
+ ready_queue.move(this, current_priority, priority);
+ current_priority = priority;
}
-SharedPtr<Thread> SetupMainThread(u32 stack_size, u32 entry_point, s32 priority) {
+SharedPtr<Thread> SetupMainThread(u32 entry_point, s32 priority) {
DEBUG_ASSERT(!GetCurrentThread());
// Initialize new "main" thread
auto thread_res = Thread::Create("main", entry_point, priority, 0,
- THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END);
+ THREADPROCESSORID_0, Memory::HEAP_VADDR_END);
SharedPtr<Thread> thread = thread_res.MoveFrom();
@@ -439,21 +481,25 @@ SharedPtr<Thread> SetupMainThread(u32 stack_size, u32 entry_point, s32 priority)
}
void Reschedule() {
- Thread* prev = GetCurrentThread();
+ PriorityBoostStarvedThreads();
+
+ Thread* cur = GetCurrentThread();
Thread* next = PopNextReadyThread();
HLE::g_reschedule = false;
- if (next != nullptr) {
- LOG_TRACE(Kernel, "context switch %u -> %u", prev->GetObjectId(), next->GetObjectId());
- SwitchContext(next);
- } else {
- LOG_TRACE(Kernel, "cannot context switch from %u, no higher priority thread!", prev->GetObjectId());
+ // Don't bother switching to the same thread
+ if (next == cur)
+ return;
- for (auto& thread : thread_list) {
- LOG_TRACE(Kernel, "\tid=%u prio=0x%02X, status=0x%08X", thread->GetObjectId(),
- thread->current_priority, thread->status);
- }
+ if (cur && next) {
+ LOG_TRACE(Kernel, "context switch %u -> %u", cur->GetObjectId(), next->GetObjectId());
+ } else if (cur) {
+ LOG_TRACE(Kernel, "context switch %u -> idle", cur->GetObjectId());
+ } else if (next) {
+ LOG_TRACE(Kernel, "context switch idle -> %u", next->GetObjectId());
}
+
+ SwitchContext(next);
}
void Thread::SetWaitSynchronizationResult(ResultCode result) {
@@ -464,13 +510,20 @@ void Thread::SetWaitSynchronizationOutput(s32 output) {
context.cpu_registers[1] = output;
}
+VAddr Thread::GetTLSAddress() const {
+ return Memory::TLS_AREA_VADDR + tls_index * 0x200;
+}
+
////////////////////////////////////////////////////////////////////////////////////////////////////
void ThreadingInit() {
ThreadWakeupEventType = CoreTiming::RegisterEvent("ThreadWakeupCallback", ThreadWakeupCallback);
- // Setup the idle thread
- SetupIdleThread();
+ current_thread = nullptr;
+ next_thread_id = 1;
+
+ thread_list.clear();
+ ready_queue.clear();
}
void ThreadingShutdown() {
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index cfd073a70..389928178 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -12,22 +12,23 @@
#include "common/common_types.h"
#include "core/core.h"
-#include "core/mem_map.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/result.h"
-enum ThreadPriority {
- THREADPRIO_HIGHEST = 0, ///< Highest thread priority
- THREADPRIO_DEFAULT = 16, ///< Default thread priority for userland apps
- THREADPRIO_LOW = 31, ///< Low range of thread priority for userland apps
- THREADPRIO_LOWEST = 63, ///< Thread priority max checked by svcCreateThread
+enum ThreadPriority : s32{
+ THREADPRIO_HIGHEST = 0, ///< Highest thread priority
+ THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps
+ THREADPRIO_DEFAULT = 48, ///< Default thread priority for userland apps
+ THREADPRIO_LOWEST = 63, ///< Lowest thread priority
};
-enum ThreadProcessorId {
- THREADPROCESSORID_0 = 0xFFFFFFFE, ///< Enables core appcode
- THREADPROCESSORID_1 = 0xFFFFFFFD, ///< Enables core syscore
- THREADPROCESSORID_ALL = 0xFFFFFFFC, ///< Enables both cores
+enum ThreadProcessorId : s32 {
+ THREADPROCESSORID_DEFAULT = -2, ///< Run thread on default core specified by exheader
+ THREADPROCESSORID_ALL = -1, ///< Run thread on either core
+ THREADPROCESSORID_0 = 0, ///< Run thread on core 0 (AppCore)
+ THREADPROCESSORID_1 = 1, ///< Run thread on core 1 (SysCore)
+ THREADPROCESSORID_MAX = 2, ///< Processor ID must be less than this
};
enum ThreadStatus {
@@ -43,6 +44,7 @@ enum ThreadStatus {
namespace Kernel {
class Mutex;
+class Process;
class Thread final : public WaitObject {
public:
@@ -70,12 +72,6 @@ public:
void Acquire() override;
/**
- * Checks if the thread is an idle (stub) thread
- * @return True if the thread is an idle (stub) thread, false otherwise
- */
- inline bool IsIdle() const { return idle; }
-
- /**
* Gets the thread's current priority
* @return The current thread's priority
*/
@@ -88,6 +84,12 @@ public:
void SetPriority(s32 priority);
/**
+ * Temporarily boosts the thread's priority until the next time it is scheduled
+ * @param priority The new priority
+ */
+ void BoostPriority(s32 priority);
+
+ /**
* Gets the thread's thread ID
* @return The thread's ID
*/
@@ -127,6 +129,12 @@ public:
*/
void Stop();
+ /*
+ * Returns the Thread Local Storage address of the current thread
+ * @returns VAddr of the thread's TLS
+ */
+ VAddr GetTLSAddress() const;
+
Core::ThreadContext context;
u32 thread_id;
@@ -135,14 +143,19 @@ public:
u32 entry_point;
u32 stack_top;
- s32 initial_priority;
- s32 current_priority;
+ s32 nominal_priority; ///< Nominal thread priority, as set by the emulated application
+ s32 current_priority; ///< Current thread priority, can be temporarily changed
+
+ u64 last_running_ticks; ///< CPU tick when thread was last running
s32 processor_id;
+ s32 tls_index; ///< Index of the Thread Local Storage of the thread
+
/// Mutexes currently held by this thread, which will be released when it exits.
boost::container::flat_set<SharedPtr<Mutex>> held_mutexes;
+ SharedPtr<Process> owner_process; ///< Process that owns this thread
std::vector<SharedPtr<WaitObject>> wait_objects; ///< Objects that the thread is waiting on
VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address
bool wait_all; ///< True if the thread is waiting on all objects before resuming
@@ -150,9 +163,6 @@ public:
std::string name;
- /// Whether this thread is intended to never actually be executed, i.e. always idle
- bool idle = false;
-
private:
Thread();
~Thread() override;
@@ -161,16 +171,13 @@ private:
Handle callback_handle;
};
-extern SharedPtr<Thread> g_main_thread;
-
/**
* Sets up the primary application thread
- * @param stack_size The size of the thread's stack
* @param entry_point The address at which the thread should start execution
* @param priority The priority to give the main thread
* @return A shared pointer to the main thread
*/
-SharedPtr<Thread> SetupMainThread(u32 stack_size, u32 entry_point, s32 priority);
+SharedPtr<Thread> SetupMainThread(u32 entry_point, s32 priority);
/**
* Reschedules to the next available thread (call after current thread is suspended)
@@ -214,14 +221,6 @@ void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wa
void WaitCurrentThread_ArbitrateAddress(VAddr wait_address);
/**
- * Sets up the idle thread, this is a thread that is intended to never execute instructions,
- * only to advance the timing. It is scheduled when there are no other ready threads in the thread queue
- * and will try to yield on every call.
- * @return The handle of the idle thread
- */
-SharedPtr<Thread> SetupIdleThread();
-
-/**
* Initialize threading
*/
void ThreadingInit();
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp
index 610e26a3c..e69fece65 100644
--- a/src/core/hle/kernel/timer.cpp
+++ b/src/core/hle/kernel/timer.cpp
@@ -2,7 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "common/common.h"
+#include "common/assert.h"
+#include "common/logging/log.h"
#include "core/core_timing.h"
#include "core/hle/kernel/kernel.h"
@@ -12,7 +13,7 @@
namespace Kernel {
/// The event type of the generic timer callback event
-static int timer_callback_event_type = -1;
+static int timer_callback_event_type;
// TODO(yuriks): This can be removed if Timer objects are explicitly pooled in the future, allowing
// us to simply use a pool index or similar.
static Kernel::HandleTable timer_callback_handle_table;
@@ -66,7 +67,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) {
SharedPtr<Timer> timer = timer_callback_handle_table.Get<Timer>(static_cast<Handle>(timer_handle));
if (timer == nullptr) {
- LOG_CRITICAL(Kernel, "Callback fired for invalid timer %08X", timer_handle);
+ LOG_CRITICAL(Kernel, "Callback fired for invalid timer %08lX", timer_handle);
return;
}
@@ -89,6 +90,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) {
}
void TimersInit() {
+ timer_callback_handle_table.Clear();
timer_callback_event_type = CoreTiming::RegisterEvent("TimerCallback", TimerCallback);
}
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 3648a168b..ce633d841 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -8,6 +8,7 @@
#include <type_traits>
#include <utility>
+#include "common/assert.h"
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
diff --git a/src/core/hle/service/am_sys.cpp b/src/core/hle/service/am_sys.cpp
index b244190a2..f9e3fe4b7 100644
--- a/src/core/hle/service/am_sys.cpp
+++ b/src/core/hle/service/am_sys.cpp
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/logging/log.h"
+
#include "core/hle/hle.h"
#include "core/hle/service/am_sys.h"
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index 5971f860b..09d463dd5 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -2,7 +2,9 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/common_paths.h"
#include "common/file_util.h"
+#include "common/logging/log.h"
#include "core/hle/service/service.h"
#include "core/hle/service/apt/apt.h"
@@ -32,23 +34,31 @@ static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem;
static Kernel::SharedPtr<Kernel::Mutex> lock;
static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event
-static Kernel::SharedPtr<Kernel::Event> pause_event = 0; ///< APT pause event
+static Kernel::SharedPtr<Kernel::Event> start_event; ///< APT start event
+
static std::vector<u8> shared_font;
+static u32 cpu_percent; ///< CPU time available to the running application
+
void Initialize(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 app_id = cmd_buff[1];
+ u32 flags = cmd_buff[2];
+ cmd_buff[2] = 0x04000000; // According to 3dbrew, this value should be 0x04000000
cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom();
- cmd_buff[4] = Kernel::g_handle_table.Create(pause_event).MoveFrom();
+ cmd_buff[4] = Kernel::g_handle_table.Create(start_event).MoveFrom();
- // TODO(bunnei): Check if these events are cleared/signaled every time Initialize is called.
+ // TODO(bunnei): Check if these events are cleared every time Initialize is called.
notification_event->Clear();
- pause_event->Signal(); // Fire start event
+ start_event->Clear();
ASSERT_MSG((nullptr != lock), "Cannot initialize without lock");
lock->Release();
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+
+ LOG_TRACE(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags);
}
void GetSharedFont(Service::Interface* self) {
@@ -74,7 +84,7 @@ void NotifyToWait(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 app_id = cmd_buff[1];
// TODO(Subv): Verify this, it seems to get SWKBD and Home Menu further.
- pause_event->Signal();
+ start_event->Signal();
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id);
@@ -190,7 +200,38 @@ void CancelParameter(Service::Interface* self) {
cmd_buff[2] = 1; // Set to Success
LOG_WARNING(Service_APT, "(STUBBED) called flag1=0x%08X, unk=0x%08X, flag2=0x%08X, app_id=0x%08X",
- flag1, unk, flag2, app_id);
+ flag1, unk, flag2, app_id);
+}
+
+void PrepareToStartApplication(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 title_info1 = cmd_buff[1];
+ u32 title_info2 = cmd_buff[2];
+ u32 title_info3 = cmd_buff[3];
+ u32 title_info4 = cmd_buff[4];
+ u32 flags = cmd_buff[5];
+
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+
+ LOG_WARNING(Service_APT, "(STUBBED) called title_info1=0x%08X, title_info2=0x%08X, title_info3=0x%08X,"
+ "title_info4=0x%08X, flags=0x%08X", title_info1, title_info2, title_info3, title_info4, flags);
+}
+
+void StartApplication(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 buffer1_size = cmd_buff[1];
+ u32 buffer2_size = cmd_buff[2];
+ u32 flag = cmd_buff[3];
+ u32 size1 = cmd_buff[4];
+ u32 buffer1_ptr = cmd_buff[5];
+ u32 size2 = cmd_buff[6];
+ u32 buffer2_ptr = cmd_buff[7];
+
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+
+ LOG_WARNING(Service_APT, "(STUBBED) called buffer1_size=0x%08X, buffer2_size=0x%08X, flag=0x%08X,"
+ "size1=0x%08X, buffer1_ptr=0x%08X, size2=0x%08X, buffer2_ptr=0x%08X",
+ buffer1_size, buffer2_size, flag, size1, buffer1_ptr, size2, buffer2_ptr);
}
void AppletUtility(Service::Interface* self) {
@@ -205,15 +246,15 @@ void AppletUtility(Service::Interface* self) {
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X, buffer1_size=0x%08x, buffer2_size=0x%08x, "
- "buffer1_addr=0x%08x, buffer2_addr=0x%08x", unk, buffer1_size, buffer2_size,
+ LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X, buffer1_size=0x%08X, buffer2_size=0x%08X, "
+ "buffer1_addr=0x%08X, buffer2_addr=0x%08X", unk, buffer1_size, buffer2_size,
buffer1_addr, buffer2_addr);
}
void SetAppCpuTimeLimit(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
- u32 value = cmd_buff[1];
- u32 percent = cmd_buff[2];
+ u32 value = cmd_buff[1];
+ cpu_percent = cmd_buff[2];
if (value != 1) {
LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value);
@@ -221,27 +262,26 @@ void SetAppCpuTimeLimit(Service::Interface* self) {
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- LOG_WARNING(Service_APT, "(STUBBED) called percent=0x%08X, value=0x%08x", percent, value);
+ LOG_WARNING(Service_APT, "(STUBBED) called cpu_percent=%u, value=%u", cpu_percent, value);
}
void GetAppCpuTimeLimit(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 value = cmd_buff[1];
+ ASSERT(cpu_percent != 0);
+
if (value != 1) {
LOG_ERROR(Service_APT, "This value should be one, but is actually %u!", value);
}
- // TODO(purpasmart96): This is incorrect, I'm pretty sure the percentage should
- // be set by the application.
-
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- cmd_buff[2] = 0x80; // Set to 80%
+ cmd_buff[2] = cpu_percent;
- LOG_WARNING(Service_APT, "(STUBBED) called value=0x%08x", value);
+ LOG_WARNING(Service_APT, "(STUBBED) called value=%u", value);
}
-void APTInit() {
+void Init() {
AddService(new APT_A_Interface);
AddService(new APT_S_Interface);
AddService(new APT_U_Interface);
@@ -264,21 +304,29 @@ void APTInit() {
file.ReadBytes(shared_font.data(), (size_t)file.GetSize());
// Create shared font memory object
- shared_font_mem = Kernel::SharedMemory::Create("APT_U:shared_font_mem");
+ using Kernel::MemoryPermission;
+ shared_font_mem = Kernel::SharedMemory::Create(3 * 1024 * 1024, // 3MB
+ MemoryPermission::ReadWrite, MemoryPermission::Read, "APT_U:shared_font_mem");
} else {
LOG_WARNING(Service_APT, "Unable to load shared font: %s", filepath.c_str());
shared_font_mem = nullptr;
}
lock = Kernel::Mutex::Create(false, "APT_U:Lock");
-
+
+ cpu_percent = 0;
+
// TODO(bunnei): Check if these are created in Initialize or on APT process startup.
notification_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Notification");
- pause_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Pause");
+ start_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Start");
}
-void APTShutdown() {
-
+void Shutdown() {
+ shared_font.clear();
+ shared_font_mem = nullptr;
+ lock = nullptr;
+ notification_event = nullptr;
+ start_event = nullptr;
}
} // namespace APT
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h
index a39adbff9..e7fa39325 100644
--- a/src/core/hle/service/apt/apt.h
+++ b/src/core/hle/service/apt/apt.h
@@ -13,10 +13,13 @@ namespace APT {
/// Signals used by APT functions
enum class SignalType : u32 {
- None = 0x0,
- AppJustStarted = 0x1,
- ReturningToApp = 0xB,
- ExitingApp = 0xC,
+ None = 0x0,
+ AppJustStarted = 0x1,
+ LibAppJustStarted = 0x2,
+ LibAppFinished = 0x3,
+ LibAppClosed = 0xA,
+ ReturningToApp = 0xB,
+ ExitingApp = 0xC,
};
/// App Id's used by APT functions
@@ -179,6 +182,40 @@ void GlanceParameter(Service::Interface* self);
void CancelParameter(Service::Interface* self);
/**
+ * APT::PrepareToStartApplication service function. When the input title-info programID is zero,
+ * NS will load the actual program ID via AMNet:GetTitleIDList. After doing some checks with the
+ * programID, NS will then set a NS state flag to value 1, then set the programID for AppID
+ * 0x300(application) to the input program ID(or the one from GetTitleIDList). A media-type field
+ * in the NS state is also set to the input media-type value
+ * (other state fields are set at this point as well). With 8.0.0-18, NS will set an u8 NS state
+ * field to value 1 when input flags bit8 is set
+ * Inputs:
+ * 1-4 : 0x10-byte title-info struct
+ * 4 : Flags
+ * Outputs:
+ * 0 : Return header
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
+void PrepareToStartApplication(Service::Interface* self);
+
+/**
+ * APT::StartApplication service function. Buf0 is copied to NS FIRMparams+0x0, then Buf1 is copied
+ * to the NS FIRMparams+0x480. Then the application is launched.
+ * Inputs:
+ * 1 : Buffer 0 size, max size is 0x300
+ * 2 : Buffer 1 size, max size is 0x20 (this can be zero)
+ * 3 : u8 flag
+ * 4 : (Size0<<14) | 2
+ * 5 : Buffer 0 pointer
+ * 6 : (Size1<<14) | 0x802
+ * 7 : Buffer 1 pointer
+ * Outputs:
+ * 0 : Return Header
+ * 1 : Result of function, 0 on success, otherwise error code
+*/
+void StartApplication(Service::Interface* self);
+
+/**
* APT::AppletUtility service function
* Inputs:
* 1 : Unknown, but clearly used for something
@@ -213,10 +250,10 @@ void SetAppCpuTimeLimit(Service::Interface* self);
void GetAppCpuTimeLimit(Service::Interface* self);
/// Initialize the APT service
-void APTInit();
+void Init();
/// Shutdown the APT service
-void APTShutdown();
+void Shutdown();
} // namespace APT
} // namespace Service
diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp
index dbe5c1d87..864934245 100644
--- a/src/core/hle/service/apt/apt_a.cpp
+++ b/src/core/hle/service/apt/apt_a.cpp
@@ -12,16 +12,16 @@ namespace APT {
const Interface::FunctionInfo FunctionTable[] = {
{0x00010040, GetLockHandle, "GetLockHandle?"},
{0x00020080, Initialize, "Initialize?"},
- {0x00030040, nullptr, "Enable?"},
+ {0x00030040, Enable, "Enable?"},
{0x00040040, nullptr, "Finalize?"},
{0x00050040, nullptr, "GetAppletManInfo?"},
{0x00060040, nullptr, "GetAppletInfo?"},
{0x000D0080, ReceiveParameter, "ReceiveParameter?"},
{0x000E0080, GlanceParameter, "GlanceParameter?"},
{0x003B0040, nullptr, "CancelLibraryApplet?"},
- {0x00430040, nullptr, "NotifyToWait?"},
+ {0x00430040, NotifyToWait, "NotifyToWait?"},
{0x00440000, GetSharedFont, "GetSharedFont?"},
- {0x004B00C2, nullptr, "AppletUtility?"},
+ {0x004B00C2, AppletUtility, "AppletUtility?"},
{0x00550040, nullptr, "WriteInputToNsState?"},
};
diff --git a/src/core/hle/service/apt/apt_s.cpp b/src/core/hle/service/apt/apt_s.cpp
index 3fd348651..396d1f04a 100644
--- a/src/core/hle/service/apt/apt_s.cpp
+++ b/src/core/hle/service/apt/apt_s.cpp
@@ -3,9 +3,6 @@
// Refer to the license.txt file included.
-#include "common/common.h"
-#include "common/file_util.h"
-
#include "core/hle/hle.h"
#include "core/hle/service/apt/apt.h"
#include "core/hle/service/apt/apt_s.h"
diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp
index 5ab23801e..d006b5930 100644
--- a/src/core/hle/service/apt/apt_u.cpp
+++ b/src/core/hle/service/apt/apt_u.cpp
@@ -3,7 +3,6 @@
// Refer to the license.txt file included.
-#include "common/common.h"
#include "common/file_util.h"
#include "core/hle/service/apt/apt.h"
diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp
index 6adadb224..2d26c9330 100644
--- a/src/core/hle/service/cfg/cfg.cpp
+++ b/src/core/hle/service/cfg/cfg.cpp
@@ -4,12 +4,16 @@
#include <algorithm>
-#include "core/hle/service/fs/archive.h"
-#include "core/hle/service/service.h"
+#include "common/logging/log.h"
+#include "common/string_util.h"
+
+#include "core/file_sys/file_backend.h"
#include "core/hle/service/cfg/cfg.h"
#include "core/hle/service/cfg/cfg_i.h"
#include "core/hle/service/cfg/cfg_s.h"
#include "core/hle/service/cfg/cfg_u.h"
+#include "core/hle/service/fs/archive.h"
+#include "core/hle/service/service.h"
namespace Service {
namespace CFG {
@@ -53,12 +57,12 @@ ResultCode GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, u8* output) {
});
if (itr == std::end(config->block_entries)) {
- LOG_ERROR(Service_CFG, "Config block %u with flags %u was not found", block_id, flag);
+ LOG_ERROR(Service_CFG, "Config block 0x%X with flags %u and size %u was not found", block_id, flag, size);
return ResultCode(ErrorDescription::NotFound, ErrorModule::Config, ErrorSummary::WrongArgument, ErrorLevel::Permanent);
}
if (itr->size != size) {
- LOG_ERROR(Service_CFG, "Invalid size %u for config block %u with flags %u", size, block_id, flag);
+ LOG_ERROR(Service_CFG, "Invalid size %u for config block 0x%X with flags %u", size, block_id, flag);
return ResultCode(ErrorDescription::InvalidSize, ErrorModule::Config, ErrorSummary::WrongArgument, ErrorLevel::Permanent);
}
@@ -170,7 +174,7 @@ ResultCode FormatConfig() {
return RESULT_SUCCESS;
}
-void CFGInit() {
+void Init() {
AddService(new CFG_I_Interface);
AddService(new CFG_S_Interface);
AddService(new CFG_U_Interface);
@@ -207,6 +211,7 @@ void CFGInit() {
// Initialize the Username block
// TODO(Subv): Initialize this directly in the variable when MSVC supports char16_t string literals
+ memset(&CONSOLE_USERNAME_BLOCK, 0, sizeof(CONSOLE_USERNAME_BLOCK));
CONSOLE_USERNAME_BLOCK.ng_word = 0;
CONSOLE_USERNAME_BLOCK.zero = 0;
@@ -218,8 +223,7 @@ void CFGInit() {
FormatConfig();
}
-void CFGShutdown() {
-
+void Shutdown() {
}
} // namespace CFG
diff --git a/src/core/hle/service/cfg/cfg.h b/src/core/hle/service/cfg/cfg.h
index e818d7bdc..3488c40d0 100644
--- a/src/core/hle/service/cfg/cfg.h
+++ b/src/core/hle/service/cfg/cfg.h
@@ -135,10 +135,10 @@ ResultCode UpdateConfigNANDSavegame();
ResultCode FormatConfig();
/// Initialize the config service
-void CFGInit();
+void Init();
/// Shutdown the config service
-void CFGShutdown();
+void Shutdown();
} // namespace CFG
} // namespace Service
diff --git a/src/core/hle/service/cfg/cfg_u.cpp b/src/core/hle/service/cfg/cfg_u.cpp
index c8c1c5b17..221de9918 100644
--- a/src/core/hle/service/cfg/cfg_u.cpp
+++ b/src/core/hle/service/cfg/cfg_u.cpp
@@ -3,7 +3,9 @@
// Refer to the license.txt file included.
#include "common/file_util.h"
+#include "common/logging/log.h"
#include "common/string_util.h"
+
#include "core/settings.h"
#include "core/file_sys/archive_systemsavedata.h"
#include "core/hle/hle.h"
diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp
index 0b3603ce1..fafb43a2f 100644
--- a/src/core/hle/service/dsp_dsp.cpp
+++ b/src/core/hle/service/dsp_dsp.cpp
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/logging/log.h"
+
#include "core/hle/hle.h"
#include "core/hle/kernel/event.h"
#include "core/hle/service/dsp_dsp.h"
@@ -11,7 +13,7 @@
namespace DSP_DSP {
-static u32 read_pipe_count = 0;
+static u32 read_pipe_count;
static Kernel::SharedPtr<Kernel::Event> semaphore_event;
static Kernel::SharedPtr<Kernel::Event> interrupt_event;
@@ -40,9 +42,9 @@ static void ConvertProcessAddressFromDspDram(Service::Interface* self) {
u32 addr = cmd_buff[1];
cmd_buff[1] = 0; // No error
- cmd_buff[2] = (addr << 1) + (Memory::DSP_MEMORY_VADDR + 0x40000);
+ cmd_buff[2] = (addr << 1) + (Memory::DSP_RAM_VADDR + 0x40000);
- LOG_WARNING(Service_DSP, "(STUBBED) called with address %u", addr);
+ LOG_WARNING(Service_DSP, "(STUBBED) called with address 0x%08X", addr);
}
/**
@@ -60,12 +62,19 @@ static void ConvertProcessAddressFromDspDram(Service::Interface* self) {
static void LoadComponent(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 size = cmd_buff[1];
+ u32 unk1 = cmd_buff[2];
+ u32 unk2 = cmd_buff[3];
+ u32 new_size = cmd_buff[4];
+ u32 buffer = cmd_buff[5];
+
cmd_buff[1] = 0; // No error
cmd_buff[2] = 1; // Pretend that we actually loaded the DSP firmware
// TODO(bunnei): Implement real DSP firmware loading
- LOG_WARNING(Service_DSP, "(STUBBED) called");
+ LOG_WARNING(Service_DSP, "(STUBBED) called size=0x%X, unk1=0x%08X, unk2=0x%08X, new_size=0x%X, buffer=0x%08X",
+ size, unk1, unk2, new_size, buffer);
}
/**
@@ -84,6 +93,33 @@ static void GetSemaphoreEventHandle(Service::Interface* self) {
}
/**
+ * DSP_DSP::FlushDataCache service function
+ *
+ * This Function is a no-op, We aren't emulating the CPU cache any time soon.
+ *
+ * Inputs:
+ * 1 : Address
+ * 2 : Size
+ * 3 : Value 0, some descriptor for the KProcess Handle
+ * 4 : KProcess handle
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
+static void FlushDataCache(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 address = cmd_buff[1];
+ u32 size = cmd_buff[2];
+ u32 process = cmd_buff[4];
+
+ // TODO(purpasmart96): Verify return header on HW
+
+ cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+
+ LOG_DEBUG(Service_DSP, "(STUBBED) called address=0x%08X, size=0x%X, process=0x%08X",
+ address, size, process);
+}
+
+/**
* DSP_DSP::RegisterInterruptEvents service function
* Inputs:
* 1 : Parameter 0 (purpose unknown)
@@ -95,6 +131,10 @@ static void GetSemaphoreEventHandle(Service::Interface* self) {
static void RegisterInterruptEvents(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 param0 = cmd_buff[1];
+ u32 param1 = cmd_buff[2];
+ u32 event_handle = cmd_buff[4];
+
auto evt = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[4]);
if (evt != nullptr) {
interrupt_event = evt;
@@ -106,7 +146,7 @@ static void RegisterInterruptEvents(Service::Interface* self) {
cmd_buff[1] = -1;
}
- LOG_WARNING(Service_DSP, "(STUBBED) called");
+ LOG_WARNING(Service_DSP, "(STUBBED) called param0=%u, param1=%u, event_handle=0x%08X", param0, param1, event_handle);
}
/**
@@ -147,7 +187,7 @@ static void WriteProcessPipe(Service::Interface* self) {
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
- LOG_WARNING(Service_DSP, "(STUBBED) called number=%u, size=0x%08X, new_size=0x%08X, buffer=0x%08X",
+ LOG_WARNING(Service_DSP, "(STUBBED) called number=%u, size=0x%X, new_size=0x%X, buffer=0x%08X",
number, size, new_size, buffer);
}
@@ -165,6 +205,8 @@ static void WriteProcessPipe(Service::Interface* self) {
static void ReadPipeIfPossible(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 unk1 = cmd_buff[1];
+ u32 unk2 = cmd_buff[2];
u32 size = cmd_buff[3] & 0xFFFF;// Lower 16 bits are size
VAddr addr = cmd_buff[0x41];
@@ -190,7 +232,8 @@ static void ReadPipeIfPossible(Service::Interface* self) {
cmd_buff[1] = 0; // No error
cmd_buff[2] = (read_pipe_count - initial_size) * sizeof(u16);
- LOG_WARNING(Service_DSP, "(STUBBED) called size=0x%08X, buffer=0x%08X", size, addr);
+ LOG_WARNING(Service_DSP, "(STUBBED) called unk1=0x%08X, unk2=0x%08X, size=0x%X, buffer=0x%08X",
+ unk1, unk2, size, addr);
}
/**
@@ -225,7 +268,7 @@ static void GetHeadphoneStatus(Service::Interface* self) {
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
cmd_buff[2] = 0; // Not using headphones?
- LOG_WARNING(Service_DSP, "(STUBBED) called");
+ LOG_DEBUG(Service_DSP, "(STUBBED) called");
}
const Interface::FunctionInfo FunctionTable[] = {
@@ -242,7 +285,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x001000C0, ReadPipeIfPossible, "ReadPipeIfPossible"},
{0x001100C2, LoadComponent, "LoadComponent"},
{0x00120000, nullptr, "UnloadComponent"},
- {0x00130082, nullptr, "FlushDataCache"},
+ {0x00130082, FlushDataCache, "FlushDataCache"},
{0x00140082, nullptr, "InvalidateDCache"},
{0x00150082, RegisterInterruptEvents, "RegisterInterruptEvents"},
{0x00160000, GetSemaphoreEventHandle, "GetSemaphoreEventHandle"},
diff --git a/src/core/hle/service/err_f.cpp b/src/core/hle/service/err_f.cpp
index 58c5acd1e..e8c06c1cf 100644
--- a/src/core/hle/service/err_f.cpp
+++ b/src/core/hle/service/err_f.cpp
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/logging/log.h"
+
#include "core/hle/hle.h"
#include "core/hle/service/err_f.h"
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp
index b0fd834c7..6d4a9c7c9 100644
--- a/src/core/hle/service/fs/archive.cpp
+++ b/src/core/hle/service/fs/archive.cpp
@@ -9,6 +9,7 @@
#include "common/common_types.h"
#include "common/file_util.h"
+#include "common/logging/log.h"
#include "common/make_unique.h"
#include "common/math_util.h"
@@ -78,6 +79,11 @@ enum class DirectoryCommand : u32 {
Close = 0x08020000,
};
+File::File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path & path)
+ : path(path), priority(0), backend(std::move(backend)) {}
+
+File::~File() {}
+
ResultVal<bool> File::SyncRequest() {
u32* cmd_buff = Kernel::GetCommandBuffer();
FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
@@ -172,6 +178,11 @@ ResultVal<bool> File::SyncRequest() {
return MakeResult<bool>(false);
}
+Directory::Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path & path)
+ : path(path), backend(std::move(backend)) {}
+
+Directory::~Directory() {}
+
ResultVal<bool> Directory::SyncRequest() {
u32* cmd_buff = Kernel::GetCommandBuffer();
DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]);
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h
index b00f0fd60..faab0cb79 100644
--- a/src/core/hle/service/fs/archive.h
+++ b/src/core/hle/service/fs/archive.h
@@ -45,31 +45,27 @@ typedef u64 ArchiveHandle;
class File : public Kernel::Session {
public:
- File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path)
- : path(path), priority(0), backend(std::move(backend)) {
- }
+ File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path);
+ ~File();
std::string GetName() const override { return "Path: " + path.DebugStr(); }
+ ResultVal<bool> SyncRequest() override;
FileSys::Path path; ///< Path of the file
u32 priority; ///< Priority of the file. TODO(Subv): Find out what this means
std::unique_ptr<FileSys::FileBackend> backend; ///< File backend interface
-
- ResultVal<bool> SyncRequest() override;
};
class Directory : public Kernel::Session {
public:
- Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path)
- : path(path), backend(std::move(backend)) {
- }
+ Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path);
+ ~Directory();
std::string GetName() const override { return "Directory: " + path.DebugStr(); }
+ ResultVal<bool> SyncRequest() override;
FileSys::Path path; ///< Path of the directory
std::unique_ptr<FileSys::DirectoryBackend> backend; ///< File backend interface
-
- ResultVal<bool> SyncRequest() override;
};
/**
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp
index d8d1d5547..0d2a426b0 100644
--- a/src/core/hle/service/fs/fs_user.cpp
+++ b/src/core/hle/service/fs/fs_user.cpp
@@ -2,10 +2,13 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "common/common.h"
+#include "common/assert.h"
+#include "common/common_types.h"
#include "common/file_util.h"
+#include "common/logging/log.h"
#include "common/scope_exit.h"
#include "common/string_util.h"
+
#include "core/hle/result.h"
#include "core/hle/service/fs/archive.h"
#include "core/hle/service/fs/fs_user.h"
@@ -20,6 +23,8 @@ using Kernel::Session;
namespace Service {
namespace FS {
+static u32 priority = -1; ///< For SetPriority and GetPriority service functions
+
static ArchiveHandle MakeArchiveHandle(u32 low_word, u32 high_word) {
return (u64)low_word | ((u64)high_word << 32);
}
@@ -215,7 +220,7 @@ static void DeleteDirectory(Service::Interface* self) {
LOG_DEBUG(Service_FS, "type=%d size=%d data=%s",
dirname_type, dirname_size, dir_path.DebugStr().c_str());
-
+
cmd_buff[1] = DeleteDirectoryFromArchive(archive_handle, dir_path).raw;
}
@@ -424,7 +429,7 @@ static void IsSdmcWriteable(Service::Interface* self) {
cmd_buff[1] = RESULT_SUCCESS.raw;
// If the SD isn't enabled, it can't be writeable...else, stubbed true
cmd_buff[2] = Settings::values.use_virtual_sd ? 1 : 0;
-
+
LOG_DEBUG(Service_FS, " (STUBBED)");
}
@@ -511,7 +516,7 @@ static void CreateExtSaveData(Service::Interface* self) {
MediaType media_type = static_cast<MediaType>(cmd_buff[1] & 0xFF);
u32 save_low = cmd_buff[2];
u32 save_high = cmd_buff[3];
-
+
LOG_WARNING(Service_FS, "(STUBBED) savedata_high=%08X savedata_low=%08X cmd_buff[3]=%08X "
"cmd_buff[4]=%08X cmd_buff[5]=%08X cmd_buff[6]=%08X cmd_buff[7]=%08X cmd_buff[8]=%08X "
"cmd_buff[9]=%08X cmd_buff[10]=%08X cmd_buff[11]=%08X", save_high, save_low,
@@ -573,7 +578,7 @@ static void DeleteSystemSaveData(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 savedata_high = cmd_buff[1];
u32 savedata_low = cmd_buff[2];
-
+
cmd_buff[1] = DeleteSystemSaveData(savedata_high, savedata_low).raw;
}
@@ -601,12 +606,72 @@ static void CreateSystemSaveData(Service::Interface* self) {
LOG_WARNING(Service_FS, "(STUBBED) savedata_high=%08X savedata_low=%08X cmd_buff[3]=%08X "
"cmd_buff[4]=%08X cmd_buff[5]=%08X cmd_buff[6]=%08X cmd_buff[7]=%08X cmd_buff[8]=%08X "
- "cmd_buff[9]=%08X", savedata_high, savedata_low, cmd_buff[3], cmd_buff[4], cmd_buff[5],
+ "cmd_buff[9]=%08X", savedata_high, savedata_low, cmd_buff[3], cmd_buff[4], cmd_buff[5],
cmd_buff[6], cmd_buff[7], cmd_buff[8], cmd_buff[9]);
cmd_buff[1] = CreateSystemSaveData(savedata_high, savedata_low).raw;
}
+/**
+ * FS_User::InitializeWithSdkVersion service function.
+ * Inputs:
+ * 0 : 0x08610042
+ * 1 : Unknown
+ * 2 : Unknown
+ * 3 : Unknown
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
+static void InitializeWithSdkVersion(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ u32 unk1 = cmd_buff[1];
+ u32 unk2 = cmd_buff[2];
+ u32 unk3 = cmd_buff[3];
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_WARNING(Service_FS, "(STUBBED) called unk1=0x%08X, unk2=0x%08X, unk3=0x%08X",
+ unk1, unk2, unk3);
+}
+
+/**
+ * FS_User::SetPriority service function.
+ * Inputs:
+ * 0 : 0x08620040
+ * 1 : priority
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
+static void SetPriority(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ priority = cmd_buff[1];
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_DEBUG(Service_FS, "called priority=0x%08X", priority);
+}
+
+/**
+ * FS_User::GetPriority service function.
+ * Inputs:
+ * 0 : 0x08630000
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : priority
+ */
+static void GetPriority(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ ASSERT(priority != -1);
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = priority;
+
+ LOG_DEBUG(Service_FS, "called priority=0x%08X", priority);
+}
+
const Interface::FunctionInfo FunctionTable[] = {
{0x000100C6, nullptr, "Dummy1"},
{0x040100C4, nullptr, "Control"},
@@ -695,15 +760,17 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x08560240, CreateSystemSaveData, "CreateSystemSaveData"},
{0x08570080, DeleteSystemSaveData, "DeleteSystemSaveData"},
{0x08580000, nullptr, "GetMovableSedHashedKeyYRandomData"},
- {0x08610042, nullptr, "InitializeWithSdkVersion"},
- {0x08620040, nullptr, "SetPriority"},
- {0x08630000, nullptr, "GetPriority"},
+ {0x08610042, InitializeWithSdkVersion, "InitializeWithSdkVersion"},
+ {0x08620040, SetPriority, "SetPriority"},
+ {0x08630000, GetPriority, "GetPriority"},
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Interface class
Interface::Interface() {
+
+ priority = -1;
Register(FunctionTable);
}
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index cff585698..c11c5faba 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -5,6 +5,7 @@
#include "common/bit_field.h"
#include "core/mem_map.h"
+#include "core/memory.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/result.h"
@@ -30,13 +31,12 @@ namespace GSP_GPU {
Kernel::SharedPtr<Kernel::Event> g_interrupt_event;
/// GSP shared memoryings
Kernel::SharedPtr<Kernel::SharedMemory> g_shared_memory;
-/// Thread index into interrupt relay queue, 1 is arbitrary
-u32 g_thread_id = 1;
+/// Thread index into interrupt relay queue
+u32 g_thread_id = 0;
/// Gets a pointer to a thread command buffer in GSP shared memory
static inline u8* GetCommandBuffer(u32 thread_id) {
- ResultVal<u8*> ptr = g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer)));
- return ptr.ValueOr(nullptr);
+ return g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer)));
}
static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) {
@@ -44,14 +44,14 @@ static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_in
// For each thread there are two FrameBufferUpdate fields
u32 offset = 0x200 + (2 * thread_id + screen_index) * sizeof(FrameBufferUpdate);
- ResultVal<u8*> ptr = g_shared_memory->GetPointer(offset);
- return reinterpret_cast<FrameBufferUpdate*>(ptr.ValueOr(nullptr));
+ u8* ptr = g_shared_memory->GetPointer(offset);
+ return reinterpret_cast<FrameBufferUpdate*>(ptr);
}
/// Gets a pointer to the interrupt relay queue for a given thread index
static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) {
- ResultVal<u8*> ptr = g_shared_memory->GetPointer(sizeof(InterruptRelayQueue) * thread_id);
- return reinterpret_cast<InterruptRelayQueue*>(ptr.ValueOr(nullptr));
+ u8* ptr = g_shared_memory->GetPointer(sizeof(InterruptRelayQueue) * thread_id);
+ return reinterpret_cast<InterruptRelayQueue*>(ptr);
}
/**
@@ -204,16 +204,18 @@ static void ReadHWRegs(Service::Interface* self) {
static void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
u32 base_address = 0x400000;
+ PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left);
+ PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right);
if (info.active_fb == 0) {
WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)), 4,
- &info.address_left);
+ &phys_address_left);
WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)), 4,
- &info.address_right);
+ &phys_address_right);
} else {
WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)), 4,
- &info.address_left);
+ &phys_address_left);
WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)), 4,
- &info.address_right);
+ &phys_address_right);
}
WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)), 4,
&info.stride);
@@ -265,6 +267,9 @@ static void FlushDataCache(Service::Interface* self) {
// TODO(purpasmart96): Verify return header on HW
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
+
+ LOG_DEBUG(Service_GSP, "(STUBBED) called address=0x%08X, size=0x%08X, process=0x%08X",
+ address, size, process);
}
/**
@@ -273,7 +278,7 @@ static void FlushDataCache(Service::Interface* self) {
* 1 : "Flags" field, purpose is unknown
* 3 : Handle to GSP synchronization event
* Outputs:
- * 0 : Result of function, 0 on success, otherwise error code
+ * 1 : Result of function, 0x2A07 on success, otherwise error code
* 2 : Thread index into GSP command buffer
* 4 : Handle to GSP shared memory
*/
@@ -283,11 +288,12 @@ static void RegisterInterruptRelayQueue(Service::Interface* self) {
g_interrupt_event = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[3]);
ASSERT_MSG((g_interrupt_event != nullptr), "handle is not valid!");
- g_shared_memory = Kernel::SharedMemory::Create("GSPSharedMem");
Handle shmem_handle = Kernel::g_handle_table.Create(g_shared_memory).MoveFrom();
- cmd_buff[1] = 0x2A07; // Value verified by 3dmoo team, purpose unknown, but needed for GSP init
+ // This specific code is required for a successful initialization, rather than 0
+ cmd_buff[1] = ResultCode((ErrorDescription)519, ErrorModule::GX,
+ ErrorSummary::Success, ErrorLevel::Success).raw;
cmd_buff[2] = g_thread_id++; // Thread ID
cmd_buff[4] = shmem_handle; // GSP shared memory
@@ -522,8 +528,12 @@ Interface::Interface() {
Register(FunctionTable);
g_interrupt_event = 0;
- g_shared_memory = 0;
- g_thread_id = 1;
+
+ using Kernel::MemoryPermission;
+ g_shared_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite,
+ MemoryPermission::ReadWrite, "GSPSharedMem");
+
+ g_thread_id = 0;
}
} // namespace
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 138603d9b..9695f7e56 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/logging/log.h"
+
#include "core/hle/service/service.h"
#include "core/hle/service/hid/hid.h"
#include "core/hle/service/hid/hid_spvr.h"
@@ -20,17 +22,17 @@ namespace HID {
static const int MAX_CIRCLEPAD_POS = 0x9C; ///< Max value for a circle pad position
// Handle to shared memory region designated to HID_User service
-static Kernel::SharedPtr<Kernel::SharedMemory> shared_mem = nullptr;
+static Kernel::SharedPtr<Kernel::SharedMemory> shared_mem;
// Event handles
-static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_1 = nullptr;
-static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_2 = nullptr;
-static Kernel::SharedPtr<Kernel::Event> event_accelerometer = nullptr;
-static Kernel::SharedPtr<Kernel::Event> event_gyroscope = nullptr;
-static Kernel::SharedPtr<Kernel::Event> event_debug_pad = nullptr;
+static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_1;
+static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_2;
+static Kernel::SharedPtr<Kernel::Event> event_accelerometer;
+static Kernel::SharedPtr<Kernel::Event> event_gyroscope;
+static Kernel::SharedPtr<Kernel::Event> event_debug_pad;
-static u32 next_pad_index = 0;
-static u32 next_touch_index = 0;
+static u32 next_pad_index;
+static u32 next_touch_index;
// TODO(peachum):
// Add a method for setting analog input from joystick device for the circle Pad.
@@ -45,8 +47,8 @@ static u32 next_touch_index = 0;
// * Set PadData.current_state.circle_left = 1 if current PadEntry.circle_pad_x <= -41
// * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_y <= -41
-void HIDUpdate() {
- SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer().ValueOr(nullptr));
+void Update() {
+ SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer());
const PadState state = VideoCore::g_emu_window->GetPadState();
if (mem == nullptr) {
@@ -155,13 +157,15 @@ void GetSoundVolume(Service::Interface* self) {
LOG_WARNING(Service_HID, "(STUBBED) called");
}
-void HIDInit() {
+void Init() {
using namespace Kernel;
AddService(new HID_U_Interface);
AddService(new HID_SPVR_Interface);
- shared_mem = SharedMemory::Create("HID:SharedMem");
+ using Kernel::MemoryPermission;
+ shared_mem = SharedMemory::Create(0x1000, MemoryPermission::ReadWrite,
+ MemoryPermission::Read, "HID:SharedMem");
next_pad_index = 0;
next_touch_index = 0;
@@ -174,7 +178,13 @@ void HIDInit() {
event_debug_pad = Event::Create(RESETTYPE_ONESHOT, "HID:EventDebugPad");
}
-void HIDShutdown() {
+void Shutdown() {
+ shared_mem = nullptr;
+ event_pad_or_touch_1 = nullptr;
+ event_pad_or_touch_2 = nullptr;
+ event_accelerometer = nullptr;
+ event_gyroscope = nullptr;
+ event_debug_pad = nullptr;
}
} // namespace HID
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 97462c7f8..897bd6764 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -200,13 +200,13 @@ void EnableGyroscopeLow(Interface* self);
void GetSoundVolume(Interface* self);
/// Checks for user input updates
-void HIDUpdate();
+void Update();
/// Initialize HID service
-void HIDInit();
+void Init();
/// Shutdown HID service
-void HIDShutdown();
+void Shutdown();
}
}
diff --git a/src/core/hle/service/ir/ir.cpp b/src/core/hle/service/ir/ir.cpp
new file mode 100644
index 000000000..adfbb258d
--- /dev/null
+++ b/src/core/hle/service/ir/ir.cpp
@@ -0,0 +1,52 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/service.h"
+#include "core/hle/service/ir/ir.h"
+#include "core/hle/service/ir/ir_rst.h"
+#include "core/hle/service/ir/ir_u.h"
+#include "core/hle/service/ir/ir_user.h"
+
+#include "core/hle/hle.h"
+#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/shared_memory.h"
+
+namespace Service {
+namespace IR {
+
+static Kernel::SharedPtr<Kernel::Event> handle_event;
+static Kernel::SharedPtr<Kernel::SharedMemory> shared_memory;
+
+void GetHandles(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = 0x4000000;
+ cmd_buff[3] = Kernel::g_handle_table.Create(Service::IR::shared_memory).MoveFrom();
+ cmd_buff[4] = Kernel::g_handle_table.Create(Service::IR::handle_event).MoveFrom();
+}
+
+void Init() {
+ using namespace Kernel;
+
+ AddService(new IR_RST_Interface);
+ AddService(new IR_U_Interface);
+ AddService(new IR_User_Interface);
+
+ using Kernel::MemoryPermission;
+ shared_memory = SharedMemory::Create(0x1000, Kernel::MemoryPermission::ReadWrite,
+ Kernel::MemoryPermission::ReadWrite, "IR:SharedMemory");
+
+ // Create event handle(s)
+ handle_event = Event::Create(RESETTYPE_ONESHOT, "IR:HandleEvent");
+}
+
+void Shutdown() {
+ shared_memory = nullptr;
+ handle_event = nullptr;
+}
+
+} // namespace IR
+
+} // namespace Service
diff --git a/src/core/hle/service/ir/ir.h b/src/core/hle/service/ir/ir.h
new file mode 100644
index 000000000..c16d963e7
--- /dev/null
+++ b/src/core/hle/service/ir/ir.h
@@ -0,0 +1,30 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace IR {
+
+/**
+ * IR::GetHandles service function
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Translate header, used by the ARM11-kernel
+ * 3 : Shared memory handle
+ * 4 : Event handle
+ */
+void GetHandles(Interface* self);
+
+/// Initialize IR service
+void Init();
+
+/// Shutdown IR service
+void Shutdown();
+
+} // namespace IR
+} // namespace Service
diff --git a/src/core/hle/service/ir/ir_rst.cpp b/src/core/hle/service/ir/ir_rst.cpp
new file mode 100644
index 000000000..96ae63420
--- /dev/null
+++ b/src/core/hle/service/ir/ir_rst.cpp
@@ -0,0 +1,24 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/hle.h"
+#include "core/hle/service/ir/ir.h"
+#include "core/hle/service/ir/ir_rst.h"
+
+namespace Service {
+namespace IR {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010000, GetHandles, "GetHandles"},
+ {0x00020080, nullptr, "Initialize"},
+ {0x00030000, nullptr, "Shutdown"},
+ {0x00090000, nullptr, "WriteToTwoFields"},
+};
+
+IR_RST_Interface::IR_RST_Interface() {
+ Register(FunctionTable);
+}
+
+} // namespace IR
+} // namespace Service
diff --git a/src/core/hle/service/ir_rst.h b/src/core/hle/service/ir/ir_rst.h
index deef701c5..a492e15c9 100644
--- a/src/core/hle/service/ir_rst.h
+++ b/src/core/hle/service/ir/ir_rst.h
@@ -6,18 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace IR_RST
+namespace Service {
+namespace IR {
-namespace IR_RST {
-
-class Interface : public Service::Interface {
+class IR_RST_Interface : public Service::Interface {
public:
- Interface();
+ IR_RST_Interface();
std::string GetPortName() const override {
return "ir:rst";
}
};
-} // namespace
+} // namespace IR
+} // namespace Service
diff --git a/src/core/hle/service/ir_u.cpp b/src/core/hle/service/ir/ir_u.cpp
index 608ed3c06..1b1e3078b 100644
--- a/src/core/hle/service/ir_u.cpp
+++ b/src/core/hle/service/ir/ir_u.cpp
@@ -3,12 +3,11 @@
// Refer to the license.txt file included.
#include "core/hle/hle.h"
-#include "core/hle/service/ir_u.h"
+#include "core/hle/service/ir/ir.h"
+#include "core/hle/service/ir/ir_u.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace IR_U
-
-namespace IR_U {
+namespace Service {
+namespace IR {
const Interface::FunctionInfo FunctionTable[] = {
{0x00010000, nullptr, "Initialize"},
@@ -31,11 +30,9 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00120040, nullptr, "SetSleepModeState"},
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+IR_U_Interface::IR_U_Interface() {
Register(FunctionTable);
}
-} // namespace
+} // namespace IR
+} // namespace Service
diff --git a/src/core/hle/service/ir/ir_u.h b/src/core/hle/service/ir/ir_u.h
new file mode 100644
index 000000000..056d2ce1a
--- /dev/null
+++ b/src/core/hle/service/ir/ir_u.h
@@ -0,0 +1,22 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace IR {
+
+class IR_U_Interface : public Service::Interface {
+public:
+ IR_U_Interface();
+
+ std::string GetPortName() const override {
+ return "ir:u";
+ }
+};
+
+} // namespace IR
+} // namespace Service
diff --git a/src/core/hle/service/ir/ir_user.cpp b/src/core/hle/service/ir/ir_user.cpp
new file mode 100644
index 000000000..8e3ff140f
--- /dev/null
+++ b/src/core/hle/service/ir/ir_user.cpp
@@ -0,0 +1,34 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/hle.h"
+#include "core/hle/service/ir/ir.h"
+#include "core/hle/service/ir/ir_user.h"
+
+namespace Service {
+namespace IR {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010182, nullptr, "InitializeIrNop"},
+ {0x00020000, nullptr, "FinalizeIrNop"},
+ {0x00030000, nullptr, "ClearReceiveBuffer"},
+ {0x00040000, nullptr, "ClearSendBuffer"},
+ {0x00060040, nullptr, "RequireConnection"},
+ {0x00090000, nullptr, "Disconnect"},
+ {0x000A0000, nullptr, "GetReceiveEvent"},
+ {0x000B0000, nullptr, "GetSendEvent"},
+ {0x000C0000, nullptr, "GetConnectionStatusEvent"},
+ {0x000D0042, nullptr, "SendIrNop"},
+ {0x000E0042, nullptr, "SendIrNopLarge"},
+ {0x00180182, nullptr, "InitializeIrNopShared"},
+ {0x00190040, nullptr, "ReleaseReceivedData"},
+ {0x001A0040, nullptr, "SetOwnMachineId"},
+};
+
+IR_User_Interface::IR_User_Interface() {
+ Register(FunctionTable);
+}
+
+} // namespace IR
+} // namespace Service
diff --git a/src/core/hle/service/ir/ir_user.h b/src/core/hle/service/ir/ir_user.h
new file mode 100644
index 000000000..71c932ffa
--- /dev/null
+++ b/src/core/hle/service/ir/ir_user.h
@@ -0,0 +1,22 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace IR {
+
+class IR_User_Interface : public Service::Interface {
+public:
+ IR_User_Interface();
+
+ std::string GetPortName() const override {
+ return "ir:USER";
+ }
+};
+
+} // namespace IR
+} // namespace Service
diff --git a/src/core/hle/service/ir_rst.cpp b/src/core/hle/service/ir_rst.cpp
deleted file mode 100644
index 4c26c2f03..000000000
--- a/src/core/hle/service/ir_rst.cpp
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "core/hle/hle.h"
-#include "core/hle/service/ir_rst.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace IR_RST
-
-namespace IR_RST {
-
-const Interface::FunctionInfo FunctionTable[] = {
- {0x00010000, nullptr, "GetHandles"},
- {0x00020080, nullptr, "Initialize"},
- {0x00030000, nullptr, "Shutdown"},
- {0x00090000, nullptr, "WriteToTwoFields"},
-};
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
- Register(FunctionTable);
-}
-
-} // namespace
diff --git a/src/core/hle/service/ldr_ro.cpp b/src/core/hle/service/ldr_ro.cpp
index c0c4a2344..155b97f69 100644
--- a/src/core/hle/service/ldr_ro.cpp
+++ b/src/core/hle/service/ldr_ro.cpp
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/logging/log.h"
+
#include "core/hle/hle.h"
#include "core/hle/service/ldr_ro.h"
diff --git a/src/core/hle/service/nim_u.cpp b/src/core/hle/service/nim_u.cpp
new file mode 100644
index 000000000..5f13bd98e
--- /dev/null
+++ b/src/core/hle/service/nim_u.cpp
@@ -0,0 +1,48 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/logging/log.h"
+
+#include "core/hle/hle.h"
+#include "core/hle/service/nim_u.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace NIM_U
+
+namespace NIM_U {
+
+/**
+ * NIM_U::CheckSysUpdateAvailable service function
+ * Inputs:
+ * 1 : None
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : flag, 0 = no system update available, 1 = system update available.
+ */
+static void CheckSysUpdateAvailable(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = 0; // No update available
+
+ LOG_WARNING(Service_NWM, "(STUBBED) called");
+}
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010000, nullptr, "StartSysUpdate"},
+ {0x00020000, nullptr, "GetUpdateDownloadProgress"},
+ {0x00040000, nullptr, "FinishTitlesInstall"},
+ {0x00050000, nullptr, "CheckForSysUpdateEvent"},
+ {0x00090000, CheckSysUpdateAvailable, "CheckSysUpdateAvailable"},
+ {0x000A0000, nullptr, "GetState"},
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Interface class
+
+Interface::Interface() {
+ Register(FunctionTable);
+}
+
+} // namespace
diff --git a/src/core/hle/service/ir_u.h b/src/core/hle/service/nim_u.h
index ec47a1524..57a1f6acf 100644
--- a/src/core/hle/service/ir_u.h
+++ b/src/core/hle/service/nim_u.h
@@ -1,4 +1,4 @@
-// Copyright 2014 Citra Emulator Project
+// Copyright 2015 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
@@ -7,16 +7,16 @@
#include "core/hle/service/service.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace IR_U
+// Namespace NIM_U
-namespace IR_U {
+namespace NIM_U {
class Interface : public Service::Interface {
public:
Interface();
std::string GetPortName() const override {
- return "ir:u";
+ return "nim:u";
}
};
diff --git a/src/core/hle/service/ns_s.cpp b/src/core/hle/service/ns_s.cpp
index 5cf3e2039..6b3ef6ece 100644
--- a/src/core/hle/service/ns_s.cpp
+++ b/src/core/hle/service/ns_s.cpp
@@ -3,8 +3,6 @@
// Refer to the license.txt file included.
-#include "common/common.h"
-
#include "core/hle/hle.h"
#include "core/hle/service/ns_s.h"
diff --git a/src/core/hle/service/nwm_uds.cpp b/src/core/hle/service/nwm_uds.cpp
index 88be6c8d9..25b01860e 100644
--- a/src/core/hle/service/nwm_uds.cpp
+++ b/src/core/hle/service/nwm_uds.cpp
@@ -2,7 +2,10 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/logging/log.h"
+
#include "core/hle/hle.h"
+#include "core/hle/kernel/event.h"
#include "core/hle/service/nwm_uds.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -10,21 +13,115 @@
namespace NWM_UDS {
+static Kernel::SharedPtr<Kernel::Event> handle_event;
+
+/**
+ * NWM_UDS::Shutdown service function
+ * Inputs:
+ * 1 : None
+ * Outputs:
+ * 0 : Return header
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
+static void Shutdown(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ // TODO(purpasmart): Verify return header on HW
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_WARNING(Service_NWM, "(STUBBED) called");
+}
+
+/**
+ * NWM_UDS::RecvBeaconBroadcastData service function
+ * Inputs:
+ * 1 : Output buffer max size
+ * 2 : Unknown
+ * 3 : Unknown
+ * 4 : MAC address?
+ * 6-14 : Unknown, usually zero / uninitialized?
+ * 15 : WLan Comm ID
+ * 16 : This is the ID also located at offset 0xE in the CTR-generation structure.
+ * 17 : Value 0
+ * 18 : Input handle
+ * 19 : (Size<<4) | 12
+ * 20 : Output buffer ptr
+ * Outputs:
+ * 0 : Return header
+ * 1 : Result of function, 0 on success, otherwise error code
+ */
+static void RecvBeaconBroadcastData(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 out_buffer_size = cmd_buff[1];
+ u32 unk1 = cmd_buff[2];
+ u32 unk2 = cmd_buff[3];
+ u32 mac_address = cmd_buff[4];
+
+ u32 unk3 = cmd_buff[6];
+
+ u32 wlan_comm_id = cmd_buff[15];
+ u32 ctr_gen_id = cmd_buff[16];
+ u32 value = cmd_buff[17];
+ u32 input_handle = cmd_buff[18];
+ u32 new_buffer_size = cmd_buff[19];
+ u32 out_buffer_ptr = cmd_buff[20];
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_WARNING(Service_NWM, "(STUBBED) called out_buffer_size=0x%08X, unk1=0x%08X, unk2=0x%08X,"
+ "mac_address=0x%08X, unk3=0x%08X, wlan_comm_id=0x%08X, ctr_gen_id=0x%08X,"
+ "value=%u, input_handle=0x%08X, new_buffer_size=0x%08X, out_buffer_ptr=0x%08X",
+ out_buffer_size, unk1, unk2, mac_address, unk3, wlan_comm_id, ctr_gen_id, value,
+ input_handle, new_buffer_size, out_buffer_ptr);
+}
+
+/**
+ * NWM_UDS::Initialize service function
+ * Inputs:
+ * 1 : Unknown
+ * 2-11 : Input Structure
+ * 12 : Unknown u16
+ * 13 : Value 0
+ * 14 : Handle
+ * Outputs:
+ * 0 : Return header
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Value 0
+ * 3 : Output handle
+ */
+static void Initialize(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 unk1 = cmd_buff[1];
+ u32 unk2 = cmd_buff[12];
+ u32 value = cmd_buff[13];
+ u32 handle = cmd_buff[14];
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = 0;
+ cmd_buff[3] = Kernel::g_handle_table.Create(handle_event).MoveFrom(); //TODO(purpasmart): Verify if this is a event handle
+
+ LOG_WARNING(Service_NWM, "(STUBBED) called unk1=0x%08X, unk2=0x%08X, value=%u, handle=0x%08X",
+ unk1, unk2, value, handle);
+}
+
const Interface::FunctionInfo FunctionTable[] = {
- {0x00030000, nullptr, "Shutdown"},
- {0x000F0404, nullptr, "RecvBeaconBroadcastData"},
- {0x00100042, nullptr, "SetBeaconAdditionalData"},
- {0x001400C0, nullptr, "RecvBroadcastDataFrame"},
- {0x001B0302, nullptr, "Initialize"},
- {0x001D0044, nullptr, "BeginHostingNetwork"},
- {0x001E0084, nullptr, "ConnectToNetwork"},
- {0x001F0006, nullptr, "DecryptBeaconData"},
+ {0x00030000, Shutdown, "Shutdown"},
+ {0x000F0404, RecvBeaconBroadcastData, "RecvBeaconBroadcastData"},
+ {0x00100042, nullptr, "SetBeaconAdditionalData"},
+ {0x001400C0, nullptr, "RecvBroadcastDataFrame"},
+ {0x001B0302, Initialize, "Initialize"},
+ {0x001D0044, nullptr, "BeginHostingNetwork"},
+ {0x001E0084, nullptr, "ConnectToNetwork"},
+ {0x001F0006, nullptr, "DecryptBeaconData"},
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Interface class
Interface::Interface() {
+ handle_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "NWM_UDS::handle_event");
+
Register(FunctionTable);
}
diff --git a/src/core/hle/service/nwm_uds.h b/src/core/hle/service/nwm_uds.h
index 9043f5aa7..82abdff28 100644
--- a/src/core/hle/service/nwm_uds.h
+++ b/src/core/hle/service/nwm_uds.h
@@ -18,7 +18,7 @@ public:
Interface();
std::string GetPortName() const override {
- return "nwm:UDS";
+ return "nwm::UDS";
}
};
diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp
index 56c918d4f..2c7d49c9f 100644
--- a/src/core/hle/service/ptm/ptm.cpp
+++ b/src/core/hle/service/ptm/ptm.cpp
@@ -2,12 +2,15 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "core/hle/service/service.h"
+#include "common/logging/log.h"
+
+#include "core/file_sys/file_backend.h"
#include "core/hle/service/fs/archive.h"
#include "core/hle/service/ptm/ptm.h"
#include "core/hle/service/ptm/ptm_play.h"
#include "core/hle/service/ptm/ptm_sysm.h"
#include "core/hle/service/ptm/ptm_u.h"
+#include "core/hle/service/service.h"
namespace Service {
namespace PTM {
@@ -18,31 +21,70 @@ static const GameCoin default_game_coin = { 0x4F00, 42, 0, 0, 0, 2014, 12, 29 };
/// Id of the SharedExtData archive used by the PTM process
static const std::vector<u8> ptm_shared_extdata_id = {0, 0, 0, 0, 0x0B, 0, 0, 0xF0, 0, 0, 0, 0};
-static bool shell_open = true;
+static bool shell_open;
-static bool battery_is_charging = true;
+static bool battery_is_charging;
+
+void GetAdapterState(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
-u32 GetAdapterState() {
// TODO(purpasmart96): This function is only a stub,
// it returns a valid result without implementing full functionality.
- return battery_is_charging ? 1 : 0;
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = battery_is_charging ? 1 : 0;
+
+ LOG_WARNING(Service_PTM, "(STUBBED) called");
}
-u32 GetShellState() {
- return shell_open ? 1 : 0;
+void GetShellState(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = shell_open ? 1 : 0;
+}
+
+void GetBatteryLevel(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ // TODO(purpasmart96): This function is only a stub,
+ // it returns a valid result without implementing full functionality.
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = static_cast<u32>(ChargeLevels::CompletelyFull); // Set to a completely full battery
+
+ LOG_WARNING(Service_PTM, "(STUBBED) called");
}
-ChargeLevels GetBatteryLevel() {
+void GetBatteryChargeState(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
// TODO(purpasmart96): This function is only a stub,
// it returns a valid result without implementing full functionality.
- return ChargeLevels::CompletelyFull; // Set to a completely full battery
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = battery_is_charging ? 1 : 0;
+
+ LOG_WARNING(Service_PTM, "(STUBBED) called");
}
-void PTMInit() {
+void IsLegacyPowerOff(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = 0;
+
+ LOG_WARNING(Service_PTM, "(STUBBED) called");
+}
+
+void Init() {
AddService(new PTM_Play_Interface);
AddService(new PTM_Sysm_Interface);
AddService(new PTM_U_Interface);
+ shell_open = true;
+ battery_is_charging = true;
+
// Open the SharedExtSaveData archive 0xF000000B and create the gamecoin.dat file if it doesn't exist
FileSys::Path archive_path(ptm_shared_extdata_id);
auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SharedExtSaveData, archive_path);
@@ -68,7 +110,7 @@ void PTMInit() {
}
}
-void PTMShutdown() {
+void Shutdown() {
}
diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h
index f697aae4d..493e6a11f 100644
--- a/src/core/hle/service/ptm/ptm.h
+++ b/src/core/hle/service/ptm/ptm.h
@@ -5,6 +5,7 @@
#pragma once
#include <array>
+#include "core/hle/service/service.h"
#include "core/hle/result.h"
namespace Service {
@@ -35,31 +36,54 @@ struct GameCoin {
};
/**
- * Returns whether the battery is charging or not.
* It is unknown if GetAdapterState is the same as GetBatteryChargeState,
* it is likely to just be a duplicate function of GetBatteryChargeState
* that controls another part of the HW.
- * @returns 1 if the battery is charging, and 0 otherwise.
+ * PTM::GetAdapterState service function
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Output of function, 0 = not charging, 1 = charging.
*/
-u32 GetAdapterState();
+void GetAdapterState(Interface* self);
/**
- * Returns whether the 3DS's physical shell casing is open or closed
- * @returns 1 if the shell is open, and 0 if otherwise
+ * PTM::GetShellState service function.
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Whether the 3DS's physical shell casing is open (1) or closed (0)
*/
-u32 GetShellState();
+void GetShellState(Interface* self);
/**
- * Get the current battery's charge level.
- * @returns The battery's charge level.
+ * PTM::GetBatteryLevel service function
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Battery level, 5 = completely full battery, 4 = mostly full battery,
+ * 3 = half full battery, 2 = low battery, 1 = critical battery.
*/
-ChargeLevels GetBatteryLevel();
+void GetBatteryLevel(Interface* self);
+
+/**
+ * PTM::GetBatteryChargeState service function
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Output of function, 0 = not charging, 1 = charging.
+ */
+void GetBatteryChargeState(Interface* self);
+
+/**
+ * PTM::IsLegacyPowerOff service function
+ * Outputs:
+ * 1: Result code, 0 on success, otherwise error code
+ * 2: Whether the system is going through a power off
+ */
+void IsLegacyPowerOff(Interface* self);
/// Initialize the PTM service
-void PTMInit();
+void Init();
/// Shutdown the PTM service
-void PTMShutdown();
+void Shutdown();
} // namespace PTM
} // namespace Service
diff --git a/src/core/hle/service/ptm/ptm_play.cpp b/src/core/hle/service/ptm/ptm_play.cpp
index 8e8ae8558..48e68a3d8 100644
--- a/src/core/hle/service/ptm/ptm_play.cpp
+++ b/src/core/hle/service/ptm/ptm_play.cpp
@@ -9,10 +9,10 @@ namespace Service {
namespace PTM {
const Interface::FunctionInfo FunctionTable[] = {
- { 0x08070082, nullptr, "GetPlayHistory" },
- { 0x08080000, nullptr, "GetPlayHistoryStart" },
- { 0x08090000, nullptr, "GetPlayHistoryLength" },
- { 0x080B0080, nullptr, "CalcPlayHistoryStart" },
+ {0x08070082, nullptr, "GetPlayHistory"},
+ {0x08080000, nullptr, "GetPlayHistoryStart"},
+ {0x08090000, nullptr, "GetPlayHistoryLength"},
+ {0x080B0080, nullptr, "CalcPlayHistoryStart"},
};
PTM_Play_Interface::PTM_Play_Interface() {
diff --git a/src/core/hle/service/ptm/ptm_sysm.cpp b/src/core/hle/service/ptm/ptm_sysm.cpp
index 2d841f69c..655658f3b 100644
--- a/src/core/hle/service/ptm/ptm_sysm.cpp
+++ b/src/core/hle/service/ptm/ptm_sysm.cpp
@@ -2,57 +2,44 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "common/make_unique.h"
-#include "core/file_sys/archive_extsavedata.h"
#include "core/hle/hle.h"
+#include "core/hle/service/ptm/ptm.h"
#include "core/hle/service/ptm/ptm_sysm.h"
namespace Service {
namespace PTM {
-/**
- * Returns whether the system is powering off (?)
- * Outputs:
- * 1: Result code, 0 on success, otherwise error code
- * 2: Whether the system is going through a power off
- */
-void IsLegacyPowerOff(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- cmd_buff[1] = RESULT_SUCCESS.raw;
- cmd_buff[2] = 0;
-}
-
const Interface::FunctionInfo FunctionTable[] = {
- {0x040100C0, nullptr, "SetRtcAlarmEx"},
- {0x04020042, nullptr, "ReplySleepQuery"},
- {0x04030042, nullptr, "NotifySleepPreparationComplete"},
- {0x04040102, nullptr, "SetWakeupTrigger"},
- {0x04050000, nullptr, "GetAwakeReason"},
- {0x04060000, nullptr, "RequestSleep"},
- {0x040700C0, nullptr, "ShutdownAsync"},
- {0x04080000, nullptr, "Awake"},
- {0x04090080, nullptr, "RebootAsync"},
- {0x040A0000, nullptr, "CheckNew3DS"},
- {0x08010640, nullptr, "SetInfoLEDPattern"},
- {0x08020040, nullptr, "SetInfoLEDPatternHeader"},
- {0x08030000, nullptr, "GetInfoLEDStatus"},
- {0x08040040, nullptr, "SetBatteryEmptyLEDPattern"},
- {0x08050000, nullptr, "ClearStepHistory"},
- {0x080600C2, nullptr, "SetStepHistory"},
- {0x08070082, nullptr, "GetPlayHistory"},
- {0x08080000, nullptr, "GetPlayHistoryStart"},
- {0x08090000, nullptr, "GetPlayHistoryLength"},
- {0x080A0000, nullptr, "ClearPlayHistory"},
- {0x080B0080, nullptr, "CalcPlayHistoryStart"},
- {0x080C0080, nullptr, "SetUserTime"},
- {0x080D0000, nullptr, "InvalidateSystemTime"},
- {0x080E0140, nullptr, "NotifyPlayEvent"},
- {0x080F0000, IsLegacyPowerOff, "IsLegacyPowerOff"},
- {0x08100000, nullptr, "ClearLegacyPowerOff"},
- {0x08110000, nullptr, "GetShellStatus"},
- {0x08120000, nullptr, "IsShutdownByBatteryEmpty"},
- {0x08130000, nullptr, "FormatSavedata"},
- {0x08140000, nullptr, "GetLegacyJumpProhibitedFlag"}
+ {0x040100C0, nullptr, "SetRtcAlarmEx"},
+ {0x04020042, nullptr, "ReplySleepQuery"},
+ {0x04030042, nullptr, "NotifySleepPreparationComplete"},
+ {0x04040102, nullptr, "SetWakeupTrigger"},
+ {0x04050000, nullptr, "GetAwakeReason"},
+ {0x04060000, nullptr, "RequestSleep"},
+ {0x040700C0, nullptr, "ShutdownAsync"},
+ {0x04080000, nullptr, "Awake"},
+ {0x04090080, nullptr, "RebootAsync"},
+ {0x040A0000, nullptr, "CheckNew3DS"},
+ {0x08010640, nullptr, "SetInfoLEDPattern"},
+ {0x08020040, nullptr, "SetInfoLEDPatternHeader"},
+ {0x08030000, nullptr, "GetInfoLEDStatus"},
+ {0x08040040, nullptr, "SetBatteryEmptyLEDPattern"},
+ {0x08050000, nullptr, "ClearStepHistory"},
+ {0x080600C2, nullptr, "SetStepHistory"},
+ {0x08070082, nullptr, "GetPlayHistory"},
+ {0x08080000, nullptr, "GetPlayHistoryStart"},
+ {0x08090000, nullptr, "GetPlayHistoryLength"},
+ {0x080A0000, nullptr, "ClearPlayHistory"},
+ {0x080B0080, nullptr, "CalcPlayHistoryStart"},
+ {0x080C0080, nullptr, "SetUserTime"},
+ {0x080D0000, nullptr, "InvalidateSystemTime"},
+ {0x080E0140, nullptr, "NotifyPlayEvent"},
+ {0x080F0000, IsLegacyPowerOff, "IsLegacyPowerOff"},
+ {0x08100000, nullptr, "ClearLegacyPowerOff"},
+ {0x08110000, nullptr, "GetShellStatus"},
+ {0x08120000, nullptr, "IsShutdownByBatteryEmpty"},
+ {0x08130000, nullptr, "FormatSavedata"},
+ {0x08140000, nullptr, "GetLegacyJumpProhibitedFlag"}
};
PTM_Sysm_Interface::PTM_Sysm_Interface() {
diff --git a/src/core/hle/service/ptm/ptm_u.cpp b/src/core/hle/service/ptm/ptm_u.cpp
index 0af7c8bf6..3f5e9c7c1 100644
--- a/src/core/hle/service/ptm/ptm_u.cpp
+++ b/src/core/hle/service/ptm/ptm_u.cpp
@@ -2,7 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "common/make_unique.h"
+#include "common/logging/log.h"
#include "core/hle/hle.h"
#include "core/hle/service/ptm/ptm.h"
@@ -11,68 +11,6 @@
namespace Service {
namespace PTM {
-/**
- * PTM_U::GetAdapterState service function
- * Outputs:
- * 1 : Result of function, 0 on success, otherwise error code
- * 2 : Output of function, 0 = not charging, 1 = charging.
- */
-static void GetAdapterState(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
-
- cmd_buff[1] = RESULT_SUCCESS.raw;
- cmd_buff[2] = GetAdapterState();
-
- LOG_WARNING(Service_PTM, "(STUBBED) called");
-}
-
-/*
- * PTM_User::GetShellState service function.
- * Outputs:
- * 1 : Result of function, 0 on success, otherwise error code
- * 2 : Whether the 3DS's physical shell casing is open (1) or closed (0)
- */
-static void GetShellState(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
-
- cmd_buff[1] = RESULT_SUCCESS.raw;
- cmd_buff[2] = GetShellState();
-}
-
-/**
- * PTM_U::GetBatteryLevel service function
- * Outputs:
- * 1 : Result of function, 0 on success, otherwise error code
- * 2 : Battery level, 5 = completely full battery, 4 = mostly full battery,
- * 3 = half full battery, 2 = low battery, 1 = critical battery.
- */
-static void GetBatteryLevel(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
-
- cmd_buff[1] = RESULT_SUCCESS.raw;
- cmd_buff[2] = static_cast<u32>(GetBatteryLevel());
-
- LOG_WARNING(Service_PTM, "(STUBBED) called");
-}
-
-/**
- * PTM_U::GetBatteryChargeState service function
- * Outputs:
- * 1 : Result of function, 0 on success, otherwise error code
- * 2 : Output of function, 0 = not charging, 1 = charging.
- */
-static void GetBatteryChargeState(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
-
- // TODO(purpasmart96): This function is only a stub,
- // it returns a valid result without implementing full functionality.
-
- cmd_buff[1] = RESULT_SUCCESS.raw;
- cmd_buff[2] = GetAdapterState();
-
- LOG_WARNING(Service_PTM, "(STUBBED) called");
-}
-
const Interface::FunctionInfo FunctionTable[] = {
{0x00010002, nullptr, "RegisterAlarmClient"},
{0x00020080, nullptr, "SetRtcAlarm"},
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 91f13cd7e..64185c62e 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -2,7 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
-#include "common/common.h"
+#include "common/logging/log.h"
#include "common/string_util.h"
#include "core/hle/service/service.h"
@@ -24,14 +24,13 @@
#include "core/hle/service/gsp_gpu.h"
#include "core/hle/service/gsp_lcd.h"
#include "core/hle/service/http_c.h"
-#include "core/hle/service/ir_rst.h"
-#include "core/hle/service/ir_u.h"
#include "core/hle/service/ldr_ro.h"
#include "core/hle/service/mic_u.h"
#include "core/hle/service/ndm_u.h"
#include "core/hle/service/news_s.h"
#include "core/hle/service/news_u.h"
#include "core/hle/service/nim_aoc.h"
+#include "core/hle/service/nim_u.h"
#include "core/hle/service/ns_s.h"
#include "core/hle/service/nwm_uds.h"
#include "core/hle/service/pm_app.h"
@@ -44,6 +43,7 @@
#include "core/hle/service/fs/archive.h"
#include "core/hle/service/cfg/cfg.h"
#include "core/hle/service/hid/hid.h"
+#include "core/hle/service/ir/ir.h"
#include "core/hle/service/ptm/ptm.h"
namespace Service {
@@ -51,6 +51,49 @@ namespace Service {
std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_ports;
std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services;
+/**
+ * Creates a function string for logging, complete with the name (or header code, depending
+ * on what's passed in) the port name, and all the cmd_buff arguments.
+ */
+static std::string MakeFunctionString(const char* name, const char* port_name, const u32* cmd_buff) {
+ // Number of params == bits 0-5 + bits 6-11
+ int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F);
+
+ std::string function_string = Common::StringFromFormat("function '%s': port=%s", name, port_name);
+ for (int i = 1; i <= num_params; ++i) {
+ function_string += Common::StringFromFormat(", cmd_buff[%i]=%u", i, cmd_buff[i]);
+ }
+ return function_string;
+}
+
+ResultVal<bool> Interface::SyncRequest() {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ auto itr = m_functions.find(cmd_buff[0]);
+
+ if (itr == m_functions.end() || itr->second.func == nullptr) {
+ std::string function_name = (itr == m_functions.end()) ? Common::StringFromFormat("0x%08X", cmd_buff[0]) : itr->second.name;
+ LOG_ERROR(Service, "unknown / unimplemented %s", MakeFunctionString(function_name.c_str(), GetPortName().c_str(), cmd_buff).c_str());
+
+ // TODO(bunnei): Hack - ignore error
+ cmd_buff[1] = 0;
+ return MakeResult<bool>(false);
+ } else {
+ LOG_TRACE(Service, "%s", MakeFunctionString(itr->second.name, GetPortName().c_str(), cmd_buff).c_str());
+ }
+
+ itr->second.func(this);
+
+ return MakeResult<bool>(false); // TODO: Implement return from actual function
+}
+
+void Interface::Register(const FunctionInfo* functions, size_t n) {
+ m_functions.reserve(n);
+ for (size_t i = 0; i < n; ++i) {
+ // Usually this array is sorted by id already, so hint to instead at the end
+ m_functions.emplace_hint(m_functions.cend(), functions[i].id, functions[i]);
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////////////////////////
// Module interface
@@ -68,10 +111,11 @@ void Init() {
AddNamedPort(new ERR_F::Interface);
Service::FS::ArchiveInit();
- Service::CFG::CFGInit();
- Service::APT::APTInit();
- Service::PTM::PTMInit();
- Service::HID::HIDInit();
+ Service::CFG::Init();
+ Service::APT::Init();
+ Service::PTM::Init();
+ Service::HID::Init();
+ Service::IR::Init();
AddService(new AC_U::Interface);
AddService(new ACT_U::Interface);
@@ -90,14 +134,13 @@ void Init() {
AddService(new GSP_GPU::Interface);
AddService(new GSP_LCD::Interface);
AddService(new HTTP_C::Interface);
- AddService(new IR_RST::Interface);
- AddService(new IR_U::Interface);
AddService(new LDR_RO::Interface);
AddService(new MIC_U::Interface);
AddService(new NDM_U::Interface);
AddService(new NEWS_S::Interface);
AddService(new NEWS_U::Interface);
AddService(new NIM_AOC::Interface);
+ AddService(new NIM_U::Interface);
AddService(new NS_S::Interface);
AddService(new NWM_UDS::Interface);
AddService(new PM_APP::Interface);
@@ -110,10 +153,11 @@ void Init() {
/// Shutdown ServiceManager
void Shutdown() {
- Service::HID::HIDShutdown();
- Service::PTM::PTMShutdown();
- Service::APT::APTShutdown();
- Service::CFG::CFGShutdown();
+ Service::IR::Shutdown();
+ Service::HID::Shutdown();
+ Service::PTM::Shutdown();
+ Service::APT::Shutdown();
+ Service::CFG::Shutdown();
Service::FS::ArchiveShutdown();
g_srv_services.clear();
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index bfe16ebad..77bfb9ff1 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -4,20 +4,15 @@
#pragma once
-#include <algorithm>
#include <string>
#include <unordered_map>
-#include <vector>
#include <boost/container/flat_map.hpp>
-#include "common/common.h"
-#include "common/string_util.h"
-#include "core/mem_map.h"
+#include "common/common_types.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/session.h"
-#include "core/hle/svc.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace Service
@@ -26,31 +21,11 @@ namespace Service {
static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters)
-class Manager;
-
/// Interface to a CTROS service
class Interface : public Kernel::Session {
// TODO(yuriks): An "Interface" being a Kernel::Object is mostly non-sense. Interface should be
// just something that encapsulates a session and acts as a helper to implement service
// processes.
-
- friend class Manager;
-
- /**
- * Creates a function string for logging, complete with the name (or header code, depending
- * on what's passed in) the port name, and all the cmd_buff arguments.
- */
- std::string MakeFunctionString(const char* name, const char* port_name, const u32* cmd_buff) {
- // Number of params == bits 0-5 + bits 6-11
- int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F);
-
- std::string function_string = Common::StringFromFormat("function '%s': port=%s", name, port_name);
- for (int i = 1; i <= num_params; ++i) {
- function_string += Common::StringFromFormat(", cmd_buff[%i]=%u", i, cmd_buff[i]);
- }
- return function_string;
- }
-
public:
std::string GetName() const override { return GetPortName(); }
@@ -70,25 +45,7 @@ public:
return "[UNKNOWN SERVICE PORT]";
}
- ResultVal<bool> SyncRequest() override {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- auto itr = m_functions.find(cmd_buff[0]);
-
- if (itr == m_functions.end() || itr->second.func == nullptr) {
- std::string function_name = (itr == m_functions.end()) ? Common::StringFromFormat("0x%08X", cmd_buff[0]) : itr->second.name;
- LOG_ERROR(Service, "unknown / unimplemented %s", MakeFunctionString(function_name.c_str(), GetPortName().c_str(), cmd_buff).c_str());
-
- // TODO(bunnei): Hack - ignore error
- cmd_buff[1] = 0;
- return MakeResult<bool>(false);
- } else {
- LOG_TRACE(Service, "%s", MakeFunctionString(itr->second.name, GetPortName().c_str(), cmd_buff).c_str());
- }
-
- itr->second.func(this);
-
- return MakeResult<bool>(false); // TODO: Implement return from actual function
- }
+ ResultVal<bool> SyncRequest() override;
protected:
@@ -96,14 +53,12 @@ protected:
* Registers the functions in the service
*/
template <size_t N>
- void Register(const FunctionInfo (&functions)[N]) {
- m_functions.reserve(N);
- for (auto& fn : functions) {
- // Usually this array is sorted by id already, so hint to instead at the end
- m_functions.emplace_hint(m_functions.cend(), fn.id, fn);
- }
+ inline void Register(const FunctionInfo (&functions)[N]) {
+ Register(functions, N);
}
+ void Register(const FunctionInfo* functions, size_t n);
+
private:
boost::container::flat_map<u32, FunctionInfo> m_functions;
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp
index 231ead185..39b8d65fd 100644
--- a/src/core/hle/service/soc_u.cpp
+++ b/src/core/hle/service/soc_u.cpp
@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/logging/log.h"
#include "common/platform.h"
#if EMU_PLATFORM == PLATFORM_WINDOWS
diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp
index cc59a03ce..6c49fa6cf 100644
--- a/src/core/hle/service/srv.cpp
+++ b/src/core/hle/service/srv.cpp
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/logging/log.h"
+
#include "core/hle/hle.h"
#include "core/hle/service/srv.h"
#include "core/hle/kernel/event.h"
diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp
index 6607965e1..085192a07 100644
--- a/src/core/hle/service/y2r_u.cpp
+++ b/src/core/hle/service/y2r_u.cpp
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/logging/log.h"
+
#include "core/hle/hle.h"
#include "core/hle/kernel/event.h"
#include "core/hle/service/y2r_u.h"
@@ -11,7 +13,7 @@
namespace Y2R_U {
-static Kernel::SharedPtr<Kernel::Event> completion_event = 0;
+static Kernel::SharedPtr<Kernel::Event> completion_event;
/**
* Y2R_U::IsBusyConversion service function
diff --git a/src/core/hle/shared_page.cpp b/src/core/hle/shared_page.cpp
index 568dad684..4014eee98 100644
--- a/src/core/hle/shared_page.cpp
+++ b/src/core/hle/shared_page.cpp
@@ -2,11 +2,13 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <cstring>
+
#include "common/common_types.h"
#include "common/common_funcs.h"
#include "core/core.h"
-#include "core/mem_map.h"
+#include "core/memory.h"
#include "core/hle/config_mem.h"
#include "core/hle/shared_page.h"
@@ -14,61 +16,15 @@
namespace SharedPage {
-// see http://3dbrew.org/wiki/Configuration_Memory#Shared_Memory_Page_For_ARM11_Processes
-
-#pragma pack(1)
-struct DateTime {
- u64 date_time; // 0x0
- u64 update_tick; // 0x8
- INSERT_PADDING_BYTES(0x20 - 0x10); // 0x10
-};
-
-struct SharedPageDef {
- // most of these names are taken from the 3dbrew page linked above.
- u32 date_time_selector; // 0x0
- u8 running_hw; // 0x4
- u8 mcu_hw_info; // 0x5: don't know what the acronyms mean
- INSERT_PADDING_BYTES(0x20 - 0x6); // 0x6
- DateTime date_time_0; // 0x20
- DateTime date_time_1; // 0x40
- u8 wifi_macaddr[6]; // 0x60
- u8 wifi_unknown1; // 0x66: 3dbrew says these are "Likely wifi hardware related"
- u8 wifi_unknown2; // 0x67
- INSERT_PADDING_BYTES(0x80 - 0x68); // 0x68
- float sliderstate_3d; // 0x80
- u8 ledstate_3d; // 0x84
- INSERT_PADDING_BYTES(0xA0 - 0x85); // 0x85
- u64 menu_title_id; // 0xA0
- u64 active_menu_title_id; // 0xA8
- INSERT_PADDING_BYTES(0x1000 - 0xB0); // 0xB0
-};
-#pragma pack()
+SharedPageDef shared_page;
-static_assert(sizeof(DateTime) == 0x20, "Datetime size is wrong");
-static_assert(sizeof(SharedPageDef) == Memory::SHARED_PAGE_SIZE, "Shared page structure size is wrong");
-
-static SharedPageDef shared_page;
-
-template <typename T>
-inline void Read(T &var, const u32 addr) {
- u32 offset = addr - Memory::SHARED_PAGE_VADDR;
- var = *(reinterpret_cast<T*>(((uintptr_t)&shared_page) + offset));
-}
-
-// Explicitly instantiate template functions because we aren't defining this in the header:
-template void Read<u64>(u64 &var, const u32 addr);
-template void Read<u32>(u32 &var, const u32 addr);
-template void Read<u16>(u16 &var, const u32 addr);
-template void Read<u8>(u8 &var, const u32 addr);
+void Init() {
+ std::memset(&shared_page, 0, sizeof(shared_page));
-void Set3DSlider(float amount) {
- shared_page.sliderstate_3d = amount;
- shared_page.ledstate_3d = (amount == 0.0f); // off when non-zero
+ shared_page.running_hw = 0x1; // product
}
-void Init() {
- shared_page.running_hw = 0x1; // product
- Set3DSlider(0.0f);
+void Shutdown() {
}
} // namespace
diff --git a/src/core/hle/shared_page.h b/src/core/hle/shared_page.h
index 8f93545ec..fd2ab66a2 100644
--- a/src/core/hle/shared_page.h
+++ b/src/core/hle/shared_page.h
@@ -11,16 +11,46 @@
*/
#include "common/common_types.h"
+#include "common/swap.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace SharedPage {
-template <typename T>
-void Read(T &var, const u32 addr);
-
-void Set3DSlider(float amount);
+// See http://3dbrew.org/wiki/Configuration_Memory#Shared_Memory_Page_For_ARM11_Processes
+
+struct DateTime {
+ u64_le date_time; // 0
+ u64_le update_tick; // 8
+ INSERT_PADDING_BYTES(0x20 - 0x10); // 10
+};
+static_assert(sizeof(DateTime) == 0x20, "Datetime size is wrong");
+
+struct SharedPageDef {
+ // Most of these names are taken from the 3dbrew page linked above.
+ u32_le date_time_selector; // 0
+ u8 running_hw; // 4
+ /// "Microcontroller hardware info"
+ u8 mcu_hw_info; // 5
+ INSERT_PADDING_BYTES(0x20 - 0x6); // 6
+ DateTime date_time_0; // 20
+ DateTime date_time_1; // 40
+ u8 wifi_macaddr[6]; // 60
+ u8 wifi_unknown1; // 66
+ u8 wifi_unknown2; // 67
+ INSERT_PADDING_BYTES(0x80 - 0x68); // 68
+ float_le sliderstate_3d; // 80
+ u8 ledstate_3d; // 84
+ INSERT_PADDING_BYTES(0xA0 - 0x85); // 85
+ u64_le menu_title_id; // A0
+ u64_le active_menu_title_id; // A8
+ INSERT_PADDING_BYTES(0x1000 - 0xB0); // B0
+};
+static_assert(sizeof(SharedPageDef) == Memory::SHARED_PAGE_SIZE, "Shared page structure size is wrong");
+
+extern SharedPageDef shared_page;
void Init();
+void Shutdown();
} // namespace
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index bbb4eb9cd..9bf886256 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -4,6 +4,8 @@
#include <map>
+#include "common/logging/log.h"
+#include "common/profiler.h"
#include "common/string_util.h"
#include "common/symbols.h"
@@ -14,6 +16,7 @@
#include "core/hle/kernel/address_arbiter.h"
#include "core/hle/kernel/event.h"
#include "core/hle/kernel/mutex.h"
+#include "core/hle/kernel/process.h"
#include "core/hle/kernel/semaphore.h"
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/kernel/thread.h"
@@ -283,8 +286,13 @@ static ResultCode ArbitrateAddress(Handle handle, u32 address, u32 type, u32 val
if (arbiter == nullptr)
return ERR_INVALID_HANDLE;
- return arbiter->ArbitrateAddress(static_cast<Kernel::ArbitrationType>(type),
- address, value, nanoseconds);
+ auto res = arbiter->ArbitrateAddress(static_cast<Kernel::ArbitrationType>(type),
+ address, value, nanoseconds);
+
+ if (res == RESULT_SUCCESS)
+ HLE::Reschedule(__func__);
+
+ return res;
}
/// Used to output a message on a debug hardware unit - does nothing on a retail unit
@@ -305,14 +313,14 @@ static ResultCode GetResourceLimit(Handle* resource_limit, Handle process) {
/// Get resource limit current values
static ResultCode GetResourceLimitCurrentValues(s64* values, Handle resource_limit, void* names,
s32 name_count) {
- LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called resource_limit=%08X, names=%s, name_count=%d",
+ LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called resource_limit=%08X, names=%p, name_count=%d",
resource_limit, names, name_count);
- Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now
+ values[0] = 0; // Normmatt: Set used memory to 0 for now
return RESULT_SUCCESS;
}
/// Creates a new thread
-static ResultCode CreateThread(u32* out_handle, u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 processor_id) {
+static ResultCode CreateThread(Handle* out_handle, s32 priority, u32 entry_point, u32 arg, u32 stack_top, s32 processor_id) {
using Kernel::Thread;
std::string name;
@@ -323,6 +331,27 @@ static ResultCode CreateThread(u32* out_handle, u32 priority, u32 entry_point, u
name = Common::StringFromFormat("unknown-%08x", entry_point);
}
+ // TODO(bunnei): Implement resource limits to return an error code instead of the below assert.
+ // The error code should be: Description::NotAuthorized, Module::OS, Summary::WrongArgument,
+ // Level::Permanent
+ ASSERT_MSG(priority >= THREADPRIO_USERLAND_MAX, "Unexpected thread priority!");
+
+ if (priority > THREADPRIO_LOWEST) {
+ return ResultCode(ErrorDescription::OutOfRange, ErrorModule::OS,
+ ErrorSummary::InvalidArgument, ErrorLevel::Usage);
+ }
+
+ switch (processor_id) {
+ case THREADPROCESSORID_DEFAULT:
+ case THREADPROCESSORID_0:
+ case THREADPROCESSORID_1:
+ break;
+ default:
+ // TODO(bunnei): Implement support for other processor IDs
+ ASSERT_MSG(false, "Unsupported thread processor ID: %d", processor_id);
+ break;
+ }
+
CASCADE_RESULT(SharedPtr<Thread> thread, Kernel::Thread::Create(
name, entry_point, priority, arg, processor_id, stack_top));
CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(thread)));
@@ -331,10 +360,7 @@ static ResultCode CreateThread(u32* out_handle, u32 priority, u32 entry_point, u
"threadpriority=0x%08X, processorid=0x%08X : created handle=0x%08X", entry_point,
name.c_str(), arg, stack_top, priority, processor_id, *out_handle);
- if (THREADPROCESSORID_1 == processor_id) {
- LOG_WARNING(Kernel_SVC,
- "thread designated for system CPU core (UNIMPLEMENTED) will be run with app core scheduling");
- }
+ HLE::Reschedule(__func__);
return RESULT_SUCCESS;
}
@@ -374,8 +400,11 @@ static ResultCode CreateMutex(Handle* out_handle, u32 initial_locked) {
SharedPtr<Mutex> mutex = Mutex::Create(initial_locked != 0);
CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(mutex)));
+ HLE::Reschedule(__func__);
+
LOG_TRACE(Kernel_SVC, "called initial_locked=%s : created handle=0x%08X",
initial_locked ? "true" : "false", *out_handle);
+
return RESULT_SUCCESS;
}
@@ -390,6 +419,37 @@ static ResultCode ReleaseMutex(Handle handle) {
return ERR_INVALID_HANDLE;
mutex->Release();
+
+ HLE::Reschedule(__func__);
+
+ return RESULT_SUCCESS;
+}
+
+/// Get the ID of the specified process
+static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
+ LOG_TRACE(Kernel_SVC, "called process=0x%08X", process_handle);
+
+ const SharedPtr<Kernel::Process> process = Kernel::g_handle_table.Get<Kernel::Process>(process_handle);
+ if (process == nullptr)
+ return ERR_INVALID_HANDLE;
+
+ *process_id = process->process_id;
+ return RESULT_SUCCESS;
+}
+
+/// Get the ID of the process that owns the specified thread
+static ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle) {
+ LOG_TRACE(Kernel_SVC, "called thread=0x%08X", thread_handle);
+
+ const SharedPtr<Kernel::Thread> thread = Kernel::g_handle_table.Get<Kernel::Thread>(thread_handle);
+ if (thread == nullptr)
+ return ERR_INVALID_HANDLE;
+
+ const SharedPtr<Kernel::Process> process = thread->owner_process;
+
+ ASSERT_MSG(process != nullptr, "Invalid parent process for thread=0x%08X", thread_handle);
+
+ *process_id = process->process_id;
return RESULT_SUCCESS;
}
@@ -428,6 +488,9 @@ static ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count)
return ERR_INVALID_HANDLE;
CASCADE_RESULT(*count, semaphore->Release(release_count));
+
+ HLE::Reschedule(__func__);
+
return RESULT_SUCCESS;
}
@@ -520,6 +583,9 @@ static ResultCode SetTimer(Handle handle, s64 initial, s64 interval) {
return ERR_INVALID_HANDLE;
timer->Set(initial, interval);
+
+ HLE::Reschedule(__func__);
+
return RESULT_SUCCESS;
}
@@ -534,6 +600,9 @@ static ResultCode CancelTimer(Handle handle) {
return ERR_INVALID_HANDLE;
timer->Cancel();
+
+ HLE::Reschedule(__func__);
+
return RESULT_SUCCESS;
}
@@ -561,14 +630,26 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32
using Kernel::SharedMemory;
// TODO(Subv): Implement this function
- SharedPtr<SharedMemory> shared_memory = SharedMemory::Create();
+ using Kernel::MemoryPermission;
+ SharedPtr<SharedMemory> shared_memory = SharedMemory::Create(size,
+ (MemoryPermission)my_permission, (MemoryPermission)other_permission);
CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory)));
LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr);
return RESULT_SUCCESS;
}
-const HLE::FunctionDef SVC_Table[] = {
+namespace {
+ struct FunctionDef {
+ using Func = void();
+
+ u32 id;
+ Func* func;
+ const char* name;
+ };
+}
+
+static const FunctionDef SVC_Table[] = {
{0x00, nullptr, "Unknown"},
{0x01, HLE::Wrap<ControlMemory>, "ControlMemory"},
{0x02, HLE::Wrap<QueryMemory>, "QueryMemory"},
@@ -622,8 +703,8 @@ const HLE::FunctionDef SVC_Table[] = {
{0x32, HLE::Wrap<SendSyncRequest>, "SendSyncRequest"},
{0x33, nullptr, "OpenProcess"},
{0x34, nullptr, "OpenThread"},
- {0x35, nullptr, "GetProcessId"},
- {0x36, nullptr, "GetProcessIdOfThread"},
+ {0x35, HLE::Wrap<GetProcessId>, "GetProcessId"},
+ {0x36, HLE::Wrap<GetProcessIdOfThread>, "GetProcessIdOfThread"},
{0x37, HLE::Wrap<GetThreadId>, "GetThreadId"},
{0x38, HLE::Wrap<GetResourceLimit>, "GetResourceLimit"},
{0x39, nullptr, "GetResourceLimitLimitValues"},
@@ -697,8 +778,28 @@ const HLE::FunctionDef SVC_Table[] = {
{0x7D, nullptr, "QueryProcessMemory"},
};
-void Register() {
- HLE::RegisterModule("SVC_Table", ARRAY_SIZE(SVC_Table), SVC_Table);
+Common::Profiling::TimingCategory profiler_svc("SVC Calls");
+
+static const FunctionDef* GetSVCInfo(u32 opcode) {
+ u32 func_num = opcode & 0xFFFFFF; // 8 bits
+ if (func_num >= ARRAY_SIZE(SVC_Table)) {
+ LOG_ERROR(Kernel_SVC, "unknown svc=0x%02X", func_num);
+ return nullptr;
+ }
+ return &SVC_Table[func_num];
+}
+
+void CallSVC(u32 opcode) {
+ Common::Profiling::ScopeTimer timer_svc(profiler_svc);
+
+ const FunctionDef *info = GetSVCInfo(opcode);
+ if (info) {
+ if (info->func) {
+ info->func();
+ } else {
+ LOG_ERROR(Kernel_SVC, "unimplemented SVC function %s(..)", info->name);
+ }
+ }
}
} // namespace
diff --git a/src/core/hle/svc.h b/src/core/hle/svc.h
index 5d020a5ba..4389aa73d 100644
--- a/src/core/hle/svc.h
+++ b/src/core/hle/svc.h
@@ -41,6 +41,6 @@ enum ArbitrationType {
namespace SVC {
-void Register();
+void CallSVC(u32 opcode);
} // namespace