summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt4
-rw-r--r--src/core/arm/interpreter/armemu.cpp8
-rw-r--r--src/core/core_timing.cpp12
-rw-r--r--src/core/file_sys/archive_sdmc.cpp2
-rw-r--r--src/core/file_sys/directory.h6
-rw-r--r--src/core/file_sys/directory_romfs.cpp4
-rw-r--r--src/core/file_sys/directory_romfs.h6
-rw-r--r--src/core/file_sys/directory_sdmc.cpp13
-rw-r--r--src/core/file_sys/directory_sdmc.h7
-rw-r--r--src/core/file_sys/file_sdmc.cpp9
-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/thread.cpp29
-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/gsp_gpu.cpp23
-rw-r--r--src/core/hle/service/service.h24
-rw-r--r--src/core/hw/gpu.cpp3
-rw-r--r--src/core/hw/gpu.h2
-rw-r--r--src/core/hw/hw.cpp13
-rw-r--r--src/core/hw/ndma.cpp47
-rw-r--r--src/core/hw/ndma.h26
-rw-r--r--src/core/loader/3dsx.cpp236
-rw-r--r--src/core/loader/3dsx.h32
-rw-r--r--src/core/loader/loader.cpp7
-rw-r--r--src/core/loader/loader.h1
-rw-r--r--src/core/mem_map.h10
-rw-r--r--src/core/mem_map_funcs.cpp42
28 files changed, 462 insertions, 214 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 48241c3d4..8f6792791 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -59,10 +59,10 @@ set(SRCS
hle/svc.cpp
hw/gpu.cpp
hw/hw.cpp
- hw/ndma.cpp
loader/elf.cpp
loader/loader.cpp
loader/ncch.cpp
+ loader/3dsx.cpp
core.cpp
core_timing.cpp
mem_map.cpp
@@ -139,10 +139,10 @@ set(HEADERS
hle/svc.h
hw/gpu.h
hw/hw.h
- hw/ndma.h
loader/elf.h
loader/loader.h
loader/ncch.h
+ loader/3dsx.h
core.h
core_timing.h
mem_map.h
diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp
index 73223874e..d717bd2c8 100644
--- a/src/core/arm/interpreter/armemu.cpp
+++ b/src/core/arm/interpreter/armemu.cpp
@@ -5724,7 +5724,7 @@ L_stm_s_takeabort:
s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
s16 b1 = (state->Reg[src2] & 0xFFFF);
s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
- state->Reg[tar] = (a1 - a2)&0xFFFF | (((b1 - b2)&0xFFFF)<< 0x10);
+ state->Reg[tar] = ((a1 - a2) & 0xFFFF) | (((b1 - b2)&0xFFFF)<< 0x10);
return 1;
}
else if ((instr & 0xFF0) == 0xf10)//sadd16
@@ -5736,7 +5736,7 @@ L_stm_s_takeabort:
s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
s16 b1 = (state->Reg[src2] & 0xFFFF);
s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
- state->Reg[tar] = (a1 + a2)&0xFFFF | (((b1 + b2)&0xFFFF)<< 0x10);
+ state->Reg[tar] = ((a1 + a2) & 0xFFFF) | (((b1 + b2)&0xFFFF)<< 0x10);
return 1;
}
else if ((instr & 0xFF0) == 0xf50)//ssax
@@ -5748,7 +5748,7 @@ L_stm_s_takeabort:
s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
s16 b1 = (state->Reg[src2] & 0xFFFF);
s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
- state->Reg[tar] = (a1 - b2) & 0xFFFF | (((a2 + b1) & 0xFFFF) << 0x10);
+ state->Reg[tar] = ((a1 + b2) & 0xFFFF) | (((a2 - b1) & 0xFFFF) << 0x10);
return 1;
}
else if ((instr & 0xFF0) == 0xf30)//sasx
@@ -5760,7 +5760,7 @@ L_stm_s_takeabort:
s16 a2 = ((state->Reg[src1] >> 0x10) & 0xFFFF);
s16 b1 = (state->Reg[src2] & 0xFFFF);
s16 b2 = ((state->Reg[src2] >> 0x10) & 0xFFFF);
- state->Reg[tar] = (a2 - b1) & 0xFFFF | (((a2 + b1) & 0xFFFF) << 0x10);
+ state->Reg[tar] = ((a1 - b2) & 0xFFFF) | (((a2 + b1) & 0xFFFF) << 0x10);
return 1;
}
else printf ("Unhandled v6 insn: sadd/ssub\n");
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 558c6cbf7..bf8acf41f 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -67,7 +67,7 @@ s64 idledCycles;
static std::recursive_mutex externalEventSection;
// Warning: not included in save state.
-void(*advanceCallback)(int cyclesExecuted) = NULL;
+void(*advanceCallback)(int cyclesExecuted) = nullptr;
void SetClockFrequencyMHz(int cpuMhz)
{
@@ -231,7 +231,7 @@ void ClearPendingEvents()
void AddEventToQueue(Event* ne)
{
- Event* prev = NULL;
+ Event* prev = nullptr;
Event** pNext = &first;
for (;;)
{
@@ -327,7 +327,7 @@ s64 UnscheduleThreadsafeEvent(int event_type, u64 userdata)
}
if (!tsFirst)
{
- tsLast = NULL;
+ tsLast = nullptr;
return result;
}
@@ -433,7 +433,7 @@ void RemoveThreadsafeEvent(int event_type)
}
if (!tsFirst)
{
- tsLast = NULL;
+ tsLast = nullptr;
return;
}
Event *prev = tsFirst;
@@ -495,7 +495,7 @@ void MoveEvents()
AddEventToQueue(tsFirst);
tsFirst = next;
}
- tsLast = NULL;
+ tsLast = nullptr;
// Move free events to threadsafe pool
while (allocatedTsEvents > 0 && eventPool)
@@ -614,7 +614,7 @@ void DoState(PointerWrap &p)
// These (should) be filled in later by the modules.
event_types.resize(n, EventType(AntiCrashCallback, "INVALID EVENT"));
- p.DoLinkedList<BaseEvent, GetNewEvent, FreeEvent, Event_DoState>(first, (Event **)NULL);
+ p.DoLinkedList<BaseEvent, GetNewEvent, FreeEvent, Event_DoState>(first, (Event **)nullptr);
p.DoLinkedList<BaseEvent, GetNewTsEvent, FreeTsEvent, Event_DoState>(tsFirst, &tsLast);
p.Do(g_clock_rate_arm11);
diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp
index 169ab0f1c..fc0b9b72d 100644
--- a/src/core/file_sys/archive_sdmc.cpp
+++ b/src/core/file_sys/archive_sdmc.cpp
@@ -100,6 +100,8 @@ bool Archive_SDMC::RenameDirectory(const FileSys::Path& src_path, const FileSys:
std::unique_ptr<Directory> Archive_SDMC::OpenDirectory(const Path& path) const {
DEBUG_LOG(FILESYS, "called path=%s", path.DebugStr().c_str());
Directory_SDMC* directory = new Directory_SDMC(this, path);
+ if (!directory->Open())
+ return nullptr;
return std::unique_ptr<Directory>(directory);
}
diff --git a/src/core/file_sys/directory.h b/src/core/file_sys/directory.h
index e10431337..1bb4101d6 100644
--- a/src/core/file_sys/directory.h
+++ b/src/core/file_sys/directory.h
@@ -42,6 +42,12 @@ public:
virtual ~Directory() { }
/**
+ * Open the directory
+ * @return true if the directory opened correctly
+ */
+ virtual bool Open() = 0;
+
+ /**
* List files contained in the directory
* @param count Number of entries to return at once in entries
* @param entries Buffer to read data into
diff --git a/src/core/file_sys/directory_romfs.cpp b/src/core/file_sys/directory_romfs.cpp
index 4e8f4c04d..e6d571391 100644
--- a/src/core/file_sys/directory_romfs.cpp
+++ b/src/core/file_sys/directory_romfs.cpp
@@ -17,6 +17,10 @@ Directory_RomFS::Directory_RomFS() {
Directory_RomFS::~Directory_RomFS() {
}
+bool Directory_RomFS::Open() {
+ return false;
+}
+
/**
* List files contained in the directory
* @param count Number of entries to return at once in entries
diff --git a/src/core/file_sys/directory_romfs.h b/src/core/file_sys/directory_romfs.h
index 4b71c4b13..e2944099e 100644
--- a/src/core/file_sys/directory_romfs.h
+++ b/src/core/file_sys/directory_romfs.h
@@ -20,6 +20,12 @@ public:
~Directory_RomFS() override;
/**
+ * Open the directory
+ * @return true if the directory opened correctly
+ */
+ bool Open() override;
+
+ /**
* List files contained in the directory
* @param count Number of entries to return at once in entries
* @param entries Buffer to read data into
diff --git a/src/core/file_sys/directory_sdmc.cpp b/src/core/file_sys/directory_sdmc.cpp
index 60a197ce9..0f156a127 100644
--- a/src/core/file_sys/directory_sdmc.cpp
+++ b/src/core/file_sys/directory_sdmc.cpp
@@ -19,15 +19,22 @@ Directory_SDMC::Directory_SDMC(const Archive_SDMC* archive, const Path& path) {
// TODO(Link Mauve): normalize path into an absolute path without "..", it can currently bypass
// the root directory we set while opening the archive.
// For example, opening /../../usr/bin can give the emulated program your installed programs.
- std::string absolute_path = archive->GetMountPoint() + path.AsString();
- FileUtil::ScanDirectoryTree(absolute_path, directory);
- children_iterator = directory.children.begin();
+ this->path = archive->GetMountPoint() + path.AsString();
+
}
Directory_SDMC::~Directory_SDMC() {
Close();
}
+bool Directory_SDMC::Open() {
+ if (!FileUtil::IsDirectory(path))
+ return false;
+ FileUtil::ScanDirectoryTree(path, directory);
+ children_iterator = directory.children.begin();
+ return true;
+}
+
/**
* List files contained in the directory
* @param count Number of entries to return at once in entries
diff --git a/src/core/file_sys/directory_sdmc.h b/src/core/file_sys/directory_sdmc.h
index 4520d0401..4c08b0d61 100644
--- a/src/core/file_sys/directory_sdmc.h
+++ b/src/core/file_sys/directory_sdmc.h
@@ -23,6 +23,12 @@ public:
~Directory_SDMC() override;
/**
+ * Open the directory
+ * @return true if the directory opened correctly
+ */
+ bool Open() override;
+
+ /**
* List files contained in the directory
* @param count Number of entries to return at once in entries
* @param entries Buffer to read data into
@@ -37,6 +43,7 @@ public:
bool Close() const override;
private:
+ std::string path;
u32 total_entries_in_directory;
FileUtil::FSTEntry directory;
diff --git a/src/core/file_sys/file_sdmc.cpp b/src/core/file_sys/file_sdmc.cpp
index a4b90670a..b01d96e3d 100644
--- a/src/core/file_sys/file_sdmc.cpp
+++ b/src/core/file_sys/file_sdmc.cpp
@@ -38,12 +38,15 @@ bool File_SDMC::Open() {
}
std::string mode_string;
- if (mode.read_flag && mode.write_flag)
+ if (mode.create_flag)
mode_string = "w+";
+ else if (mode.write_flag)
+ mode_string = "r+"; // Files opened with Write access can be read from
else if (mode.read_flag)
mode_string = "r";
- else if (mode.write_flag)
- mode_string = "w";
+
+ // Open the file in binary mode, to avoid problems with CR/LF on Windows systems
+ mode_string += "b";
file = new FileUtil::IOFile(path, mode_string.c_str());
return true;
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/thread.cpp b/src/core/hle/kernel/thread.cpp
index c01d76e4d..492b917e1 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -64,6 +64,7 @@ public:
WaitType wait_type;
Handle wait_handle;
+ VAddr wait_address;
std::vector<Handle> waiting_threads;
@@ -127,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
@@ -147,11 +149,17 @@ 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);
@@ -173,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;
}
@@ -201,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;
@@ -226,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);
}
}
@@ -281,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;
@@ -293,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);
@@ -343,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/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);
}
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index af5e1b39b..77557e582 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -154,8 +154,7 @@ inline void Write(u32 addr, const T data) {
if (config.trigger & 1)
{
u32* buffer = (u32*)Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalAddress()));
- u32 size = config.size << 3;
- Pica::CommandProcessor::ProcessCommandList(buffer, size);
+ Pica::CommandProcessor::ProcessCommandList(buffer, config.size);
}
break;
}
diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h
index 3fa7b9ccf..86cd5e680 100644
--- a/src/core/hw/gpu.h
+++ b/src/core/hw/gpu.h
@@ -169,7 +169,7 @@ struct Regs {
INSERT_PADDING_WORDS(0x331);
struct {
- // command list size
+ // command list size (in bytes)
u32 size;
INSERT_PADDING_WORDS(0x1);
diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp
index ea001673a..73a4f1e53 100644
--- a/src/core/hw/hw.cpp
+++ b/src/core/hw/hw.cpp
@@ -6,7 +6,6 @@
#include "core/hw/hw.h"
#include "core/hw/gpu.h"
-#include "core/hw/ndma.h"
namespace HW {
@@ -40,11 +39,6 @@ template <typename T>
inline void Read(T &var, const u32 addr) {
switch (addr & 0xFFFFF000) {
- // TODO(bunnei): What is the virtual address of NDMA?
- // case VADDR_NDMA:
- // NDMA::Read(var, addr);
- // break;
-
case VADDR_GPU:
GPU::Read(var, addr);
break;
@@ -58,11 +52,6 @@ template <typename T>
inline void Write(u32 addr, const T data) {
switch (addr & 0xFFFFF000) {
- // TODO(bunnei): What is the virtual address of NDMA?
- // case VADDR_NDMA
- // NDMA::Write(addr, data);
- // break;
-
case VADDR_GPU:
GPU::Write(addr, data);
break;
@@ -87,13 +76,11 @@ template void Write<u8>(u32 addr, const u8 data);
/// Update hardware
void Update() {
GPU::Update();
- NDMA::Update();
}
/// Initialize hardware
void Init() {
GPU::Init();
- NDMA::Init();
NOTICE_LOG(HW, "initialized OK");
}
diff --git a/src/core/hw/ndma.cpp b/src/core/hw/ndma.cpp
deleted file mode 100644
index 593e5de30..000000000
--- a/src/core/hw/ndma.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2
-// Refer to the license.txt file included.
-
-#include "common/common_types.h"
-
-#include "core/hw/ndma.h"
-
-namespace NDMA {
-
-template <typename T>
-inline void Read(T &var, const u32 addr) {
- ERROR_LOG(NDMA, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr);
-}
-
-template <typename T>
-inline void Write(u32 addr, const T data) {
- ERROR_LOG(NDMA, "unknown Write%lu 0x%08X @ 0x%08X", sizeof(data) * 8, (u32)data, addr);
-}
-
-// Explicitly instantiate template functions because we aren't defining this in the header:
-
-template void Read<u64>(u64 &var, const u32 addr);
-template void Read<u32>(u32 &var, const u32 addr);
-template void Read<u16>(u16 &var, const u32 addr);
-template void Read<u8>(u8 &var, const u32 addr);
-
-template void Write<u64>(u32 addr, const u64 data);
-template void Write<u32>(u32 addr, const u32 data);
-template void Write<u16>(u32 addr, const u16 data);
-template void Write<u8>(u32 addr, const u8 data);
-
-/// Update hardware
-void Update() {
-}
-
-/// Initialize hardware
-void Init() {
- NOTICE_LOG(GPU, "initialized OK");
-}
-
-/// Shutdown hardware
-void Shutdown() {
- NOTICE_LOG(GPU, "shutdown OK");
-}
-
-} // namespace
diff --git a/src/core/hw/ndma.h b/src/core/hw/ndma.h
deleted file mode 100644
index d8fa3d40b..000000000
--- a/src/core/hw/ndma.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include "common/common_types.h"
-
-namespace NDMA {
-
-template <typename T>
-inline void Read(T &var, const u32 addr);
-
-template <typename T>
-inline void Write(u32 addr, const T data);
-
-/// Update hardware
-void Update();
-
-/// Initialize hardware
-void Init();
-
-/// Shutdown hardware
-void Shutdown();
-
-} // namespace
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp
new file mode 100644
index 000000000..7ef146359
--- /dev/null
+++ b/src/core/loader/3dsx.cpp
@@ -0,0 +1,236 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include <algorithm>
+#include <vector>
+
+#include "core/file_sys/archive_romfs.h"
+#include "core/loader/elf.h"
+#include "core/loader/ncch.h"
+#include "core/hle/kernel/archive.h"
+#include "core/mem_map.h"
+
+#include "3dsx.h"
+
+
+namespace Loader {
+
+
+/**
+ * File layout:
+ * - File header
+ * - Code, rodata and data relocation table headers
+ * - Code segment
+ * - Rodata segment
+ * - Loadable (non-BSS) part of the data segment
+ * - Code relocation table
+ * - Rodata relocation table
+ * - Data relocation table
+ *
+ * Memory layout before relocations are applied:
+ * [0..codeSegSize) -> code segment
+ * [codeSegSize..rodataSegSize) -> rodata segment
+ * [rodataSegSize..dataSegSize) -> data segment
+ *
+ * Memory layout after relocations are applied: well, however the loader sets it up :)
+ * The entrypoint is always the start of the code segment.
+ * The BSS section must be cleared manually by the application.
+ */
+enum THREEDSX_Error {
+ ERROR_NONE = 0,
+ ERROR_READ = 1,
+ ERROR_FILE = 2,
+ ERROR_ALLOC = 3
+};
+static const u32 RELOCBUFSIZE = 512;
+
+// File header
+static const u32 THREEDSX_MAGIC = 0x58534433; // '3DSX'
+#pragma pack(1)
+struct THREEDSX_Header
+{
+ u32 magic;
+ u16 header_size, reloc_hdr_size;
+ u32 format_ver;
+ u32 flags;
+
+ // Sizes of the code, rodata and data segments +
+ // size of the BSS section (uninitialized latter half of the data segment)
+ u32 code_seg_size, rodata_seg_size, data_seg_size, bss_size;
+};
+
+// Relocation header: all fields (even extra unknown fields) are guaranteed to be relocation counts.
+struct THREEDSX_RelocHdr
+{
+ // # of absolute relocations (that is, fix address to post-relocation memory layout)
+ u32 cross_segment_absolute;
+ // # of cross-segment relative relocations (that is, 32bit signed offsets that need to be patched)
+ u32 cross_segment_relative;
+ // more?
+
+ // Relocations are written in this order:
+ // - Absolute relocations
+ // - Relative relocations
+};
+
+// Relocation entry: from the current pointer, skip X words and patch Y words
+struct THREEDSX_Reloc
+{
+ u16 skip, patch;
+};
+#pragma pack()
+
+struct THREEloadinfo
+{
+ u8* seg_ptrs[3]; // code, rodata & data
+ u32 seg_addrs[3];
+ u32 seg_sizes[3];
+};
+
+class THREEDSXReader {
+public:
+ static int Load3DSXFile(const std::string& filename, u32 base_addr);
+};
+
+static u32 TranslateAddr(u32 addr, THREEloadinfo *loadinfo, u32* offsets)
+{
+ if (addr < offsets[0])
+ return loadinfo->seg_addrs[0] + addr;
+ if (addr < offsets[1])
+ return loadinfo->seg_addrs[1] + addr - offsets[0];
+ return loadinfo->seg_addrs[2] + addr - offsets[1];
+}
+
+int THREEDSXReader::Load3DSXFile(const std::string& filename, u32 base_addr)
+{
+ FileUtil::IOFile file(filename, "rb");
+ if (!file.IsOpen()) {
+ return ERROR_FILE;
+ }
+ THREEDSX_Header hdr;
+ if (file.ReadBytes(&hdr, sizeof(hdr)) != sizeof(hdr))
+ return ERROR_READ;
+
+ THREEloadinfo loadinfo;
+ //loadinfo segments must be a multiple of 0x1000
+ loadinfo.seg_sizes[0] = (hdr.code_seg_size + 0xFFF) &~0xFFF;
+ loadinfo.seg_sizes[1] = (hdr.rodata_seg_size + 0xFFF) &~0xFFF;
+ loadinfo.seg_sizes[2] = (hdr.data_seg_size + 0xFFF) &~0xFFF;
+ u32 offsets[2] = { loadinfo.seg_sizes[0], loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] };
+ u32 data_load_size = (hdr.data_seg_size - hdr.bss_size + 0xFFF) &~0xFFF;
+ u32 bss_load_size = loadinfo.seg_sizes[2] - data_load_size;
+ u32 n_reloc_tables = hdr.reloc_hdr_size / 4;
+ std::vector<u8> all_mem(loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] + loadinfo.seg_sizes[2] + 3 * n_reloc_tables);
+
+ loadinfo.seg_addrs[0] = base_addr;
+ loadinfo.seg_addrs[1] = loadinfo.seg_addrs[0] + loadinfo.seg_sizes[0];
+ loadinfo.seg_addrs[2] = loadinfo.seg_addrs[1] + loadinfo.seg_sizes[1];
+ loadinfo.seg_ptrs[0] = &all_mem[0];
+ loadinfo.seg_ptrs[1] = loadinfo.seg_ptrs[0] + loadinfo.seg_sizes[0];
+ loadinfo.seg_ptrs[2] = loadinfo.seg_ptrs[1] + loadinfo.seg_sizes[1];
+
+ // Skip header for future compatibility
+ file.Seek(hdr.header_size, SEEK_SET);
+
+ // Read the relocation headers
+ u32* relocs = (u32*)(loadinfo.seg_ptrs[2] + hdr.data_seg_size);
+
+ for (u32 current_segment = 0; current_segment < 3; current_segment++) {
+ if (file.ReadBytes(&relocs[current_segment*n_reloc_tables], n_reloc_tables * 4) != n_reloc_tables * 4)
+ return ERROR_READ;
+ }
+
+ // Read the segments
+ if (file.ReadBytes(loadinfo.seg_ptrs[0], hdr.code_seg_size) != hdr.code_seg_size)
+ return ERROR_READ;
+ if (file.ReadBytes(loadinfo.seg_ptrs[1], hdr.rodata_seg_size) != hdr.rodata_seg_size)
+ return ERROR_READ;
+ if (file.ReadBytes(loadinfo.seg_ptrs[2], hdr.data_seg_size - hdr.bss_size) != hdr.data_seg_size - hdr.bss_size)
+ return ERROR_READ;
+
+ // BSS clear
+ memset((char*)loadinfo.seg_ptrs[2] + hdr.data_seg_size - hdr.bss_size, 0, hdr.bss_size);
+
+ // Relocate the segments
+ for (u32 current_segment = 0; current_segment < 3; current_segment++) {
+ for (u32 current_segment_reloc_table = 0; current_segment_reloc_table < n_reloc_tables; current_segment_reloc_table++) {
+ u32 n_relocs = relocs[current_segment*n_reloc_tables + current_segment_reloc_table];
+ if (current_segment_reloc_table >= 2) {
+ // We are not using this table - ignore it because we don't know what it dose
+ file.Seek(n_relocs*sizeof(THREEDSX_Reloc), SEEK_CUR);
+ continue;
+ }
+ static THREEDSX_Reloc reloc_table[RELOCBUFSIZE];
+
+ u32* pos = (u32*)loadinfo.seg_ptrs[current_segment];
+ u32* end_pos = pos + (loadinfo.seg_sizes[current_segment] / 4);
+
+ while (n_relocs) {
+ u32 remaining = std::min(RELOCBUFSIZE, n_relocs);
+ n_relocs -= remaining;
+
+ if (file.ReadBytes(reloc_table, remaining*sizeof(THREEDSX_Reloc)) != remaining*sizeof(THREEDSX_Reloc))
+ return ERROR_READ;
+
+ for (u32 current_inprogress = 0; current_inprogress < remaining && pos < end_pos; current_inprogress++) {
+ DEBUG_LOG(LOADER, "(t=%d,skip=%u,patch=%u)\n",
+ current_segment_reloc_table, (u32)reloc_table[current_inprogress].skip, (u32)reloc_table[current_inprogress].patch);
+ pos += reloc_table[current_inprogress].skip;
+ s32 num_patches = reloc_table[current_inprogress].patch;
+ while (0 < num_patches && pos < end_pos) {
+ u32 in_addr = (char*)pos - (char*)&all_mem[0];
+ u32 addr = TranslateAddr(*pos, &loadinfo, offsets);
+ DEBUG_LOG(LOADER, "Patching %08X <-- rel(%08X,%d) (%08X)\n",
+ base_addr + in_addr, addr, current_segment_reloc_table, *pos);
+ switch (current_segment_reloc_table) {
+ case 0: *pos = (addr); break;
+ case 1: *pos = (addr - in_addr); break;
+ default: break; //this should never happen
+ }
+ pos++;
+ num_patches--;
+ }
+ }
+ }
+ }
+ }
+
+ // Write the data
+ memcpy(Memory::GetPointer(base_addr), &all_mem[0], loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] + loadinfo.seg_sizes[2]);
+
+ DEBUG_LOG(LOADER, "CODE: %u pages\n", loadinfo.seg_sizes[0] / 0x1000);
+ DEBUG_LOG(LOADER, "RODATA: %u pages\n", loadinfo.seg_sizes[1] / 0x1000);
+ DEBUG_LOG(LOADER, "DATA: %u pages\n", data_load_size / 0x1000);
+ DEBUG_LOG(LOADER, "BSS: %u pages\n", bss_load_size / 0x1000);
+
+ return ERROR_NONE;
+}
+
+ /// AppLoader_DSX constructor
+ AppLoader_THREEDSX::AppLoader_THREEDSX(const std::string& filename) : filename(filename) {
+ }
+
+ /// AppLoader_DSX destructor
+ AppLoader_THREEDSX::~AppLoader_THREEDSX() {
+ }
+
+ /**
+ * Loads a 3DSX file
+ * @return Success on success, otherwise Error
+ */
+ ResultStatus AppLoader_THREEDSX::Load() {
+ INFO_LOG(LOADER, "Loading 3DSX file %s...", filename.c_str());
+ FileUtil::IOFile file(filename, "rb");
+ if (file.IsOpen()) {
+
+ THREEDSXReader reader;
+ reader.Load3DSXFile(filename, 0x00100000);
+ Kernel::LoadExec(0x00100000);
+ } else {
+ return ResultStatus::Error;
+ }
+ return ResultStatus::Success;
+ }
+
+} // namespace Loader
diff --git a/src/core/loader/3dsx.h b/src/core/loader/3dsx.h
new file mode 100644
index 000000000..848d3ef8a
--- /dev/null
+++ b/src/core/loader/3dsx.h
@@ -0,0 +1,32 @@
+// Copyright 2014 Dolphin Emulator Project / Citra Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "common/common_types.h"
+#include "core/loader/loader.h"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Loader namespace
+
+namespace Loader {
+
+/// Loads an 3DSX file
+class AppLoader_THREEDSX final : public AppLoader {
+public:
+ AppLoader_THREEDSX(const std::string& filename);
+ ~AppLoader_THREEDSX() override;
+
+ /**
+ * Load the bootable file
+ * @return ResultStatus result of function
+ */
+ ResultStatus Load() override;
+
+private:
+ std::string filename;
+ bool is_loaded;
+};
+
+} // namespace Loader
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index a268e021a..174397b05 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -5,6 +5,7 @@
#include <memory>
#include "core/file_sys/archive_romfs.h"
+#include "core/loader/3dsx.h"
#include "core/loader/elf.h"
#include "core/loader/ncch.h"
#include "core/hle/kernel/archive.h"
@@ -42,6 +43,8 @@ FileType IdentifyFile(const std::string &filename) {
return FileType::CCI;
} else if (extension == ".bin") {
return FileType::BIN;
+ } else if (extension == ".3dsx") {
+ return FileType::THREEDSX;
}
return FileType::Unknown;
}
@@ -56,6 +59,10 @@ ResultStatus LoadFile(const std::string& filename) {
switch (IdentifyFile(filename)) {
+ //3DSX file format...
+ case FileType::THREEDSX:
+ return AppLoader_THREEDSX(filename).Load();
+
// Standard ELF file format...
case FileType::ELF:
return AppLoader_ELF(filename).Load();
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 68f843005..0f836d285 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -22,6 +22,7 @@ enum class FileType {
CIA,
ELF,
BIN,
+ THREEDSX, //3DSX
};
/// Return type for functions in Loader namespace
diff --git a/src/core/mem_map.h b/src/core/mem_map.h
index c9529f84c..f17afb60d 100644
--- a/src/core/mem_map.h
+++ b/src/core/mem_map.h
@@ -26,12 +26,10 @@ enum : u32 {
FCRAM_PADDR_END = (FCRAM_PADDR + FCRAM_SIZE), ///< FCRAM end of physical space
FCRAM_VADDR = 0x08000000, ///< FCRAM virtual address
FCRAM_VADDR_END = (FCRAM_VADDR + FCRAM_SIZE), ///< FCRAM end of virtual space
- FCRAM_MASK = (FCRAM_SIZE - 1), ///< FCRAM mask
SHARED_MEMORY_SIZE = 0x04000000, ///< Shared memory size
SHARED_MEMORY_VADDR = 0x10000000, ///< Shared memory
SHARED_MEMORY_VADDR_END = (SHARED_MEMORY_VADDR + SHARED_MEMORY_SIZE),
- SHARED_MEMORY_MASK = (SHARED_MEMORY_SIZE - 1),
DSP_MEMORY_SIZE = 0x00080000, ///< DSP memory size
DSP_MEMORY_VADDR = 0x1FF00000, ///< DSP memory virtual address
@@ -39,37 +37,31 @@ enum : u32 {
CONFIG_MEMORY_SIZE = 0x00001000, ///< Configuration memory size
CONFIG_MEMORY_VADDR = 0x1FF80000, ///< Configuration memory virtual address
CONFIG_MEMORY_VADDR_END = (CONFIG_MEMORY_VADDR + CONFIG_MEMORY_SIZE),
- CONFIG_MEMORY_MASK = (CONFIG_MEMORY_SIZE - 1),
KERNEL_MEMORY_SIZE = 0x00001000, ///< Kernel memory size
KERNEL_MEMORY_VADDR = 0xFFFF0000, ///< Kernel memory where the kthread objects etc are
KERNEL_MEMORY_VADDR_END = (KERNEL_MEMORY_VADDR + KERNEL_MEMORY_SIZE),
- KERNEL_MEMORY_MASK = (KERNEL_MEMORY_SIZE - 1),
EXEFS_CODE_SIZE = 0x03F00000,
EXEFS_CODE_VADDR = 0x00100000, ///< ExeFS:/.code is loaded here
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),
HEAP_VADDR = 0x08000000,
HEAP_VADDR_END = (HEAP_VADDR + HEAP_SIZE),
- HEAP_MASK = (HEAP_SIZE - 1),
HEAP_GSP_SIZE = 0x02000000, ///< GSP heap size... TODO: Define correctly?
HEAP_GSP_VADDR = 0x14000000,
HEAP_GSP_VADDR_END = (HEAP_GSP_VADDR + HEAP_GSP_SIZE),
HEAP_GSP_PADDR = 0x00000000,
HEAP_GSP_PADDR_END = (HEAP_GSP_PADDR + HEAP_GSP_SIZE),
- HEAP_GSP_MASK = (HEAP_GSP_SIZE - 1),
HARDWARE_IO_SIZE = 0x01000000,
HARDWARE_IO_PADDR = 0x10000000, ///< IO physical address start
@@ -82,12 +74,10 @@ enum : u32 {
VRAM_VADDR = 0x1F000000,
VRAM_PADDR_END = (VRAM_PADDR + VRAM_SIZE),
VRAM_VADDR_END = (VRAM_VADDR + VRAM_SIZE),
- VRAM_MASK = 0x007FFFFF,
SCRATCHPAD_SIZE = 0x00004000, ///< Typical stack size - TODO: Read from exheader
SCRATCHPAD_VADDR_END = 0x10000000,
SCRATCHPAD_VADDR = (SCRATCHPAD_VADDR_END - SCRATCHPAD_SIZE), ///< Stack space
- SCRATCHPAD_MASK = (SCRATCHPAD_SIZE - 1), ///< Scratchpad memory mask
};
////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/mem_map_funcs.cpp b/src/core/mem_map_funcs.cpp
index e8747840c..1887bcedb 100644
--- a/src/core/mem_map_funcs.cpp
+++ b/src/core/mem_map_funcs.cpp
@@ -56,7 +56,7 @@ inline void Read(T &var, const VAddr vaddr) {
// Kernel memory command buffer
if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) {
- var = *((const T*)&g_kernel_mem[vaddr & KERNEL_MEMORY_MASK]);
+ var = *((const T*)&g_kernel_mem[vaddr - KERNEL_MEMORY_VADDR]);
// Hardware I/O register reads
// 0x10XXXXXX- is physical address space, 0x1EXXXXXX is virtual address space
@@ -65,23 +65,23 @@ inline void Read(T &var, const VAddr vaddr) {
// ExeFS:/.code is loaded here
} else if ((vaddr >= EXEFS_CODE_VADDR) && (vaddr < EXEFS_CODE_VADDR_END)) {
- var = *((const T*)&g_exefs_code[vaddr & EXEFS_CODE_MASK]);
+ var = *((const T*)&g_exefs_code[vaddr - EXEFS_CODE_VADDR]);
// FCRAM - GSP heap
} else if ((vaddr >= HEAP_GSP_VADDR) && (vaddr < HEAP_GSP_VADDR_END)) {
- var = *((const T*)&g_heap_gsp[vaddr & HEAP_GSP_MASK]);
+ var = *((const T*)&g_heap_gsp[vaddr - HEAP_GSP_VADDR]);
// FCRAM - application heap
} else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) {
- var = *((const T*)&g_heap[vaddr & HEAP_MASK]);
+ var = *((const T*)&g_heap[vaddr - HEAP_VADDR]);
// Shared memory
} else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
- var = *((const T*)&g_shared_mem[vaddr & SHARED_MEMORY_MASK]);
+ var = *((const T*)&g_shared_mem[vaddr - SHARED_MEMORY_VADDR]);
// System memory
} else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) {
- var = *((const T*)&g_system_mem[vaddr & SYSTEM_MEMORY_MASK]);
+ var = *((const T*)&g_system_mem[vaddr - SYSTEM_MEMORY_VADDR]);
// Config memory
} else if ((vaddr >= CONFIG_MEMORY_VADDR) && (vaddr < CONFIG_MEMORY_VADDR_END)) {
@@ -89,7 +89,7 @@ inline void Read(T &var, const VAddr vaddr) {
// VRAM
} else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) {
- var = *((const T*)&g_vram[vaddr & VRAM_MASK]);
+ var = *((const T*)&g_vram[vaddr - VRAM_VADDR]);
} else {
ERROR_LOG(MEMMAP, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, vaddr);
@@ -101,7 +101,7 @@ inline void Write(const VAddr vaddr, const T data) {
// Kernel memory command buffer
if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) {
- *(T*)&g_kernel_mem[vaddr & KERNEL_MEMORY_MASK] = data;
+ *(T*)&g_kernel_mem[vaddr - KERNEL_MEMORY_VADDR] = data;
// Hardware I/O register writes
// 0x10XXXXXX- is physical address space, 0x1EXXXXXX is virtual address space
@@ -110,27 +110,27 @@ inline void Write(const VAddr vaddr, const T data) {
// ExeFS:/.code is loaded here
} else if ((vaddr >= EXEFS_CODE_VADDR) && (vaddr < EXEFS_CODE_VADDR_END)) {
- *(T*)&g_exefs_code[vaddr & EXEFS_CODE_MASK] = data;
+ *(T*)&g_exefs_code[vaddr - EXEFS_CODE_VADDR] = data;
// FCRAM - GSP heap
} else if ((vaddr >= HEAP_GSP_VADDR) && (vaddr < HEAP_GSP_VADDR_END)) {
- *(T*)&g_heap_gsp[vaddr & HEAP_GSP_MASK] = data;
+ *(T*)&g_heap_gsp[vaddr - HEAP_GSP_VADDR] = data;
// FCRAM - application heap
} else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) {
- *(T*)&g_heap[vaddr & HEAP_MASK] = data;
+ *(T*)&g_heap[vaddr - HEAP_VADDR] = data;
// Shared memory
} else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
- *(T*)&g_shared_mem[vaddr & SHARED_MEMORY_MASK] = data;
+ *(T*)&g_shared_mem[vaddr - SHARED_MEMORY_VADDR] = data;
// System memory
} else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) {
- *(T*)&g_system_mem[vaddr & SYSTEM_MEMORY_MASK] = data;
+ *(T*)&g_system_mem[vaddr - SYSTEM_MEMORY_VADDR] = data;
// VRAM
} else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) {
- *(T*)&g_vram[vaddr & VRAM_MASK] = data;
+ *(T*)&g_vram[vaddr - VRAM_VADDR] = data;
//} else if ((vaddr & 0xFFF00000) == 0x1FF00000) {
// _assert_msg_(MEMMAP, false, "umimplemented write to DSP memory");
@@ -148,31 +148,31 @@ inline void Write(const VAddr vaddr, const T data) {
u8 *GetPointer(const VAddr vaddr) {
// Kernel memory command buffer
if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) {
- return g_kernel_mem + (vaddr & KERNEL_MEMORY_MASK);
+ return g_kernel_mem + (vaddr - KERNEL_MEMORY_VADDR);
// ExeFS:/.code is loaded here
} else if ((vaddr >= EXEFS_CODE_VADDR) && (vaddr < EXEFS_CODE_VADDR_END)) {
- return g_exefs_code + (vaddr & EXEFS_CODE_MASK);
+ return g_exefs_code + (vaddr - EXEFS_CODE_VADDR);
// FCRAM - GSP heap
} else if ((vaddr >= HEAP_GSP_VADDR) && (vaddr < HEAP_GSP_VADDR_END)) {
- return g_heap_gsp + (vaddr & HEAP_GSP_MASK);
+ return g_heap_gsp + (vaddr - HEAP_GSP_VADDR);
// FCRAM - application heap
} else if ((vaddr >= HEAP_VADDR) && (vaddr < HEAP_VADDR_END)) {
- return g_heap + (vaddr & HEAP_MASK);
+ return g_heap + (vaddr - HEAP_VADDR);
// Shared memory
} else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) {
- return g_shared_mem + (vaddr & SHARED_MEMORY_MASK);
+ return g_shared_mem + (vaddr - SHARED_MEMORY_VADDR);
// System memory
} else if ((vaddr >= SYSTEM_MEMORY_VADDR) && (vaddr < SYSTEM_MEMORY_VADDR_END)) {
- return g_system_mem + (vaddr & SYSTEM_MEMORY_MASK);
+ return g_system_mem + (vaddr - SYSTEM_MEMORY_VADDR);
// VRAM
} else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) {
- return g_vram + (vaddr & VRAM_MASK);
+ return g_vram + (vaddr - VRAM_VADDR);
} else {
ERROR_LOG(MEMMAP, "unknown GetPointer @ 0x%08x", vaddr);