summaryrefslogtreecommitdiffstats
path: root/src/core/hle
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle')
-rw-r--r--src/core/hle/kernel/address_arbiter.cpp2
-rw-r--r--src/core/hle/kernel/archive.cpp5
-rw-r--r--src/core/hle/kernel/mutex.cpp94
-rw-r--r--src/core/hle/kernel/mutex.h6
-rw-r--r--src/core/hle/kernel/thread.cpp33
-rw-r--r--src/core/hle/kernel/thread.h11
-rw-r--r--src/core/hle/service/cfg_u.cpp92
-rw-r--r--src/core/hle/service/dsp_dsp.cpp46
-rw-r--r--src/core/hle/service/gsp_gpu.cpp23
-rw-r--r--src/core/hle/service/service.h24
10 files changed, 222 insertions, 114 deletions
diff --git a/src/core/hle/kernel/address_arbiter.cpp b/src/core/hle/kernel/address_arbiter.cpp
index db571b895..ce4f3c854 100644
--- a/src/core/hle/kernel/address_arbiter.cpp
+++ b/src/core/hle/kernel/address_arbiter.cpp
@@ -53,7 +53,7 @@ ResultCode ArbitrateAddress(Handle handle, ArbitrationType type, u32 address, s3
// Wait current thread (acquire the arbiter)...
case ArbitrationType::WaitIfLessThan:
if ((s32)Memory::Read32(address) <= value) {
- Kernel::WaitCurrentThread(WAITTYPE_ARB, handle);
+ Kernel::WaitCurrentThread(WAITTYPE_ARB, handle, address);
HLE::Reschedule(__func__);
}
break;
diff --git a/src/core/hle/kernel/archive.cpp b/src/core/hle/kernel/archive.cpp
index 647f0dea9..a875fa7ff 100644
--- a/src/core/hle/kernel/archive.cpp
+++ b/src/core/hle/kernel/archive.cpp
@@ -421,6 +421,11 @@ ResultVal<Handle> OpenDirectoryFromArchive(Handle archive_handle, const FileSys:
directory->path = path;
directory->backend = archive->backend->OpenDirectory(path);
+ if (!directory->backend) {
+ return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,
+ ErrorSummary::NotFound, ErrorLevel::Permanent);
+ }
+
return MakeResult<Handle>(handle);
}
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index d07e9761b..5a173e129 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -27,21 +27,7 @@ public:
std::vector<Handle> waiting_threads; ///< Threads that are waiting for the mutex
std::string name; ///< Name of mutex (optional)
- ResultVal<bool> SyncRequest() override {
- // TODO(bunnei): ImplementMe
- locked = true;
- return MakeResult<bool>(false);
- }
-
- ResultVal<bool> WaitSynchronization() override {
- // TODO(bunnei): ImplementMe
- bool wait = locked;
- if (locked) {
- Kernel::WaitCurrentThread(WAITTYPE_MUTEX, GetHandle());
- }
-
- return MakeResult<bool>(wait);
- }
+ ResultVal<bool> WaitSynchronization() override;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -49,21 +35,46 @@ public:
typedef std::multimap<Handle, Handle> MutexMap;
static MutexMap g_mutex_held_locks;
-void MutexAcquireLock(Mutex* mutex, Handle thread) {
+/**
+ * Acquires the specified mutex for the specified thread
+ * @param mutex Mutex that is to be acquired
+ * @param thread Thread that will acquired
+ */
+void MutexAcquireLock(Mutex* mutex, Handle thread = GetCurrentThreadHandle()) {
g_mutex_held_locks.insert(std::make_pair(thread, mutex->GetHandle()));
mutex->lock_thread = thread;
}
-void MutexAcquireLock(Mutex* mutex) {
- Handle thread = GetCurrentThreadHandle();
+bool ReleaseMutexForThread(Mutex* mutex, Handle thread) {
MutexAcquireLock(mutex, thread);
+ Kernel::ResumeThreadFromWait(thread);
+ return true;
+}
+
+/**
+ * Resumes a thread waiting for the specified mutex
+ * @param mutex The mutex that some thread is waiting on
+ */
+void ResumeWaitingThread(Mutex* mutex) {
+ // Find the next waiting thread for the mutex...
+ if (mutex->waiting_threads.empty()) {
+ // Reset mutex lock thread handle, nothing is waiting
+ mutex->locked = false;
+ mutex->lock_thread = -1;
+ }
+ else {
+ // Resume the next waiting thread and re-lock the mutex
+ std::vector<Handle>::iterator iter = mutex->waiting_threads.begin();
+ ReleaseMutexForThread(mutex, *iter);
+ mutex->waiting_threads.erase(iter);
+ }
}
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) {
+ if (iter->second == handle) {
g_mutex_held_locks.erase(iter);
break;
}
@@ -71,6 +82,19 @@ void MutexEraseLock(Mutex* mutex) {
mutex->lock_thread = -1;
}
+void ReleaseThreadMutexes(Handle thread) {
+ auto locked = g_mutex_held_locks.equal_range(thread);
+
+ // Release every mutex that the thread holds, and resume execution on the waiting threads
+ for (MutexMap::iterator iter = locked.first; iter != locked.second; ++iter) {
+ Mutex* mutex = g_object_pool.GetFast<Mutex>(iter->second);
+ ResumeWaitingThread(mutex);
+ }
+
+ // Erase all the locks that this thread holds
+ g_mutex_held_locks.erase(thread);
+}
+
bool LockMutex(Mutex* mutex) {
// Mutex alread locked?
if (mutex->locked) {
@@ -80,26 +104,9 @@ bool LockMutex(Mutex* mutex) {
return true;
}
-bool ReleaseMutexForThread(Mutex* mutex, Handle thread) {
- MutexAcquireLock(mutex, thread);
- Kernel::ResumeThreadFromWait(thread);
- return true;
-}
-
bool ReleaseMutex(Mutex* mutex) {
MutexEraseLock(mutex);
-
- // Find the next waiting thread for the mutex...
- while (!mutex->waiting_threads.empty()) {
- std::vector<Handle>::iterator iter = mutex->waiting_threads.begin();
- ReleaseMutexForThread(mutex, *iter);
- mutex->waiting_threads.erase(iter);
- }
-
- // Reset mutex lock thread handle, nothing is waiting
- mutex->locked = false;
- mutex->lock_thread = -1;
-
+ ResumeWaitingThread(mutex);
return true;
}
@@ -157,4 +164,17 @@ Handle CreateMutex(bool initial_locked, const std::string& name) {
return handle;
}
+ResultVal<bool> Mutex::WaitSynchronization() {
+ bool wait = locked;
+ if (locked) {
+ Kernel::WaitCurrentThread(WAITTYPE_MUTEX, GetHandle());
+ }
+ else {
+ // Lock the mutex when the first thread accesses it
+ locked = true;
+ MutexAcquireLock(this);
+ }
+
+ return MakeResult<bool>(wait);
+}
} // namespace
diff --git a/src/core/hle/kernel/mutex.h b/src/core/hle/kernel/mutex.h
index 155449f95..7f4909a6e 100644
--- a/src/core/hle/kernel/mutex.h
+++ b/src/core/hle/kernel/mutex.h
@@ -24,4 +24,10 @@ ResultCode ReleaseMutex(Handle handle);
*/
Handle CreateMutex(bool initial_locked, const std::string& name="Unknown");
+/**
+ * Releases all the mutexes held by the specified thread
+ * @param thread Thread that is holding the mutexes
+ */
+void ReleaseThreadMutexes(Handle thread);
+
} // namespace
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 8d65dc84d..492b917e1 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -14,6 +14,7 @@
#include "core/hle/hle.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/thread.h"
+#include "core/hle/kernel/mutex.h"
#include "core/hle/result.h"
#include "core/mem_map.h"
@@ -63,6 +64,7 @@ public:
WaitType wait_type;
Handle wait_handle;
+ VAddr wait_address;
std::vector<Handle> waiting_threads;
@@ -126,6 +128,7 @@ void ResetThread(Thread* t, u32 arg, s32 lowest_priority) {
}
t->wait_type = WAITTYPE_NONE;
t->wait_handle = 0;
+ t->wait_address = 0;
}
/// Change a thread to "ready" state
@@ -146,16 +149,25 @@ void ChangeReadyState(Thread* t, bool ready) {
}
/// Verify that a thread has not been released from waiting
-inline bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle) {
+static bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle) {
_dbg_assert_(KERNEL, thread != nullptr);
return (type == thread->wait_type) && (wait_handle == thread->wait_handle) && (thread->IsWaiting());
}
+/// Verify that a thread has not been released from waiting (with wait address)
+static bool VerifyWait(const Thread* thread, WaitType type, Handle wait_handle, VAddr wait_address) {
+ _dbg_assert_(KERNEL, thread != nullptr);
+ return VerifyWait(thread, type, wait_handle) && (wait_address == thread->wait_address);
+}
+
/// Stops the current thread
ResultCode StopThread(Handle handle, const char* reason) {
Thread* thread = g_object_pool.Get<Thread>(handle);
if (thread == nullptr) return InvalidHandle(ErrorModule::Kernel);
+ // Release all the mutexes that this thread holds
+ ReleaseThreadMutexes(handle);
+
ChangeReadyState(thread, false);
thread->status = THREADSTATUS_DORMANT;
for (Handle waiting_handle : thread->waiting_threads) {
@@ -169,6 +181,7 @@ ResultCode StopThread(Handle handle, const char* reason) {
// Stopped threads are never waiting.
thread->wait_type = WAITTYPE_NONE;
thread->wait_handle = 0;
+ thread->wait_address = 0;
return RESULT_SUCCESS;
}
@@ -197,12 +210,12 @@ Handle ArbitrateHighestPriorityThread(u32 arbiter, u32 address) {
for (Handle handle : thread_queue) {
Thread* thread = g_object_pool.Get<Thread>(handle);
- // TODO(bunnei): Verify arbiter address...
- if (!VerifyWait(thread, WAITTYPE_ARB, arbiter))
+ if (!VerifyWait(thread, WAITTYPE_ARB, arbiter, address))
continue;
if (thread == nullptr)
continue; // TODO(yuriks): Thread handle will hang around forever. Should clean up.
+
if(thread->current_priority <= priority) {
highest_priority_thread = handle;
priority = thread->current_priority;
@@ -222,8 +235,7 @@ void ArbitrateAllThreads(u32 arbiter, u32 address) {
for (Handle handle : thread_queue) {
Thread* thread = g_object_pool.Get<Thread>(handle);
- // TODO(bunnei): Verify arbiter address...
- if (VerifyWait(thread, WAITTYPE_ARB, arbiter))
+ if (VerifyWait(thread, WAITTYPE_ARB, arbiter, address))
ResumeThreadFromWait(handle);
}
}
@@ -277,11 +289,6 @@ Thread* NextThread() {
return Kernel::g_object_pool.Get<Thread>(next);
}
-/**
- * Puts the current thread in the wait state for the given type
- * @param wait_type Type of wait
- * @param wait_handle Handle of Kernel object that we are waiting on, defaults to current thread
- */
void WaitCurrentThread(WaitType wait_type, Handle wait_handle) {
Thread* thread = GetCurrentThread();
thread->wait_type = wait_type;
@@ -289,6 +296,11 @@ void WaitCurrentThread(WaitType wait_type, Handle wait_handle) {
ChangeThreadState(thread, ThreadStatus(THREADSTATUS_WAIT | (thread->status & THREADSTATUS_SUSPEND)));
}
+void WaitCurrentThread(WaitType wait_type, Handle wait_handle, VAddr wait_address) {
+ WaitCurrentThread(wait_type, wait_handle);
+ GetCurrentThread()->wait_address = wait_address;
+}
+
/// Resumes a thread from waiting by marking it as "ready"
void ResumeThreadFromWait(Handle handle) {
Thread* thread = Kernel::g_object_pool.Get<Thread>(handle);
@@ -339,6 +351,7 @@ Thread* CreateThread(Handle& handle, const char* name, u32 entry_point, s32 prio
thread->processor_id = processor_id;
thread->wait_type = WAITTYPE_NONE;
thread->wait_handle = 0;
+ thread->wait_address = 0;
thread->name = name;
return thread;
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 53a19d779..be7adface 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -5,6 +5,9 @@
#pragma once
#include "common/common_types.h"
+
+#include "core/mem_map.h"
+
#include "core/hle/kernel/kernel.h"
#include "core/hle/result.h"
@@ -85,6 +88,14 @@ Handle GetCurrentThreadHandle();
*/
void WaitCurrentThread(WaitType wait_type, Handle wait_handle=GetCurrentThreadHandle());
+/**
+ * Puts the current thread in the wait state for the given type
+ * @param wait_type Type of wait
+ * @param wait_handle Handle of Kernel object that we are waiting on, defaults to current thread
+ * @param wait_address Arbitration address used to resume from wait
+ */
+void WaitCurrentThread(WaitType wait_type, Handle wait_handle, VAddr wait_address);
+
/// Put current thread in a wait state - on WaitSynchronization
void WaitThread_Synchronization();
diff --git a/src/core/hle/service/cfg_u.cpp b/src/core/hle/service/cfg_u.cpp
index d6b586ea0..82bab5797 100644
--- a/src/core/hle/service/cfg_u.cpp
+++ b/src/core/hle/service/cfg_u.cpp
@@ -11,33 +11,38 @@
namespace CFG_U {
-static const std::array<const char*, 187> country_codes = {
- nullptr, "JP", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // 0-7
- "AI", "AG", "AR", "AW", "BS", "BB", "BZ", "BO", // 8-15
- "BR", "VG", "CA", "KY", "CL", "CO", "CR", "DM", // 16-23
- "DO", "EC", "SV", "GF", "GD", "GP", "GT", "GY", // 24-31
- "HT", "HN", "JM", "MQ", "MX", "MS", "AN", "NI", // 32-39
- "PA", "PY", "PE", "KN", "LC", "VC", "SR", "TT", // 40-47
- "TC", "US", "UY", "VI", "VE", nullptr, nullptr, nullptr, // 48-55
- nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // 56-63
- "AL", "AU", "AT", "BE", "BA", "BW", "BG", "HR", // 64-71
- "CY", "CZ", "DK", "EE", "FI", "FR", "DE", "GR", // 72-79
- "HU", "IS", "IE", "IT", "LV", "LS", "LI", "LT", // 80-87
- "LU", "MK", "MT", "ME", "MZ", "NA", "NL", "NZ", // 88-95
- "NO", "PL", "PT", "RO", "RU", "RS", "SK", "SI", // 96-103
- "ZA", "ES", "SZ", "SE", "CH", "TR", "GB", "ZM", // 104-111
- "ZW", "AZ", "MR", "ML", "NE", "TD", "SD", "ER", // 112-119
- "DJ", "SO", "AD", "GI", "GG", "IM", "JE", "MC", // 120-127
- "TW", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // 128-135
- "KR", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // 136-143
- "HK", "MO", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // 144-151
- "ID", "SG", "TH", "PH", "MY", nullptr, nullptr, nullptr, // 152-159
- "CN", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // 160-167
- "AE", "IN", "EG", "OM", "QA", "KW", "SA", "SY", // 168-175
- "BH", "JO", nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, // 176-183
- "SM", "VA", "BM", // 184-186
+// TODO(Link Mauve): use a constexpr once MSVC starts supporting it.
+#define C(code) ((code)[0] | ((code)[1] << 8))
+
+static const std::array<u16, 187> country_codes = {
+ 0, C("JP"), 0, 0, 0, 0, 0, 0, // 0-7
+ C("AI"), C("AG"), C("AR"), C("AW"), C("BS"), C("BB"), C("BZ"), C("BO"), // 8-15
+ C("BR"), C("VG"), C("CA"), C("KY"), C("CL"), C("CO"), C("CR"), C("DM"), // 16-23
+ C("DO"), C("EC"), C("SV"), C("GF"), C("GD"), C("GP"), C("GT"), C("GY"), // 24-31
+ C("HT"), C("HN"), C("JM"), C("MQ"), C("MX"), C("MS"), C("AN"), C("NI"), // 32-39
+ C("PA"), C("PY"), C("PE"), C("KN"), C("LC"), C("VC"), C("SR"), C("TT"), // 40-47
+ C("TC"), C("US"), C("UY"), C("VI"), C("VE"), 0, 0, 0, // 48-55
+ 0, 0, 0, 0, 0, 0, 0, 0, // 56-63
+ C("AL"), C("AU"), C("AT"), C("BE"), C("BA"), C("BW"), C("BG"), C("HR"), // 64-71
+ C("CY"), C("CZ"), C("DK"), C("EE"), C("FI"), C("FR"), C("DE"), C("GR"), // 72-79
+ C("HU"), C("IS"), C("IE"), C("IT"), C("LV"), C("LS"), C("LI"), C("LT"), // 80-87
+ C("LU"), C("MK"), C("MT"), C("ME"), C("MZ"), C("NA"), C("NL"), C("NZ"), // 88-95
+ C("NO"), C("PL"), C("PT"), C("RO"), C("RU"), C("RS"), C("SK"), C("SI"), // 96-103
+ C("ZA"), C("ES"), C("SZ"), C("SE"), C("CH"), C("TR"), C("GB"), C("ZM"), // 104-111
+ C("ZW"), C("AZ"), C("MR"), C("ML"), C("NE"), C("TD"), C("SD"), C("ER"), // 112-119
+ C("DJ"), C("SO"), C("AD"), C("GI"), C("GG"), C("IM"), C("JE"), C("MC"), // 120-127
+ C("TW"), 0, 0, 0, 0, 0, 0, 0, // 128-135
+ C("KR"), 0, 0, 0, 0, 0, 0, 0, // 136-143
+ C("HK"), C("MO"), 0, 0, 0, 0, 0, 0, // 144-151
+ C("ID"), C("SG"), C("TH"), C("PH"), C("MY"), 0, 0, 0, // 152-159
+ C("CN"), 0, 0, 0, 0, 0, 0, 0, // 160-167
+ C("AE"), C("IN"), C("EG"), C("OM"), C("QA"), C("KW"), C("SA"), C("SY"), // 168-175
+ C("BH"), C("JO"), 0, 0, 0, 0, 0, 0, // 176-183
+ C("SM"), C("VA"), C("BM") // 184-186
};
+#undef C
+
/**
* CFG_User::GetCountryCodeString service function
* Inputs:
@@ -50,20 +55,14 @@ static void GetCountryCodeString(Service::Interface* self) {
u32* cmd_buffer = Service::GetCommandBuffer();
u32 country_code_id = cmd_buffer[1];
- if (country_code_id >= country_codes.size()) {
+ if (country_code_id >= country_codes.size() || 0 == country_codes[country_code_id]) {
ERROR_LOG(KERNEL, "requested country code id=%d is invalid", country_code_id);
cmd_buffer[1] = ResultCode(ErrorDescription::NotFound, ErrorModule::Config, ErrorSummary::WrongArgument, ErrorLevel::Permanent).raw;
return;
}
-
- const char* code = country_codes[country_code_id];
- if (code != nullptr) {
- cmd_buffer[1] = 0;
- cmd_buffer[2] = code[0] | (code[1] << 8);
- } else {
- cmd_buffer[1] = ResultCode(ErrorDescription::NotFound, ErrorModule::Config, ErrorSummary::WrongArgument, ErrorLevel::Permanent).raw;
- DEBUG_LOG(KERNEL, "requested country code id=%d is not set", country_code_id);
- }
+
+ cmd_buffer[1] = 0;
+ cmd_buffer[2] = country_codes[country_code_id];
}
/**
@@ -77,20 +76,25 @@ static void GetCountryCodeString(Service::Interface* self) {
static void GetCountryCodeID(Service::Interface* self) {
u32* cmd_buffer = Service::GetCommandBuffer();
u16 country_code = cmd_buffer[1];
- u16 country_code_id = -1;
+ u16 country_code_id = 0;
- for (u32 i = 0; i < country_codes.size(); ++i) {
- const char* code_string = country_codes[i];
+ // The following algorithm will fail if the first country code isn't 0.
+ _dbg_assert_(HLE, country_codes[0] == 0);
- if (code_string != nullptr) {
- u16 code = code_string[0] | (code_string[1] << 8);
- if (code == country_code) {
- country_code_id = i;
- break;
- }
+ for (size_t id = 0; id < country_codes.size(); ++id) {
+ if (country_codes[id] == country_code) {
+ country_code_id = id;
+ break;
}
}
+ if (0 == country_code_id) {
+ ERROR_LOG(KERNEL, "requested country code name=%c%c is invalid", country_code & 0xff, country_code >> 8);
+ cmd_buffer[1] = ResultCode(ErrorDescription::NotFound, ErrorModule::Config, ErrorSummary::WrongArgument, ErrorLevel::Permanent).raw;
+ cmd_buffer[2] = 0xFFFF;
+ return;
+ }
+
cmd_buffer[1] = 0;
cmd_buffer[2] = country_code_id;
}
diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp
index 72be4c817..e89c8aae3 100644
--- a/src/core/hle/service/dsp_dsp.cpp
+++ b/src/core/hle/service/dsp_dsp.cpp
@@ -12,6 +12,7 @@
namespace DSP_DSP {
+static u32 read_pipe_count;
static Handle semaphore_event;
static Handle interrupt_event;
@@ -108,6 +109,48 @@ void WriteReg0x10(Service::Interface* self) {
DEBUG_LOG(KERNEL, "(STUBBED) called");
}
+/**
+ * DSP_DSP::ReadPipeIfPossible service function
+ * Inputs:
+ * 1 : Unknown
+ * 2 : Unknown
+ * 3 : Size in bytes of read (observed only lower half word used)
+ * 0x41 : Virtual address to read from DSP pipe to in memory
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : Number of bytes read from pipe
+ */
+void ReadPipeIfPossible(Service::Interface* self) {
+ u32* cmd_buff = Service::GetCommandBuffer();
+
+ u32 size = cmd_buff[3] & 0xFFFF;// Lower 16 bits are size
+ VAddr addr = cmd_buff[0x41];
+
+ // Canned DSP responses that games expect. These were taken from HW by 3dmoo team.
+ // TODO: Remove this hack :)
+ static const std::array<u16, 16> canned_read_pipe = {
+ 0x000F, 0xBFFF, 0x9E8E, 0x8680, 0xA78E, 0x9430, 0x8400, 0x8540,
+ 0x948E, 0x8710, 0x8410, 0xA90E, 0xAA0E, 0xAACE, 0xAC4E, 0xAC58
+ };
+
+ u32 initial_size = read_pipe_count;
+
+ for (unsigned offset = 0; offset < size; offset += sizeof(u16)) {
+ if (read_pipe_count < canned_read_pipe.size()) {
+ Memory::Write16(addr + offset, canned_read_pipe[read_pipe_count]);
+ read_pipe_count++;
+ } else {
+ ERROR_LOG(KERNEL, "canned read pipe log exceeded!");
+ break;
+ }
+ }
+
+ cmd_buff[1] = 0; // No error
+ cmd_buff[2] = (read_pipe_count - initial_size) * sizeof(u16);
+
+ DEBUG_LOG(KERNEL, "(STUBBED) called size=0x%08X, buffer=0x%08X", size, addr);
+}
+
const Interface::FunctionInfo FunctionTable[] = {
{0x00010040, nullptr, "RecvData"},
{0x00020040, nullptr, "RecvDataIsReady"},
@@ -119,7 +162,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x000B0000, nullptr, "CheckSemaphoreRequest"},
{0x000C0040, ConvertProcessAddressFromDspDram, "ConvertProcessAddressFromDspDram"},
{0x000D0082, nullptr, "WriteProcessPipe"},
- {0x001000C0, nullptr, "ReadPipeIfPossible"},
+ {0x001000C0, ReadPipeIfPossible, "ReadPipeIfPossible"},
{0x001100C2, LoadComponent, "LoadComponent"},
{0x00120000, nullptr, "UnloadComponent"},
{0x00130082, nullptr, "FlushDataCache"},
@@ -142,6 +185,7 @@ const Interface::FunctionInfo FunctionTable[] = {
Interface::Interface() {
semaphore_event = Kernel::CreateEvent(RESETTYPE_ONESHOT, "DSP_DSP::semaphore_event");
interrupt_event = 0;
+ read_pipe_count = 0;
Register(FunctionTable, ARRAY_SIZE(FunctionTable));
}
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index de1bd3f61..34eabac45 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -162,7 +162,8 @@ static void RegisterInterruptRelayQueue(Service::Interface* self) {
_assert_msg_(GSP, (g_interrupt_event != 0), "handle is not valid!");
- cmd_buff[2] = g_thread_id++; // ThreadID
+ cmd_buff[1] = 0x2A07; // Value verified by 3dmoo team, purpose unknown, but needed for GSP init
+ cmd_buff[2] = g_thread_id++; // Thread ID
cmd_buff[4] = g_shared_memory; // GSP shared memory
Kernel::SignalEvent(g_interrupt_event); // TODO(bunnei): Is this correct?
@@ -172,6 +173,7 @@ static void RegisterInterruptRelayQueue(Service::Interface* self) {
* Signals that the specified interrupt type has occurred to userland code
* @param interrupt_id ID of interrupt that is being signalled
* @todo This should probably take a thread_id parameter and only signal this thread?
+ * @todo This probably does not belong in the GSP module, instead move to video_core
*/
void SignalInterrupt(InterruptId interrupt_id) {
if (0 == g_interrupt_event) {
@@ -210,6 +212,7 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
memcpy(Memory::GetPointer(command.dma_request.dest_address),
Memory::GetPointer(command.dma_request.source_address),
command.dma_request.size);
+ SignalInterrupt(InterruptId::DMA);
break;
// ctrulib homebrew sends all relevant command list data with this command,
@@ -218,13 +221,13 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
case CommandId::SET_COMMAND_LIST_LAST:
{
auto& params = command.set_command_list_last;
+
WriteGPURegister(GPU_REG_INDEX(command_processor_config.address), Memory::VirtualToPhysicalAddress(params.address) >> 3);
- WriteGPURegister(GPU_REG_INDEX(command_processor_config.size), params.size >> 3);
+ WriteGPURegister(GPU_REG_INDEX(command_processor_config.size), params.size);
// TODO: Not sure if we are supposed to always write this .. seems to trigger processing though
WriteGPURegister(GPU_REG_INDEX(command_processor_config.trigger), 1);
- SignalInterrupt(InterruptId::P3D);
break;
}
@@ -242,6 +245,8 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[1].address_end), Memory::VirtualToPhysicalAddress(params.end2) >> 3);
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[1].size), params.end2 - params.start2);
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[1].value), params.value2);
+
+ SignalInterrupt(InterruptId::PSC0);
break;
}
@@ -255,14 +260,9 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.flags), params.flags);
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.trigger), 1);
- // TODO(bunnei): Signalling all of these interrupts here is totally wrong, but it seems to
- // work well enough for running demos. Need to figure out how these all work and trigger
- // them correctly.
- SignalInterrupt(InterruptId::PSC0);
+ // TODO(bunnei): Determine if these interrupts should be signalled here.
SignalInterrupt(InterruptId::PSC1);
SignalInterrupt(InterruptId::PPF);
- SignalInterrupt(InterruptId::P3D);
- SignalInterrupt(InterruptId::DMA);
// Update framebuffer information if requested
for (int screen_id = 0; screen_id < 2; ++screen_id) {
@@ -305,6 +305,8 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
/// This triggers handling of the GX command written to the command buffer in shared memory.
static void TriggerCmdReqQueue(Service::Interface* self) {
+ DEBUG_LOG(GSP, "called");
+
// Iterate through each thread's command queue...
for (unsigned thread_id = 0; thread_id < 0x4; ++thread_id) {
CommandBuffer* command_buffer = (CommandBuffer*)GetCommandBuffer(thread_id);
@@ -320,6 +322,9 @@ static void TriggerCmdReqQueue(Service::Interface* self) {
command_buffer->number_commands = command_buffer->number_commands - 1;
}
}
+
+ u32* cmd_buff = Service::GetCommandBuffer();
+ cmd_buff[1] = 0; // No error
}
const Interface::FunctionInfo FunctionTable[] = {
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 20e7fb4d3..3a7d6c469 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -10,6 +10,7 @@
#include <string>
#include "common/common.h"
+#include "common/string_util.h"
#include "core/mem_map.h"
#include "core/hle/kernel/kernel.h"
@@ -79,21 +80,20 @@ public:
u32* cmd_buff = GetCommandBuffer();
auto itr = m_functions.find(cmd_buff[0]);
- if (itr == m_functions.end()) {
- ERROR_LOG(OSHLE, "unknown/unimplemented function: port=%s, command=0x%08X",
- GetPortName().c_str(), cmd_buff[0]);
+ if (itr == m_functions.end() || itr->second.func == nullptr) {
+ // Number of params == bits 0-5 + bits 6-11
+ int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F);
- // TODO(bunnei): Hack - ignore error
- u32* cmd_buff = Service::GetCommandBuffer();
- cmd_buff[1] = 0;
- return MakeResult<bool>(false);
- }
- if (itr->second.func == nullptr) {
- ERROR_LOG(OSHLE, "unimplemented function: port=%s, name=%s",
- GetPortName().c_str(), itr->second.name.c_str());
+ std::string error = "unknown/unimplemented function '%s': port=%s";
+ for (int i = 1; i <= num_params; ++i) {
+ error += Common::StringFromFormat(", cmd_buff[%i]=%u", i, cmd_buff[i]);
+ }
+
+ std::string name = (itr == m_functions.end()) ? Common::StringFromFormat("0x%08X", cmd_buff[0]) : itr->second.name;
+
+ ERROR_LOG(OSHLE, error.c_str(), name.c_str(), GetPortName().c_str());
// TODO(bunnei): Hack - ignore error
- u32* cmd_buff = Service::GetCommandBuffer();
cmd_buff[1] = 0;
return MakeResult<bool>(false);
}