From daf7a7880a9e3b84c340aaf690310fb68e287372 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Fri, 9 May 2014 20:54:51 -0400
Subject: added kernel logger to common
---
src/common/log.h | 4 +++-
src/common/log_manager.cpp | 4 ++--
2 files changed, 5 insertions(+), 3 deletions(-)
(limited to 'src')
diff --git a/src/common/log.h b/src/common/log.h
index d95f51f56..8b39b03a1 100644
--- a/src/common/log.h
+++ b/src/common/log.h
@@ -5,6 +5,8 @@
#ifndef _LOG_H_
#define _LOG_H_
+#define LOGGING
+
#define NOTICE_LEVEL 1 // VERY important information that is NOT errors. Like startup and OSReports.
#define ERROR_LEVEL 2 // Critical errors
#define WARNING_LEVEL 3 // Something is suspicious.
@@ -53,7 +55,7 @@ enum LOG_TYPE {
WII_IPC_ES,
WII_IPC_FILEIO,
WII_IPC_HID,
- WII_IPC_HLE,
+ KERNEL,
SVC,
NDMA,
HLE,
diff --git a/src/common/log_manager.cpp b/src/common/log_manager.cpp
index 80fd473b9..146472888 100644
--- a/src/common/log_manager.cpp
+++ b/src/common/log_manager.cpp
@@ -60,13 +60,13 @@ LogManager::LogManager()
m_Log[LogTypes::LOADER] = new LogContainer("Loader", "Loader");
m_Log[LogTypes::FILESYS] = new LogContainer("FileSys", "File System");
m_Log[LogTypes::WII_IPC_HID] = new LogContainer("WII_IPC_HID", "WII IPC HID");
- m_Log[LogTypes::WII_IPC_HLE] = new LogContainer("WII_IPC_HLE", "WII IPC HLE");
+ m_Log[LogTypes::KERNEL] = new LogContainer("KERNEL", "KERNEL HLE");
m_Log[LogTypes::WII_IPC_DVD] = new LogContainer("WII_IPC_DVD", "WII IPC DVD");
m_Log[LogTypes::WII_IPC_ES] = new LogContainer("WII_IPC_ES", "WII IPC ES");
m_Log[LogTypes::WII_IPC_FILEIO] = new LogContainer("WII_IPC_FILEIO", "WII IPC FILEIO");
m_Log[LogTypes::RENDER] = new LogContainer("RENDER", "RENDER");
m_Log[LogTypes::LCD] = new LogContainer("LCD", "LCD");
- m_Log[LogTypes::SVC] = new LogContainer("SVC", "Supervisor Call");
+ m_Log[LogTypes::SVC] = new LogContainer("SVC", "Supervisor Call HLE");
m_Log[LogTypes::NDMA] = new LogContainer("NDMA", "NDMA");
m_Log[LogTypes::HLE] = new LogContainer("HLE", "High Level Emulation");
m_Log[LogTypes::HW] = new LogContainer("HW", "Hardware");
--
cgit v1.2.3
From 6b264518a50ce21cb1be55ff3eac4e1c85582cfe Mon Sep 17 00:00:00 2001
From: bunnei
Date: Fri, 9 May 2014 22:11:18 -0400
Subject: added initial kernel/thread modules
---
src/core/CMakeLists.txt | 2 +
src/core/core.vcxproj | 4 +
src/core/core.vcxproj.filters | 15 +++
src/core/hle/kernel/kernel.cpp | 142 +++++++++++++++++++++++++
src/core/hle/kernel/kernel.h | 121 ++++++++++++++++++++++
src/core/hle/kernel/thread.cpp | 228 +++++++++++++++++++++++++++++++++++++++++
src/core/hle/kernel/thread.h | 36 +++++++
7 files changed, 548 insertions(+)
create mode 100644 src/core/hle/kernel/kernel.cpp
create mode 100644 src/core/hle/kernel/kernel.h
create mode 100644 src/core/hle/kernel/thread.cpp
create mode 100644 src/core/hle/kernel/thread.h
(limited to 'src')
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index eb4fef381..3fa5f51f1 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -22,6 +22,8 @@ set(SRCS core.cpp
hle/config_mem.cpp
hle/coprocessor.cpp
hle/syscall.cpp
+ hle/kernel/kernel.cpp
+ hle/kernel/thread.cpp
hle/service/apt.cpp
hle/service/gsp.cpp
hle/service/hid.cpp
diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj
index b56661e48..59fc6f4fc 100644
--- a/src/core/core.vcxproj
+++ b/src/core/core.vcxproj
@@ -156,6 +156,8 @@
+
+
@@ -198,6 +200,8 @@
+
+
diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters
index 5c947ec23..ff988c116 100644
--- a/src/core/core.vcxproj.filters
+++ b/src/core/core.vcxproj.filters
@@ -28,6 +28,9 @@
{812c5189-ca49-4704-b842-3ffad09092d3}
+
+ {f2b132eb-caff-4b04-aaae-88d24393a711}
+
@@ -114,6 +117,12 @@
hle
+
+ hle\kernel
+
+
+ hle\kernel
+
@@ -223,6 +232,12 @@
hle
+
+ hle\kernel
+
+
+ hle\kernel
+
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
new file mode 100644
index 000000000..fc494fe30
--- /dev/null
+++ b/src/core/hle/kernel/kernel.cpp
@@ -0,0 +1,142 @@
+// Copyright 2014 Citra Emulator Project / PPSSPP Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include
+
+#include "common/common.h"
+
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/thread.h"
+
+KernelObjectPool g_kernel_objects;
+
+void __KernelInit() {
+ __KernelThreadingInit();
+}
+
+void __KernelShutdown() {
+ __KernelThreadingShutdown();
+}
+
+KernelObjectPool::KernelObjectPool() {
+ memset(occupied, 0, sizeof(bool) * MAX_COUNT);
+ next_id = INITIAL_NEXT_ID;
+}
+
+UID KernelObjectPool::Create(KernelObject *obj, int range_bottom, int range_top) {
+ if (range_top > MAX_COUNT) {
+ range_top = MAX_COUNT;
+ }
+ if (next_id >= range_bottom && next_id < range_top) {
+ range_bottom = next_id++;
+ }
+ for (int i = range_bottom; i < range_top; i++) {
+ if (!occupied[i]) {
+ occupied[i] = true;
+ pool[i] = obj;
+ pool[i]->uid = i + HANDLE_OFFSET;
+ return i + HANDLE_OFFSET;
+ }
+ }
+ ERROR_LOG(HLE, "Unable to allocate kernel object, too many objects slots in use.");
+ return 0;
+}
+
+bool KernelObjectPool::IsValid(UID handle)
+{
+ int index = handle - HANDLE_OFFSET;
+ if (index < 0)
+ return false;
+ if (index >= MAX_COUNT)
+ return false;
+
+ return occupied[index];
+}
+
+void KernelObjectPool::Clear()
+{
+ for (int i = 0; i < MAX_COUNT; i++)
+ {
+ //brutally clear everything, no validation
+ if (occupied[i])
+ delete pool[i];
+ occupied[i] = false;
+ }
+ memset(pool, 0, sizeof(KernelObject*)*MAX_COUNT);
+ next_id = INITIAL_NEXT_ID;
+}
+
+KernelObject *&KernelObjectPool::operator [](UID handle)
+{
+ _dbg_assert_msg_(KERNEL, IsValid(handle), "GRABBING UNALLOCED KERNEL OBJ");
+ return pool[handle - HANDLE_OFFSET];
+}
+
+void KernelObjectPool::List() {
+ for (int i = 0; i < MAX_COUNT; i++) {
+ if (occupied[i]) {
+ if (pool[i]) {
+ INFO_LOG(KERNEL, "KO %i: %s \"%s\"", i + HANDLE_OFFSET, pool[i]->GetTypeName(),
+ pool[i]->GetName());
+ }
+ }
+ }
+}
+
+int KernelObjectPool::GetCount()
+{
+ int count = 0;
+ for (int i = 0; i < MAX_COUNT; i++)
+ {
+ if (occupied[i])
+ count++;
+ }
+ return count;
+}
+
+KernelObject *KernelObjectPool::CreateByIDType(int type) {
+ // Used for save states. This is ugly, but what other way is there?
+ switch (type) {
+ //case SCE_KERNEL_TMID_Alarm:
+ // return __KernelAlarmObject();
+ //case SCE_KERNEL_TMID_EventFlag:
+ // return __KernelEventFlagObject();
+ //case SCE_KERNEL_TMID_Mbox:
+ // return __KernelMbxObject();
+ //case SCE_KERNEL_TMID_Fpl:
+ // return __KernelMemoryFPLObject();
+ //case SCE_KERNEL_TMID_Vpl:
+ // return __KernelMemoryVPLObject();
+ //case PPSSPP_KERNEL_TMID_PMB:
+ // return __KernelMemoryPMBObject();
+ //case PPSSPP_KERNEL_TMID_Module:
+ // return __KernelModuleObject();
+ //case SCE_KERNEL_TMID_Mpipe:
+ // return __KernelMsgPipeObject();
+ //case SCE_KERNEL_TMID_Mutex:
+ // return __KernelMutexObject();
+ //case SCE_KERNEL_TMID_LwMutex:
+ // return __KernelLwMutexObject();
+ //case SCE_KERNEL_TMID_Semaphore:
+ // return __KernelSemaphoreObject();
+ //case SCE_KERNEL_TMID_Callback:
+ // return __KernelCallbackObject();
+ //case SCE_KERNEL_TMID_Thread:
+ // return __KernelThreadObject();
+ //case SCE_KERNEL_TMID_VTimer:
+ // return __KernelVTimerObject();
+ //case SCE_KERNEL_TMID_Tlspl:
+ // return __KernelTlsplObject();
+ //case PPSSPP_KERNEL_TMID_File:
+ // return __KernelFileNodeObject();
+ //case PPSSPP_KERNEL_TMID_DirList:
+ // return __KernelDirListingObject();
+
+ default:
+ ERROR_LOG(COMMON, "Unable to load state: could not find object type %d.", type);
+ return NULL;
+ }
+}
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
new file mode 100644
index 000000000..2381ca7f7
--- /dev/null
+++ b/src/core/hle/kernel/kernel.h
@@ -0,0 +1,121 @@
+// Copyright 2014 Citra Emulator Project / PPSSPP Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+
+typedef u32 UID;
+
+class KernelObjectPool;
+
+class KernelObject {
+ friend class KernelObjectPool;
+ u32 uid;
+public:
+ virtual ~KernelObject() {}
+ UID GetUID() const { return uid; }
+ virtual const char *GetTypeName() { return "[BAD KERNEL OBJECT TYPE]"; }
+ virtual const char *GetName() { return "[UNKNOWN KERNEL OBJECT]"; }
+ virtual int GetIDType() const = 0;
+ //virtual void GetQuickInfo(char *ptr, int size);
+};
+
+class KernelObjectPool {
+public:
+ KernelObjectPool();
+ ~KernelObjectPool() {}
+
+ // Allocates a UID within the range and inserts the object into the map.
+ UID Create(KernelObject *obj, int range_bottom=INITIAL_NEXT_ID, int range_top=0x7FFFFFFF);
+
+ static KernelObject *CreateByIDType(int type);
+
+ template
+ u32 Destroy(UID handle) {
+ u32 error;
+ if (Get(handle, error)) {
+ occupied[handle - handleOffset] = false;
+ delete pool[handle - handleOffset];
+ }
+ return error;
+ };
+
+ bool IsValid(UID handle);
+
+ template
+ T* Get(UID handle, u32& outError) {
+ if (handle < handleOffset || handle >= handleOffset + maxCount || !occupied[handle - handleOffset]) {
+ // Tekken 6 spams 0x80020001 gets wrong with no ill effects, also on the real PSP
+ if (handle != 0 && (u32)handle != 0x80020001) {
+ WARN_LOG(SCEKERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle);
+ }
+ outError = T::GetMissingErrorCode();
+ return 0;
+ } else {
+ // Previously we had a dynamic_cast here, but since RTTI was disabled traditionally,
+ // it just acted as a static case and everything worked. This means that we will never
+ // see the Wrong type object error below, but we'll just have to live with that danger.
+ T* t = static_cast(pool[handle - handleOffset]);
+ if (t == 0 || t->GetIDType() != T::GetStaticIDType()) {
+ WARN_LOG(SCEKERNEL, "Kernel: Wrong object type for %i (%08x)", handle, handle);
+ outError = T::GetMissingErrorCode();
+ return 0;
+ }
+ outError = SCE_KERNEL_ERROR_OK;
+ return t;
+ }
+ }
+
+ // ONLY use this when you know the handle is valid.
+ template
+ T *GetFast(UID handle) {
+ const UID realHandle = handle - handleOffset;
+ _dbg_assert_(SCEKERNEL, realHandle >= 0 && realHandle < maxCount && occupied[realHandle]);
+ return static_cast(pool[realHandle]);
+ }
+
+ template
+ void Iterate(bool func(T *, ArgT), ArgT arg) {
+ int type = T::GetStaticIDType();
+ for (int i = 0; i < maxCount; i++)
+ {
+ if (!occupied[i])
+ continue;
+ T *t = static_cast(pool[i]);
+ if (t->GetIDType() == type) {
+ if (!func(t, arg))
+ break;
+ }
+ }
+ }
+
+ bool GetIDType(UID handle, int *type) const {
+ if ((handle < HANDLE_OFFSET) || (handle >= HANDLE_OFFSET + MAX_COUNT) ||
+ !occupied[handle - HANDLE_OFFSET]) {
+ ERROR_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle);
+ return false;
+ }
+ KernelObject *t = pool[handle - HANDLE_OFFSET];
+ *type = t->GetIDType();
+ return true;
+ }
+
+ KernelObject *&operator [](UID handle);
+ void List();
+ void Clear();
+ int GetCount();
+
+private:
+ enum {
+ MAX_COUNT = 0x1000,
+ HANDLE_OFFSET = 0x100,
+ INITIAL_NEXT_ID = 0x10,
+ };
+ KernelObject *pool[MAX_COUNT];
+ bool occupied[MAX_COUNT];
+ int next_id;
+};
+
+extern KernelObjectPool g_kernel_objects;
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
new file mode 100644
index 000000000..0ed35de83
--- /dev/null
+++ b/src/core/hle/kernel/thread.cpp
@@ -0,0 +1,228 @@
+// Copyright 2014 Citra Emulator Project / PPSSPP Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include
+
+#include
+#include
+#include
diff --git a/src/common/thread_queue_list.h b/src/common/thread_queue_list.h
new file mode 100644
index 000000000..4a89572f6
--- /dev/null
+++ b/src/common/thread_queue_list.h
@@ -0,0 +1,216 @@
+// Copyright 2014 Citra Emulator Project / PPSSPP Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common.h"
+
+namespace Common {
+
+template
+struct ThreadQueueList {
+ // Number of queues (number of priority levels starting at 0.)
+ static const int NUM_QUEUES = 128;
+
+ // Initial number of threads a single queue can handle.
+ static const int INITIAL_CAPACITY = 32;
+
+ struct Queue {
+ // Next ever-been-used queue (worse priority.)
+ Queue *next;
+ // First valid item in data.
+ int first;
+ // One after last valid item in data.
+ int end;
+ // A too-large array with room on the front and end.
+ IdType *data;
+ // Size of data array.
+ int capacity;
+ };
+
+ ThreadQueueList() {
+ memset(queues, 0, sizeof(queues));
+ first = invalid();
+ }
+
+ ~ThreadQueueList() {
+ for (int i = 0; i < NUM_QUEUES; ++i)
+ {
+ if (queues[i].data != NULL)
+ free(queues[i].data);
+ }
+ }
+
+ // Only for debugging, returns priority level.
+ int contains(const IdType uid) {
+ for (int i = 0; i < NUM_QUEUES; ++i)
+ {
+ if (queues[i].data == NULL)
+ continue;
+
+ Queue *cur = &queues[i];
+ for (int j = cur->first; j < cur->end; ++j)
+ {
+ if (cur->data[j] == uid)
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ inline IdType pop_first() {
+ Queue *cur = first;
+ while (cur != invalid())
+ {
+ if (cur->end - cur->first > 0)
+ return cur->data[cur->first++];
+ cur = cur->next;
+ }
+
+ //_dbg_assert_msg_(SCEKERNEL, false, "ThreadQueueList should not be empty.");
+ return 0;
+ }
+
+ inline IdType pop_first_better(u32 priority) {
+ Queue *cur = first;
+ Queue *stop = &queues[priority];
+ while (cur < stop)
+ {
+ if (cur->end - cur->first > 0)
+ return cur->data[cur->first++];
+ cur = cur->next;
+ }
+
+ return 0;
+ }
+
+ inline void push_front(u32 priority, const IdType threadID) {
+ Queue *cur = &queues[priority];
+ cur->data[--cur->first] = threadID;
+ if (cur->first == 0)
+ rebalance(priority);
+ }
+
+ inline void push_back(u32 priority, const IdType threadID) {
+ Queue *cur = &queues[priority];
+ cur->data[cur->end++] = threadID;
+ if (cur->end == cur->capacity)
+ rebalance(priority);
+ }
+
+ inline void remove(u32 priority, const IdType threadID) {
+ Queue *cur = &queues[priority];
+ //_dbg_assert_msg_(SCEKERNEL, cur->next != NULL, "ThreadQueueList::Queue should already be linked up.");
+
+ for (int i = cur->first; i < cur->end; ++i)
+ {
+ if (cur->data[i] == threadID)
+ {
+ int remaining = --cur->end - i;
+ if (remaining > 0)
+ memmove(&cur->data[i], &cur->data[i + 1], remaining * sizeof(IdType));
+ return;
+ }
+ }
+
+ // Wasn't there.
+ }
+
+ inline void rotate(u32 priority) {
+ Queue *cur = &queues[priority];
+ //_dbg_assert_msg_(SCEKERNEL, cur->next != NULL, "ThreadQueueList::Queue should already be linked up.");
+
+ if (cur->end - cur->first > 1)
+ {
+ cur->data[cur->end++] = cur->data[cur->first++];
+ if (cur->end == cur->capacity)
+ rebalance(priority);
+ }
+ }
+
+ inline void clear() {
+ for (int i = 0; i < NUM_QUEUES; ++i)
+ {
+ if (queues[i].data != NULL)
+ free(queues[i].data);
+ }
+ memset(queues, 0, sizeof(queues));
+ first = invalid();
+ }
+
+ inline bool empty(u32 priority) const {
+ const Queue *cur = &queues[priority];
+ return cur->first == cur->end;
+ }
+
+ inline void prepare(u32 priority) {
+ Queue *cur = &queues[priority];
+ if (cur->next == NULL)
+ link(priority, INITIAL_CAPACITY);
+ }
+
+private:
+ Queue *invalid() const {
+ return (Queue *) -1;
+ }
+
+ void link(u32 priority, int size) {
+ //_dbg_assert_msg_(SCEKERNEL, queues[priority].data == NULL, "ThreadQueueList::Queue should only be initialized once.");
+
+ if (size <= INITIAL_CAPACITY)
+ size = INITIAL_CAPACITY;
+ else
+ {
+ int goal = size;
+ size = INITIAL_CAPACITY;
+ while (size < goal)
+ size *= 2;
+ }
+ Queue *cur = &queues[priority];
+ cur->data = (IdType *) malloc(sizeof(IdType) * size);
+ cur->capacity = size;
+ cur->first = size / 2;
+ cur->end = size / 2;
+
+ for (int i = (int) priority - 1; i >= 0; --i)
+ {
+ if (queues[i].next != NULL)
+ {
+ cur->next = queues[i].next;
+ queues[i].next = cur;
+ return;
+ }
+ }
+
+ cur->next = first;
+ first = cur;
+ }
+
+ void rebalance(u32 priority) {
+ Queue *cur = &queues[priority];
+ int size = cur->end - cur->first;
+ if (size >= cur->capacity - 2) {
+ IdType *new_data = (IdType *)realloc(cur->data, cur->capacity * 2 * sizeof(IdType));
+ if (new_data != NULL) {
+ cur->capacity *= 2;
+ cur->data = new_data;
+ }
+ }
+
+ int newFirst = (cur->capacity - size) / 2;
+ if (newFirst != cur->first) {
+ memmove(&cur->data[newFirst], &cur->data[cur->first], size * sizeof(IdType));
+ cur->first = newFirst;
+ cur->end = newFirst + size;
+ }
+ }
+
+ // The first queue that's ever been used.
+ Queue *first;
+ // The priority level queues of thread ids.
+ Queue queues[NUM_QUEUES];
+};
+
+} // namespace
--
cgit v1.2.3
From 367d63691fe810c83979fee04b181338f96cfb50 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Thu, 15 May 2014 18:25:56 -0400
Subject: - added ThreadContext struct
- cleaned up CreateThread svc
---
src/core/hle/syscall.cpp | 20 ++++++++++++--------
src/core/hle/syscall.h | 14 ++++++++++++++
2 files changed, 26 insertions(+), 8 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/syscall.cpp b/src/core/hle/syscall.cpp
index c697bc277..0700d9e82 100644
--- a/src/core/hle/syscall.cpp
+++ b/src/core/hle/syscall.cpp
@@ -9,6 +9,7 @@
#include "core/hle/function_wrappers.h"
#include "core/hle/syscall.h"
#include "core/hle/service/service.h"
+#include "core/hle/kernel/thread.h"
#include "common/symbols.h"
@@ -139,16 +140,19 @@ Result GetResourceLimitCurrentValues(void* _values, Handle resource_limit, void*
return 0;
}
-Result CreateThread(void* thread, u32 threadpriority, u32 entrypoint, u32 arg, u32 stacktop, u32 processorid) {
- std::string symbol_name = "unknown";
- if (Symbols::HasSymbol(entrypoint)) {
- TSymbol symbol = Symbols::GetSymbol(entrypoint);
- symbol_name = symbol.name;
+Result CreateThread(void* thread, u32 thread_priority, u32 entry_point, u32 arg, u32 stack_top, u32 processor_id) {
+ std::string thread_name;
+ if (Symbols::HasSymbol(entry_point)) {
+ TSymbol symbol = Symbols::GetSymbol(entry_point);
+ thread_name = symbol.name;
+ } else {
+ char buff[100];
+ sprintf(buff, "%s", "unk-%08X", entry_point);
+ thread_name = buff;
}
- // stack top: 0x0056A4A0
DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateThread called entrypoint=0x%08X (%s), arg=0x%08X, "
- "stacktop=0x%08X, threadpriority=0x%08X, processorid=0x%08X", entrypoint,
- symbol_name.c_str(), arg, stacktop, threadpriority, processorid);
+ "stacktop=0x%08X, threadpriority=0x%08X, processorid=0x%08X", entry_point,
+ thread_name.c_str(), arg, stack_top, thread_priority, processor_id);
return 0;
}
diff --git a/src/core/hle/syscall.h b/src/core/hle/syscall.h
index 7a94e0136..15af5e138 100644
--- a/src/core/hle/syscall.h
+++ b/src/core/hle/syscall.h
@@ -6,6 +6,20 @@
#include "common/common_types.h"
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// SVC structures
+
+struct ThreadContext {
+ u32 cpu_registers[13];
+ u32 sp;
+ u32 lr;
+ u32 pc;
+ u32 cpsr;
+ u32 fpu_registers[32];
+ u32 fpscr;
+ u32 fpexc;
+};
+
////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace Syscall
--
cgit v1.2.3
From a7cc430aa4da2962dcf08db2f6009fc272bdda70 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Thu, 15 May 2014 18:26:28 -0400
Subject: changed "UID" to "Handle" to be a little more consistent with CTR
naming
---
src/core/hle/kernel/kernel.cpp | 10 +++++-----
src/core/hle/kernel/kernel.h | 29 ++++++++++++++++-------------
2 files changed, 21 insertions(+), 18 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 1c26fb388..f7145ddd8 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -27,7 +27,7 @@ KernelObjectPool::KernelObjectPool() {
next_id = INITIAL_NEXT_ID;
}
-UID KernelObjectPool::Create(KernelObject *obj, int range_bottom, int range_top) {
+Handle KernelObjectPool::Create(KernelObject *obj, int range_bottom, int range_top) {
if (range_top > MAX_COUNT) {
range_top = MAX_COUNT;
}
@@ -38,7 +38,7 @@ UID KernelObjectPool::Create(KernelObject *obj, int range_bottom, int range_top)
if (!occupied[i]) {
occupied[i] = true;
pool[i] = obj;
- pool[i]->uid = i + HANDLE_OFFSET;
+ pool[i]->handle = i + HANDLE_OFFSET;
return i + HANDLE_OFFSET;
}
}
@@ -46,7 +46,7 @@ UID KernelObjectPool::Create(KernelObject *obj, int range_bottom, int range_top)
return 0;
}
-bool KernelObjectPool::IsValid(UID handle)
+bool KernelObjectPool::IsValid(Handle handle)
{
int index = handle - HANDLE_OFFSET;
if (index < 0)
@@ -70,7 +70,7 @@ void KernelObjectPool::Clear()
next_id = INITIAL_NEXT_ID;
}
-KernelObject *&KernelObjectPool::operator [](UID handle)
+KernelObject *&KernelObjectPool::operator [](Handle handle)
{
_dbg_assert_msg_(KERNEL, IsValid(handle), "GRABBING UNALLOCED KERNEL OBJ");
return pool[handle - HANDLE_OFFSET];
@@ -148,7 +148,7 @@ bool __KernelLoadExec(u32 entry_point) {
Core::g_app_core->SetPC(entry_point);
// 0x30 is the typical main thread priority I've seen used so far
- UID thread_id = __KernelSetupRootThread(0xDEADBEEF, 0, 0x30);
+ Handle thread_id = __KernelSetupMainThread(0x30);
return true;
}
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 0eb58210c..24d422682 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -6,7 +6,7 @@
#include "common/common_types.h"
-typedef u32 UID;
+typedef s32 Handle;
enum KernelIDType {
KERNEL_ID_TYPE_THREAD = 1,
@@ -15,20 +15,23 @@ enum KernelIDType {
KERNEL_ID_TYPE_EVENT = 4,
};
+enum {
+ KERNELOBJECT_MAX_NAME_LENGTH = 255,
+};
+
#define KERNELOBJECT_MAX_NAME_LENGTH 31
class KernelObjectPool;
class KernelObject {
friend class KernelObjectPool;
- u32 uid;
+ u32 handle;
public:
virtual ~KernelObject() {}
- UID GetUID() const { return uid; }
+ Handle GetHandle() const { return handle; }
virtual const char *GetTypeName() { return "[BAD KERNEL OBJECT TYPE]"; }
virtual const char *GetName() { return "[UNKNOWN KERNEL OBJECT]"; }
virtual KernelIDType GetIDType() const = 0;
- //virtual void GetQuickInfo(char *ptr, int size);
};
class KernelObjectPool {
@@ -36,13 +39,13 @@ public:
KernelObjectPool();
~KernelObjectPool() {}
- // Allocates a UID within the range and inserts the object into the map.
- UID Create(KernelObject *obj, int range_bottom=INITIAL_NEXT_ID, int range_top=0x7FFFFFFF);
+ // Allocates a handle within the range and inserts the object into the map.
+ Handle Create(KernelObject *obj, int range_bottom=INITIAL_NEXT_ID, int range_top=0x7FFFFFFF);
static KernelObject *CreateByIDType(int type);
template
- u32 Destroy(UID handle) {
+ u32 Destroy(Handle handle) {
u32 error;
if (Get(handle, error)) {
occupied[handle - HANDLE_OFFSET] = false;
@@ -51,10 +54,10 @@ public:
return error;
};
- bool IsValid(UID handle);
+ bool IsValid(Handle handle);
template
- T* Get(UID handle, u32& outError) {
+ T* Get(Handle handle, u32& outError) {
if (handle < HANDLE_OFFSET || handle >= HANDLE_OFFSET + MAX_COUNT || !occupied[handle - HANDLE_OFFSET]) {
// Tekken 6 spams 0x80020001 gets wrong with no ill effects, also on the real PSP
if (handle != 0 && (u32)handle != 0x80020001) {
@@ -79,8 +82,8 @@ public:
// ONLY use this when you know the handle is valid.
template
- T *GetFast(UID handle) {
- const UID realHandle = handle - HANDLE_OFFSET;
+ T *GetFast(Handle handle) {
+ const Handle realHandle = handle - HANDLE_OFFSET;
_dbg_assert_(KERNEL, realHandle >= 0 && realHandle < MAX_COUNT && occupied[realHandle]);
return static_cast(pool[realHandle]);
}
@@ -100,7 +103,7 @@ public:
}
}
- bool GetIDType(UID handle, int *type) const {
+ bool GetIDType(Handle handle, int *type) const {
if ((handle < HANDLE_OFFSET) || (handle >= HANDLE_OFFSET + MAX_COUNT) ||
!occupied[handle - HANDLE_OFFSET]) {
ERROR_LOG(KERNEL, "Kernel: Bad object handle %i (%08x)", handle, handle);
@@ -111,7 +114,7 @@ public:
return true;
}
- KernelObject *&operator [](UID handle);
+ KernelObject *&operator [](Handle handle);
void List();
void Clear();
int GetCount();
--
cgit v1.2.3
From 940330c6e12b3eefb9fb035f75f4b090c969cb75 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Thu, 15 May 2014 18:27:08 -0400
Subject: completely gutted/refactored threading code to be simpler
---
src/core/hle/kernel/thread.cpp | 844 +++++++++++------------------------------
src/core/hle/kernel/thread.h | 44 +--
2 files changed, 230 insertions(+), 658 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index b6d02aa12..833a1b4ba 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -10,6 +10,7 @@
#include
#include "common/common.h"
+#include "common/thread_queue_list.h"
#include "core/core.h"
#include "core/mem_map.h"
@@ -18,698 +19,309 @@
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/thread.h"
-struct ThreadQueueList {
- // Number of queues (number of priority levels starting at 0.)
- static const int NUM_QUEUES = 128;
- // Initial number of threads a single queue can handle.
- static const int INITIAL_CAPACITY = 32;
-
- struct Queue {
- // Next ever-been-used queue (worse priority.)
- Queue *next;
- // First valid item in data.
- int first;
- // One after last valid item in data.
- int end;
- // A too-large array with room on the front and end.
- UID *data;
- // Size of data array.
- int capacity;
- };
-
- ThreadQueueList() {
- memset(queues, 0, sizeof(queues));
- first = invalid();
- }
-
- ~ThreadQueueList() {
- for (int i = 0; i < NUM_QUEUES; ++i) {
- if (queues[i].data != NULL) {
- free(queues[i].data);
- }
- }
- }
-
- // Only for debugging, returns priority level.
- int contains(const UID uid) {
- for (int i = 0; i < NUM_QUEUES; ++i) {
- if (queues[i].data == NULL) {
- continue;
- }
- Queue *cur = &queues[i];
- for (int j = cur->first; j < cur->end; ++j) {
- if (cur->data[j] == uid) {
- return i;
- }
- }
- }
- return -1;
- }
-
- inline UID pop_first() {
- Queue *cur = first;
- while (cur != invalid()) {
- if (cur->end - cur->first > 0) {
- return cur->data[cur->first++];
- }
- cur = cur->next;
- }
-
- _dbg_assert_msg_(KERNEL, false, "ThreadQueueList should not be empty.");
- return 0;
- }
-
- inline UID pop_first_better(u32 priority) {
- Queue *cur = first;
- Queue *stop = &queues[priority];
- while (cur < stop) {
- if (cur->end - cur->first > 0) {
- return cur->data[cur->first++];
- }
- cur = cur->next;
- }
- return 0;
- }
-
- inline void push_front(u32 priority, const UID thread_id) {
- Queue *cur = &queues[priority];
- cur->data[--cur->first] = thread_id;
- if (cur->first == 0) {
- rebalance(priority);
- }
- }
-
- inline void push_back(u32 priority, const UID thread_id)
- {
- Queue *cur = &queues[priority];
- cur->data[cur->end++] = thread_id;
- if (cur->end == cur->capacity) {
- rebalance(priority);
- }
- }
-
- inline void remove(u32 priority, const UID thread_id) {
- Queue *cur = &queues[priority];
- _dbg_assert_msg_(KERNEL, cur->next != NULL, "ThreadQueueList::Queue should already be linked up.");
-
- for (int i = cur->first; i < cur->end; ++i) {
- if (cur->data[i] == thread_id) {
- int remaining = --cur->end - i;
- if (remaining > 0) {
- memmove(&cur->data[i], &cur->data[i + 1], remaining * sizeof(UID));
- }
- return;
- }
- }
-
- // Wasn't there.
- }
-
- inline void rotate(u32 priority) {
- Queue *cur = &queues[priority];
- _dbg_assert_msg_(KERNEL, cur->next != NULL, "ThreadQueueList::Queue should already be linked up.");
-
- if (cur->end - cur->first > 1) {
- cur->data[cur->end++] = cur->data[cur->first++];
- if (cur->end == cur->capacity) {
- rebalance(priority);
- }
- }
- }
-
- inline void clear() {
- for (int i = 0; i < NUM_QUEUES; ++i) {
- if (queues[i].data != NULL) {
- free(queues[i].data);
- }
- }
- memset(queues, 0, sizeof(queues));
- first = invalid();
- }
-
- inline bool empty(u32 priority) const {
- const Queue *cur = &queues[priority];
- return cur->first == cur->end;
- }
-
- inline void prepare(u32 priority) {
- Queue *cur = &queues[priority];
- if (cur->next == NULL) {
- link(priority, INITIAL_CAPACITY);
- }
- }
-
-private:
- Queue *invalid() const {
- return (Queue *)-1;
- }
-
- void link(u32 priority, int size) {
- _dbg_assert_msg_(KERNEL, queues[priority].data == NULL, "ThreadQueueList::Queue should only be initialized once.");
-
- if (size <= INITIAL_CAPACITY) {
- size = INITIAL_CAPACITY;
- } else {
- int goal = size;
- size = INITIAL_CAPACITY;
- while (size < goal)
- size *= 2;
- }
- Queue *cur = &queues[priority];
- cur->data = (UID*)malloc(sizeof(UID)* size);
- cur->capacity = size;
- cur->first = size / 2;
- cur->end = size / 2;
-
- for (int i = (int)priority - 1; i >= 0; --i) {
- if (queues[i].next != NULL) {
- cur->next = queues[i].next;
- queues[i].next = cur;
- return;
- }
- }
-
- cur->next = first;
- first = cur;
- }
-
- void rebalance(u32 priority) {
- Queue *cur = &queues[priority];
- int size = cur->end - cur->first;
- if (size >= cur->capacity - 2) {
- UID* new_data = (UID*)realloc(cur->data, cur->capacity * 2 * sizeof(UID));
- if (new_data != NULL) {
- cur->capacity *= 2;
- cur->data = new_data;
- }
- }
+// Enums
- int newFirst = (cur->capacity - size) / 2;
- if (newFirst != cur->first) {
- memmove(&cur->data[newFirst], &cur->data[cur->first], size * sizeof(UID));
- cur->first = newFirst;
- cur->end = newFirst + size;
- }
- }
+enum ThreadPriority {
+ THREADPRIO_HIGHEST = 0,
+ THREADPRIO_DEFAULT = 16,
+ THREADPRIO_LOWEST = 31,
+};
- // The first queue that's ever been used.
- Queue* first;
- // The priority level queues of thread ids.
- Queue queues[NUM_QUEUES];
+enum ThreadStatus {
+ THREADSTATUS_RUNNING = 1,
+ THREADSTATUS_READY = 2,
+ THREADSTATUS_WAIT = 4,
+ THREADSTATUS_SUSPEND = 8,
+ THREADSTATUS_DORMANT = 16,
+ THREADSTATUS_DEAD = 32,
+ THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND
};
-// Supposed to represent a real CTR struct... but not sure of the correct fields yet.
-struct NativeThread {
- //u32 Pointer to vtable
- //u32 Reference count
- //KProcess* Process the thread belongs to (virtual address)
- //u32 Thread id
- //u32* ptr = *(KThread+0x8C) - 0xB0
- //u32* End-address of the page for this thread allocated in the 0xFF4XX000 region. Thus,
- // if the beginning of this mapped page is 0xFF401000, this ptr would be 0xFF402000.
- //KThread* Previous ? (virtual address)
- //KThread* Next ? (virtual address)
-
- u32_le native_size;
- char name[KERNELOBJECT_MAX_NAME_LENGTH + 1];
-
- // Threading stuff
- u32_le status;
- u32_le entry_point;
- u32_le initial_stack;
- u32_le stack_top;
- u32_le stack_size;
+enum WaitType {
+ WAITTYPE_NONE,
+ WAITTYPE_SLEEP,
+ WAITTYPE_SEMA,
+ WAITTYPE_EVENTFLAG,
+ WAITTYPE_THREADEND,
+ WAITTYPE_VBLANK,
+ WAITTYPE_MUTEX,
+ WAITTYPE_SYNCH,
- u32_le arg;
- u32_le processor_id;
-
- s32_le initial_priority;
- s32_le current_priority;
+ NUM_WAITTYPES
};
-struct ThreadWaitInfo {
- u32 wait_value;
- u32 timeout_ptr;
-};
+typedef s32 Handle;
class Thread : public KernelObject {
public:
- /*const char *GetName() { return nt.name; }*/
+
+ const char *GetName() { return name; }
const char *GetTypeName() { return "Thread"; }
- //void GetQuickInfo(char *ptr, int size)
- //{
- // sprintf(ptr, "pc= %08x sp= %08x %s %s %s %s %s %s (wt=%i wid=%i wv= %08x )",
- // context.pc, context.r[13], // 13 is stack pointer
- // (nt.status & THREADSTATUS_RUNNING) ? "RUN" : "",
- // (nt.status & THREADSTATUS_READY) ? "READY" : "",
- // (nt.status & THREADSTATUS_WAIT) ? "WAIT" : "",
- // (nt.status & THREADSTATUS_SUSPEND) ? "SUSPEND" : "",
- // (nt.status & THREADSTATUS_DORMANT) ? "DORMANT" : "",
- // (nt.status & THREADSTATUS_DEAD) ? "DEAD" : "",
- // nt.waitType,
- // nt.waitID,
- // waitInfo.waitValue);
- //}
-
- //static u32 GetMissingErrorCode() { return SCE_KERNEL_ERROR_UNKNOWN_THID; }
+
static KernelIDType GetStaticIDType() { return KERNEL_ID_TYPE_THREAD; }
KernelIDType GetIDType() const { return KERNEL_ID_TYPE_THREAD; }
- bool SetupStack(u32 stack_top, int stack_size) {
- current_stack.start = stack_top;
- nt.initial_stack = current_stack.start;
- nt.stack_size = stack_size;
- return true;
- }
-
- //bool FillStack() {
- // // Fill the stack.
- // if ((nt.attr & PSP_THREAD_ATTR_NO_FILLSTACK) == 0) {
- // Memory::Memset(current_stack.start, 0xFF, nt.stack_size);
- // }
- // context.r[MIPS_REG_SP] = current_stack.start + nt.stack_size;
- // current_stack.end = context.r[MIPS_REG_SP];
- // // The k0 section is 256 bytes at the top of the stack.
- // context.r[MIPS_REG_SP] -= 256;
- // context.r[MIPS_REG_K0] = context.r[MIPS_REG_SP];
- // u32 k0 = context.r[MIPS_REG_K0];
- // Memory::Memset(k0, 0, 0x100);
- // Memory::Write_U32(GetUID(), k0 + 0xc0);
- // Memory::Write_U32(nt.initialStack, k0 + 0xc8);
- // Memory::Write_U32(0xffffffff, k0 + 0xf8);
- // Memory::Write_U32(0xffffffff, k0 + 0xfc);
- // // After k0 comes the arguments, which is done by sceKernelStartThread().
-
- // Memory::Write_U32(GetUID(), nt.initialStack);
- // return true;
- //}
-
- //void FreeStack() {
- // if (current_stack.start != 0) {
- // DEBUG_LOG(KERNEL, "Freeing thread stack %s", nt.name);
-
- // if ((nt.attr & PSP_THREAD_ATTR_CLEAR_STACK) != 0 && nt.initialStack != 0) {
- // Memory::Memset(nt.initialStack, 0, nt.stack_size);
- // }
-
- // if (nt.attr & PSP_THREAD_ATTR_KERNEL) {
- // kernelMemory.Free(current_stack.start);
- // }
- // else {
- // userMemory.Free(current_stack.start);
- // }
- // current_stack.start = 0;
- // }
- //}
-
- //bool PushExtendedStack(u32 size) {
- // u32 stack = userMemory.Alloc(size, true, (std::string("extended/") + nt.name).c_str());
- // if (stack == (u32)-1)
- // return false;
-
- // pushed_stacks.push_back(current_stack);
- // current_stack.start = stack;
- // current_stack.end = stack + size;
- // nt.initialStack = current_stack.start;
- // nt.stack_size = current_stack.end - current_stack.start;
-
- // // We still drop the thread_id at the bottom and fill it, but there's no k0.
- // Memory::Memset(current_stack.start, 0xFF, nt.stack_size);
- // Memory::Write_U32(GetUID(), nt.initialStack);
- // return true;
- //}
-
- //bool PopExtendedStack() {
- // if (pushed_stacks.size() == 0) {
- // return false;
- // }
- // userMemory.Free(current_stack.start);
- // current_stack = pushed_stacks.back();
- // pushed_stacks.pop_back();
- // nt.initialStack = current_stack.start;
- // nt.stack_size = current_stack.end - current_stack.start;
- // return true;
- //}
-
- Thread() {
- current_stack.start = 0;
- }
-
- // Can't use a destructor since savestates will call that too.
- //void Cleanup() {
- // // Callbacks are automatically deleted when their owning thread is deleted.
- // for (auto it = callbacks.begin(), end = callbacks.end(); it != end; ++it)
- // g_kernel_objects.Destroy(*it);
-
- // if (pushed_stacks.size() != 0)
- // {
- // WARN_LOG(KERNEL, "Thread ended within an extended stack");
- // for (size_t i = 0; i < pushed_stacks.size(); ++i)
- // userMemory.Free(pushed_stacks[i].start);
- // }
- // FreeStack();
- //}
-
- void setReturnValue(u32 retval);
- void setReturnValue(u64 retval);
- void resumeFromWait();
- //bool isWaitingFor(WaitType type, int id);
- //int getWaitID(WaitType type);
- ThreadWaitInfo getWaitInfo();
-
- // Utils
- inline bool IsRunning() const { return (nt.status & THREADSTATUS_RUNNING) != 0; }
- inline bool IsStopped() const { return (nt.status & THREADSTATUS_DORMANT) != 0; }
- inline bool IsReady() const { return (nt.status & THREADSTATUS_READY) != 0; }
- inline bool IsWaiting() const { return (nt.status & THREADSTATUS_WAIT) != 0; }
- inline bool IsSuspended() const { return (nt.status & THREADSTATUS_SUSPEND) != 0; }
-
- NativeThread nt;
-
- ThreadWaitInfo waitInfo;
- UID moduleId;
-
- //bool isProcessingCallbacks;
- //u32 currentMipscallId;
- //UID currentCallbackId;
+ inline bool IsRunning() const { return (status & THREADSTATUS_RUNNING) != 0; }
+ inline bool IsStopped() const { return (status & THREADSTATUS_DORMANT) != 0; }
+ inline bool IsReady() const { return (status & THREADSTATUS_READY) != 0; }
+ inline bool IsWaiting() const { return (status & THREADSTATUS_WAIT) != 0; }
+ inline bool IsSuspended() const { return (status & THREADSTATUS_SUSPEND) != 0; }
ThreadContext context;
- std::vector callbacks;
+ u32 status;
+ u32 entry_point;
+ u32 stack_top;
+ u32 stack_size;
- std::list pending_calls;
+ s32 initial_priority;
+ s32 current_priority;
- struct StackInfo {
- u32 start;
- u32 end;
- };
- // This is a stack of... stacks, since sceKernelExtendThreadStack() can recurse.
- // These are stacks that aren't "active" right now, but will pop off once the func returns.
- std::vector pushed_stacks;
+ s32 processor_id;
- StackInfo current_stack;
+ WaitType wait_type;
- // For thread end.
- std::vector waiting_threads;
- // Key is the callback id it was for, or if no callback, the thread id.
- std::map paused_waits;
+ char name[KERNELOBJECT_MAX_NAME_LENGTH+1];
};
-void ThreadContext::reset() {
- for (int i = 0; i < 16; i++) {
- reg[i] = 0;
- }
- cpsr = 0;
-}
-
// Lists all thread ids that aren't deleted/etc.
-std::vector g_thread_queue;
+std::vector g_thread_queue;
-// Lists only ready thread ids
-ThreadQueueList g_thread_ready_queue;
+// Lists only ready thread ids.
+Common::ThreadQueueList g_thread_ready_queue;
-UID g_current_thread = 0;
-Thread* g_current_thread_ptr = NULL;
-const char* g_hle_current_thread_name = NULL;
+Handle g_current_thread_handle;
-/// Creates a new thread
-Thread* __KernelCreateThread(UID& id, UID module_id, const char* name, u32 priority,
- u32 entry_point, u32 arg, u32 stack_top, u32 processor_id, int stack_size) {
+Thread* g_current_thread;
- Thread *t = new Thread;
- id = g_kernel_objects.Create(t);
-
- g_thread_queue.push_back(id);
- g_thread_ready_queue.prepare(priority);
-
- memset(&t->nt, 0xCD, sizeof(t->nt));
- t->nt.entry_point = entry_point;
- t->nt.native_size = sizeof(t->nt);
- t->nt.initial_priority = t->nt.current_priority = priority;
- t->nt.status = THREADSTATUS_DORMANT;
- t->nt.initial_stack = t->nt.stack_top = stack_top;
- t->nt.stack_size = stack_size;
- t->nt.processor_id = processor_id;
+inline Thread *__GetCurrentThread() {
+ return g_current_thread;
+}
- strncpy(t->nt.name, name, KERNELOBJECT_MAX_NAME_LENGTH);
- t->nt.name[KERNELOBJECT_MAX_NAME_LENGTH] = '\0';
+inline void __SetCurrentThread(Thread *t) {
+ g_current_thread = t;
+ g_current_thread_handle = t->GetHandle();
+}
- t->nt.stack_size = stack_size;
- t->SetupStack(stack_top, stack_size);
+////////////////////////////////////////////////////////////////////////////////////////////////////
- return t;
+/// Saves the current CPU context
+void __KernelSaveContext(ThreadContext &ctx) {
+ ctx.cpu_registers[0] = Core::g_app_core->GetReg(0);
+ ctx.cpu_registers[1] = Core::g_app_core->GetReg(1);
+ ctx.cpu_registers[2] = Core::g_app_core->GetReg(2);
+ ctx.cpu_registers[3] = Core::g_app_core->GetReg(3);
+ ctx.cpu_registers[4] = Core::g_app_core->GetReg(4);
+ ctx.cpu_registers[5] = Core::g_app_core->GetReg(5);
+ ctx.cpu_registers[6] = Core::g_app_core->GetReg(6);
+ ctx.cpu_registers[7] = Core::g_app_core->GetReg(7);
+ ctx.cpu_registers[8] = Core::g_app_core->GetReg(8);
+ ctx.cpu_registers[9] = Core::g_app_core->GetReg(9);
+ ctx.cpu_registers[10] = Core::g_app_core->GetReg(10);
+ ctx.cpu_registers[11] = Core::g_app_core->GetReg(11);
+ ctx.cpu_registers[12] = Core::g_app_core->GetReg(12);
+ ctx.sp = Core::g_app_core->GetReg(13);
+ ctx.lr = Core::g_app_core->GetReg(14);
+ ctx.pc = Core::g_app_core->GetPC();
+ ctx.cpsr = Core::g_app_core->GetCPSR();
}
-UID __KernelCreateThread(UID module_id, const char* name, u32 priority, u32 entry_point, u32 arg,
- u32 stack_top, u32 processor_id, int stack_size) {
- UID id;
- __KernelCreateThread(id, module_id, name, priority, entry_point, arg, stack_top, processor_id,
- stack_size);
-
- HLE::EatCycles(32000);
- HLE::ReSchedule("thread created");
-
- return id;
+/// Loads a CPU context
+void __KernelLoadContext(const ThreadContext &ctx) {
+ Core::g_app_core->SetReg(0, ctx.cpu_registers[0]);
+ Core::g_app_core->SetReg(1, ctx.cpu_registers[1]);
+ Core::g_app_core->SetReg(2, ctx.cpu_registers[2]);
+ Core::g_app_core->SetReg(3, ctx.cpu_registers[3]);
+ Core::g_app_core->SetReg(4, ctx.cpu_registers[4]);
+ Core::g_app_core->SetReg(5, ctx.cpu_registers[5]);
+ Core::g_app_core->SetReg(6, ctx.cpu_registers[6]);
+ Core::g_app_core->SetReg(7, ctx.cpu_registers[7]);
+ Core::g_app_core->SetReg(8, ctx.cpu_registers[8]);
+ Core::g_app_core->SetReg(9, ctx.cpu_registers[9]);
+ Core::g_app_core->SetReg(10, ctx.cpu_registers[10]);
+ Core::g_app_core->SetReg(11, ctx.cpu_registers[11]);
+ Core::g_app_core->SetReg(12, ctx.cpu_registers[12]);
+ Core::g_app_core->SetReg(13, ctx.sp);
+ Core::g_app_core->SetReg(14, ctx.lr);
+ //Core::g_app_core->SetReg(15, ctx.pc);
+
+ Core::g_app_core->SetPC(ctx.pc);
+ Core::g_app_core->SetCPSR(ctx.cpsr);
}
-/// Resets the specified thread back to initial calling state
-void __KernelResetThread(Thread *t, int lowest_priority) {
- t->context.reset();
- t->context.pc = t->nt.entry_point;
- t->context.reg[13] = t->nt.initial_stack;
+/// Resets a thread
+void __KernelResetThread(Thread *t, s32 lowest_priority) {
+ memset(&t->context, 0, sizeof(ThreadContext));
- // If the thread would be better than lowestPriority, reset to its initial. Yes, kinda odd...
- if (t->nt.current_priority < lowest_priority) {
- t->nt.current_priority = t->nt.initial_priority;
+ t->context.pc = t->entry_point;
+ t->context.sp = t->stack_top;
+
+ if (t->current_priority < lowest_priority) {
+ t->current_priority = t->initial_priority;
}
-
- memset(&t->waitInfo, 0, sizeof(t->waitInfo));
-}
-
-/// Returns the current executing thread
-inline Thread *__GetCurrentThread() {
- return g_current_thread_ptr;
+
+ t->wait_type = WAITTYPE_NONE;
}
-/// Sets the current executing thread
-inline void __SetCurrentThread(Thread *thread, UID thread_id, const char *name) {
- g_current_thread = thread_id;
- g_current_thread_ptr = thread;
- g_hle_current_thread_name = name;
+/// Creates a new thread
+Thread *__KernelCreateThread(Handle &handle, const char *name, u32 entry_point, s32 priority, s32 processor_id, u32 stack_top, int stack_size=0x4000) {
+ static u32 _handle_count = 1;
+
+ Thread *t = new Thread;
+
+ handle = (_handle_count++);
+
+ g_thread_queue.push_back(handle);
+ g_thread_ready_queue.prepare(priority);
+
+ t->status = THREADSTATUS_DORMANT;
+ t->entry_point = entry_point;
+ t->stack_top = stack_top;
+ t->stack_size = stack_size;
+ t->initial_priority = t->current_priority = priority;
+ t->processor_id = processor_id;
+ t->wait_type = WAITTYPE_NONE;
+
+ strncpy(t->name, name, KERNELOBJECT_MAX_NAME_LENGTH);
+ t->name[KERNELOBJECT_MAX_NAME_LENGTH] = '\0';
+
+ return t;
}
-// TODO: Use __KernelChangeThreadState instead? It has other affects...
-void __KernelChangeReadyState(Thread *thread, UID thread_id, bool ready) {
- // Passing the id as a parameter is just an optimization, if it's wrong it will cause havoc.
- _dbg_assert_msg_(KERNEL, thread->GetUID() == thread_id, "Incorrect thread_id");
- int prio = thread->nt.current_priority;
-
- if (thread->IsReady()) {
- if (!ready)
- g_thread_ready_queue.remove(prio, thread_id);
- } else if (ready) {
- if (thread->IsRunning()) {
- g_thread_ready_queue.push_front(prio, thread_id);
+/// Change a thread to "ready" state
+void __KernelChangeReadyState(Thread *t, bool ready) {
+ Handle handle = t->GetHandle();
+ if (t->IsReady()) {
+ if (!ready) {
+ g_thread_ready_queue.remove(t->current_priority, handle);
+ }
+ } else if (ready) {
+ if (t->IsRunning()) {
+ g_thread_ready_queue.push_front(t->current_priority, handle);
} else {
- g_thread_ready_queue.push_back(prio, thread_id);
+ g_thread_ready_queue.push_back(t->current_priority, handle);
}
- thread->nt.status = THREADSTATUS_READY;
+ t->status = THREADSTATUS_READY;
}
}
-void __KernelChangeReadyState(UID thread_id, bool ready) {
- u32 error;
- Thread *thread = g_kernel_objects.Get(thread_id, error);
- if (thread) {
- __KernelChangeReadyState(thread, thread_id, ready);
- } else {
- WARN_LOG(KERNEL, "Trying to change the ready state of an unknown thread?");
+/// Changes a threads state
+void __KernelChangeThreadState(Thread *t, ThreadStatus new_status) {
+ if (!t || t->status == new_status) {
+ return;
+ }
+ __KernelChangeReadyState(t, (new_status & THREADSTATUS_READY) != 0);
+ t->status = new_status;
+
+ if (new_status == THREADSTATUS_WAIT) {
+ if (t->wait_type == WAITTYPE_NONE) {
+ printf("ERROR: Waittype none not allowed here\n");
+ }
}
}
-/// Returns NULL if the current thread is fine.
-Thread* __KernelNextThread() {
- UID best_thread;
-
- // If the current thread is running, it's a valid candidate.
+/// Switches CPU context to that of the specified thread
+void __KernelSwitchContext(Thread* t, const char *reason) {
Thread *cur = __GetCurrentThread();
- if (cur && cur->IsRunning()) {
- best_thread = g_thread_ready_queue.pop_first_better(cur->nt.current_priority);
- if (best_thread != 0) {
- __KernelChangeReadyState(cur, g_current_thread, true);
+
+ // Save context for current thread
+ if (cur) {
+ __KernelSaveContext(cur->context);
+
+ if (cur->IsRunning()) {
+ __KernelChangeReadyState(cur, true);
}
- } else {
- best_thread = g_thread_ready_queue.pop_first();
}
- // Assume g_thread_ready_queue has not become corrupt.
- if (best_thread != 0) {
- return g_kernel_objects.GetFast(best_thread);
+ // Load context of new thread
+ if (t) {
+ __SetCurrentThread(t);
+ __KernelChangeReadyState(t, false);
+ t->status = (t->status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY;
+ t->wait_type = WAITTYPE_NONE;
+ __KernelLoadContext(t->context);
} else {
- return NULL;
+ __SetCurrentThread(NULL);
}
}
-/// Saves the current CPU context
-void __KernelSaveContext(ThreadContext *ctx) {
- ctx->reg[0] = Core::g_app_core->GetReg(0);
- ctx->reg[1] = Core::g_app_core->GetReg(1);
- ctx->reg[2] = Core::g_app_core->GetReg(2);
- ctx->reg[3] = Core::g_app_core->GetReg(3);
- ctx->reg[4] = Core::g_app_core->GetReg(4);
- ctx->reg[5] = Core::g_app_core->GetReg(5);
- ctx->reg[6] = Core::g_app_core->GetReg(6);
- ctx->reg[7] = Core::g_app_core->GetReg(7);
- ctx->reg[8] = Core::g_app_core->GetReg(8);
- ctx->reg[9] = Core::g_app_core->GetReg(9);
- ctx->reg[10] = Core::g_app_core->GetReg(10);
- ctx->reg[11] = Core::g_app_core->GetReg(11);
- ctx->reg[12] = Core::g_app_core->GetReg(12);
- ctx->reg[13] = Core::g_app_core->GetReg(13);
- ctx->reg[14] = Core::g_app_core->GetReg(14);
- ctx->reg[15] = Core::g_app_core->GetReg(15);
- ctx->pc = Core::g_app_core->GetPC();
- ctx->cpsr = Core::g_app_core->GetCPSR();
-}
-
-/// Loads a CPU context
-void __KernelLoadContext(ThreadContext *ctx) {
- Core::g_app_core->SetReg(0, ctx->reg[0]);
- Core::g_app_core->SetReg(1, ctx->reg[1]);
- Core::g_app_core->SetReg(2, ctx->reg[2]);
- Core::g_app_core->SetReg(3, ctx->reg[3]);
- Core::g_app_core->SetReg(4, ctx->reg[4]);
- Core::g_app_core->SetReg(5, ctx->reg[5]);
- Core::g_app_core->SetReg(6, ctx->reg[6]);
- Core::g_app_core->SetReg(7, ctx->reg[7]);
- Core::g_app_core->SetReg(8, ctx->reg[8]);
- Core::g_app_core->SetReg(9, ctx->reg[9]);
- Core::g_app_core->SetReg(10, ctx->reg[10]);
- Core::g_app_core->SetReg(11, ctx->reg[11]);
- Core::g_app_core->SetReg(12, ctx->reg[12]);
- Core::g_app_core->SetReg(13, ctx->reg[13]);
- Core::g_app_core->SetReg(14, ctx->reg[14]);
- Core::g_app_core->SetReg(15, ctx->reg[15]);
- Core::g_app_core->SetPC(ctx->pc);
- Core::g_app_core->SetCPSR(ctx->cpsr);
-}
-
-/// Switches thread context
-void __KernelSwitchContext(Thread *target, const char *reason) {
- u32 old_pc = 0;
- UID old_uid = 0;
- const char *old_name = g_hle_current_thread_name != NULL ? g_hle_current_thread_name : "(none)";
+/// Gets the next thread that is ready to be run by priority
+Thread *__KernelNextThread() {
+ Handle next;
Thread *cur = __GetCurrentThread();
-
- if (cur) { // It might just have been deleted.
- __KernelSaveContext(&cur->context);
- old_pc = Core::g_app_core->GetPC();
- old_uid = cur->GetUID();
-
- // Normally this is taken care of in __KernelNextThread().
- if (cur->IsRunning())
- __KernelChangeReadyState(cur, old_uid, true);
+
+ if (cur && cur->IsRunning()) {
+ next = g_thread_ready_queue.pop_first_better(cur->current_priority);
+ } else {
+ next = g_thread_ready_queue.pop_first();
}
- if (target) {
- __SetCurrentThread(target, target->GetUID(), target->nt.name);
- __KernelChangeReadyState(target, g_current_thread, false);
-
- target->nt.status = (target->nt.status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY;
-
- __KernelLoadContext(&target->context);
- } else {
- __SetCurrentThread(NULL, 0, NULL);
+ if (next < 0) {
+ return NULL;
}
+ return g_kernel_objects.GetFast(next);
}
-bool __KernelSwitchToThread(UID thread_id, const char *reason) {
- if (!reason) {
- reason = "switch to thread";
+/// Calls a thread by marking it as "ready" (note: will not actually execute until current thread yields)
+void __KernelCallThread(Thread *t) {
+ // Stop waiting
+ if (t->wait_type != WAITTYPE_NONE) {
+ t->wait_type = WAITTYPE_NONE;
}
- if (g_current_thread == thread_id) {
- return false;
- }
- u32 error;
- Thread *t = g_kernel_objects.Get(thread_id, error);
- if (!t) {
- ERROR_LOG(KERNEL, "__KernelSwitchToThread: %x doesn't exist", thread_id);
- HLE::ReSchedule("switch to deleted thread");
- } else if (t->IsReady() || t->IsRunning()) {
- Thread *current = __GetCurrentThread();
- if (current && current->IsRunning()) {
- __KernelChangeReadyState(current, g_current_thread, true);
- }
- __KernelSwitchContext(t, reason);
- return true;
- } else {
- HLE::ReSchedule("switch to waiting thread");
- }
- return false;
+ __KernelChangeThreadState(t, THREADSTATUS_READY);
}
-/// Sets up the root (primary) thread of execution
-UID __KernelSetupRootThread(UID module_id, int arg, int prio, int stack_size) {
- UID id;
-
- Thread *thread = __KernelCreateThread(id, module_id, "root", prio, Core::g_app_core->GetPC(),
- arg, Memory::SCRATCHPAD_VADDR_END, 0xFFFFFFFE, stack_size=stack_size);
-
- if (thread->current_stack.start == 0) {
- ERROR_LOG(KERNEL, "Unable to allocate stack for root thread.");
- }
- __KernelResetThread(thread, 0);
-
- Thread *prev_thread = __GetCurrentThread();
- if (prev_thread && prev_thread->IsRunning())
- __KernelChangeReadyState(g_current_thread, true);
- __SetCurrentThread(thread, id, "root");
- thread->nt.status = THREADSTATUS_RUNNING; // do not schedule
-
- strcpy(thread->nt.name, "root");
-
- __KernelLoadContext(&thread->context);
+/// Sets up the primary application thread
+Handle __KernelSetupMainThread(s32 priority, int stack_size) {
+ Handle handle;
- // NOTE(bunnei): Not sure this is really correct, ignore args for now...
- //Core::g_app_core->SetReg(0, args);
- //Core::g_app_core->SetReg(13, (args + 0xf) & ~0xf); // Setup SP - probably not correct
- //u32 location = Core::g_app_core->GetReg(13); // SP
- //Core::g_app_core->SetReg(1, location);
+ // Initialize new "main" thread
+ Thread *t = __KernelCreateThread(handle, "main", Core::g_app_core->GetPC(), priority,
+ 0xFFFFFFFE, Memory::SCRATCHPAD_VADDR_END, stack_size);
- //if (argp)
- // Memory::Memcpy(location, argp, args);
- //// Let's assume same as starting a new thread, 64 bytes for safety/kernel.
- //Core::g_app_core->SetReg(13, Core::g_app_core->GetReg(13) - 64);
-
- return id;
-}
-
-int __KernelRotateThreadReadyQueue(int priority) {
+ __KernelResetThread(t, 0);
+
+ // If running another thread already, set it to "ready" state
Thread *cur = __GetCurrentThread();
-
- // 0 is special, it means "my current priority."
- if (priority == 0) {
- priority = cur->nt.current_priority;
+ if (cur && cur->IsRunning()) {
+ __KernelChangeReadyState(cur, true);
}
- //if (priority <= 0x07 || priority > 0x77)
- // return SCE_KERNEL_ERROR_ILLEGAL_PRIORITY;
+
+ // Run new "main" thread
+ __SetCurrentThread(t);
+ t->status = THREADSTATUS_RUNNING;
+ __KernelLoadContext(t->context);
- if (!g_thread_ready_queue.empty(priority)) {
- // In other words, yield to everyone else.
- if (cur->nt.current_priority == priority) {
- g_thread_ready_queue.push_back(priority, g_current_thread);
- cur->nt.status = (cur->nt.status & ~THREADSTATUS_RUNNING) | THREADSTATUS_READY;
+ return handle;
+}
- // Yield the next thread of this priority to all other threads of same priority.
- } else {
- g_thread_ready_queue.rotate(priority);
+/// Resumes a thread from waiting by marking it as "ready"
+void __KernelResumeThreadFromWait(Handle handle) {
+ u32 error;
+ Thread *t = g_kernel_objects.Get(handle, error);
+ if (t) {
+ t->status &= ~THREADSTATUS_WAIT;
+ if (!(t->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) {
+ __KernelChangeReadyState(t, true);
}
}
- HLE::EatCycles(250);
- HLE::ReSchedule("rotatethreadreadyqueue");
+}
- return 0;
+/// Puts a thread in the wait state for the given type/reason
+void __KernelWaitCurThread(WaitType wait_type, const char *reason) {
+ Thread *t = __GetCurrentThread();
+ t->wait_type = wait_type;
+ __KernelChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND)));
}
+/// Reschedules to the next available thread (call after current thread is suspended)
+void __KernelReschedule(const char *reason) {
+ Thread *next = __KernelNextThread();
+ if (next > 0) {
+ __KernelSwitchContext(next, reason);
+ }
+}
+
+
void __KernelThreadingInit() {
}
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 05468fb2e..cca4e85fd 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -7,50 +7,10 @@
#include "common/common_types.h"
#include "core/hle/kernel/kernel.h"
-enum ThreadStatus {
- THREADSTATUS_RUNNING = 1,
- THREADSTATUS_READY = 2,
- THREADSTATUS_WAIT = 4,
- THREADSTATUS_SUSPEND = 8,
- THREADSTATUS_DORMANT = 16,
- THREADSTATUS_DEAD = 32,
-
- THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND
-};
-
-struct ThreadContext {
- void reset();
-
- u32 reg[16];
- u32 cpsr;
- u32 pc;
-};
-
class Thread;
-Thread* __KernelCreateThread(UID& id, UID module_id, const char* name, u32 priority, u32 entrypoint,
- u32 arg, u32 stack_top, u32 processor_id, int stack_size=0x4000);
-
-UID __KernelCreateThread(UID module_id, const char* name, u32 priority, u32 entry_point, u32 arg,
- u32 stack_top, u32 processor_id, int stack_size=0x4000);
-
-void __KernelResetThread(Thread *t, int lowest_priority);
-void __KernelChangeReadyState(Thread *thread, UID thread_id, bool ready);
-void __KernelChangeReadyState(UID thread_id, bool ready);
-Thread* __KernelNextThread();
-void __KernelSaveContext(ThreadContext *ctx);
-void __KernelLoadContext(ThreadContext *ctx);
-void __KernelSwitchContext(Thread *target, const char *reason);
-bool __KernelSwitchToThread(UID thread_id, const char *reason);
-UID __KernelSetupRootThread(UID module_id, int arg, int prio, int stack_size=0x4000);
-int __KernelRotateThreadReadyQueue(int priority=0);
+/// Sets up the primary application thread
+Handle __KernelSetupMainThread(s32 priority, int stack_size=0x4000);
void __KernelThreadingInit();
void __KernelThreadingShutdown();
-
-//const char *__KernelGetThreadName(SceUID threadID);
-//
-//void __KernelSaveContext(ThreadContext *ctx);
-//void __KernelLoadContext(ThreadContext *ctx);
-
-//void __KernelSwitchContext(Thread *target, const char *reason);
\ No newline at end of file
--
cgit v1.2.3
From 3c240abf10c7f4f47cc6a8ad2ba6ee060abaa96b Mon Sep 17 00:00:00 2001
From: bunnei
Date: Thu, 15 May 2014 18:54:57 -0400
Subject: added ability to load AXF files (same as ELF)
---
src/citra_qt/main.cpp | 2 +-
src/core/loader.cpp | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index 76e0c68c3..9be982909 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -142,7 +142,7 @@ void GMainWindow::BootGame(const char* filename)
void GMainWindow::OnMenuLoadFile()
{
- QString filename = QFileDialog::getOpenFileName(this, tr("Load file"), QString(), tr("3DS homebrew (*.elf *.dat *.bin)"));
+ QString filename = QFileDialog::getOpenFileName(this, tr("Load file"), QString(), tr("3DS homebrew (*.elf *.axf *.dat *.bin)"));
if (filename.size())
BootGame(filename.toLatin1().data());
}
diff --git a/src/core/loader.cpp b/src/core/loader.cpp
index a1f5dcdb5..444b75feb 100644
--- a/src/core/loader.cpp
+++ b/src/core/loader.cpp
@@ -187,6 +187,9 @@ FileType IdentifyFile(std::string &filename) {
else if (!strcasecmp(extension.c_str(), ".elf")) {
return FILETYPE_CTR_ELF; // TODO(bunnei): Do some filetype checking :p
}
+ else if (!strcasecmp(extension.c_str(), ".axf")) {
+ return FILETYPE_CTR_ELF; // TODO(bunnei): Do some filetype checking :p
+ }
else if (!strcasecmp(extension.c_str(), ".bin")) {
return FILETYPE_CTR_BIN;
}
--
cgit v1.2.3
From 4910b6f3369f33a2dc6728e4156a62368c2c9cb1 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Thu, 15 May 2014 18:56:28 -0400
Subject: added memory mapped region for system mem - sdk demos load a segment
here on ELF load
---
src/core/mem_map.cpp | 3 +++
src/core/mem_map.h | 7 +++++++
src/core/mem_map_funcs.cpp | 14 +++++++++++++-
3 files changed, 23 insertions(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/core/mem_map.cpp b/src/core/mem_map.cpp
index 59560b87d..c45746be9 100644
--- a/src/core/mem_map.cpp
+++ b/src/core/mem_map.cpp
@@ -17,6 +17,7 @@ u8* g_base = NULL; ///< The base pointer to the aut
MemArena g_arena; ///< The MemArena class
u8* g_exefs_code = NULL; ///< ExeFS:/.code is loaded here
+u8* g_system_mem = NULL; ///< System memory
u8* g_heap = NULL; ///< Application heap (main memory)
u8* g_heap_gsp = NULL; ///< GSP heap (main memory)
u8* g_vram = NULL; ///< Video memory (VRAM) pointer
@@ -27,6 +28,7 @@ u8* g_physical_bootrom = NULL; ///< Bootrom physical memory
u8* g_uncached_bootrom = NULL;
u8* g_physical_exefs_code = NULL; ///< Phsical ExeFS:/.code is loaded here
+u8* g_physical_system_mem = NULL; ///< System physical memory
u8* g_physical_fcram = NULL; ///< Main physical memory (FCRAM)
u8* g_physical_heap_gsp = NULL; ///< GSP heap physical memory
u8* g_physical_vram = NULL; ///< Video physical memory (VRAM)
@@ -39,6 +41,7 @@ static MemoryView g_views[] = {
{&g_vram, &g_physical_vram, VRAM_VADDR, VRAM_SIZE, 0},
{&g_heap, &g_physical_fcram, HEAP_VADDR, HEAP_SIZE, MV_IS_PRIMARY_RAM},
{&g_shared_mem, &g_physical_shared_mem, SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, 0},
+ {&g_system_mem, &g_physical_system_mem, SYSTEM_MEMORY_VADDR, SYSTEM_MEMORY_SIZE, 0},
{&g_kernel_mem, &g_physical_kernel_mem, KERNEL_MEMORY_VADDR, KERNEL_MEMORY_SIZE, 0},
{&g_heap_gsp, &g_physical_heap_gsp, HEAP_GSP_VADDR, HEAP_GSP_SIZE, 0},
};
diff --git a/src/core/mem_map.h b/src/core/mem_map.h
index af2212a5f..12d497ef3 100644
--- a/src/core/mem_map.h
+++ b/src/core/mem_map.h
@@ -47,6 +47,12 @@ enum {
EXEFS_CODE_VADDR_END = (EXEFS_CODE_VADDR + EXEFS_CODE_SIZE),
EXEFS_CODE_MASK = 0x03FFFFFF,
+ // Region of FCRAM used by system
+ SYSTEM_MEMORY_SIZE = 0x02C00000, ///< 44MB
+ SYSTEM_MEMORY_VADDR = 0x04000000,
+ SYSTEM_MEMORY_VADDR_END = (SYSTEM_MEMORY_VADDR + SYSTEM_MEMORY_SIZE),
+ SYSTEM_MEMORY_MASK = 0x03FFFFFF,
+
HEAP_SIZE = FCRAM_SIZE, ///< Application heap size
//HEAP_PADDR = HEAP_GSP_SIZE,
//HEAP_PADDR_END = (HEAP_PADDR + HEAP_SIZE),
@@ -116,6 +122,7 @@ extern u8* g_heap; ///< Application heap (main memory)
extern u8* g_vram; ///< Video memory (VRAM)
extern u8* g_shared_mem; ///< Shared memory
extern u8* g_kernel_mem; ///< Kernel memory
+extern u8* g_system_mem; ///< System memory
extern u8* g_exefs_code; ///< ExeFS:/.code is loaded here
void Init();
diff --git a/src/core/mem_map_funcs.cpp b/src/core/mem_map_funcs.cpp
index 8ab647714..86e9eaa20 100644
--- a/src/core/mem_map_funcs.cpp
+++ b/src/core/mem_map_funcs.cpp
@@ -73,6 +73,10 @@ inline void _Read(T &var, const u32 addr) {
} else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
var = *((const T*)&g_shared_mem[vaddr & SHARED_MEMORY_MASK]);
+ // System memory
+ } else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) {
+ var = *((const T*)&g_system_mem[vaddr & SYSTEM_MEMORY_MASK]);
+
// Config memory
} else if ((vaddr >= CONFIG_MEMORY_VADDR) && (vaddr < CONFIG_MEMORY_VADDR_END)) {
ConfigMem::Read(var, vaddr);
@@ -115,6 +119,10 @@ inline void _Write(u32 addr, const T data) {
} else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
*(T*)&g_shared_mem[vaddr & SHARED_MEMORY_MASK] = data;
+ // System memory
+ } else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) {
+ *(T*)&g_system_mem[vaddr & SYSTEM_MEMORY_MASK] = data;
+
// VRAM
} else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) {
*(T*)&g_vram[vaddr & VRAM_MASK] = data;
@@ -153,9 +161,13 @@ u8 *GetPointer(const u32 addr) {
return g_heap + (vaddr & HEAP_MASK);
// Shared memory
- } else if ((vaddr > SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
+ } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
return g_shared_mem + (vaddr & SHARED_MEMORY_MASK);
+ // System memory
+ } else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) {
+ return g_system_mem + (vaddr & SYSTEM_MEMORY_MASK);
+
// VRAM
} else if ((vaddr > VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) {
return g_vram + (vaddr & VRAM_MASK);
--
cgit v1.2.3
From 4fba4f36bf20c2721e2602c450eafcc1117ac643 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Thu, 15 May 2014 20:17:30 -0400
Subject: - added SVC stubs for QueryMemory and GetThreadId
- added SVC structs MemoryInfo and PageInfo
---
src/core/hle/function_wrappers.h | 5 +++++
src/core/hle/syscall.cpp | 16 ++++++++++++++--
src/core/hle/syscall.h | 11 +++++++++++
3 files changed, 30 insertions(+), 2 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h
index 83be7648b..61790e5a3 100644
--- a/src/core/hle/function_wrappers.h
+++ b/src/core/hle/function_wrappers.h
@@ -734,6 +734,11 @@ template void WrapI_VU(){
RETURN(retval);
}
+template void WrapI_VVU(){
+ u32 retval = func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2));
+ RETURN(retval);
+}
+
template void WrapI_VUVI(){
u32 retval = func(Memory::GetPointer(PARAM(0)), PARAM(1), Memory::GetPointer(PARAM(2)), PARAM(3));
RETURN(retval);
diff --git a/src/core/hle/syscall.cpp b/src/core/hle/syscall.cpp
index 0700d9e82..0765bce7a 100644
--- a/src/core/hle/syscall.cpp
+++ b/src/core/hle/syscall.cpp
@@ -169,10 +169,22 @@ Result ReleaseMutex(Handle handle) {
return 0;
}
+Result GetThreadId(void* thread_id, u32 thread) {
+ DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetThreadId called thread=0x%08X", thread);
+ return 0;
+}
+
+Result QueryMemory(void *_info, void *_out, u32 addr) {
+ MemoryInfo* info = (MemoryInfo*) _info;
+ PageInfo* out = (PageInfo*) _out;
+ DEBUG_LOG(SVC, "(UNIMPLEMENTED) QueryMemory called addr=0x%08X", addr);
+ return 0;
+}
+
const HLE::FunctionDef Syscall_Table[] = {
{0x00, NULL, "Unknown"},
{0x01, WrapI_VUUUUU, "ControlMemory"},
- {0x02, NULL, "QueryMemory"},
+ {0x02, WrapI_VVU, "QueryMemory"},
{0x03, NULL, "ExitProcess"},
{0x04, NULL, "GetProcessAffinityMask"},
{0x05, NULL, "SetProcessAffinityMask"},
@@ -225,7 +237,7 @@ const HLE::FunctionDef Syscall_Table[] = {
{0x34, NULL, "OpenThread"},
{0x35, NULL, "GetProcessId"},
{0x36, NULL, "GetProcessIdOfThread"},
- {0x37, NULL, "GetThreadId"},
+ {0x37, WrapI_VU, "GetThreadId"},
{0x38, WrapI_VU, "GetResourceLimit"},
{0x39, NULL, "GetResourceLimitLimitValues"},
{0x3A, WrapI_VUVI, "GetResourceLimitCurrentValues"},
diff --git a/src/core/hle/syscall.h b/src/core/hle/syscall.h
index 15af5e138..17f190266 100644
--- a/src/core/hle/syscall.h
+++ b/src/core/hle/syscall.h
@@ -9,6 +9,17 @@
////////////////////////////////////////////////////////////////////////////////////////////////////
// SVC structures
+struct MemoryInfo {
+ u32 base_address;
+ u32 size;
+ u32 permission;
+ u32 state;
+};
+
+struct PageInfo {
+ u32 flags;
+};
+
struct ThreadContext {
u32 cpu_registers[13];
u32 sp;
--
cgit v1.2.3
From 540a693eae210d090b87426ead8cfac5893a9ef8 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Fri, 16 May 2014 23:23:56 -0400
Subject: updated APT_U::GetLockHandle to return a valid handle
---
src/core/hle/service/apt.cpp | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/core/hle/service/apt.cpp b/src/core/hle/service/apt.cpp
index 709ac5493..ddb975607 100644
--- a/src/core/hle/service/apt.cpp
+++ b/src/core/hle/service/apt.cpp
@@ -19,7 +19,11 @@ void Initialize(Service::Interface* self) {
void GetLockHandle(Service::Interface* self) {
u32* cmd_buff = Service::GetCommandBuffer();
- cmd_buff[5] = 0x00000000; // TODO: This should be an actual mutex handle
+ u32 flags = cmd_buff[1];
+
+ // TODO: This should be an actual mutex handle. Games will check that this is not non-zero
+ // (NULL), and fail if such. A faked non-zero value will at least enable further booting.
+ cmd_buff[5] = 0xDEADBEEF;
}
const Interface::FunctionInfo FunctionTable[] = {
--
cgit v1.2.3
From 4faed70b40ae44a0a5c63366ad4e6dfa6340e73f Mon Sep 17 00:00:00 2001
From: bunnei
Date: Fri, 16 May 2014 23:24:39 -0400
Subject: add kernel.* and thread.* to VS filters
---
src/core/core.vcxproj.filters | 15 +++++++++++++++
1 file changed, 15 insertions(+)
(limited to 'src')
diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters
index edf34ce2f..6aedeb54b 100644
--- a/src/core/core.vcxproj.filters
+++ b/src/core/core.vcxproj.filters
@@ -31,6 +31,9 @@
{13ef9860-2ba0-47e9-a93d-b4052adab269}
+
+ {8089d94b-5faa-43dc-854b-ffd2fa2e7fe3}
+
@@ -153,6 +156,12 @@
arm\interpreter\mmu
+
+ hle\kernel
+
+
+ hle\kernel
+
@@ -274,6 +283,12 @@
arm\interpreter\mmu
+
+ hle\kernel
+
+
+ hle\kernel
+
--
cgit v1.2.3
From 39ee75fc8d2a3291195448696f6a9bda8b1d58ad Mon Sep 17 00:00:00 2001
From: bunnei
Date: Fri, 16 May 2014 23:25:16 -0400
Subject: added stubbed GetProcSemaphore - does nothing but avoids an exception
---
src/core/hle/service/srv.cpp | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp
index 071741444..303a943d4 100644
--- a/src/core/hle/service/srv.cpp
+++ b/src/core/hle/service/srv.cpp
@@ -16,6 +16,12 @@ void Initialize(Service::Interface* self) {
NOTICE_LOG(OSHLE, "SRV::Sync - Initialize");
}
+void GetProcSemaphore(Service::Interface* self) {
+ // Get process semaphore?
+ u32* cmd_buff = Service::GetCommandBuffer();
+ cmd_buff[3] = 0xDEADBEEF; // Return something... 0 == NULL, raises an exception
+}
+
void GetServiceHandle(Service::Interface* self) {
Syscall::Result res = 0;
u32* cmd_buff = Service::GetCommandBuffer();
@@ -39,7 +45,7 @@ void GetServiceHandle(Service::Interface* self) {
const Interface::FunctionInfo FunctionTable[] = {
{0x00010002, Initialize, "Initialize"},
- {0x00020000, NULL, "GetProcSemaphore"},
+ {0x00020000, GetProcSemaphore, "GetProcSemaphore"},
{0x00030100, NULL, "RegisterService"},
{0x000400C0, NULL, "UnregisterService"},
{0x00050100, GetServiceHandle, "GetServiceHandle"},
--
cgit v1.2.3
From 7cdb70505944b2ed456d7f5376594e05f3b3357f Mon Sep 17 00:00:00 2001
From: bunnei
Date: Fri, 16 May 2014 23:48:15 -0400
Subject: - replaced KERNELOBJECT_MAX_NAME_LENGTH with KERNEL_MAX_NAME_LENGTH
- added KERNEL_DEFAULT_STACK_SIZE definition (0x4000)
---
src/core/hle/kernel/kernel.h | 5 ++---
src/core/hle/kernel/thread.cpp | 9 +++++----
src/core/hle/kernel/thread.h | 6 +++++-
3 files changed, 12 insertions(+), 8 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 24d422682..2608eecc9 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -16,11 +16,10 @@ enum KernelIDType {
};
enum {
- KERNELOBJECT_MAX_NAME_LENGTH = 255,
+ KERNEL_MAX_NAME_LENGTH = 0x100,
+ KERNEL_DEFAULT_STACK_SIZE = 0x4000,
};
-#define KERNELOBJECT_MAX_NAME_LENGTH 31
-
class KernelObjectPool;
class KernelObject {
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 833a1b4ba..76a73747d 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -81,7 +81,7 @@ public:
WaitType wait_type;
- char name[KERNELOBJECT_MAX_NAME_LENGTH+1];
+ char name[KERNEL_MAX_NAME_LENGTH+1];
};
// Lists all thread ids that aren't deleted/etc.
@@ -165,7 +165,8 @@ void __KernelResetThread(Thread *t, s32 lowest_priority) {
}
/// Creates a new thread
-Thread *__KernelCreateThread(Handle &handle, const char *name, u32 entry_point, s32 priority, s32 processor_id, u32 stack_top, int stack_size=0x4000) {
+Thread *__KernelCreateThread(Handle &handle, const char *name, u32 entry_point, s32 priority,
+ s32 processor_id, u32 stack_top, int stack_size) {
static u32 _handle_count = 1;
Thread *t = new Thread;
@@ -183,8 +184,8 @@ Thread *__KernelCreateThread(Handle &handle, const char *name, u32 entry_point,
t->processor_id = processor_id;
t->wait_type = WAITTYPE_NONE;
- strncpy(t->name, name, KERNELOBJECT_MAX_NAME_LENGTH);
- t->name[KERNELOBJECT_MAX_NAME_LENGTH] = '\0';
+ strncpy(t->name, name, KERNEL_MAX_NAME_LENGTH);
+ t->name[KERNEL_MAX_NAME_LENGTH] = '\0';
return t;
}
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index cca4e85fd..add6107d7 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -9,8 +9,12 @@
class Thread;
+/// Creates a new thread
+Thread *__KernelCreateThread(Handle &handle, const char *name, u32 entry_point, s32 priority,
+ s32 processor_id, u32 stack_top, int stack_size=KERNEL_DEFAULT_STACK_SIZE);
+
/// Sets up the primary application thread
-Handle __KernelSetupMainThread(s32 priority, int stack_size=0x4000);
+Handle __KernelSetupMainThread(s32 priority, int stack_size=KERNEL_DEFAULT_STACK_SIZE);
void __KernelThreadingInit();
void __KernelThreadingShutdown();
--
cgit v1.2.3
From 43bc2ac724e1e1340827dd777ec4dbb6b94b4603 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Sat, 17 May 2014 00:53:41 -0400
Subject: added MIN, MAX, and CLAMP macros to common_funcs
---
src/common/common_funcs.h | 5 +++++
1 file changed, 5 insertions(+)
(limited to 'src')
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index f8d10eb3e..dca4dc47f 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -22,6 +22,11 @@ template<> struct CompileTimeAssert {};
#define b32(x) (b16(x) | (b16(x) >>16) )
#define ROUND_UP_POW2(x) (b32(x - 1) + 1)
+#define MIN(a, b) ((a)<(b)?(a):(b))
+#define MAX(a, b) ((a)>(b)?(a):(b))
+
+#define CLAMP(x, min, max) (((x) > max) ? max : (((x) < min) ? min : (x)))
+
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
#ifndef _WIN32
--
cgit v1.2.3
From 14ae026386cf3f984d60401e2104165c3ca3266b Mon Sep 17 00:00:00 2001
From: bunnei
Date: Sat, 17 May 2014 00:56:00 -0400
Subject: - added enum ThreadProcessorId
- reorganized some kernel thread functions
- added placeholder __KernelWaitThread_Synchronization function
---
src/core/hle/kernel/thread.cpp | 141 ++++++++++++++++++++++++++---------------
src/core/hle/kernel/thread.h | 19 +++++-
2 files changed, 107 insertions(+), 53 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 76a73747d..b967b3c62 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -21,20 +21,14 @@
// Enums
-enum ThreadPriority {
- THREADPRIO_HIGHEST = 0,
- THREADPRIO_DEFAULT = 16,
- THREADPRIO_LOWEST = 31,
-};
-
enum ThreadStatus {
- THREADSTATUS_RUNNING = 1,
- THREADSTATUS_READY = 2,
- THREADSTATUS_WAIT = 4,
- THREADSTATUS_SUSPEND = 8,
- THREADSTATUS_DORMANT = 16,
- THREADSTATUS_DEAD = 32,
- THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND
+ THREADSTATUS_RUNNING = 1,
+ THREADSTATUS_READY = 2,
+ THREADSTATUS_WAIT = 4,
+ THREADSTATUS_SUSPEND = 8,
+ THREADSTATUS_DORMANT = 16,
+ THREADSTATUS_DEAD = 32,
+ THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND
};
enum WaitType {
@@ -46,8 +40,6 @@ enum WaitType {
WAITTYPE_VBLANK,
WAITTYPE_MUTEX,
WAITTYPE_SYNCH,
-
- NUM_WAITTYPES
};
typedef s32 Handle;
@@ -164,32 +156,6 @@ void __KernelResetThread(Thread *t, s32 lowest_priority) {
t->wait_type = WAITTYPE_NONE;
}
-/// Creates a new thread
-Thread *__KernelCreateThread(Handle &handle, const char *name, u32 entry_point, s32 priority,
- s32 processor_id, u32 stack_top, int stack_size) {
- static u32 _handle_count = 1;
-
- Thread *t = new Thread;
-
- handle = (_handle_count++);
-
- g_thread_queue.push_back(handle);
- g_thread_ready_queue.prepare(priority);
-
- t->status = THREADSTATUS_DORMANT;
- t->entry_point = entry_point;
- t->stack_top = stack_top;
- t->stack_size = stack_size;
- t->initial_priority = t->current_priority = priority;
- t->processor_id = processor_id;
- t->wait_type = WAITTYPE_NONE;
-
- strncpy(t->name, name, KERNEL_MAX_NAME_LENGTH);
- t->name[KERNEL_MAX_NAME_LENGTH] = '\0';
-
- return t;
-}
-
/// Change a thread to "ready" state
void __KernelChangeReadyState(Thread *t, bool ready) {
Handle handle = t->GetHandle();
@@ -222,6 +188,79 @@ void __KernelChangeThreadState(Thread *t, ThreadStatus new_status) {
}
}
+/// Calls a thread by marking it as "ready" (note: will not actually execute until current thread yields)
+void __KernelCallThread(Thread *t) {
+ // Stop waiting
+ if (t->wait_type != WAITTYPE_NONE) {
+ t->wait_type = WAITTYPE_NONE;
+ }
+ __KernelChangeThreadState(t, THREADSTATUS_READY);
+}
+
+/// Creates a new thread
+Thread *__KernelCreateThread(Handle &handle, const char *name, u32 entry_point, s32 priority,
+ s32 processor_id, u32 stack_top, int stack_size) {
+
+ Thread *t = new Thread;
+
+ handle = g_kernel_objects.Create(t);
+
+ g_thread_queue.push_back(handle);
+ g_thread_ready_queue.prepare(priority);
+
+ t->status = THREADSTATUS_DORMANT;
+ t->entry_point = entry_point;
+ t->stack_top = stack_top;
+ t->stack_size = stack_size;
+ t->initial_priority = t->current_priority = priority;
+ t->processor_id = processor_id;
+ t->wait_type = WAITTYPE_NONE;
+
+ strncpy(t->name, name, KERNEL_MAX_NAME_LENGTH);
+ t->name[KERNEL_MAX_NAME_LENGTH] = '\0';
+
+ return t;
+}
+
+/// Creates a new thread - wrapper for external user
+Handle __KernelCreateThread(const char *name, u32 entry_point, s32 priority, s32 processor_id,
+ u32 stack_top, int stack_size) {
+ if (name == NULL) {
+ ERROR_LOG(KERNEL, "__KernelCreateThread(): NULL name");
+ return -1;
+ }
+ if ((u32)stack_size < 0x200) {
+ ERROR_LOG(KERNEL, "__KernelCreateThread(name=%s): invalid stack_size=0x%08X", name,
+ stack_size);
+ return -1;
+ }
+ if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) {
+ s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST);
+ WARN_LOG(KERNEL, "__KernelCreateThread(name=%s): invalid priority=0x%08X, clamping to %08X",
+ name, priority, new_priority);
+ // TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm
+ // validity of this
+ priority = new_priority;
+ }
+ if (!Memory::GetPointer(entry_point)) {
+ ERROR_LOG(KERNEL, "__KernelCreateThread(name=%s): invalid entry %08x", name, entry_point);
+ return -1;
+ }
+ Handle handle;
+ Thread *t = __KernelCreateThread(handle, name, entry_point, priority, processor_id, stack_top,
+ stack_size);
+
+ HLE::EatCycles(32000);
+
+ // This won't schedule to the new thread, but it may to one woken from eating cycles.
+ // Technically, this should not eat all at once, and reschedule in the middle, but that's hard.
+ HLE::ReSchedule("thread created");
+
+ __KernelCallThread(t);
+
+ return handle;
+}
+
/// Switches CPU context to that of the specified thread
void __KernelSwitchContext(Thread* t, const char *reason) {
Thread *cur = __GetCurrentThread();
@@ -262,22 +301,13 @@ Thread *__KernelNextThread() {
return g_kernel_objects.GetFast(next);
}
-/// Calls a thread by marking it as "ready" (note: will not actually execute until current thread yields)
-void __KernelCallThread(Thread *t) {
- // Stop waiting
- if (t->wait_type != WAITTYPE_NONE) {
- t->wait_type = WAITTYPE_NONE;
- }
- __KernelChangeThreadState(t, THREADSTATUS_READY);
-}
-
/// Sets up the primary application thread
Handle __KernelSetupMainThread(s32 priority, int stack_size) {
Handle handle;
// Initialize new "main" thread
Thread *t = __KernelCreateThread(handle, "main", Core::g_app_core->GetPC(), priority,
- 0xFFFFFFFE, Memory::SCRATCHPAD_VADDR_END, stack_size);
+ THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size);
__KernelResetThread(t, 0);
@@ -322,6 +352,15 @@ void __KernelReschedule(const char *reason) {
}
}
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+/// Wait thread - on WaitSynchronization
+void __KernelWaitThread_Synchronization() {
+ // TODO(bunnei): Just a placeholder function for now... FixMe
+ __KernelWaitCurThread(WAITTYPE_SYNCH, "waitSynchronization called");
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
void __KernelThreadingInit() {
}
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index add6107d7..8138be26f 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -9,8 +9,20 @@
class Thread;
-/// Creates a new thread
-Thread *__KernelCreateThread(Handle &handle, const char *name, u32 entry_point, s32 priority,
+enum ThreadPriority {
+ THREADPRIO_HIGHEST = 0,
+ THREADPRIO_DEFAULT = 16,
+ THREADPRIO_LOWEST = 31,
+};
+
+enum ThreadProcessorId {
+ THREADPROCESSORID_0 = 0xFFFFFFFE,
+ THREADPROCESSORID_1 = 0xFFFFFFFD,
+ THREADPROCESSORID_ALL = 0xFFFFFFFC,
+};
+
+/// Creates a new thread - wrapper for external user
+Handle __KernelCreateThread(const char *name, u32 entry_point, s32 priority,
s32 processor_id, u32 stack_top, int stack_size=KERNEL_DEFAULT_STACK_SIZE);
/// Sets up the primary application thread
@@ -18,3 +30,6 @@ Handle __KernelSetupMainThread(s32 priority, int stack_size=KERNEL_DEFAULT_STACK
void __KernelThreadingInit();
void __KernelThreadingShutdown();
+
+/// Wait thread - on WaitSynchronization
+void __KernelWaitThread_Synchronization();
--
cgit v1.2.3
From cfea5fdd5878968e8a1de99b86966c57d0fc5697 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Sat, 17 May 2014 13:47:44 -0400
Subject: cleanups to SVC CreateThread
---
src/core/hle/syscall.cpp | 23 +++++++++++++++--------
1 file changed, 15 insertions(+), 8 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/syscall.cpp b/src/core/hle/syscall.cpp
index 0765bce7a..0c78b19fb 100644
--- a/src/core/hle/syscall.cpp
+++ b/src/core/hle/syscall.cpp
@@ -6,6 +6,9 @@
#include "core/mem_map.h"
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/thread.h"
+
#include "core/hle/function_wrappers.h"
#include "core/hle/syscall.h"
#include "core/hle/service/service.h"
@@ -140,19 +143,23 @@ Result GetResourceLimitCurrentValues(void* _values, Handle resource_limit, void*
return 0;
}
-Result CreateThread(void* thread, u32 thread_priority, u32 entry_point, u32 arg, u32 stack_top, u32 processor_id) {
- std::string thread_name;
+Result CreateThread(void* thread, u32 priority, u32 entry_point, u32 arg, u32 stack_top,
+ u32 processor_id) {
+ std::string name;
if (Symbols::HasSymbol(entry_point)) {
TSymbol symbol = Symbols::GetSymbol(entry_point);
- thread_name = symbol.name;
+ name = symbol.name;
} else {
char buff[100];
- sprintf(buff, "%s", "unk-%08X", entry_point);
- thread_name = buff;
+ sprintf(buff, "%s", "unknown-%08X", entry_point);
+ name = buff;
}
- DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateThread called entrypoint=0x%08X (%s), arg=0x%08X, "
- "stacktop=0x%08X, threadpriority=0x%08X, processorid=0x%08X", entry_point,
- thread_name.c_str(), arg, stack_top, thread_priority, processor_id);
+ DEBUG_LOG(SVC, "CreateThread called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, "
+ "threadpriority=0x%08X, processorid=0x%08X", entry_point, name.c_str(), arg, stack_top,
+ priority, processor_id);
+
+ Handle handle = __KernelCreateThread(name.c_str(), entry_point, priority, processor_id,
+ stack_top);
return 0;
}
--
cgit v1.2.3
From 09b8e8fb6afbbcc3dd6127ee02f7ac1611eb85aa Mon Sep 17 00:00:00 2001
From: bunnei
Date: Sat, 17 May 2014 13:47:55 -0400
Subject: changed a comment
---
src/core/hle/kernel/thread.cpp | 2 +-
src/core/hle/kernel/thread.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index b967b3c62..d0bc9c8d8 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -354,7 +354,7 @@ void __KernelReschedule(const char *reason) {
////////////////////////////////////////////////////////////////////////////////////////////////////
-/// Wait thread - on WaitSynchronization
+/// Put current thread in a wait state - on WaitSynchronization
void __KernelWaitThread_Synchronization() {
// TODO(bunnei): Just a placeholder function for now... FixMe
__KernelWaitCurThread(WAITTYPE_SYNCH, "waitSynchronization called");
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 8138be26f..0d0f46500 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -31,5 +31,5 @@ Handle __KernelSetupMainThread(s32 priority, int stack_size=KERNEL_DEFAULT_STACK
void __KernelThreadingInit();
void __KernelThreadingShutdown();
-/// Wait thread - on WaitSynchronization
+/// Put current thread in a wait state - on WaitSynchronization
void __KernelWaitThread_Synchronization();
--
cgit v1.2.3
From fbc04ad0c7c2bafde1b7b50957799c7bbab8f77b Mon Sep 17 00:00:00 2001
From: bunnei
Date: Sat, 17 May 2014 13:48:27 -0400
Subject: ignore thumbemu 0xDEADCODE debugging catch on MCR
---
src/core/arm/interpreter/armemu.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
(limited to 'src')
diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp
index 32e315f4b..aa1ff17bb 100644
--- a/src/core/arm/interpreter/armemu.cpp
+++ b/src/core/arm/interpreter/armemu.cpp
@@ -4478,8 +4478,7 @@ ARMul_Emulate26 (ARMul_State * state)
isize) &
R15PCBITS));
#endif
- }
- else
+ } else if (instr != 0xDEADC0DE) // thumbemu uses 0xDEADCODE for debugging to catch non updates
ARMul_MCR (state, instr,
DEST);
}
--
cgit v1.2.3
From 6a6c7eeccbf2e9a766ad6b942f25b3ef6e008944 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Sat, 17 May 2014 23:37:25 -0400
Subject: added stubbed function for WaitSynchronizationN
---
src/core/hle/function_wrappers.h | 7 ++++++-
src/core/hle/syscall.cpp | 16 +++++++++++++---
2 files changed, 19 insertions(+), 4 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h
index 61790e5a3..24cc74fc6 100644
--- a/src/core/hle/function_wrappers.h
+++ b/src/core/hle/function_wrappers.h
@@ -750,6 +750,11 @@ template void WrapI_VUUUUU(){
}
template void WrapI_US64() {
- int retval = func(PARAM(0), PARAM64(2));
+ int retval = func(PARAM(0), PARAM64(1));
+ RETURN(retval);
+}
+
+template void WrapI_VVUUS64() {
+ int retval = func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2), PARAM(3), PARAM(4));
RETURN(retval);
}
diff --git a/src/core/hle/syscall.cpp b/src/core/hle/syscall.cpp
index 0c78b19fb..728679378 100644
--- a/src/core/hle/syscall.cpp
+++ b/src/core/hle/syscall.cpp
@@ -104,10 +104,20 @@ Result CloseHandle(Handle handle) {
}
/// Wait for a handle to synchronize, timeout after the specified nanoseconds
-Result WaitSynchronization1(Handle handle, s64 nanoseconds) {
+Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
// ImplementMe
DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronization1 called handle=0x%08X, nanoseconds=%d",
- handle, nanoseconds);
+ handle, nano_seconds);
+ return 0;
+}
+
+/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
+Result WaitSynchronizationN(void* _out, void* _handles, u32 handle_count, u32 wait_all, s64 nano_seconds) {
+ s32* out = (s32*)_out;
+ Handle* handles = (Handle*)_handles;
+ // ImplementMe
+ DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronizationN called handle_count=%d, wait_all=%d, nanoseconds=%d",
+ handle_count, wait_all, nano_seconds);
return 0;
}
@@ -226,7 +236,7 @@ const HLE::FunctionDef Syscall_Table[] = {
{0x22, NULL, "ArbitrateAddress"},
{0x23, WrapI_U, "CloseHandle"},
{0x24, WrapI_US64, "WaitSynchronization1"},
- {0x25, NULL, "WaitSynchronizationN"},
+ {0x25, WrapI_VVUUS64, "WaitSynchronizationN"},
{0x26, NULL, "SignalAndWait"},
{0x27, NULL, "DuplicateHandle"},
{0x28, NULL, "GetSystemTick"},
--
cgit v1.2.3
From 8fba88d5d59ad4cd89a343e1562a314874bd88a4 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Sun, 18 May 2014 17:52:02 -0400
Subject: - added stub for CreateEvent
- changed some stubbed SVCs to return unique handle names for debugging purposes
---
src/core/hle/syscall.cpp | 30 ++++++++++++++++++++++--------
1 file changed, 22 insertions(+), 8 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/syscall.cpp b/src/core/hle/syscall.cpp
index 728679378..047d8c40f 100644
--- a/src/core/hle/syscall.cpp
+++ b/src/core/hle/syscall.cpp
@@ -3,6 +3,9 @@
// Refer to the license.txt file included.
#include
@@ -226,9 +226,6 @@
hle\service
-
- hle
-
hle\service
@@ -289,6 +286,9 @@
hle\kernel
+
+ hle
+
diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp
index 452384571..080c36abf 100644
--- a/src/core/hle/hle.cpp
+++ b/src/core/hle/hle.cpp
@@ -6,7 +6,7 @@
#include "core/mem_map.h"
#include "core/hle/hle.h"
-#include "core/hle/syscall.h"
+#include "core/hle/svc.h"
#include "core/hle/service/service.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -15,17 +15,17 @@ namespace HLE {
static std::vector g_module_db;
-const FunctionDef* GetSyscallInfo(u32 opcode) {
+const FunctionDef* GetSVCInfo(u32 opcode) {
u32 func_num = opcode & 0xFFFFFF; // 8 bits
if (func_num > 0xFF) {
- ERROR_LOG(HLE,"Unknown syscall: 0x%02X", func_num);
+ ERROR_LOG(HLE,"Unknown SVC: 0x%02X", func_num);
return NULL;
}
return &g_module_db[0].func_table[func_num];
}
-void CallSyscall(u32 opcode) {
- const FunctionDef *info = GetSyscallInfo(opcode);
+void CallSVC(u32 opcode) {
+ const FunctionDef *info = GetSVCInfo(opcode);
if (!info) {
return;
@@ -33,7 +33,7 @@ void CallSyscall(u32 opcode) {
if (info->func) {
info->func();
} else {
- ERROR_LOG(HLE, "Unimplemented SysCall function %s(..)", info->name.c_str());
+ ERROR_LOG(HLE, "Unimplemented SVC function %s(..)", info->name.c_str());
}
}
@@ -54,7 +54,7 @@ void RegisterModule(std::string name, int num_functions, const FunctionDef* func
}
void RegisterAllModules() {
- Syscall::Register();
+ SVC::Register();
}
void Init() {
diff --git a/src/core/hle/hle.h b/src/core/hle/hle.h
index 452546e1f..c075147c3 100644
--- a/src/core/hle/hle.h
+++ b/src/core/hle/hle.h
@@ -34,7 +34,7 @@ struct ModuleDef {
void RegisterModule(std::string name, int num_functions, const FunctionDef *func_table);
-void CallSyscall(u32 opcode);
+void CallSVC(u32 opcode);
void EatCycles(u32 cycles);
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index cfc5327a3..136fff021 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -15,7 +15,7 @@
#include "core/core.h"
#include "core/mem_map.h"
#include "core/hle/hle.h"
-#include "core/hle/syscall.h"
+#include "core/hle/svc.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/thread.h"
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index f334dbcb8..eba730efb 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -14,7 +14,7 @@
#include "core/mem_map.h"
#include "core/hle/kernel/kernel.h"
-#include "core/hle/syscall.h"
+#include "core/hle/svc.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace Service
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
new file mode 100644
index 000000000..a9141699c
--- /dev/null
+++ b/src/core/hle/svc.cpp
@@ -0,0 +1,350 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include
+#include
+
+#include "common/symbols.h"
+
+#include "core/mem_map.h"
+
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/thread.h"
+
+#include "core/hle/function_wrappers.h"
+#include "core/hle/svc.h"
+#include "core/hle/service/service.h"
+#include "core/hle/kernel/thread.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace SVC
+
+namespace SVC {
+
+enum ControlMemoryOperation {
+ MEMORY_OPERATION_HEAP = 0x00000003,
+ MEMORY_OPERATION_GSP_HEAP = 0x00010003,
+};
+
+enum MapMemoryPermission {
+ MEMORY_PERMISSION_UNMAP = 0x00000000,
+ MEMORY_PERMISSION_NORMAL = 0x00000001,
+};
+
+/// Map application or GSP heap memory
+Result ControlMemory(void* _outaddr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) {
+ u32* outaddr = (u32*)_outaddr;
+ u32 virtual_address = 0x00000000;
+
+ DEBUG_LOG(SVC, "ControlMemory called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X",
+ operation, addr0, addr1, size, permissions);
+
+ switch (operation) {
+
+ // Map normal heap memory
+ case MEMORY_OPERATION_HEAP:
+ virtual_address = Memory::MapBlock_Heap(size, operation, permissions);
+ break;
+
+ // Map GSP heap memory
+ case MEMORY_OPERATION_GSP_HEAP:
+ virtual_address = Memory::MapBlock_HeapGSP(size, operation, permissions);
+ break;
+
+ // Unknown ControlMemory operation
+ default:
+ ERROR_LOG(SVC, "ControlMemory unknown operation=0x%08X", operation);
+ }
+ if (NULL != outaddr) {
+ *outaddr = virtual_address;
+ }
+ Core::g_app_core->SetReg(1, virtual_address);
+
+ return 0;
+}
+
+/// Maps a memory block to specified address
+Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherpermission) {
+ DEBUG_LOG(SVC, "MapMemoryBlock called memblock=0x08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d",
+ memblock, addr, mypermissions, otherpermission);
+ switch (mypermissions) {
+ case MEMORY_PERMISSION_NORMAL:
+ case MEMORY_PERMISSION_NORMAL + 1:
+ case MEMORY_PERMISSION_NORMAL + 2:
+ Memory::MapBlock_Shared(memblock, addr, mypermissions);
+ break;
+ default:
+ ERROR_LOG(OSHLE, "MapMemoryBlock unknown permissions=0x%08X", mypermissions);
+ }
+ return 0;
+}
+
+/// Connect to an OS service given the port name, returns the handle to the port to out
+Result ConnectToPort(void* out, const char* port_name) {
+ Service::Interface* service = Service::g_manager->FetchFromPortName(port_name);
+ Core::g_app_core->SetReg(1, service->GetHandle());
+ DEBUG_LOG(SVC, "ConnectToPort called port_name=%s", port_name);
+ return 0;
+}
+
+/// Synchronize to an OS service
+Result SendSyncRequest(Handle handle) {
+ DEBUG_LOG(SVC, "SendSyncRequest called handle=0x%08X");
+ Service::Interface* service = Service::g_manager->FetchFromHandle(handle);
+ service->Sync();
+ return 0;
+}
+
+/// Close a handle
+Result CloseHandle(Handle handle) {
+ // ImplementMe
+ DEBUG_LOG(SVC, "(UNIMPLEMENTED) CloseHandle called handle=0x%08X", handle);
+ return 0;
+}
+
+/// Wait for a handle to synchronize, timeout after the specified nanoseconds
+Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
+ // ImplementMe
+ DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronization1 called handle=0x%08X, nanoseconds=%d",
+ handle, nano_seconds);
+ return 0;
+}
+
+/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
+Result WaitSynchronizationN(void* _out, void* _handles, u32 handle_count, u32 wait_all, s64 nano_seconds) {
+ s32* out = (s32*)_out;
+ Handle* handles = (Handle*)_handles;
+ // ImplementMe
+
+ DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronizationN called handle_count=%d, wait_all=%s, nanoseconds=%d %s",
+ handle_count, (wait_all ? "true" : "false"), nano_seconds);
+
+ for (u32 i = 0; i < handle_count; i++) {
+ DEBUG_LOG(SVC, "\thandle[%d]=0x%08X", i, handles[i]);
+ }
+ __KernelReschedule("WaitSynchronizationN");
+
+ return 0;
+}
+
+/// Create an address arbiter (to allocate access to shared resources)
+Result CreateAddressArbiter(void* arbiter) {
+ // ImplementMe
+ DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateAddressArbiter called");
+ Core::g_app_core->SetReg(1, 0xFABBDADD);
+ return 0;
+}
+
+/// Used to output a message on a debug hardware unit - does nothing on a retail unit
+void OutputDebugString(const char* string) {
+ NOTICE_LOG(SVC, "## OSDEBUG: %08X %s", Core::g_app_core->GetPC(), string);
+}
+
+/// Get resource limit
+Result GetResourceLimit(void* resource_limit, Handle process) {
+ // With regards to proceess values:
+ // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for
+ // the current KThread.
+ DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetResourceLimit called process=0x%08X", process);
+ Core::g_app_core->SetReg(1, 0xDEADBEEF);
+ return 0;
+}
+
+/// Get resource limit current values
+Result GetResourceLimitCurrentValues(void* _values, Handle resource_limit, void* names, s32 name_count) {
+ //s64* values = (s64*)_values;
+ DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetResourceLimitCurrentValues called resource_limit=%08X, names=%s, 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
+ return 0;
+}
+
+Result CreateThread(void* thread, u32 priority, u32 entry_point, u32 arg, u32 stack_top,
+ u32 processor_id) {
+ std::string name;
+ if (Symbols::HasSymbol(entry_point)) {
+ TSymbol symbol = Symbols::GetSymbol(entry_point);
+ name = symbol.name;
+ } else {
+ char buff[100];
+ sprintf(buff, "%s", "unknown-%08X", entry_point);
+ name = buff;
+ }
+ DEBUG_LOG(SVC, "CreateThread called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, "
+ "threadpriority=0x%08X, processorid=0x%08X", entry_point, name.c_str(), arg, stack_top,
+ priority, processor_id);
+
+ Handle handle = __KernelCreateThread(name.c_str(), entry_point, priority, processor_id,
+ stack_top);
+ Core::g_app_core->SetReg(1, 0xFEEDDEAF);
+
+ return 0;
+}
+
+Result CreateMutex(void* _mutex, u32 initial_locked) {
+ Handle* mutex = (Handle*)_mutex;
+ DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateMutex called initial_locked=%s",
+ initial_locked ? "true" : "false");
+ Core::g_app_core->SetReg(1, 0xF00D0BAD);
+ return 0;
+}
+
+Result ReleaseMutex(Handle handle) {
+ DEBUG_LOG(SVC, "(UNIMPLEMENTED) ReleaseMutex called handle=0x%08X", handle);
+ return 0;
+}
+
+Result GetThreadId(void* thread_id, u32 thread) {
+ DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetThreadId called thread=0x%08X", thread);
+ return 0;
+}
+
+Result QueryMemory(void *_info, void *_out, u32 addr) {
+ MemoryInfo* info = (MemoryInfo*) _info;
+ PageInfo* out = (PageInfo*) _out;
+ DEBUG_LOG(SVC, "(UNIMPLEMENTED) QueryMemory called addr=0x%08X", addr);
+ return 0;
+}
+
+Result CreateEvent(void* _event, u32 reset_type) {
+ Handle* event = (Handle*)_event;
+ DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateEvent called reset_type=0x%08X", reset_type);
+ Core::g_app_core->SetReg(1, 0xBADC0DE0);
+ return 0;
+}
+
+const HLE::FunctionDef SVC_Table[] = {
+ {0x00, NULL, "Unknown"},
+ {0x01, WrapI_VUUUUU, "ControlMemory"},
+ {0x02, WrapI_VVU, "QueryMemory"},
+ {0x03, NULL, "ExitProcess"},
+ {0x04, NULL, "GetProcessAffinityMask"},
+ {0x05, NULL, "SetProcessAffinityMask"},
+ {0x06, NULL, "GetProcessIdealProcessor"},
+ {0x07, NULL, "SetProcessIdealProcessor"},
+ {0x08, WrapI_VUUUUU, "CreateThread"},
+ {0x09, NULL, "ExitThread"},
+ {0x0A, NULL, "SleepThread"},
+ {0x0B, NULL, "GetThreadPriority"},
+ {0x0C, NULL, "SetThreadPriority"},
+ {0x0D, NULL, "GetThreadAffinityMask"},
+ {0x0E, NULL, "SetThreadAffinityMask"},
+ {0x0F, NULL, "GetThreadIdealProcessor"},
+ {0x10, NULL, "SetThreadIdealProcessor"},
+ {0x11, NULL, "GetCurrentProcessorNumber"},
+ {0x12, NULL, "Run"},
+ {0x13, WrapI_VU, "CreateMutex"},
+ {0x14, WrapI_U, "ReleaseMutex"},
+ {0x15, NULL, "CreateSemaphore"},
+ {0x16, NULL, "ReleaseSemaphore"},
+ {0x17, WrapI_VU, "CreateEvent"},
+ {0x18, NULL, "SignalEvent"},
+ {0x19, NULL, "ClearEvent"},
+ {0x1A, NULL, "CreateTimer"},
+ {0x1B, NULL, "SetTimer"},
+ {0x1C, NULL, "CancelTimer"},
+ {0x1D, NULL, "ClearTimer"},
+ {0x1E, NULL, "CreateMemoryBlock"},
+ {0x1F, WrapI_UUUU, "MapMemoryBlock"},
+ {0x20, NULL, "UnmapMemoryBlock"},
+ {0x21, WrapI_V, "CreateAddressArbiter"},
+ {0x22, NULL, "ArbitrateAddress"},
+ {0x23, WrapI_U, "CloseHandle"},
+ {0x24, WrapI_US64, "WaitSynchronization1"},
+ {0x25, WrapI_VVUUS64, "WaitSynchronizationN"},
+ {0x26, NULL, "SignalAndWait"},
+ {0x27, NULL, "DuplicateHandle"},
+ {0x28, NULL, "GetSystemTick"},
+ {0x29, NULL, "GetHandleInfo"},
+ {0x2A, NULL, "GetSystemInfo"},
+ {0x2B, NULL, "GetProcessInfo"},
+ {0x2C, NULL, "GetThreadInfo"},
+ {0x2D, WrapI_VC, "ConnectToPort"},
+ {0x2E, NULL, "SendSyncRequest1"},
+ {0x2F, NULL, "SendSyncRequest2"},
+ {0x30, NULL, "SendSyncRequest3"},
+ {0x31, NULL, "SendSyncRequest4"},
+ {0x32, WrapI_U, "SendSyncRequest"},
+ {0x33, NULL, "OpenProcess"},
+ {0x34, NULL, "OpenThread"},
+ {0x35, NULL, "GetProcessId"},
+ {0x36, NULL, "GetProcessIdOfThread"},
+ {0x37, WrapI_VU, "GetThreadId"},
+ {0x38, WrapI_VU, "GetResourceLimit"},
+ {0x39, NULL, "GetResourceLimitLimitValues"},
+ {0x3A, WrapI_VUVI, "GetResourceLimitCurrentValues"},
+ {0x3B, NULL, "GetThreadContext"},
+ {0x3C, NULL, "Break"},
+ {0x3D, WrapV_C, "OutputDebugString"},
+ {0x3E, NULL, "ControlPerformanceCounter"},
+ {0x3F, NULL, "Unknown"},
+ {0x40, NULL, "Unknown"},
+ {0x41, NULL, "Unknown"},
+ {0x42, NULL, "Unknown"},
+ {0x43, NULL, "Unknown"},
+ {0x44, NULL, "Unknown"},
+ {0x45, NULL, "Unknown"},
+ {0x46, NULL, "Unknown"},
+ {0x47, NULL, "CreatePort"},
+ {0x48, NULL, "CreateSessionToPort"},
+ {0x49, NULL, "CreateSession"},
+ {0x4A, NULL, "AcceptSession"},
+ {0x4B, NULL, "ReplyAndReceive1"},
+ {0x4C, NULL, "ReplyAndReceive2"},
+ {0x4D, NULL, "ReplyAndReceive3"},
+ {0x4E, NULL, "ReplyAndReceive4"},
+ {0x4F, NULL, "ReplyAndReceive"},
+ {0x50, NULL, "BindInterrupt"},
+ {0x51, NULL, "UnbindInterrupt"},
+ {0x52, NULL, "InvalidateProcessDataCache"},
+ {0x53, NULL, "StoreProcessDataCache"},
+ {0x54, NULL, "FlushProcessDataCache"},
+ {0x55, NULL, "StartInterProcessDma"},
+ {0x56, NULL, "StopDma"},
+ {0x57, NULL, "GetDmaState"},
+ {0x58, NULL, "RestartDma"},
+ {0x59, NULL, "Unknown"},
+ {0x5A, NULL, "Unknown"},
+ {0x5B, NULL, "Unknown"},
+ {0x5C, NULL, "Unknown"},
+ {0x5D, NULL, "Unknown"},
+ {0x5E, NULL, "Unknown"},
+ {0x5F, NULL, "Unknown"},
+ {0x60, NULL, "DebugActiveProcess"},
+ {0x61, NULL, "BreakDebugProcess"},
+ {0x62, NULL, "TerminateDebugProcess"},
+ {0x63, NULL, "GetProcessDebugEvent"},
+ {0x64, NULL, "ContinueDebugEvent"},
+ {0x65, NULL, "GetProcessList"},
+ {0x66, NULL, "GetThreadList"},
+ {0x67, NULL, "GetDebugThreadContext"},
+ {0x68, NULL, "SetDebugThreadContext"},
+ {0x69, NULL, "QueryDebugProcessMemory"},
+ {0x6A, NULL, "ReadProcessMemory"},
+ {0x6B, NULL, "WriteProcessMemory"},
+ {0x6C, NULL, "SetHardwareBreakPoint"},
+ {0x6D, NULL, "GetDebugThreadParam"},
+ {0x6E, NULL, "Unknown"},
+ {0x6F, NULL, "Unknown"},
+ {0x70, NULL, "ControlProcessMemory"},
+ {0x71, NULL, "MapProcessMemory"},
+ {0x72, NULL, "UnmapProcessMemory"},
+ {0x73, NULL, "Unknown"},
+ {0x74, NULL, "Unknown"},
+ {0x75, NULL, "Unknown"},
+ {0x76, NULL, "TerminateProcess"},
+ {0x77, NULL, "Unknown"},
+ {0x78, NULL, "CreateResourceLimit"},
+ {0x79, NULL, "Unknown"},
+ {0x7A, NULL, "Unknown"},
+ {0x7B, NULL, "Unknown"},
+ {0x7C, NULL, "KernelSetState"},
+ {0x7D, NULL, "QueryProcessMemory"},
+};
+
+void Register() {
+ HLE::RegisterModule("SVC_Table", ARRAY_SIZE(SVC_Table), SVC_Table);
+}
+
+} // namespace
diff --git a/src/core/hle/svc.h b/src/core/hle/svc.h
new file mode 100644
index 000000000..5c35977d1
--- /dev/null
+++ b/src/core/hle/svc.h
@@ -0,0 +1,48 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// SVC types
+
+struct MemoryInfo {
+ u32 base_address;
+ u32 size;
+ u32 permission;
+ u32 state;
+};
+
+struct PageInfo {
+ u32 flags;
+};
+
+struct ThreadContext {
+ u32 cpu_registers[13];
+ u32 sp;
+ u32 lr;
+ u32 pc;
+ u32 cpsr;
+ u32 fpu_registers[32];
+ u32 fpscr;
+ u32 fpexc;
+};
+
+enum ResetType {
+ RESETTYPE_ONESHOT,
+ RESETTYPE_STICKY,
+ RESETTYPE_PULSE,
+ RESETTYPE_MAX_BIT = (1u << 31),
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Namespace SVC
+
+namespace SVC {
+
+void Register();
+
+} // namespace
diff --git a/src/core/hle/syscall.cpp b/src/core/hle/syscall.cpp
deleted file mode 100644
index 9a1235246..000000000
--- a/src/core/hle/syscall.cpp
+++ /dev/null
@@ -1,348 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2
-// Refer to the license.txt file included.
-
-#include
-#include
-
-#include "common/symbols.h"
-
-#include "core/mem_map.h"
-
-#include "core/hle/kernel/kernel.h"
-#include "core/hle/kernel/thread.h"
-
-#include "core/hle/function_wrappers.h"
-#include "core/hle/syscall.h"
-#include "core/hle/service/service.h"
-#include "core/hle/kernel/thread.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace Syscall
-
-namespace Syscall {
-
-enum ControlMemoryOperation {
- MEMORY_OPERATION_HEAP = 0x00000003,
- MEMORY_OPERATION_GSP_HEAP = 0x00010003,
-};
-
-enum MapMemoryPermission {
- MEMORY_PERMISSION_UNMAP = 0x00000000,
- MEMORY_PERMISSION_NORMAL = 0x00000001,
-};
-
-/// Map application or GSP heap memory
-Result ControlMemory(void* _outaddr, u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) {
- u32* outaddr = (u32*)_outaddr;
- u32 virtual_address = 0x00000000;
-
- DEBUG_LOG(SVC, "ControlMemory called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X",
- operation, addr0, addr1, size, permissions);
-
- switch (operation) {
-
- // Map normal heap memory
- case MEMORY_OPERATION_HEAP:
- virtual_address = Memory::MapBlock_Heap(size, operation, permissions);
- break;
-
- // Map GSP heap memory
- case MEMORY_OPERATION_GSP_HEAP:
- virtual_address = Memory::MapBlock_HeapGSP(size, operation, permissions);
- break;
-
- // Unknown ControlMemory operation
- default:
- ERROR_LOG(SVC, "ControlMemory unknown operation=0x%08X", operation);
- }
- if (NULL != outaddr) {
- *outaddr = virtual_address;
- }
- Core::g_app_core->SetReg(1, virtual_address);
-
- return 0;
-}
-
-/// Maps a memory block to specified address
-Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherpermission) {
- DEBUG_LOG(SVC, "MapMemoryBlock called memblock=0x08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d",
- memblock, addr, mypermissions, otherpermission);
- switch (mypermissions) {
- case MEMORY_PERMISSION_NORMAL:
- case MEMORY_PERMISSION_NORMAL + 1:
- case MEMORY_PERMISSION_NORMAL + 2:
- Memory::MapBlock_Shared(memblock, addr, mypermissions);
- break;
- default:
- ERROR_LOG(OSHLE, "MapMemoryBlock unknown permissions=0x%08X", mypermissions);
- }
- return 0;
-}
-
-/// Connect to an OS service given the port name, returns the handle to the port to out
-Result ConnectToPort(void* out, const char* port_name) {
- Service::Interface* service = Service::g_manager->FetchFromPortName(port_name);
- Core::g_app_core->SetReg(1, service->GetHandle());
- DEBUG_LOG(SVC, "ConnectToPort called port_name=%s", port_name);
- return 0;
-}
-
-/// Synchronize to an OS service
-Result SendSyncRequest(Handle handle) {
- DEBUG_LOG(SVC, "SendSyncRequest called handle=0x%08X");
- Service::Interface* service = Service::g_manager->FetchFromHandle(handle);
- service->Sync();
- return 0;
-}
-
-/// Close a handle
-Result CloseHandle(Handle handle) {
- // ImplementMe
- DEBUG_LOG(SVC, "(UNIMPLEMENTED) CloseHandle called handle=0x%08X", handle);
- return 0;
-}
-
-/// Wait for a handle to synchronize, timeout after the specified nanoseconds
-Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
- // ImplementMe
- DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronization1 called handle=0x%08X, nanoseconds=%d",
- handle, nano_seconds);
- return 0;
-}
-
-/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
-Result WaitSynchronizationN(void* _out, void* _handles, u32 handle_count, u32 wait_all, s64 nano_seconds) {
- s32* out = (s32*)_out;
- Handle* handles = (Handle*)_handles;
- // ImplementMe
-
- DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronizationN called handle_count=%d, wait_all=%s, nanoseconds=%d %s",
- handle_count, (wait_all ? "true" : "false"), nano_seconds);
-
- for (u32 i = 0; i < handle_count; i++) {
- DEBUG_LOG(SVC, "\thandle[%d]=0x%08X", i, handles[i]);
- }
- return 0;
-}
-
-/// Create an address arbiter (to allocate access to shared resources)
-Result CreateAddressArbiter(void* arbiter) {
- // ImplementMe
- DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateAddressArbiter called");
- Core::g_app_core->SetReg(1, 0xFABBDADD);
- return 0;
-}
-
-/// Used to output a message on a debug hardware unit - does nothing on a retail unit
-void OutputDebugString(const char* string) {
- NOTICE_LOG(SVC, "## OSDEBUG: %08X %s", Core::g_app_core->GetPC(), string);
-}
-
-/// Get resource limit
-Result GetResourceLimit(void* resource_limit, Handle process) {
- // With regards to proceess values:
- // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for
- // the current KThread.
- DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetResourceLimit called process=0x%08X", process);
- Core::g_app_core->SetReg(1, 0xDEADBEEF);
- return 0;
-}
-
-/// Get resource limit current values
-Result GetResourceLimitCurrentValues(void* _values, Handle resource_limit, void* names, s32 name_count) {
- //s64* values = (s64*)_values;
- DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetResourceLimitCurrentValues called resource_limit=%08X, names=%s, 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
- return 0;
-}
-
-Result CreateThread(void* thread, u32 priority, u32 entry_point, u32 arg, u32 stack_top,
- u32 processor_id) {
- std::string name;
- if (Symbols::HasSymbol(entry_point)) {
- TSymbol symbol = Symbols::GetSymbol(entry_point);
- name = symbol.name;
- } else {
- char buff[100];
- sprintf(buff, "%s", "unknown-%08X", entry_point);
- name = buff;
- }
- DEBUG_LOG(SVC, "CreateThread called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, "
- "threadpriority=0x%08X, processorid=0x%08X", entry_point, name.c_str(), arg, stack_top,
- priority, processor_id);
-
- Handle handle = __KernelCreateThread(name.c_str(), entry_point, priority, processor_id,
- stack_top);
- Core::g_app_core->SetReg(1, 0xFEEDDEAF);
-
- return 0;
-}
-
-Result CreateMutex(void* _mutex, u32 initial_locked) {
- Handle* mutex = (Handle*)_mutex;
- DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateMutex called initial_locked=%s",
- initial_locked ? "true" : "false");
- Core::g_app_core->SetReg(1, 0xF00D0BAD);
- return 0;
-}
-
-Result ReleaseMutex(Handle handle) {
- DEBUG_LOG(SVC, "(UNIMPLEMENTED) ReleaseMutex called handle=0x%08X", handle);
- return 0;
-}
-
-Result GetThreadId(void* thread_id, u32 thread) {
- DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetThreadId called thread=0x%08X", thread);
- return 0;
-}
-
-Result QueryMemory(void *_info, void *_out, u32 addr) {
- MemoryInfo* info = (MemoryInfo*) _info;
- PageInfo* out = (PageInfo*) _out;
- DEBUG_LOG(SVC, "(UNIMPLEMENTED) QueryMemory called addr=0x%08X", addr);
- return 0;
-}
-
-Result CreateEvent(void* _event, u32 reset_type) {
- Handle* event = (Handle*)_event;
- DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateEvent called reset_type=0x%08X", reset_type);
- Core::g_app_core->SetReg(1, 0xBADC0DE0);
- return 0;
-}
-
-const HLE::FunctionDef Syscall_Table[] = {
- {0x00, NULL, "Unknown"},
- {0x01, WrapI_VUUUUU, "ControlMemory"},
- {0x02, WrapI_VVU, "QueryMemory"},
- {0x03, NULL, "ExitProcess"},
- {0x04, NULL, "GetProcessAffinityMask"},
- {0x05, NULL, "SetProcessAffinityMask"},
- {0x06, NULL, "GetProcessIdealProcessor"},
- {0x07, NULL, "SetProcessIdealProcessor"},
- {0x08, WrapI_VUUUUU, "CreateThread"},
- {0x09, NULL, "ExitThread"},
- {0x0A, NULL, "SleepThread"},
- {0x0B, NULL, "GetThreadPriority"},
- {0x0C, NULL, "SetThreadPriority"},
- {0x0D, NULL, "GetThreadAffinityMask"},
- {0x0E, NULL, "SetThreadAffinityMask"},
- {0x0F, NULL, "GetThreadIdealProcessor"},
- {0x10, NULL, "SetThreadIdealProcessor"},
- {0x11, NULL, "GetCurrentProcessorNumber"},
- {0x12, NULL, "Run"},
- {0x13, WrapI_VU, "CreateMutex"},
- {0x14, WrapI_U, "ReleaseMutex"},
- {0x15, NULL, "CreateSemaphore"},
- {0x16, NULL, "ReleaseSemaphore"},
- {0x17, WrapI_VU, "CreateEvent"},
- {0x18, NULL, "SignalEvent"},
- {0x19, NULL, "ClearEvent"},
- {0x1A, NULL, "CreateTimer"},
- {0x1B, NULL, "SetTimer"},
- {0x1C, NULL, "CancelTimer"},
- {0x1D, NULL, "ClearTimer"},
- {0x1E, NULL, "CreateMemoryBlock"},
- {0x1F, WrapI_UUUU, "MapMemoryBlock"},
- {0x20, NULL, "UnmapMemoryBlock"},
- {0x21, WrapI_V, "CreateAddressArbiter"},
- {0x22, NULL, "ArbitrateAddress"},
- {0x23, WrapI_U, "CloseHandle"},
- {0x24, WrapI_US64, "WaitSynchronization1"},
- {0x25, WrapI_VVUUS64, "WaitSynchronizationN"},
- {0x26, NULL, "SignalAndWait"},
- {0x27, NULL, "DuplicateHandle"},
- {0x28, NULL, "GetSystemTick"},
- {0x29, NULL, "GetHandleInfo"},
- {0x2A, NULL, "GetSystemInfo"},
- {0x2B, NULL, "GetProcessInfo"},
- {0x2C, NULL, "GetThreadInfo"},
- {0x2D, WrapI_VC, "ConnectToPort"},
- {0x2E, NULL, "SendSyncRequest1"},
- {0x2F, NULL, "SendSyncRequest2"},
- {0x30, NULL, "SendSyncRequest3"},
- {0x31, NULL, "SendSyncRequest4"},
- {0x32, WrapI_U, "SendSyncRequest"},
- {0x33, NULL, "OpenProcess"},
- {0x34, NULL, "OpenThread"},
- {0x35, NULL, "GetProcessId"},
- {0x36, NULL, "GetProcessIdOfThread"},
- {0x37, WrapI_VU, "GetThreadId"},
- {0x38, WrapI_VU, "GetResourceLimit"},
- {0x39, NULL, "GetResourceLimitLimitValues"},
- {0x3A, WrapI_VUVI, "GetResourceLimitCurrentValues"},
- {0x3B, NULL, "GetThreadContext"},
- {0x3C, NULL, "Break"},
- {0x3D, WrapV_C, "OutputDebugString"},
- {0x3E, NULL, "ControlPerformanceCounter"},
- {0x3F, NULL, "Unknown"},
- {0x40, NULL, "Unknown"},
- {0x41, NULL, "Unknown"},
- {0x42, NULL, "Unknown"},
- {0x43, NULL, "Unknown"},
- {0x44, NULL, "Unknown"},
- {0x45, NULL, "Unknown"},
- {0x46, NULL, "Unknown"},
- {0x47, NULL, "CreatePort"},
- {0x48, NULL, "CreateSessionToPort"},
- {0x49, NULL, "CreateSession"},
- {0x4A, NULL, "AcceptSession"},
- {0x4B, NULL, "ReplyAndReceive1"},
- {0x4C, NULL, "ReplyAndReceive2"},
- {0x4D, NULL, "ReplyAndReceive3"},
- {0x4E, NULL, "ReplyAndReceive4"},
- {0x4F, NULL, "ReplyAndReceive"},
- {0x50, NULL, "BindInterrupt"},
- {0x51, NULL, "UnbindInterrupt"},
- {0x52, NULL, "InvalidateProcessDataCache"},
- {0x53, NULL, "StoreProcessDataCache"},
- {0x54, NULL, "FlushProcessDataCache"},
- {0x55, NULL, "StartInterProcessDma"},
- {0x56, NULL, "StopDma"},
- {0x57, NULL, "GetDmaState"},
- {0x58, NULL, "RestartDma"},
- {0x59, NULL, "Unknown"},
- {0x5A, NULL, "Unknown"},
- {0x5B, NULL, "Unknown"},
- {0x5C, NULL, "Unknown"},
- {0x5D, NULL, "Unknown"},
- {0x5E, NULL, "Unknown"},
- {0x5F, NULL, "Unknown"},
- {0x60, NULL, "DebugActiveProcess"},
- {0x61, NULL, "BreakDebugProcess"},
- {0x62, NULL, "TerminateDebugProcess"},
- {0x63, NULL, "GetProcessDebugEvent"},
- {0x64, NULL, "ContinueDebugEvent"},
- {0x65, NULL, "GetProcessList"},
- {0x66, NULL, "GetThreadList"},
- {0x67, NULL, "GetDebugThreadContext"},
- {0x68, NULL, "SetDebugThreadContext"},
- {0x69, NULL, "QueryDebugProcessMemory"},
- {0x6A, NULL, "ReadProcessMemory"},
- {0x6B, NULL, "WriteProcessMemory"},
- {0x6C, NULL, "SetHardwareBreakPoint"},
- {0x6D, NULL, "GetDebugThreadParam"},
- {0x6E, NULL, "Unknown"},
- {0x6F, NULL, "Unknown"},
- {0x70, NULL, "ControlProcessMemory"},
- {0x71, NULL, "MapProcessMemory"},
- {0x72, NULL, "UnmapProcessMemory"},
- {0x73, NULL, "Unknown"},
- {0x74, NULL, "Unknown"},
- {0x75, NULL, "Unknown"},
- {0x76, NULL, "TerminateProcess"},
- {0x77, NULL, "Unknown"},
- {0x78, NULL, "CreateResourceLimit"},
- {0x79, NULL, "Unknown"},
- {0x7A, NULL, "Unknown"},
- {0x7B, NULL, "Unknown"},
- {0x7C, NULL, "KernelSetState"},
- {0x7D, NULL, "QueryProcessMemory"},
-};
-
-void Register() {
- HLE::RegisterModule("SyscallTable", ARRAY_SIZE(Syscall_Table), Syscall_Table);
-}
-
-} // namespace
diff --git a/src/core/hle/syscall.h b/src/core/hle/syscall.h
deleted file mode 100644
index 3da349ed5..000000000
--- a/src/core/hle/syscall.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include "common/common_types.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// SVC types
-
-struct MemoryInfo {
- u32 base_address;
- u32 size;
- u32 permission;
- u32 state;
-};
-
-struct PageInfo {
- u32 flags;
-};
-
-struct ThreadContext {
- u32 cpu_registers[13];
- u32 sp;
- u32 lr;
- u32 pc;
- u32 cpsr;
- u32 fpu_registers[32];
- u32 fpscr;
- u32 fpexc;
-};
-
-enum ResetType {
- RESETTYPE_ONESHOT,
- RESETTYPE_STICKY,
- RESETTYPE_PULSE,
- RESETTYPE_MAX_BIT = (1u << 31),
-};
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace Syscall
-
-namespace Syscall {
-
-void Register();
-
-} // namespace
--
cgit v1.2.3
From 49dc2ce8ac4fc37a008fa28e0771c8c74c576b05 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Tue, 20 May 2014 18:50:16 -0400
Subject: ARM_Interface: added SaveContext and LoadContext functions for HLE
thread switching
---
src/core/arm/arm_interface.h | 16 +++++++++++-
src/core/arm/interpreter/arm_interpreter.cpp | 36 ++++++++++++++++++++++++++
src/core/arm/interpreter/arm_interpreter.h | 12 +++++++++
src/core/hle/kernel/thread.cpp | 38 ++--------------------------
4 files changed, 65 insertions(+), 37 deletions(-)
(limited to 'src')
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index 5c382ebbd..52bc82115 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -7,6 +7,8 @@
#include "common/common.h"
#include "common/common_types.h"
+#include "core/hle/svc.h"
+
/// Generic ARM11 CPU interface
class ARM_Interface : NonCopyable {
public:
@@ -75,6 +77,18 @@ public:
*/
virtual u64 GetTicks() const = 0;
+ /**
+ * Saves the current CPU context
+ * @param ctx Thread context to save
+ */
+ virtual void SaveContext(ThreadContext& ctx) = 0;
+
+ /**
+ * Loads a CPU context
+ * @param ctx Thread context to load
+ */
+ virtual void LoadContext(const ThreadContext& ctx) = 0;
+
/// Getter for m_num_instructions
u64 GetNumInstructions() {
return m_num_instructions;
@@ -90,6 +104,6 @@ protected:
private:
- u64 m_num_instructions; ///< Number of instructions executed
+ u64 m_num_instructions; ///< Number of instructions executed
};
diff --git a/src/core/arm/interpreter/arm_interpreter.cpp b/src/core/arm/interpreter/arm_interpreter.cpp
index c21ff0464..b8c46cdfc 100644
--- a/src/core/arm/interpreter/arm_interpreter.cpp
+++ b/src/core/arm/interpreter/arm_interpreter.cpp
@@ -101,3 +101,39 @@ void ARM_Interpreter::ExecuteInstructions(int num_instructions) {
m_state->NumInstrsToExecute = num_instructions;
ARMul_Emulate32(m_state);
}
+
+/**
+ * Saves the current CPU context
+ * @param ctx Thread context to save
+ * @todo Do we need to save Reg[15] and NextInstr?
+ */
+void ARM_Interpreter::SaveContext(ThreadContext& ctx) {
+ memcpy(ctx.cpu_registers, m_state->Reg, sizeof(ctx.cpu_registers));
+ memcpy(ctx.fpu_registers, m_state->ExtReg, sizeof(ctx.fpu_registers));
+
+ ctx.sp = m_state->Reg[13];
+ ctx.lr = m_state->Reg[14];
+ ctx.pc = m_state->pc;
+ ctx.cpsr = m_state->Cpsr;
+
+ ctx.fpscr = m_state->VFP[1];
+ ctx.fpexc = m_state->VFP[2];
+}
+
+/**
+ * Loads a CPU context
+ * @param ctx Thread context to load
+ * @param Do we need to load Reg[15] and NextInstr?
+ */
+void ARM_Interpreter::LoadContext(const ThreadContext& ctx) {
+ memcpy(m_state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers));
+ memcpy(m_state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers));
+
+ m_state->Reg[13] = ctx.sp;
+ m_state->Reg[14] = ctx.lr;
+ m_state->pc = ctx.pc;
+ m_state->Cpsr = ctx.cpsr;
+
+ m_state->VFP[1] = ctx.fpscr;
+ m_state->VFP[2] = ctx.fpexc;
+}
diff --git a/src/core/arm/interpreter/arm_interpreter.h b/src/core/arm/interpreter/arm_interpreter.h
index 474ba3e45..15240568c 100644
--- a/src/core/arm/interpreter/arm_interpreter.h
+++ b/src/core/arm/interpreter/arm_interpreter.h
@@ -60,6 +60,18 @@ public:
*/
u64 GetTicks() const;
+ /**
+ * Saves the current CPU context
+ * @param ctx Thread context to save
+ */
+ void SaveContext(ThreadContext& ctx);
+
+ /**
+ * Loads a CPU context
+ * @param ctx Thread context to load
+ */
+ void LoadContext(const ThreadContext& ctx);
+
protected:
/**
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 136fff021..b3d306c53 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -98,46 +98,12 @@ inline void __SetCurrentThread(Thread* t) {
/// Saves the current CPU context
void __KernelSaveContext(ThreadContext& ctx) {
- ctx.cpu_registers[0] = Core::g_app_core->GetReg(0);
- ctx.cpu_registers[1] = Core::g_app_core->GetReg(1);
- ctx.cpu_registers[2] = Core::g_app_core->GetReg(2);
- ctx.cpu_registers[3] = Core::g_app_core->GetReg(3);
- ctx.cpu_registers[4] = Core::g_app_core->GetReg(4);
- ctx.cpu_registers[5] = Core::g_app_core->GetReg(5);
- ctx.cpu_registers[6] = Core::g_app_core->GetReg(6);
- ctx.cpu_registers[7] = Core::g_app_core->GetReg(7);
- ctx.cpu_registers[8] = Core::g_app_core->GetReg(8);
- ctx.cpu_registers[9] = Core::g_app_core->GetReg(9);
- ctx.cpu_registers[10] = Core::g_app_core->GetReg(10);
- ctx.cpu_registers[11] = Core::g_app_core->GetReg(11);
- ctx.cpu_registers[12] = Core::g_app_core->GetReg(12);
- ctx.sp = Core::g_app_core->GetReg(13);
- ctx.lr = Core::g_app_core->GetReg(14);
- ctx.pc = Core::g_app_core->GetPC();
- ctx.cpsr = Core::g_app_core->GetCPSR();
+ Core::g_app_core->SaveContext(ctx);
}
/// Loads a CPU context
void __KernelLoadContext(const ThreadContext& ctx) {
- Core::g_app_core->SetReg(0, ctx.cpu_registers[0]);
- Core::g_app_core->SetReg(1, ctx.cpu_registers[1]);
- Core::g_app_core->SetReg(2, ctx.cpu_registers[2]);
- Core::g_app_core->SetReg(3, ctx.cpu_registers[3]);
- Core::g_app_core->SetReg(4, ctx.cpu_registers[4]);
- Core::g_app_core->SetReg(5, ctx.cpu_registers[5]);
- Core::g_app_core->SetReg(6, ctx.cpu_registers[6]);
- Core::g_app_core->SetReg(7, ctx.cpu_registers[7]);
- Core::g_app_core->SetReg(8, ctx.cpu_registers[8]);
- Core::g_app_core->SetReg(9, ctx.cpu_registers[9]);
- Core::g_app_core->SetReg(10, ctx.cpu_registers[10]);
- Core::g_app_core->SetReg(11, ctx.cpu_registers[11]);
- Core::g_app_core->SetReg(12, ctx.cpu_registers[12]);
- Core::g_app_core->SetReg(13, ctx.sp);
- Core::g_app_core->SetReg(14, ctx.lr);
- //Core::g_app_core->SetReg(15, ctx.pc);
-
- Core::g_app_core->SetPC(ctx.pc);
- Core::g_app_core->SetCPSR(ctx.cpsr);
+ Core::g_app_core->LoadContext(ctx);
}
/// Resets a thread
--
cgit v1.2.3
From 001280245685ade50326301409e8aee28602504d Mon Sep 17 00:00:00 2001
From: bunnei
Date: Tue, 20 May 2014 18:52:54 -0400
Subject: ARM_Interpreter/ARM_Interface: Fixed member variable naming to be
consistent with style guide
---
src/core/arm/arm_interface.h | 10 ++--
src/core/arm/interpreter/arm_interpreter.cpp | 78 ++++++++++++++--------------
src/core/arm/interpreter/arm_interpreter.h | 2 +-
3 files changed, 45 insertions(+), 45 deletions(-)
(limited to 'src')
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h
index 52bc82115..b73786ccd 100644
--- a/src/core/arm/arm_interface.h
+++ b/src/core/arm/arm_interface.h
@@ -13,7 +13,7 @@
class ARM_Interface : NonCopyable {
public:
ARM_Interface() {
- m_num_instructions = 0;
+ num_instructions = 0;
}
~ARM_Interface() {
@@ -25,7 +25,7 @@ public:
*/
void Run(int num_instructions) {
ExecuteInstructions(num_instructions);
- m_num_instructions += num_instructions;
+ num_instructions += num_instructions;
}
/// Step CPU by one instruction
@@ -89,9 +89,9 @@ public:
*/
virtual void LoadContext(const ThreadContext& ctx) = 0;
- /// Getter for m_num_instructions
+ /// Getter for num_instructions
u64 GetNumInstructions() {
- return m_num_instructions;
+ return num_instructions;
}
protected:
@@ -104,6 +104,6 @@ protected:
private:
- u64 m_num_instructions; ///< Number of instructions executed
+ u64 num_instructions; ///< Number of instructions executed
};
diff --git a/src/core/arm/interpreter/arm_interpreter.cpp b/src/core/arm/interpreter/arm_interpreter.cpp
index b8c46cdfc..a9ec94820 100644
--- a/src/core/arm/interpreter/arm_interpreter.cpp
+++ b/src/core/arm/interpreter/arm_interpreter.cpp
@@ -9,30 +9,30 @@ const static cpu_config_t s_arm11_cpu_info = {
};
ARM_Interpreter::ARM_Interpreter() {
- m_state = new ARMul_State;
+ state = new ARMul_State;
ARMul_EmulateInit();
- ARMul_NewState(m_state);
+ ARMul_NewState(state);
- m_state->abort_model = 0;
- m_state->cpu = (cpu_config_t*)&s_arm11_cpu_info;
- m_state->bigendSig = LOW;
+ state->abort_model = 0;
+ state->cpu = (cpu_config_t*)&s_arm11_cpu_info;
+ state->bigendSig = LOW;
- ARMul_SelectProcessor(m_state, ARM_v6_Prop | ARM_v5_Prop | ARM_v5e_Prop);
- m_state->lateabtSig = LOW;
- mmu_init(m_state);
+ ARMul_SelectProcessor(state, ARM_v6_Prop | ARM_v5_Prop | ARM_v5e_Prop);
+ state->lateabtSig = LOW;
+ mmu_init(state);
// Reset the core to initial state
- ARMul_Reset(m_state);
- m_state->NextInstr = 0;
- m_state->Emulate = 3;
+ ARMul_Reset(state);
+ state->NextInstr = 0;
+ state->Emulate = 3;
- m_state->pc = m_state->Reg[15] = 0x00000000;
- m_state->Reg[13] = 0x10000000; // Set stack pointer to the top of the stack
+ state->pc = state->Reg[15] = 0x00000000;
+ state->Reg[13] = 0x10000000; // Set stack pointer to the top of the stack
}
ARM_Interpreter::~ARM_Interpreter() {
- delete m_state;
+ delete state;
}
/**
@@ -40,7 +40,7 @@ ARM_Interpreter::~ARM_Interpreter() {
* @param addr Address to set PC to
*/
void ARM_Interpreter::SetPC(u32 pc) {
- m_state->pc = m_state->Reg[15] = pc;
+ state->pc = state->Reg[15] = pc;
}
/*
@@ -48,7 +48,7 @@ void ARM_Interpreter::SetPC(u32 pc) {
* @return Returns current PC
*/
u32 ARM_Interpreter::GetPC() const {
- return m_state->pc;
+ return state->pc;
}
/**
@@ -57,7 +57,7 @@ u32 ARM_Interpreter::GetPC() const {
* @return Returns the value in the register
*/
u32 ARM_Interpreter::GetReg(int index) const {
- return m_state->Reg[index];
+ return state->Reg[index];
}
/**
@@ -66,7 +66,7 @@ u32 ARM_Interpreter::GetReg(int index) const {
* @param value Value to set register to
*/
void ARM_Interpreter::SetReg(int index, u32 value) {
- m_state->Reg[index] = value;
+ state->Reg[index] = value;
}
/**
@@ -74,7 +74,7 @@ void ARM_Interpreter::SetReg(int index, u32 value) {
* @return Returns the value of the CPSR register
*/
u32 ARM_Interpreter::GetCPSR() const {
- return m_state->Cpsr;
+ return state->Cpsr;
}
/**
@@ -82,7 +82,7 @@ u32 ARM_Interpreter::GetCPSR() const {
* @param cpsr Value to set CPSR to
*/
void ARM_Interpreter::SetCPSR(u32 cpsr) {
- m_state->Cpsr = cpsr;
+ state->Cpsr = cpsr;
}
/**
@@ -90,7 +90,7 @@ void ARM_Interpreter::SetCPSR(u32 cpsr) {
* @return Returns number of clock ticks
*/
u64 ARM_Interpreter::GetTicks() const {
- return ARMul_Time(m_state);
+ return ARMul_Time(state);
}
/**
@@ -98,8 +98,8 @@ u64 ARM_Interpreter::GetTicks() const {
* @param num_instructions Number of instructions to executes
*/
void ARM_Interpreter::ExecuteInstructions(int num_instructions) {
- m_state->NumInstrsToExecute = num_instructions;
- ARMul_Emulate32(m_state);
+ state->NumInstrsToExecute = num_instructions;
+ ARMul_Emulate32(state);
}
/**
@@ -108,16 +108,16 @@ void ARM_Interpreter::ExecuteInstructions(int num_instructions) {
* @todo Do we need to save Reg[15] and NextInstr?
*/
void ARM_Interpreter::SaveContext(ThreadContext& ctx) {
- memcpy(ctx.cpu_registers, m_state->Reg, sizeof(ctx.cpu_registers));
- memcpy(ctx.fpu_registers, m_state->ExtReg, sizeof(ctx.fpu_registers));
+ memcpy(ctx.cpu_registers, state->Reg, sizeof(ctx.cpu_registers));
+ memcpy(ctx.fpu_registers, state->ExtReg, sizeof(ctx.fpu_registers));
- ctx.sp = m_state->Reg[13];
- ctx.lr = m_state->Reg[14];
- ctx.pc = m_state->pc;
- ctx.cpsr = m_state->Cpsr;
+ ctx.sp = state->Reg[13];
+ ctx.lr = state->Reg[14];
+ ctx.pc = state->pc;
+ ctx.cpsr = state->Cpsr;
- ctx.fpscr = m_state->VFP[1];
- ctx.fpexc = m_state->VFP[2];
+ ctx.fpscr = state->VFP[1];
+ ctx.fpexc = state->VFP[2];
}
/**
@@ -126,14 +126,14 @@ void ARM_Interpreter::SaveContext(ThreadContext& ctx) {
* @param Do we need to load Reg[15] and NextInstr?
*/
void ARM_Interpreter::LoadContext(const ThreadContext& ctx) {
- memcpy(m_state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers));
- memcpy(m_state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers));
+ memcpy(state->Reg, ctx.cpu_registers, sizeof(ctx.cpu_registers));
+ memcpy(state->ExtReg, ctx.fpu_registers, sizeof(ctx.fpu_registers));
- m_state->Reg[13] = ctx.sp;
- m_state->Reg[14] = ctx.lr;
- m_state->pc = ctx.pc;
- m_state->Cpsr = ctx.cpsr;
+ state->Reg[13] = ctx.sp;
+ state->Reg[14] = ctx.lr;
+ state->pc = ctx.pc;
+ state->Cpsr = ctx.cpsr;
- m_state->VFP[1] = ctx.fpscr;
- m_state->VFP[2] = ctx.fpexc;
+ state->VFP[1] = ctx.fpscr;
+ state->VFP[2] = ctx.fpexc;
}
diff --git a/src/core/arm/interpreter/arm_interpreter.h b/src/core/arm/interpreter/arm_interpreter.h
index 15240568c..6a531e497 100644
--- a/src/core/arm/interpreter/arm_interpreter.h
+++ b/src/core/arm/interpreter/arm_interpreter.h
@@ -82,6 +82,6 @@ protected:
private:
- ARMul_State* m_state;
+ ARMul_State* state;
};
--
cgit v1.2.3
From 75c6d2a8fa3547946227094af6c179e5ccba0e1e Mon Sep 17 00:00:00 2001
From: bunnei
Date: Tue, 20 May 2014 19:37:46 -0400
Subject: thread: moved threading calls to the Kernel namespace
---
src/core/hle/kernel/kernel.cpp | 6 +-
src/core/hle/kernel/thread.cpp | 184 +++++++++++++++++++++--------------------
src/core/hle/kernel/thread.h | 26 ++++--
src/core/hle/svc.cpp | 4 +-
4 files changed, 117 insertions(+), 103 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index b1fdffde5..45e36173c 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -132,11 +132,11 @@ Object* ObjectPool::CreateByIDType(int type) {
}
void Init() {
- __KernelThreadingInit();
+ Kernel::ThreadingInit();
}
void Shutdown() {
- __KernelThreadingShutdown();
+ Kernel::ThreadingShutdown();
}
} // namespace
@@ -147,7 +147,7 @@ bool __KernelLoadExec(u32 entry_point) {
Core::g_app_core->SetPC(entry_point);
// 0x30 is the typical main thread priority I've seen used so far
- Handle thread_id = __KernelSetupMainThread(0x30);
+ Handle thread_id = Kernel::SetupMainThread(0x30);
return true;
}
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index b3d306c53..7b4f0ea47 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -19,7 +19,7 @@
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/thread.h"
-// Enums
+namespace Kernel {
enum ThreadStatus {
THREADSTATUS_RUNNING = 1,
@@ -81,33 +81,32 @@ std::vector g_thread_queue;
Common::ThreadQueueList g_thread_ready_queue;
Handle g_current_thread_handle;
-
Thread* g_current_thread;
+/// Gets the current thread
inline Thread* __GetCurrentThread() {
return g_current_thread;
}
+/// Sets the current thread
inline void __SetCurrentThread(Thread* t) {
g_current_thread = t;
g_current_thread_handle = t->GetHandle();
}
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
/// Saves the current CPU context
-void __KernelSaveContext(ThreadContext& ctx) {
+void __SaveContext(ThreadContext& ctx) {
Core::g_app_core->SaveContext(ctx);
}
/// Loads a CPU context
-void __KernelLoadContext(const ThreadContext& ctx) {
+void __LoadContext(const ThreadContext& ctx) {
Core::g_app_core->LoadContext(ctx);
}
/// Resets a thread
-void __KernelResetThread(Thread* t, s32 lowest_priority) {
+void __ResetThread(Thread* t, s32 lowest_priority) {
memset(&t->context, 0, sizeof(ThreadContext));
t->context.pc = t->entry_point;
@@ -121,7 +120,7 @@ void __KernelResetThread(Thread* t, s32 lowest_priority) {
}
/// Change a thread to "ready" state
-void __KernelChangeReadyState(Thread* t, bool ready) {
+void __ChangeReadyState(Thread* t, bool ready) {
Handle handle = t->GetHandle();
if (t->IsReady()) {
if (!ready) {
@@ -138,11 +137,11 @@ void __KernelChangeReadyState(Thread* t, bool ready) {
}
/// Changes a threads state
-void __KernelChangeThreadState(Thread* t, ThreadStatus new_status) {
+void __ChangeThreadState(Thread* t, ThreadStatus new_status) {
if (!t || t->status == new_status) {
return;
}
- __KernelChangeReadyState(t, (new_status & THREADSTATUS_READY) != 0);
+ __ChangeReadyState(t, (new_status & THREADSTATUS_READY) != 0);
t->status = new_status;
if (new_status == THREADSTATUS_WAIT) {
@@ -153,16 +152,75 @@ void __KernelChangeThreadState(Thread* t, ThreadStatus new_status) {
}
/// Calls a thread by marking it as "ready" (note: will not actually execute until current thread yields)
-void __KernelCallThread(Thread* t) {
+void __CallThread(Thread* t) {
// Stop waiting
if (t->wait_type != WAITTYPE_NONE) {
t->wait_type = WAITTYPE_NONE;
}
- __KernelChangeThreadState(t, THREADSTATUS_READY);
+ __ChangeThreadState(t, THREADSTATUS_READY);
+}
+
+/// Switches CPU context to that of the specified thread
+void __SwitchContext(Thread* t, const char* reason) {
+ Thread* cur = __GetCurrentThread();
+
+ // Save context for current thread
+ if (cur) {
+ __SaveContext(cur->context);
+
+ if (cur->IsRunning()) {
+ __ChangeReadyState(cur, true);
+ }
+ }
+ // Load context of new thread
+ if (t) {
+ __SetCurrentThread(t);
+ __ChangeReadyState(t, false);
+ t->status = (t->status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY;
+ t->wait_type = WAITTYPE_NONE;
+ __LoadContext(t->context);
+ } else {
+ __SetCurrentThread(NULL);
+ }
+}
+
+/// Gets the next thread that is ready to be run by priority
+Thread* __NextThread() {
+ Handle next;
+ Thread* cur = __GetCurrentThread();
+
+ if (cur && cur->IsRunning()) {
+ next = g_thread_ready_queue.pop_first_better(cur->current_priority);
+ } else {
+ next = g_thread_ready_queue.pop_first();
+ }
+ if (next < 0) {
+ return NULL;
+ }
+ return Kernel::g_object_pool.GetFast(next);
+}
+
+/// Resumes a thread from waiting by marking it as "ready"
+void __ResumeThreadFromWait(Handle handle) {
+ u32 error;
+ Thread* t = Kernel::g_object_pool.Get(handle, error);
+ if (t) {
+ t->status &= ~THREADSTATUS_WAIT;
+ if (!(t->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) {
+ __ChangeReadyState(t, true);
+ }
+ }
+}
+
+/// Puts a thread in the wait state for the given type/reason
+void __WaitCurThread(WaitType wait_type, const char* reason) {
+ Thread* t = __GetCurrentThread();
+ t->wait_type = wait_type;
+ __ChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND)));
}
/// Creates a new thread
-Thread* __KernelCreateThread(Handle& handle, const char* name, u32 entry_point, s32 priority,
+Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 priority,
s32 processor_id, u32 stack_top, int stack_size) {
Thread* t = new Thread;
@@ -187,31 +245,31 @@ Thread* __KernelCreateThread(Handle& handle, const char* name, u32 entry_point,
}
/// Creates a new thread - wrapper for external user
-Handle __KernelCreateThread(const char* name, u32 entry_point, s32 priority, s32 processor_id,
+Handle CreateThread(const char* name, u32 entry_point, s32 priority, s32 processor_id,
u32 stack_top, int stack_size) {
if (name == NULL) {
- ERROR_LOG(KERNEL, "__KernelCreateThread(): NULL name");
+ ERROR_LOG(KERNEL, "CreateThread(): NULL name");
return -1;
}
if ((u32)stack_size < 0x200) {
- ERROR_LOG(KERNEL, "__KernelCreateThread(name=%s): invalid stack_size=0x%08X", name,
+ ERROR_LOG(KERNEL, "CreateThread(name=%s): invalid stack_size=0x%08X", name,
stack_size);
return -1;
}
if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) {
s32 new_priority = CLAMP(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST);
- WARN_LOG(KERNEL, "__KernelCreateThread(name=%s): invalid priority=0x%08X, clamping to %08X",
+ WARN_LOG(KERNEL, "CreateThread(name=%s): invalid priority=0x%08X, clamping to %08X",
name, priority, new_priority);
// TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm
// validity of this
priority = new_priority;
}
if (!Memory::GetPointer(entry_point)) {
- ERROR_LOG(KERNEL, "__KernelCreateThread(name=%s): invalid entry %08x", name, entry_point);
+ ERROR_LOG(KERNEL, "CreateThread(name=%s): invalid entry %08x", name, entry_point);
return -1;
}
Handle handle;
- Thread* t = __KernelCreateThread(handle, name, entry_point, priority, processor_id, stack_top,
+ Thread* t = CreateThread(handle, name, entry_point, priority, processor_id, stack_top,
stack_size);
HLE::EatCycles(32000);
@@ -220,114 +278,62 @@ Handle __KernelCreateThread(const char* name, u32 entry_point, s32 priority, s32
// Technically, this should not eat all at once, and reschedule in the middle, but that's hard.
HLE::ReSchedule("thread created");
- __KernelCallThread(t);
+ __CallThread(t);
return handle;
}
-/// Switches CPU context to that of the specified thread
-void __KernelSwitchContext(Thread* t, const char* reason) {
- Thread* cur = __GetCurrentThread();
-
- // Save context for current thread
- if (cur) {
- __KernelSaveContext(cur->context);
-
- if (cur->IsRunning()) {
- __KernelChangeReadyState(cur, true);
- }
- }
- // Load context of new thread
- if (t) {
- __SetCurrentThread(t);
- __KernelChangeReadyState(t, false);
- t->status = (t->status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY;
- t->wait_type = WAITTYPE_NONE;
- __KernelLoadContext(t->context);
- } else {
- __SetCurrentThread(NULL);
- }
-}
-
-/// Gets the next thread that is ready to be run by priority
-Thread* __KernelNextThread() {
- Handle next;
- Thread* cur = __GetCurrentThread();
-
- if (cur && cur->IsRunning()) {
- next = g_thread_ready_queue.pop_first_better(cur->current_priority);
- } else {
- next = g_thread_ready_queue.pop_first();
- }
- if (next < 0) {
- return NULL;
- }
- return Kernel::g_object_pool.GetFast(next);
+/// Gets the current thread
+Handle GetCurrentThread() {
+ return __GetCurrentThread()->GetHandle();
}
/// Sets up the primary application thread
-Handle __KernelSetupMainThread(s32 priority, int stack_size) {
+Handle SetupMainThread(s32 priority, int stack_size) {
Handle handle;
// Initialize new "main" thread
- Thread* t = __KernelCreateThread(handle, "main", Core::g_app_core->GetPC(), priority,
+ Thread* t = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority,
THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size);
- __KernelResetThread(t, 0);
+ __ResetThread(t, 0);
// If running another thread already, set it to "ready" state
Thread* cur = __GetCurrentThread();
if (cur && cur->IsRunning()) {
- __KernelChangeReadyState(cur, true);
+ __ChangeReadyState(cur, true);
}
// Run new "main" thread
__SetCurrentThread(t);
t->status = THREADSTATUS_RUNNING;
- __KernelLoadContext(t->context);
+ __LoadContext(t->context);
return handle;
}
-/// Resumes a thread from waiting by marking it as "ready"
-void __KernelResumeThreadFromWait(Handle handle) {
- u32 error;
- Thread* t = Kernel::g_object_pool.Get(handle, error);
- if (t) {
- t->status &= ~THREADSTATUS_WAIT;
- if (!(t->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) {
- __KernelChangeReadyState(t, true);
- }
- }
-}
-
-/// Puts a thread in the wait state for the given type/reason
-void __KernelWaitCurThread(WaitType wait_type, const char* reason) {
- Thread* t = __GetCurrentThread();
- t->wait_type = wait_type;
- __KernelChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND)));
-}
-
/// Reschedules to the next available thread (call after current thread is suspended)
-void __KernelReschedule(const char* reason) {
- Thread* next = __KernelNextThread();
+void Reschedule(const char* reason) {
+ Thread* next = __NextThread();
if (next > 0) {
- __KernelSwitchContext(next, reason);
+ __SwitchContext(next, reason);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
/// Put current thread in a wait state - on WaitSynchronization
-void __KernelWaitThread_Synchronization() {
+void WaitThread_Synchronization() {
// TODO(bunnei): Just a placeholder function for now... FixMe
- __KernelWaitCurThread(WAITTYPE_SYNCH, "waitSynchronization called");
+ __WaitCurThread(WAITTYPE_SYNCH, "waitSynchronization called");
}
////////////////////////////////////////////////////////////////////////////////////////////////////
-void __KernelThreadingInit() {
+void ThreadingInit() {
}
-void __KernelThreadingShutdown() {
+void ThreadingShutdown() {
}
+
+} // namespace
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 72e9a416d..2c0199273 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -7,8 +7,6 @@
#include "common/common_types.h"
#include "core/hle/kernel/kernel.h"
-class Thread;
-
enum ThreadPriority {
THREADPRIO_HIGHEST = 0,
THREADPRIO_DEFAULT = 16,
@@ -21,18 +19,28 @@ enum ThreadProcessorId {
THREADPROCESSORID_ALL = 0xFFFFFFFC,
};
+namespace Kernel {
+
/// Creates a new thread - wrapper for external user
-Handle __KernelCreateThread(const char* name, u32 entry_point, s32 priority,
- s32 processor_id, u32 stack_top, int stack_size=Kernel::DEFAULT_STACK_SIZE);
+Handle CreateThread(const char* name, u32 entry_point, s32 priority, s32 processor_id,
+ u32 stack_top, int stack_size=Kernel::DEFAULT_STACK_SIZE);
/// Sets up the primary application thread
-Handle __KernelSetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE);
+Handle SetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE);
/// Reschedules to the next available thread (call after current thread is suspended)
-void __KernelReschedule(const char* reason);
+void Reschedule(const char* reason);
-void __KernelThreadingInit();
-void __KernelThreadingShutdown();
+/// Gets the current thread
+Handle GetCurrentThread();
/// Put current thread in a wait state - on WaitSynchronization
-void __KernelWaitThread_Synchronization();
+void WaitThread_Synchronization();
+
+/// Initialize threading
+void ThreadingInit();
+
+/// Shutdown threading
+void ThreadingShutdown();
+
+} // namespace
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index a9141699c..6f0f099c6 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -123,7 +123,7 @@ Result WaitSynchronizationN(void* _out, void* _handles, u32 handle_count, u32 wa
for (u32 i = 0; i < handle_count; i++) {
DEBUG_LOG(SVC, "\thandle[%d]=0x%08X", i, handles[i]);
}
- __KernelReschedule("WaitSynchronizationN");
+ Kernel::Reschedule("WaitSynchronizationN");
return 0;
}
@@ -175,7 +175,7 @@ Result CreateThread(void* thread, u32 priority, u32 entry_point, u32 arg, u32 st
"threadpriority=0x%08X, processorid=0x%08X", entry_point, name.c_str(), arg, stack_top,
priority, processor_id);
- Handle handle = __KernelCreateThread(name.c_str(), entry_point, priority, processor_id,
+ Handle handle = Kernel::CreateThread(name.c_str(), entry_point, priority, processor_id,
stack_top);
Core::g_app_core->SetReg(1, 0xFEEDDEAF);
--
cgit v1.2.3
From bed4e920fa17c6ab1e1cfde1f3ee81d0ca4aaff9 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Tue, 20 May 2014 21:00:10 -0400
Subject: thread: exposed ResumeThreadFromWait function for use in other kernel
modules
---
src/core/hle/kernel/thread.cpp | 16 ++++++++--------
src/core/hle/kernel/thread.h | 3 +++
2 files changed, 11 insertions(+), 8 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 7b4f0ea47..af9188faa 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -200,8 +200,15 @@ Thread* __NextThread() {
return Kernel::g_object_pool.GetFast(next);
}
+/// Puts a thread in the wait state for the given type/reason
+void __WaitCurThread(WaitType wait_type, const char* reason) {
+ Thread* t = __GetCurrentThread();
+ t->wait_type = wait_type;
+ __ChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND)));
+}
+
/// Resumes a thread from waiting by marking it as "ready"
-void __ResumeThreadFromWait(Handle handle) {
+void ResumeThreadFromWait(Handle handle) {
u32 error;
Thread* t = Kernel::g_object_pool.Get(handle, error);
if (t) {
@@ -212,13 +219,6 @@ void __ResumeThreadFromWait(Handle handle) {
}
}
-/// Puts a thread in the wait state for the given type/reason
-void __WaitCurThread(WaitType wait_type, const char* reason) {
- Thread* t = __GetCurrentThread();
- t->wait_type = wait_type;
- __ChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND)));
-}
-
/// Creates a new thread
Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 priority,
s32 processor_id, u32 stack_top, int stack_size) {
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 2c0199273..bb48ddc79 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -31,6 +31,9 @@ Handle SetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE);
/// Reschedules to the next available thread (call after current thread is suspended)
void Reschedule(const char* reason);
+/// Resumes a thread from waiting by marking it as "ready"
+void ResumeThreadFromWait(Handle handle);
+
/// Gets the current thread
Handle GetCurrentThread();
--
cgit v1.2.3
From 203541da119cad61096fda20b3ff8a8cb5906fd6 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Tue, 20 May 2014 21:02:35 -0400
Subject: thread: added correct lowest thread priority, added a thread priority
check, and added some comments
---
src/core/hle/kernel/thread.cpp | 3 +++
src/core/hle/kernel/thread.h | 13 +++++++------
2 files changed, 10 insertions(+), 6 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index af9188faa..294e03ca6 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -223,6 +223,9 @@ void ResumeThreadFromWait(Handle handle) {
Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 priority,
s32 processor_id, u32 stack_top, int stack_size) {
+ _assert_msg_(KERNEL, (priority >= THREADPRIO_HIGHEST && priority <= THREADPRIO_LOWEST),
+ "CreateThread priority=%d, outside of allowable range!", priority)
+
Thread* t = new Thread;
handle = Kernel::g_object_pool.Create(t);
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index bb48ddc79..0d1fe19bf 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -8,15 +8,16 @@
#include "core/hle/kernel/kernel.h"
enum ThreadPriority {
- THREADPRIO_HIGHEST = 0,
- THREADPRIO_DEFAULT = 16,
- THREADPRIO_LOWEST = 31,
+ 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 ThreadProcessorId {
- THREADPROCESSORID_0 = 0xFFFFFFFE,
- THREADPROCESSORID_1 = 0xFFFFFFFD,
- THREADPROCESSORID_ALL = 0xFFFFFFFC,
+ THREADPROCESSORID_0 = 0xFFFFFFFE, ///< Enables core appcode
+ THREADPROCESSORID_1 = 0xFFFFFFFD, ///< Enables core syscore
+ THREADPROCESSORID_ALL = 0xFFFFFFFC, ///< Enables both cores
};
namespace Kernel {
--
cgit v1.2.3
From 22eb9a8981c9b4283e37f7d403c598402339ed7f Mon Sep 17 00:00:00 2001
From: bunnei
Date: Tue, 20 May 2014 22:25:40 -0400
Subject: armemu: missed rename of "Syscall" to "SVC"
---
src/core/arm/interpreter/armemu.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp
index aa1ff17bb..e5dc7bd44 100644
--- a/src/core/arm/interpreter/armemu.cpp
+++ b/src/core/arm/interpreter/armemu.cpp
@@ -4548,7 +4548,7 @@ ARMul_Emulate26 (ARMul_State * state)
// ARMul_OSHandleSWI (state, BITS (0, 23));
// break;
//}
- HLE::CallSyscall(instr);
+ HLE::CallSVC(instr);
ARMul_Abort (state, ARMul_SWIV);
break;
}
--
cgit v1.2.3
From a721a4eb33a06b532e36e5a49578abd8338d0d28 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Tue, 20 May 2014 22:26:40 -0400
Subject: arm: removed include of windows.h from armdefs.h to arminit.c (only
module that uses it)
---
src/core/arm/interpreter/armdefs.h | 4 ----
src/core/arm/interpreter/arminit.cpp | 3 +++
2 files changed, 3 insertions(+), 4 deletions(-)
(limited to 'src')
diff --git a/src/core/arm/interpreter/armdefs.h b/src/core/arm/interpreter/armdefs.h
index 5b2abc7f7..d8eae4d3f 100644
--- a/src/core/arm/interpreter/armdefs.h
+++ b/src/core/arm/interpreter/armdefs.h
@@ -24,10 +24,6 @@
#include "common/platform.h"
-#if EMU_PLATFORM == PLATFORM_WINDOWS
-#include
-#endif
-
//teawater add for arm2x86 2005.02.14-------------------------------------------
// koodailar remove it for mingw 2005.12.18----------------
//anthonylee modify it for portable 2007.01.30
diff --git a/src/core/arm/interpreter/arminit.cpp b/src/core/arm/interpreter/arminit.cpp
index 2c771cdda..e05667bea 100644
--- a/src/core/arm/interpreter/arminit.cpp
+++ b/src/core/arm/interpreter/arminit.cpp
@@ -17,8 +17,11 @@
#include "common/platform.h"
+
#if EMU_PLATFORM == PLATFORM_LINUX
#include
+#elif EMU_PLATFORM == PLATFORM_WINDOWS
+#include
#endif
#include
--
cgit v1.2.3
From 9bf7ce535a604d5523bfc14ea8057477ce1a4e0f Mon Sep 17 00:00:00 2001
From: bunnei
Date: Tue, 20 May 2014 22:27:12 -0400
Subject: service: removed redundant include of common_types.h
---
src/core/hle/service/service.h | 1 -
1 file changed, 1 deletion(-)
(limited to 'src')
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index eba730efb..716669bed 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -10,7 +10,6 @@
#include
#include "common/common.h"
-#include "common/common_types.h"
#include "core/mem_map.h"
#include "core/hle/kernel/kernel.h"
--
cgit v1.2.3
From 1c5802c35a668cbb326cb497708bde341cd63f6d Mon Sep 17 00:00:00 2001
From: bunnei
Date: Tue, 20 May 2014 22:27:46 -0400
Subject: kernel: fixed include, in general include "common.h" not
"common_types.h"
---
src/core/hle/kernel/kernel.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 19edb7b57..180339914 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -4,7 +4,7 @@
#pragma once
-#include "common/common_types.h"
+#include "common/common.h"
typedef u32 Handle;
typedef s32 Result;
--
cgit v1.2.3
From 08e6a9bf896b386a339fccc65066ee51c8592b9c Mon Sep 17 00:00:00 2001
From: bunnei
Date: Tue, 20 May 2014 22:57:54 -0400
Subject: svc: added some comments
---
src/core/hle/svc.cpp | 7 +++++++
1 file changed, 7 insertions(+)
(limited to 'src')
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 6f0f099c6..3674a08c5 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -10,6 +10,7 @@
#include "core/mem_map.h"
#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/mutex.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/function_wrappers.h"
@@ -160,6 +161,7 @@ Result GetResourceLimitCurrentValues(void* _values, Handle resource_limit, void*
return 0;
}
+/// Creates a new thread
Result CreateThread(void* thread, u32 priority, u32 entry_point, u32 arg, u32 stack_top,
u32 processor_id) {
std::string name;
@@ -182,6 +184,7 @@ Result CreateThread(void* thread, u32 priority, u32 entry_point, u32 arg, u32 st
return 0;
}
+/// Create a mutex
Result CreateMutex(void* _mutex, u32 initial_locked) {
Handle* mutex = (Handle*)_mutex;
DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateMutex called initial_locked=%s",
@@ -190,16 +193,19 @@ Result CreateMutex(void* _mutex, u32 initial_locked) {
return 0;
}
+/// Release a mutex
Result ReleaseMutex(Handle handle) {
DEBUG_LOG(SVC, "(UNIMPLEMENTED) ReleaseMutex called handle=0x%08X", handle);
return 0;
}
+/// Get current thread ID
Result GetThreadId(void* thread_id, u32 thread) {
DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetThreadId called thread=0x%08X", thread);
return 0;
}
+/// Query memory
Result QueryMemory(void *_info, void *_out, u32 addr) {
MemoryInfo* info = (MemoryInfo*) _info;
PageInfo* out = (PageInfo*) _out;
@@ -207,6 +213,7 @@ Result QueryMemory(void *_info, void *_out, u32 addr) {
return 0;
}
+/// Create an event
Result CreateEvent(void* _event, u32 reset_type) {
Handle* event = (Handle*)_event;
DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateEvent called reset_type=0x%08X", reset_type);
--
cgit v1.2.3
From 978e1d4653cd12a68d6bfa05af57edb1645da0f5 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Tue, 20 May 2014 23:03:45 -0400
Subject: mutex: initial commit of HLE module
---
src/core/CMakeLists.txt | 1 +
src/core/core.vcxproj | 2 +
src/core/core.vcxproj.filters | 6 +++
src/core/hle/kernel/mutex.cpp | 122 ++++++++++++++++++++++++++++++++++++++++++
src/core/hle/kernel/mutex.h | 26 +++++++++
src/core/hle/service/apt.cpp | 10 ++--
src/core/hle/svc.cpp | 9 ++--
7 files changed, 166 insertions(+), 10 deletions(-)
create mode 100644 src/core/hle/kernel/mutex.cpp
create mode 100644 src/core/hle/kernel/mutex.h
(limited to 'src')
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index e006502da..6ad308798 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -35,6 +35,7 @@ set(SRCS core.cpp
hle/coprocessor.cpp
hle/svc.cpp
hle/kernel/kernel.cpp
+ hle/kernel/mutex.cpp
hle/kernel/thread.cpp
hle/service/apt.cpp
hle/service/gsp.cpp
diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj
index 6eb58a636..f271d336e 100644
--- a/src/core/core.vcxproj
+++ b/src/core/core.vcxproj
@@ -169,6 +169,7 @@
+
@@ -217,6 +218,7 @@
+
diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters
index fc4e35edb..f664debec 100644
--- a/src/core/core.vcxproj.filters
+++ b/src/core/core.vcxproj.filters
@@ -162,6 +162,9 @@
hle
+
+ hle\kernel
+
@@ -289,6 +292,9 @@
hle
+
+ hle\kernel
+
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
new file mode 100644
index 000000000..2b2cff4ea
--- /dev/null
+++ b/src/core/hle/kernel/mutex.cpp
@@ -0,0 +1,122 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#include
+#include
+
+#include "common/common.h"
+
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/kernel/thread.h"
+
+namespace Kernel {
+
+class Mutex : public Object {
+public:
+ const char* GetTypeName() { return "Mutex"; }
+
+ static Kernel::HandleType GetStaticHandleType() { return Kernel::HandleType::Mutex; }
+ Kernel::HandleType GetHandleType() const { return Kernel::HandleType::Mutex; }
+
+ bool initial_locked; ///< Initial lock state when mutex was created
+ bool locked; ///< Current locked state
+ Handle lock_thread; ///< Handle to thread that currently has mutex
+ std::vector waiting_threads; ///< Threads that are waiting for the mutex
+};
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
+typedef std::multimap MutexMap;
+static MutexMap g_mutex_held_locks;
+
+void __MutexAcquireLock(Mutex* mutex, Handle thread) {
+ g_mutex_held_locks.insert(std::make_pair(thread, mutex->GetHandle()));
+ mutex->lock_thread = thread;
+}
+
+void __MutexAcquireLock(Mutex* mutex) {
+ Handle thread = GetCurrentThread();
+ __MutexAcquireLock(mutex, thread);
+}
+
+void __MutexEraseLock(Mutex* mutex) {
+ Handle handle = mutex->GetHandle();
+ auto locked = g_mutex_held_locks.equal_range(mutex->lock_thread);
+ for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) {
+ if ((*iter).second == handle) {
+ g_mutex_held_locks.erase(iter);
+ break;
+ }
+ }
+ mutex->lock_thread = -1;
+}
+
+bool __LockMutex(Mutex* mutex) {
+ // Mutex alread locked?
+ if (mutex->locked) {
+ return false;
+ }
+ __MutexAcquireLock(mutex);
+ return true;
+}
+
+bool __ReleaseMutexForThread(Mutex* mutex, Handle thread) {
+ __MutexAcquireLock(mutex, thread);
+ Kernel::ResumeThreadFromWait(thread);
+ return true;
+}
+
+bool __ReleaseMutex(Mutex* mutex) {
+ __MutexEraseLock(mutex);
+ bool woke_threads = false;
+ auto iter = mutex->waiting_threads.begin();
+
+ // Find the next waiting thread for the mutex...
+ while (!woke_threads && !mutex->waiting_threads.empty()) {
+ woke_threads |= __ReleaseMutexForThread(mutex, *iter);
+ mutex->waiting_threads.erase(iter);
+ }
+ // Reset mutex lock thread handle, nothing is waiting
+ if (!woke_threads) {
+ mutex->locked = false;
+ mutex->lock_thread = -1;
+ }
+ return woke_threads;
+}
+
+/**
+ * Releases a mutex
+ * @param handle Handle to mutex to release
+ */
+Result ReleaseMutex(Handle handle) {
+ Mutex* mutex = Kernel::g_object_pool.GetFast(handle);
+ if (!__ReleaseMutex(mutex)) {
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * Creates a mutex
+ * @param handle Reference to handle for the newly created mutex
+ * @param initial_locked Specifies if the mutex should be locked initially
+ */
+Result CreateMutex(Handle& handle, bool initial_locked) {
+ Mutex* mutex = new Mutex;
+ handle = Kernel::g_object_pool.Create(mutex);
+
+ mutex->locked = mutex->initial_locked = initial_locked;
+
+ // Acquire mutex with current thread if initialized as locked...
+ if (mutex->locked) {
+ __MutexAcquireLock(mutex);
+
+ // Otherwise, reset lock thread handle
+ } else {
+ mutex->lock_thread = -1;
+ }
+ return 0;
+}
+
+} // namespace
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
new file mode 100644
index 000000000..1f843e979
--- /dev/null
+++ b/src/core/hle/kernel/mutex.h
@@ -0,0 +1,26 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+
+#include "core/hle/kernel/kernel.h"
+
+namespace Kernel {
+
+/**
+ * Releases a mutex
+ * @param handle Handle to mutex to release
+ */
+Result ReleaseMutex(Handle handle);
+
+/**
+ * Creates a mutex
+ * @param handle Reference to handle for the newly created mutex
+ * @param initial_locked Specifies if the mutex should be locked initially
+ */
+Result CreateMutex(Handle& handle, bool initial_locked);
+
+} // namespace
diff --git a/src/core/hle/service/apt.cpp b/src/core/hle/service/apt.cpp
index 1f6a70eab..ecec4da00 100644
--- a/src/core/hle/service/apt.cpp
+++ b/src/core/hle/service/apt.cpp
@@ -3,9 +3,10 @@
// Refer to the license.txt file included.
-#include "common/log.h"
+#include "common/common.h"
#include "core/hle/hle.h"
+#include "core/hle/kernel/mutex.h"
#include "core/hle/service/apt.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -19,11 +20,8 @@ void Initialize(Service::Interface* self) {
void GetLockHandle(Service::Interface* self) {
u32* cmd_buff = Service::GetCommandBuffer();
- u32 flags = cmd_buff[1];
-
- // TODO: This should be an actual mutex handle. Games will check that this is not non-zero
- // (NULL), and fail if such. A faked non-zero value will at least enable further booting.
- cmd_buff[5] = 0x12345678;
+ u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field
+ cmd_buff[1] = Kernel::CreateMutex(cmd_buff[5], false);
}
const Interface::FunctionInfo FunctionTable[] = {
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 3674a08c5..73ab073f5 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -187,15 +187,16 @@ Result CreateThread(void* thread, u32 priority, u32 entry_point, u32 arg, u32 st
/// Create a mutex
Result CreateMutex(void* _mutex, u32 initial_locked) {
Handle* mutex = (Handle*)_mutex;
- DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateMutex called initial_locked=%s",
- initial_locked ? "true" : "false");
- Core::g_app_core->SetReg(1, 0xF00D0BAD);
+ DEBUG_LOG(SVC, "CreateMutex called initial_locked=%s", initial_locked ? "true" : "false");
+ Kernel::CreateMutex(*mutex, (bool)initial_locked);
+ Core::g_app_core->SetReg(1, *mutex);
return 0;
}
/// Release a mutex
Result ReleaseMutex(Handle handle) {
- DEBUG_LOG(SVC, "(UNIMPLEMENTED) ReleaseMutex called handle=0x%08X", handle);
+ DEBUG_LOG(SVC, "ReleaseMutex called handle=0x%08X", handle);
+ Kernel::ReleaseMutex(handle);
return 0;
}
--
cgit v1.2.3
From eb537c560a33db9955413a96afd3b98203a729fe Mon Sep 17 00:00:00 2001
From: bunnei
Date: Tue, 20 May 2014 23:23:58 -0400
Subject: mutex: refactored the interface to code to return a Mutex* handle
---
src/core/hle/kernel/mutex.cpp | 14 ++++++++++++--
src/core/hle/kernel/mutex.h | 2 +-
src/core/hle/service/apt.cpp | 3 ++-
src/core/hle/svc.cpp | 2 +-
4 files changed, 16 insertions(+), 5 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 2b2cff4ea..7cf3439e9 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -102,7 +102,7 @@ Result ReleaseMutex(Handle handle) {
* @param handle Reference to handle for the newly created mutex
* @param initial_locked Specifies if the mutex should be locked initially
*/
-Result CreateMutex(Handle& handle, bool initial_locked) {
+Mutex* CreateMutex(Handle& handle, bool initial_locked) {
Mutex* mutex = new Mutex;
handle = Kernel::g_object_pool.Create(mutex);
@@ -116,7 +116,17 @@ Result CreateMutex(Handle& handle, bool initial_locked) {
} else {
mutex->lock_thread = -1;
}
- return 0;
+ return mutex;
+}
+
+/**
+ * Creates a mutex
+ * @param initial_locked Specifies if the mutex should be locked initially
+ */
+Handle CreateMutex(bool initial_locked) {
+ Handle handle;
+ Mutex* mutex = CreateMutex(handle, initial_locked);
+ return handle;
}
} // namespace
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index 1f843e979..871e2e562 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -21,6 +21,6 @@ Result ReleaseMutex(Handle handle);
* @param handle Reference to handle for the newly created mutex
* @param initial_locked Specifies if the mutex should be locked initially
*/
-Result CreateMutex(Handle& handle, bool initial_locked);
+Handle CreateMutex(bool initial_locked);
} // namespace
diff --git a/src/core/hle/service/apt.cpp b/src/core/hle/service/apt.cpp
index ecec4da00..b01f35ac5 100644
--- a/src/core/hle/service/apt.cpp
+++ b/src/core/hle/service/apt.cpp
@@ -21,7 +21,8 @@ void Initialize(Service::Interface* self) {
void GetLockHandle(Service::Interface* self) {
u32* cmd_buff = Service::GetCommandBuffer();
u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field
- cmd_buff[1] = Kernel::CreateMutex(cmd_buff[5], false);
+ cmd_buff[1] = 0; // No error
+ cmd_buff[5] = Kernel::CreateMutex(false);
}
const Interface::FunctionInfo FunctionTable[] = {
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 73ab073f5..ffacdfb86 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -188,7 +188,7 @@ Result CreateThread(void* thread, u32 priority, u32 entry_point, u32 arg, u32 st
Result CreateMutex(void* _mutex, u32 initial_locked) {
Handle* mutex = (Handle*)_mutex;
DEBUG_LOG(SVC, "CreateMutex called initial_locked=%s", initial_locked ? "true" : "false");
- Kernel::CreateMutex(*mutex, (bool)initial_locked);
+ *mutex = Kernel::CreateMutex((initial_locked != 0));
Core::g_app_core->SetReg(1, *mutex);
return 0;
}
--
cgit v1.2.3
From 706584f007f48cd319fe7511969f914843951088 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Tue, 20 May 2014 23:36:35 -0400
Subject: svc: enabled use of newly created kernel thread handle
---
src/core/hle/svc.cpp | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index ffacdfb86..6f6f5b2f5 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -162,8 +162,7 @@ Result GetResourceLimitCurrentValues(void* _values, Handle resource_limit, void*
}
/// Creates a new thread
-Result CreateThread(void* thread, u32 priority, u32 entry_point, u32 arg, u32 stack_top,
- u32 processor_id) {
+Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 processor_id) {
std::string name;
if (Symbols::HasSymbol(entry_point)) {
TSymbol symbol = Symbols::GetSymbol(entry_point);
@@ -177,9 +176,10 @@ Result CreateThread(void* thread, u32 priority, u32 entry_point, u32 arg, u32 st
"threadpriority=0x%08X, processorid=0x%08X", entry_point, name.c_str(), arg, stack_top,
priority, processor_id);
- Handle handle = Kernel::CreateThread(name.c_str(), entry_point, priority, processor_id,
+ Handle thread = Kernel::CreateThread(name.c_str(), entry_point, priority, processor_id,
stack_top);
- Core::g_app_core->SetReg(1, 0xFEEDDEAF);
+
+ Core::g_app_core->SetReg(1, thread);
return 0;
}
@@ -231,7 +231,7 @@ const HLE::FunctionDef SVC_Table[] = {
{0x05, NULL, "SetProcessAffinityMask"},
{0x06, NULL, "GetProcessIdealProcessor"},
{0x07, NULL, "SetProcessIdealProcessor"},
- {0x08, WrapI_VUUUUU, "CreateThread"},
+ {0x08, WrapI_UUUUU, "CreateThread"},
{0x09, NULL, "ExitThread"},
{0x0A, NULL, "SleepThread"},
{0x0B, NULL, "GetThreadPriority"},
--
cgit v1.2.3
From 06e3c3d55a6e8e58295bd9e7bebecdc777145b20 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Wed, 21 May 2014 21:41:40 -0400
Subject: svc: added Kernel::Reschedule to svc WaitSynchronization1, updated
log messages to include newly created handles
---
src/core/hle/svc.cpp | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 6f6f5b2f5..14d512b99 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -109,6 +109,7 @@ Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
// ImplementMe
DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronization1 called handle=0x%08X, nanoseconds=%d",
handle, nano_seconds);
+ Kernel::Reschedule("WaitSynchronization1");
return 0;
}
@@ -172,14 +173,15 @@ Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 p
sprintf(buff, "%s", "unknown-%08X", entry_point);
name = buff;
}
- DEBUG_LOG(SVC, "CreateThread called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, "
- "threadpriority=0x%08X, processorid=0x%08X", entry_point, name.c_str(), arg, stack_top,
- priority, processor_id);
Handle thread = Kernel::CreateThread(name.c_str(), entry_point, priority, processor_id,
stack_top);
Core::g_app_core->SetReg(1, thread);
+
+ DEBUG_LOG(SVC, "CreateThread called entrypoint=0x%08X (%s), arg=0x%08X, stacktop=0x%08X, "
+ "threadpriority=0x%08X, processorid=0x%08X : created handle 0x%08X", entry_point,
+ name.c_str(), arg, stack_top, priority, processor_id, thread);
return 0;
}
@@ -187,9 +189,10 @@ Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 p
/// Create a mutex
Result CreateMutex(void* _mutex, u32 initial_locked) {
Handle* mutex = (Handle*)_mutex;
- DEBUG_LOG(SVC, "CreateMutex called initial_locked=%s", initial_locked ? "true" : "false");
*mutex = Kernel::CreateMutex((initial_locked != 0));
Core::g_app_core->SetReg(1, *mutex);
+ DEBUG_LOG(SVC, "CreateMutex called initial_locked=%s : created handle 0x%08X",
+ initial_locked ? "true" : "false", *mutex);
return 0;
}
--
cgit v1.2.3
From 6a78be5930fd5eabbea740a5cf17efa5a7f1bc98 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Wed, 21 May 2014 21:42:18 -0400
Subject: thread: fixed bug where result of __NextThread was not being properly
checked when NULL
---
src/core/hle/kernel/thread.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 294e03ca6..ef705e327 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -194,7 +194,7 @@ Thread* __NextThread() {
} else {
next = g_thread_ready_queue.pop_first();
}
- if (next < 0) {
+ if (next == 0) {
return NULL;
}
return Kernel::g_object_pool.GetFast(next);
--
cgit v1.2.3
From 481d936d34c595b994f48b00819bb2c4bcfa7e57 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Thu, 22 May 2014 18:47:42 -0400
Subject: arm_interpreter: fixed load context to currently resume a thread
---
src/core/arm/interpreter/arm_interpreter.cpp | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/core/arm/interpreter/arm_interpreter.cpp b/src/core/arm/interpreter/arm_interpreter.cpp
index a9ec94820..17f787b86 100644
--- a/src/core/arm/interpreter/arm_interpreter.cpp
+++ b/src/core/arm/interpreter/arm_interpreter.cpp
@@ -115,7 +115,7 @@ void ARM_Interpreter::SaveContext(ThreadContext& ctx) {
ctx.lr = state->Reg[14];
ctx.pc = state->pc;
ctx.cpsr = state->Cpsr;
-
+
ctx.fpscr = state->VFP[1];
ctx.fpexc = state->VFP[2];
}
@@ -136,4 +136,7 @@ void ARM_Interpreter::LoadContext(const ThreadContext& ctx) {
state->VFP[1] = ctx.fpscr;
state->VFP[2] = ctx.fpexc;
+
+ state->Reg[15] = ctx.pc;
+ state->NextInstr = RESUME;
}
--
cgit v1.2.3
From 9fddba68435f6e276bfb40c793f1ca0f8b984ec9 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Thu, 22 May 2014 18:48:14 -0400
Subject: APT_U: added a debug log on calling GetLockHandle
---
src/core/hle/service/apt.cpp | 1 +
1 file changed, 1 insertion(+)
(limited to 'src')
diff --git a/src/core/hle/service/apt.cpp b/src/core/hle/service/apt.cpp
index b01f35ac5..32759a087 100644
--- a/src/core/hle/service/apt.cpp
+++ b/src/core/hle/service/apt.cpp
@@ -23,6 +23,7 @@ void GetLockHandle(Service::Interface* self) {
u32 flags = cmd_buff[1]; // TODO(bunnei): Figure out the purpose of the flag field
cmd_buff[1] = 0; // No error
cmd_buff[5] = Kernel::CreateMutex(false);
+ DEBUG_LOG(KERNEL, "APT_U::GetLockHandle called : created handle 0x%08X", cmd_buff[5]);
}
const Interface::FunctionInfo FunctionTable[] = {
--
cgit v1.2.3
From 14bd37c5dc67c7777d4bea8d996bf2dfd8c7bdcc Mon Sep 17 00:00:00 2001
From: bunnei
Date: Thu, 22 May 2014 18:50:36 -0400
Subject: thread: moved ThreadStatus/WaitType to header, added support for arg
on CreateThread, added correct CPSR reset
---
src/core/hle/kernel/thread.cpp | 49 +++++++++++++-----------------------------
src/core/hle/kernel/thread.h | 26 +++++++++++++++++++++-
2 files changed, 40 insertions(+), 35 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index ef705e327..934ca87c4 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -21,27 +21,6 @@
namespace Kernel {
-enum ThreadStatus {
- THREADSTATUS_RUNNING = 1,
- THREADSTATUS_READY = 2,
- THREADSTATUS_WAIT = 4,
- THREADSTATUS_SUSPEND = 8,
- THREADSTATUS_DORMANT = 16,
- THREADSTATUS_DEAD = 32,
- THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND
-};
-
-enum WaitType {
- WAITTYPE_NONE,
- WAITTYPE_SLEEP,
- WAITTYPE_SEMA,
- WAITTYPE_EVENTFLAG,
- WAITTYPE_THREADEND,
- WAITTYPE_VBLANK,
- WAITTYPE_MUTEX,
- WAITTYPE_SYNCH,
-};
-
class Thread : public Kernel::Object {
public:
@@ -101,16 +80,18 @@ void __SaveContext(ThreadContext& ctx) {
}
/// Loads a CPU context
-void __LoadContext(const ThreadContext& ctx) {
+void __LoadContext(ThreadContext& ctx) {
Core::g_app_core->LoadContext(ctx);
}
/// Resets a thread
-void __ResetThread(Thread* t, s32 lowest_priority) {
+void __ResetThread(Thread* t, u32 arg, s32 lowest_priority) {
memset(&t->context, 0, sizeof(ThreadContext));
+ t->context.cpu_registers[0] = arg;
t->context.pc = t->entry_point;
t->context.sp = t->stack_top;
+ t->context.cpsr = 0x1F; // Usermode
if (t->current_priority < lowest_priority) {
t->current_priority = t->initial_priority;
@@ -201,7 +182,7 @@ Thread* __NextThread() {
}
/// Puts a thread in the wait state for the given type/reason
-void __WaitCurThread(WaitType wait_type, const char* reason) {
+void WaitCurThread(WaitType wait_type, const char* reason) {
Thread* t = __GetCurrentThread();
t->wait_type = wait_type;
__ChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND)));
@@ -248,7 +229,7 @@ Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 prio
}
/// Creates a new thread - wrapper for external user
-Handle CreateThread(const char* name, u32 entry_point, s32 priority, s32 processor_id,
+Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s32 processor_id,
u32 stack_top, int stack_size) {
if (name == NULL) {
ERROR_LOG(KERNEL, "CreateThread(): NULL name");
@@ -275,6 +256,8 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, s32 process
Thread* t = CreateThread(handle, name, entry_point, priority, processor_id, stack_top,
stack_size);
+ __ResetThread(t, arg, 0);
+
HLE::EatCycles(32000);
// This won't schedule to the new thread, but it may to one woken from eating cycles.
@@ -299,7 +282,7 @@ Handle SetupMainThread(s32 priority, int stack_size) {
Thread* t = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority,
THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size);
- __ResetThread(t, 0);
+ __ResetThread(t, 0, 0);
// If running another thread already, set it to "ready" state
Thread* cur = __GetCurrentThread();
@@ -317,18 +300,16 @@ Handle SetupMainThread(s32 priority, int stack_size) {
/// Reschedules to the next available thread (call after current thread is suspended)
void Reschedule(const char* reason) {
+ Thread* prev = __GetCurrentThread();
Thread* next = __NextThread();
if (next > 0) {
__SwitchContext(next, reason);
- }
-}
-////////////////////////////////////////////////////////////////////////////////////////////////////
-
-/// Put current thread in a wait state - on WaitSynchronization
-void WaitThread_Synchronization() {
- // TODO(bunnei): Just a placeholder function for now... FixMe
- __WaitCurThread(WAITTYPE_SYNCH, "waitSynchronization called");
+ // Hack - automatically change previous thread (which would have been in "wait" state) to
+ // "ready" state, so that we can immediately resume to it when new thread yields. FixMe to
+ // actually wait for whatever event it is supposed to be waiting on.
+ __ChangeReadyState(prev, true);
+ }
}
////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 0d1fe19bf..82bf16082 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -20,10 +20,31 @@ enum ThreadProcessorId {
THREADPROCESSORID_ALL = 0xFFFFFFFC, ///< Enables both cores
};
+enum ThreadStatus {
+ THREADSTATUS_RUNNING = 1,
+ THREADSTATUS_READY = 2,
+ THREADSTATUS_WAIT = 4,
+ THREADSTATUS_SUSPEND = 8,
+ THREADSTATUS_DORMANT = 16,
+ THREADSTATUS_DEAD = 32,
+ THREADSTATUS_WAITSUSPEND = THREADSTATUS_WAIT | THREADSTATUS_SUSPEND
+};
+
+enum WaitType {
+ WAITTYPE_NONE,
+ WAITTYPE_SLEEP,
+ WAITTYPE_SEMA,
+ WAITTYPE_EVENTFLAG,
+ WAITTYPE_THREADEND,
+ WAITTYPE_VBLANK,
+ WAITTYPE_MUTEX,
+ WAITTYPE_SYNCH,
+};
+
namespace Kernel {
/// Creates a new thread - wrapper for external user
-Handle CreateThread(const char* name, u32 entry_point, s32 priority, s32 processor_id,
+Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s32 processor_id,
u32 stack_top, int stack_size=Kernel::DEFAULT_STACK_SIZE);
/// Sets up the primary application thread
@@ -32,6 +53,9 @@ Handle SetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE);
/// Reschedules to the next available thread (call after current thread is suspended)
void Reschedule(const char* reason);
+/// Puts a thread in the wait state for the given type/reason
+void WaitCurThread(WaitType wait_type, const char* reason);
+
/// Resumes a thread from waiting by marking it as "ready"
void ResumeThreadFromWait(Handle handle);
--
cgit v1.2.3
From ac21e8f2db8fbedeacbcef2989e8dbad524b9d44 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Thu, 22 May 2014 18:51:55 -0400
Subject: core: moved armcopro.cpp to correct filter folder (arm/interpreter)
---
src/core/core.vcxproj.filters | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
(limited to 'src')
diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters
index f664debec..b6c1d5b93 100644
--- a/src/core/core.vcxproj.filters
+++ b/src/core/core.vcxproj.filters
@@ -147,9 +147,6 @@
arm\interpreter\mmu
-
- arm
-
arm\interpreter\mmu
@@ -165,6 +162,9 @@
hle\kernel
+
+ arm\interpreter
+
--
cgit v1.2.3
From d26f3d4c1ff27f740fe7185e1bca7dcfc5851919 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Thu, 22 May 2014 19:06:12 -0400
Subject: kernel: refactored function naming to remove "__" prefix
---
src/core/hle/kernel/kernel.cpp | 15 +++++---
src/core/hle/kernel/kernel.h | 9 +++--
src/core/hle/kernel/mutex.cpp | 28 +++++++--------
src/core/hle/kernel/thread.cpp | 78 +++++++++++++++++++++---------------------
src/core/hle/kernel/thread.h | 4 +--
src/core/loader.cpp | 6 ++--
6 files changed, 75 insertions(+), 65 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 45e36173c..de80de893 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -139,15 +139,20 @@ void Shutdown() {
Kernel::ThreadingShutdown();
}
-} // namespace
-
-bool __KernelLoadExec(u32 entry_point) {
- Kernel::Init();
+/**
+ * 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) {
+ Init();
Core::g_app_core->SetPC(entry_point);
// 0x30 is the typical main thread priority I've seen used so far
- Handle thread_id = Kernel::SetupMainThread(0x30);
+ Handle thread = Kernel::SetupMainThread(0x30);
return true;
}
+
+} // namespace
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 180339914..7cd79c2c4 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -144,6 +144,11 @@ private:
extern ObjectPool g_object_pool;
-} // namespace
+/**
+ * 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);
-bool __KernelLoadExec(u32 entry_point);
+} // namespace
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 7cf3439e9..019efbc78 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -30,17 +30,17 @@ public:
typedef std::multimap MutexMap;
static MutexMap g_mutex_held_locks;
-void __MutexAcquireLock(Mutex* mutex, Handle thread) {
+void MutexAcquireLock(Mutex* mutex, Handle thread) {
g_mutex_held_locks.insert(std::make_pair(thread, mutex->GetHandle()));
mutex->lock_thread = thread;
}
-void __MutexAcquireLock(Mutex* mutex) {
- Handle thread = GetCurrentThread();
- __MutexAcquireLock(mutex, thread);
+void MutexAcquireLock(Mutex* mutex) {
+ Handle thread = GetCurrentThreadHandle();
+ MutexAcquireLock(mutex, thread);
}
-void __MutexEraseLock(Mutex* mutex) {
+void MutexEraseLock(Mutex* mutex) {
Handle handle = mutex->GetHandle();
auto locked = g_mutex_held_locks.equal_range(mutex->lock_thread);
for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) {
@@ -52,29 +52,29 @@ void __MutexEraseLock(Mutex* mutex) {
mutex->lock_thread = -1;
}
-bool __LockMutex(Mutex* mutex) {
+bool LockMutex(Mutex* mutex) {
// Mutex alread locked?
if (mutex->locked) {
return false;
}
- __MutexAcquireLock(mutex);
+ MutexAcquireLock(mutex);
return true;
}
-bool __ReleaseMutexForThread(Mutex* mutex, Handle thread) {
- __MutexAcquireLock(mutex, thread);
+bool ReleaseMutexForThread(Mutex* mutex, Handle thread) {
+ MutexAcquireLock(mutex, thread);
Kernel::ResumeThreadFromWait(thread);
return true;
}
-bool __ReleaseMutex(Mutex* mutex) {
- __MutexEraseLock(mutex);
+bool ReleaseMutex(Mutex* mutex) {
+ MutexEraseLock(mutex);
bool woke_threads = false;
auto iter = mutex->waiting_threads.begin();
// Find the next waiting thread for the mutex...
while (!woke_threads && !mutex->waiting_threads.empty()) {
- woke_threads |= __ReleaseMutexForThread(mutex, *iter);
+ woke_threads |= ReleaseMutexForThread(mutex, *iter);
mutex->waiting_threads.erase(iter);
}
// Reset mutex lock thread handle, nothing is waiting
@@ -91,7 +91,7 @@ bool __ReleaseMutex(Mutex* mutex) {
*/
Result ReleaseMutex(Handle handle) {
Mutex* mutex = Kernel::g_object_pool.GetFast(handle);
- if (!__ReleaseMutex(mutex)) {
+ if (!ReleaseMutex(mutex)) {
return -1;
}
return 0;
@@ -110,7 +110,7 @@ Mutex* CreateMutex(Handle& handle, bool initial_locked) {
// Acquire mutex with current thread if initialized as locked...
if (mutex->locked) {
- __MutexAcquireLock(mutex);
+ MutexAcquireLock(mutex);
// Otherwise, reset lock thread handle
} else {
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 934ca87c4..5f1d5c400 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -64,28 +64,33 @@ Thread* g_current_thread;
/// Gets the current thread
-inline Thread* __GetCurrentThread() {
+inline Thread* GetCurrentThread() {
return g_current_thread;
}
+/// Gets the current thread handle
+Handle GetCurrentThreadHandle() {
+ return GetCurrentThread()->GetHandle();
+}
+
/// Sets the current thread
-inline void __SetCurrentThread(Thread* t) {
+inline void SetCurrentThread(Thread* t) {
g_current_thread = t;
g_current_thread_handle = t->GetHandle();
}
/// Saves the current CPU context
-void __SaveContext(ThreadContext& ctx) {
+void SaveContext(ThreadContext& ctx) {
Core::g_app_core->SaveContext(ctx);
}
/// Loads a CPU context
-void __LoadContext(ThreadContext& ctx) {
+void LoadContext(ThreadContext& ctx) {
Core::g_app_core->LoadContext(ctx);
}
/// Resets a thread
-void __ResetThread(Thread* t, u32 arg, s32 lowest_priority) {
+void ResetThread(Thread* t, u32 arg, s32 lowest_priority) {
memset(&t->context, 0, sizeof(ThreadContext));
t->context.cpu_registers[0] = arg;
@@ -101,7 +106,7 @@ void __ResetThread(Thread* t, u32 arg, s32 lowest_priority) {
}
/// Change a thread to "ready" state
-void __ChangeReadyState(Thread* t, bool ready) {
+void ChangeReadyState(Thread* t, bool ready) {
Handle handle = t->GetHandle();
if (t->IsReady()) {
if (!ready) {
@@ -118,11 +123,11 @@ void __ChangeReadyState(Thread* t, bool ready) {
}
/// Changes a threads state
-void __ChangeThreadState(Thread* t, ThreadStatus new_status) {
+void ChangeThreadState(Thread* t, ThreadStatus new_status) {
if (!t || t->status == new_status) {
return;
}
- __ChangeReadyState(t, (new_status & THREADSTATUS_READY) != 0);
+ ChangeReadyState(t, (new_status & THREADSTATUS_READY) != 0);
t->status = new_status;
if (new_status == THREADSTATUS_WAIT) {
@@ -133,42 +138,42 @@ void __ChangeThreadState(Thread* t, ThreadStatus new_status) {
}
/// Calls a thread by marking it as "ready" (note: will not actually execute until current thread yields)
-void __CallThread(Thread* t) {
+void CallThread(Thread* t) {
// Stop waiting
if (t->wait_type != WAITTYPE_NONE) {
t->wait_type = WAITTYPE_NONE;
}
- __ChangeThreadState(t, THREADSTATUS_READY);
+ ChangeThreadState(t, THREADSTATUS_READY);
}
/// Switches CPU context to that of the specified thread
-void __SwitchContext(Thread* t, const char* reason) {
- Thread* cur = __GetCurrentThread();
+void SwitchContext(Thread* t, const char* reason) {
+ Thread* cur = GetCurrentThread();
// Save context for current thread
if (cur) {
- __SaveContext(cur->context);
+ SaveContext(cur->context);
if (cur->IsRunning()) {
- __ChangeReadyState(cur, true);
+ ChangeReadyState(cur, true);
}
}
// Load context of new thread
if (t) {
- __SetCurrentThread(t);
- __ChangeReadyState(t, false);
+ SetCurrentThread(t);
+ ChangeReadyState(t, false);
t->status = (t->status | THREADSTATUS_RUNNING) & ~THREADSTATUS_READY;
t->wait_type = WAITTYPE_NONE;
- __LoadContext(t->context);
+ LoadContext(t->context);
} else {
- __SetCurrentThread(NULL);
+ SetCurrentThread(NULL);
}
}
/// Gets the next thread that is ready to be run by priority
-Thread* __NextThread() {
+Thread* NextThread() {
Handle next;
- Thread* cur = __GetCurrentThread();
+ Thread* cur = GetCurrentThread();
if (cur && cur->IsRunning()) {
next = g_thread_ready_queue.pop_first_better(cur->current_priority);
@@ -183,9 +188,9 @@ Thread* __NextThread() {
/// Puts a thread in the wait state for the given type/reason
void WaitCurThread(WaitType wait_type, const char* reason) {
- Thread* t = __GetCurrentThread();
+ Thread* t = GetCurrentThread();
t->wait_type = wait_type;
- __ChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND)));
+ ChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND)));
}
/// Resumes a thread from waiting by marking it as "ready"
@@ -195,7 +200,7 @@ void ResumeThreadFromWait(Handle handle) {
if (t) {
t->status &= ~THREADSTATUS_WAIT;
if (!(t->status & (THREADSTATUS_WAITSUSPEND | THREADSTATUS_DORMANT | THREADSTATUS_DEAD))) {
- __ChangeReadyState(t, true);
+ ChangeReadyState(t, true);
}
}
}
@@ -256,7 +261,7 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3
Thread* t = CreateThread(handle, name, entry_point, priority, processor_id, stack_top,
stack_size);
- __ResetThread(t, arg, 0);
+ ResetThread(t, arg, 0);
HLE::EatCycles(32000);
@@ -264,16 +269,11 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3
// Technically, this should not eat all at once, and reschedule in the middle, but that's hard.
HLE::ReSchedule("thread created");
- __CallThread(t);
+ CallThread(t);
return handle;
}
-/// Gets the current thread
-Handle GetCurrentThread() {
- return __GetCurrentThread()->GetHandle();
-}
-
/// Sets up the primary application thread
Handle SetupMainThread(s32 priority, int stack_size) {
Handle handle;
@@ -282,33 +282,33 @@ Handle SetupMainThread(s32 priority, int stack_size) {
Thread* t = CreateThread(handle, "main", Core::g_app_core->GetPC(), priority,
THREADPROCESSORID_0, Memory::SCRATCHPAD_VADDR_END, stack_size);
- __ResetThread(t, 0, 0);
+ ResetThread(t, 0, 0);
// If running another thread already, set it to "ready" state
- Thread* cur = __GetCurrentThread();
+ Thread* cur = GetCurrentThread();
if (cur && cur->IsRunning()) {
- __ChangeReadyState(cur, true);
+ ChangeReadyState(cur, true);
}
// Run new "main" thread
- __SetCurrentThread(t);
+ SetCurrentThread(t);
t->status = THREADSTATUS_RUNNING;
- __LoadContext(t->context);
+ LoadContext(t->context);
return handle;
}
/// Reschedules to the next available thread (call after current thread is suspended)
void Reschedule(const char* reason) {
- Thread* prev = __GetCurrentThread();
- Thread* next = __NextThread();
+ Thread* prev = GetCurrentThread();
+ Thread* next = NextThread();
if (next > 0) {
- __SwitchContext(next, reason);
+ SwitchContext(next, reason);
// Hack - automatically change previous thread (which would have been in "wait" state) to
// "ready" state, so that we can immediately resume to it when new thread yields. FixMe to
// actually wait for whatever event it is supposed to be waiting on.
- __ChangeReadyState(prev, true);
+ ChangeReadyState(prev, true);
}
}
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 82bf16082..a9e9eb95f 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -59,8 +59,8 @@ void WaitCurThread(WaitType wait_type, const char* reason);
/// Resumes a thread from waiting by marking it as "ready"
void ResumeThreadFromWait(Handle handle);
-/// Gets the current thread
-Handle GetCurrentThread();
+/// Gets the current thread handle
+Handle GetCurrentThreadHandle();
/// Put current thread in a wait state - on WaitSynchronization
void WaitThread_Synchronization();
diff --git a/src/core/loader.cpp b/src/core/loader.cpp
index 444b75feb..ff1c873bb 100644
--- a/src/core/loader.cpp
+++ b/src/core/loader.cpp
@@ -56,7 +56,7 @@ bool Load_ELF(std::string &filename) {
elf_reader = new ElfReader(buffer);
elf_reader->LoadInto(0x00100000);
- __KernelLoadExec(elf_reader->GetEntryPoint());
+ Kernel::LoadExec(elf_reader->GetEntryPoint());
delete[] buffer;
delete elf_reader;
@@ -102,7 +102,7 @@ bool Load_DAT(std::string &filename) {
*d++ = (*s++);
}
- __KernelLoadExec(entry_point);
+ Kernel::LoadExec(entry_point);
delete[] buffer;
@@ -144,7 +144,7 @@ bool Load_BIN(std::string &filename) {
*d++ = (*s++);
}
- __KernelLoadExec(entry_point);
+ Kernel::LoadExec(entry_point);
delete[] buffer;
}
--
cgit v1.2.3
From 7c0b0060764e75738bc9d4417d0bfd510e54ae4e Mon Sep 17 00:00:00 2001
From: bunnei
Date: Thu, 22 May 2014 19:32:45 -0400
Subject: thread: removed unused SwitchContext/Reschedule reason field, added
missing arg parameter to SVC CreateThread
---
src/core/hle/kernel/thread.cpp | 6 +++---
src/core/hle/kernel/thread.h | 2 +-
src/core/hle/svc.cpp | 13 +++++--------
3 files changed, 9 insertions(+), 12 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 5f1d5c400..189f7d5f5 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -147,7 +147,7 @@ void CallThread(Thread* t) {
}
/// Switches CPU context to that of the specified thread
-void SwitchContext(Thread* t, const char* reason) {
+void SwitchContext(Thread* t) {
Thread* cur = GetCurrentThread();
// Save context for current thread
@@ -299,11 +299,11 @@ Handle SetupMainThread(s32 priority, int stack_size) {
}
/// Reschedules to the next available thread (call after current thread is suspended)
-void Reschedule(const char* reason) {
+void Reschedule() {
Thread* prev = GetCurrentThread();
Thread* next = NextThread();
if (next > 0) {
- SwitchContext(next, reason);
+ SwitchContext(next);
// Hack - automatically change previous thread (which would have been in "wait" state) to
// "ready" state, so that we can immediately resume to it when new thread yields. FixMe to
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index a9e9eb95f..d54f47aaf 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -51,7 +51,7 @@ Handle CreateThread(const char* name, u32 entry_point, s32 priority, u32 arg, s3
Handle SetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE);
/// Reschedules to the next available thread (call after current thread is suspended)
-void Reschedule(const char* reason);
+void Reschedule();
/// Puts a thread in the wait state for the given type/reason
void WaitCurThread(WaitType wait_type, const char* reason);
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 14d512b99..b1854a36e 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -106,10 +106,9 @@ Result CloseHandle(Handle handle) {
/// Wait for a handle to synchronize, timeout after the specified nanoseconds
Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
- // ImplementMe
DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronization1 called handle=0x%08X, nanoseconds=%d",
handle, nano_seconds);
- Kernel::Reschedule("WaitSynchronization1");
+ Kernel::WaitCurThread(WAITTYPE_SYNCH, "WaitSynchronization1"); // TODO(bunnei): Is this correct?
return 0;
}
@@ -117,16 +116,14 @@ Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
Result WaitSynchronizationN(void* _out, void* _handles, u32 handle_count, u32 wait_all, s64 nano_seconds) {
s32* out = (s32*)_out;
Handle* handles = (Handle*)_handles;
- // ImplementMe
-
+
DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronizationN called handle_count=%d, wait_all=%s, nanoseconds=%d %s",
handle_count, (wait_all ? "true" : "false"), nano_seconds);
-
+
for (u32 i = 0; i < handle_count; i++) {
DEBUG_LOG(SVC, "\thandle[%d]=0x%08X", i, handles[i]);
}
- Kernel::Reschedule("WaitSynchronizationN");
-
+ Kernel::WaitCurThread(WAITTYPE_SYNCH, "WaitSynchronizationN"); // TODO(bunnei): Is this correct?
return 0;
}
@@ -174,7 +171,7 @@ Result CreateThread(u32 priority, u32 entry_point, u32 arg, u32 stack_top, u32 p
name = buff;
}
- Handle thread = Kernel::CreateThread(name.c_str(), entry_point, priority, processor_id,
+ Handle thread = Kernel::CreateThread(name.c_str(), entry_point, priority, arg, processor_id,
stack_top);
Core::g_app_core->SetReg(1, thread);
--
cgit v1.2.3
From b99ac2c3d67e2bcaa2c6eac220f1e93f4576c4fe Mon Sep 17 00:00:00 2001
From: bunnei
Date: Thu, 22 May 2014 19:36:56 -0400
Subject: thread: renamed "WaitCurThread" to "WaitCurrentThread", removed
unused "reason" argument
---
src/core/hle/kernel/thread.cpp | 4 ++--
src/core/hle/kernel/thread.h | 4 ++--
src/core/hle/svc.cpp | 4 ++--
3 files changed, 6 insertions(+), 6 deletions(-)
(limited to 'src')
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 189f7d5f5..bf4c8353c 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -186,8 +186,8 @@ Thread* NextThread() {
return Kernel::g_object_pool.GetFast(next);
}
-/// Puts a thread in the wait state for the given type/reason
-void WaitCurThread(WaitType wait_type, const char* reason) {
+/// Puts the current thread in the wait state for the given type
+void WaitCurrentThread(WaitType wait_type) {
Thread* t = GetCurrentThread();
t->wait_type = wait_type;
ChangeThreadState(t, ThreadStatus(THREADSTATUS_WAIT | (t->status & THREADSTATUS_SUSPEND)));
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index d54f47aaf..9628f165d 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -53,8 +53,8 @@ Handle SetupMainThread(s32 priority, int stack_size=Kernel::DEFAULT_STACK_SIZE);
/// Reschedules to the next available thread (call after current thread is suspended)
void Reschedule();
-/// Puts a thread in the wait state for the given type/reason
-void WaitCurThread(WaitType wait_type, const char* reason);
+/// Puts the current thread in the wait state for the given type
+void WaitCurrentThread(WaitType wait_type);
/// Resumes a thread from waiting by marking it as "ready"
void ResumeThreadFromWait(Handle handle);
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index b1854a36e..8018a43a2 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -108,7 +108,7 @@ Result CloseHandle(Handle handle) {
Result WaitSynchronization1(Handle handle, s64 nano_seconds) {
DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronization1 called handle=0x%08X, nanoseconds=%d",
handle, nano_seconds);
- Kernel::WaitCurThread(WAITTYPE_SYNCH, "WaitSynchronization1"); // TODO(bunnei): Is this correct?
+ Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct?
return 0;
}
@@ -123,7 +123,7 @@ Result WaitSynchronizationN(void* _out, void* _handles, u32 handle_count, u32 wa
for (u32 i = 0; i < handle_count; i++) {
DEBUG_LOG(SVC, "\thandle[%d]=0x%08X", i, handles[i]);
}
- Kernel::WaitCurThread(WAITTYPE_SYNCH, "WaitSynchronizationN"); // TODO(bunnei): Is this correct?
+ Kernel::WaitCurrentThread(WAITTYPE_SYNCH); // TODO(bunnei): Is this correct?
return 0;
}
--
cgit v1.2.3
From 7bb66421a08ee4c061d7336efc20c69f70e97cd9 Mon Sep 17 00:00:00 2001
From: bunnei
Date: Thu, 22 May 2014 20:01:04 -0400
Subject: lcd: added thread wait after (faked) vblank interrupt (would have)
occurred
---
src/core/hw/lcd.cpp | 4 ++++
1 file changed, 4 insertions(+)
(limited to 'src')
diff --git a/src/core/hw/lcd.cpp b/src/core/hw/lcd.cpp
index 6468053f2..b57563a73 100644
--- a/src/core/hw/lcd.cpp
+++ b/src/core/hw/lcd.cpp
@@ -11,6 +11,8 @@
#include "video_core/video_core.h"
+#include "core/hle/kernel/thread.h"
+
namespace LCD {
Registers g_regs;
@@ -130,9 +132,11 @@ template void Write(u32 addr, const u8 data);
void Update() {
u64 current_ticks = Core::g_app_core->GetTicks();
+ // Fake a vertical blank
if ((current_ticks - g_last_ticks) >= kFrameTicks) {
g_last_ticks = current_ticks;
VideoCore::g_renderer->SwapBuffers();
+ Kernel::WaitCurrentThread(WAITTYPE_VBLANK);
}
}
--
cgit v1.2.3
From f8a98ab0228f25431d2df87f88310b41bb381b8e Mon Sep 17 00:00:00 2001
From: bunnei
Date: Thu, 22 May 2014 22:49:29 -0400
Subject: svc: added a check to ensure that a service was implemented before
attempting to connect to its port
---
src/core/hle/svc.cpp | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 8018a43a2..90c05cb74 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -84,7 +84,11 @@ Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherper
/// Connect to an OS service given the port name, returns the handle to the port to out
Result ConnectToPort(void* out, const char* port_name) {
Service::Interface* service = Service::g_manager->FetchFromPortName(port_name);
- Core::g_app_core->SetReg(1, service->GetHandle());
+ if (service) {
+ Core::g_app_core->SetReg(1, service->GetHandle());
+ } else {
+ PanicYesNo("ConnectToPort called port_name=%s, but it is not implemented!", port_name);
+ }
DEBUG_LOG(SVC, "ConnectToPort called port_name=%s", port_name);
return 0;
}
--
cgit v1.2.3
From 51f636b3d44e0c963d73cbc4e1a555633980b3fb Mon Sep 17 00:00:00 2001
From: bunnei
Date: Thu, 22 May 2014 22:54:07 -0400
Subject: core: added Kernel::Reschedule() call to check for thread changes,
shortened delay time to 100 instructions
---
src/core/core.cpp | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
(limited to 'src')
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 61c237b2c..f88bcd704 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -12,6 +12,8 @@
#include "core/arm/disassembler/arm_disasm.h"
#include "core/arm/interpreter/arm_interpreter.h"
+#include "core/hle/kernel/thread.h"
+
namespace Core {
ARM_Disasm* g_disasm = NULL; ///< ARM disassembler
@@ -21,14 +23,17 @@ ARM_Interface* g_sys_core = NULL; ///< ARM11 system (OS) core
/// Run the core CPU loop
void RunLoop() {
for (;;){
- g_app_core->Run(10000);
+ g_app_core->Run(100);
HW::Update();
+ Kernel::Reschedule();
}
}
/// Step the CPU one instruction
void SingleStep() {
g_app_core->Step();
+ HW::Update();
+ Kernel::Reschedule();
}
/// Halt the core
--
cgit v1.2.3