aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/hle
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle')
-rw-r--r--src/core/hle/function_wrappers.h17
-rw-r--r--src/core/hle/kernel/event.cpp3
-rw-r--r--src/core/hle/kernel/kernel.cpp22
-rw-r--r--src/core/hle/kernel/kernel.h6
-rw-r--r--src/core/hle/kernel/mutex.cpp9
-rw-r--r--src/core/hle/kernel/resource_limit.h8
-rw-r--r--src/core/hle/kernel/semaphore.cpp10
-rw-r--r--src/core/hle/kernel/thread.cpp84
-rw-r--r--src/core/hle/kernel/thread.h14
-rw-r--r--src/core/hle/kernel/timer.cpp2
-rw-r--r--src/core/hle/kernel/vm_manager.cpp245
-rw-r--r--src/core/hle/kernel/vm_manager.h200
-rw-r--r--src/core/hle/service/am/am.cpp55
-rw-r--r--src/core/hle/service/am/am.h47
-rw-r--r--src/core/hle/service/am/am_app.cpp20
-rw-r--r--src/core/hle/service/am/am_app.h22
-rw-r--r--src/core/hle/service/am/am_net.cpp (renamed from src/core/hle/service/am_net.cpp)17
-rw-r--r--src/core/hle/service/am/am_net.h22
-rw-r--r--src/core/hle/service/am/am_sys.cpp22
-rw-r--r--src/core/hle/service/am/am_sys.h22
-rw-r--r--src/core/hle/service/am/am_u.cpp22
-rw-r--r--src/core/hle/service/am/am_u.h22
-rw-r--r--src/core/hle/service/am_app.cpp23
-rw-r--r--src/core/hle/service/am_app.h23
-rw-r--r--src/core/hle/service/am_net.h23
-rw-r--r--src/core/hle/service/am_sys.cpp62
-rw-r--r--src/core/hle/service/am_sys.h23
-rw-r--r--src/core/hle/service/apt/apt.cpp4
-rw-r--r--src/core/hle/service/apt/apt.h8
-rw-r--r--src/core/hle/service/boss/boss.cpp29
-rw-r--r--src/core/hle/service/boss/boss.h20
-rw-r--r--src/core/hle/service/boss/boss_p.cpp20
-rw-r--r--src/core/hle/service/boss/boss_p.h22
-rw-r--r--src/core/hle/service/boss/boss_u.cpp21
-rw-r--r--src/core/hle/service/boss/boss_u.h22
-rw-r--r--src/core/hle/service/boss_p.cpp23
-rw-r--r--src/core/hle/service/boss_p.h23
-rw-r--r--src/core/hle/service/boss_u.cpp24
-rw-r--r--src/core/hle/service/boss_u.h23
-rw-r--r--src/core/hle/service/cam/cam.cpp35
-rw-r--r--src/core/hle/service/cam/cam.h20
-rw-r--r--src/core/hle/service/cam/cam_c.cpp20
-rw-r--r--src/core/hle/service/cam/cam_c.h22
-rw-r--r--src/core/hle/service/cam/cam_q.cpp20
-rw-r--r--src/core/hle/service/cam/cam_q.h22
-rw-r--r--src/core/hle/service/cam/cam_s.cpp20
-rw-r--r--src/core/hle/service/cam/cam_s.h22
-rw-r--r--src/core/hle/service/cam/cam_u.cpp20
-rw-r--r--src/core/hle/service/cam/cam_u.h22
-rw-r--r--src/core/hle/service/cam_u.cpp23
-rw-r--r--src/core/hle/service/cam_u.h23
-rw-r--r--src/core/hle/service/cecd/cecd.cpp31
-rw-r--r--src/core/hle/service/cecd/cecd.h20
-rw-r--r--src/core/hle/service/cecd/cecd_s.cpp20
-rw-r--r--src/core/hle/service/cecd/cecd_s.h (renamed from src/core/hle/service/cecd_s.h)13
-rw-r--r--src/core/hle/service/cecd/cecd_u.cpp20
-rw-r--r--src/core/hle/service/cecd/cecd_u.h (renamed from src/core/hle/service/cecd_u.h)13
-rw-r--r--src/core/hle/service/cecd_s.cpp23
-rw-r--r--src/core/hle/service/cecd_u.cpp23
-rw-r--r--src/core/hle/service/cfg/cfg.cpp4
-rw-r--r--src/core/hle/service/frd/frd.cpp29
-rw-r--r--src/core/hle/service/frd/frd.h20
-rw-r--r--src/core/hle/service/frd/frd_a.cpp20
-rw-r--r--src/core/hle/service/frd/frd_a.h (renamed from src/core/hle/service/frd_a.h)13
-rw-r--r--src/core/hle/service/frd/frd_u.cpp (renamed from src/core/hle/service/frd_u.cpp)17
-rw-r--r--src/core/hle/service/frd/frd_u.h (renamed from src/core/hle/service/frd_u.h)13
-rw-r--r--src/core/hle/service/frd_a.cpp23
-rw-r--r--src/core/hle/service/fs/archive.cpp29
-rw-r--r--src/core/hle/service/fs/archive.h4
-rw-r--r--src/core/hle/service/fs/fs_user.cpp20
-rw-r--r--src/core/hle/service/gsp_gpu.cpp68
-rw-r--r--src/core/hle/service/hid/hid.cpp6
-rw-r--r--src/core/hle/service/hid/hid_spvr.cpp2
-rw-r--r--src/core/hle/service/hid/hid_user.h2
-rw-r--r--src/core/hle/service/news/news.cpp31
-rw-r--r--src/core/hle/service/news/news.h20
-rw-r--r--src/core/hle/service/news/news_s.cpp21
-rw-r--r--src/core/hle/service/news/news_s.h (renamed from src/core/hle/service/news_s.h)13
-rw-r--r--src/core/hle/service/news/news_u.cpp21
-rw-r--r--src/core/hle/service/news/news_u.h (renamed from src/core/hle/service/news_u.h)13
-rw-r--r--src/core/hle/service/news_s.cpp24
-rw-r--r--src/core/hle/service/news_u.cpp24
-rw-r--r--src/core/hle/service/nim/nim.cpp42
-rw-r--r--src/core/hle/service/nim/nim.h30
-rw-r--r--src/core/hle/service/nim/nim_aoc.cpp (renamed from src/core/hle/service/nim_aoc.cpp)16
-rw-r--r--src/core/hle/service/nim/nim_aoc.h22
-rw-r--r--src/core/hle/service/nim/nim_s.cpp22
-rw-r--r--src/core/hle/service/nim/nim_s.h22
-rw-r--r--src/core/hle/service/nim/nim_u.cpp27
-rw-r--r--src/core/hle/service/nim/nim_u.h22
-rw-r--r--src/core/hle/service/nim_aoc.h23
-rw-r--r--src/core/hle/service/nim_u.cpp48
-rw-r--r--src/core/hle/service/nim_u.h23
-rw-r--r--src/core/hle/service/ptm/ptm.h6
-rw-r--r--src/core/hle/service/ptm/ptm_play.cpp2
-rw-r--r--src/core/hle/service/service.cpp60
-rw-r--r--src/core/hle/service/soc_u.cpp30
-rw-r--r--src/core/hle/svc.cpp32
98 files changed, 1788 insertions, 792 deletions
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h
index 23c86a72..5949cb47 100644
--- a/src/core/hle/function_wrappers.h
+++ b/src/core/hle/function_wrappers.h
@@ -9,11 +9,15 @@
#include "core/arm/arm_interface.h"
#include "core/memory.h"
#include "core/hle/hle.h"
+#include "core/hle/result.h"
namespace HLE {
#define PARAM(n) Core::g_app_core->GetReg(n)
+/// An invalid result code that is meant to be overwritten when a thread resumes from waiting
+static const ResultCode RESULT_INVALID(0xDEADC0DE);
+
/**
* HLE a function return from the current ARM11 userland process
* @param res Result to return
@@ -57,8 +61,11 @@ template<ResultCode func(s32*, u32*, s32, bool, s64)> void Wrap() {
s32 param_1 = 0;
s32 retval = func(&param_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2),
(PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0))).raw;
- Core::g_app_core->SetReg(1, (u32)param_1);
- FuncReturn(retval);
+
+ if (retval != RESULT_INVALID.raw) {
+ Core::g_app_core->SetReg(1, (u32)param_1);
+ FuncReturn(retval);
+ }
}
template<ResultCode func(u32, u32, u32, u32, s64)> void Wrap() {
@@ -73,7 +80,11 @@ template<ResultCode func(u32*)> void Wrap(){
}
template<ResultCode func(u32, s64)> void Wrap() {
- FuncReturn(func(PARAM(0), (((s64)PARAM(3) << 32) | PARAM(2))).raw);
+ s32 retval = func(PARAM(0), (((s64)PARAM(3) << 32) | PARAM(2))).raw;
+
+ if (retval != RESULT_INVALID.raw) {
+ FuncReturn(retval);
+ }
}
template<ResultCode func(void*, void*, u32)> void Wrap(){
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp
index e45deb1c..f338f326 100644
--- a/src/core/hle/kernel/event.cpp
+++ b/src/core/hle/kernel/event.cpp
@@ -41,10 +41,7 @@ void Event::Acquire() {
void Event::Signal() {
signaled = true;
-
WakeupAllWaitingThreads();
-
- HLE::Reschedule(__func__);
}
void Event::Clear() {
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 726e4d2f..20e11da1 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -32,27 +32,13 @@ void WaitObject::RemoveWaitingThread(Thread* thread) {
waiting_threads.erase(itr);
}
-SharedPtr<Thread> WaitObject::WakeupNextThread() {
- if (waiting_threads.empty())
- return nullptr;
-
- auto next_thread = std::move(waiting_threads.front());
- waiting_threads.erase(waiting_threads.begin());
-
- next_thread->ReleaseWaitObject(this);
-
- return next_thread;
-}
-
void WaitObject::WakeupAllWaitingThreads() {
- auto waiting_threads_copy = waiting_threads;
+ for (auto thread : waiting_threads)
+ thread->ResumeFromWait();
- // We use a copy because ReleaseWaitObject will remove the thread from this object's
- // waiting_threads list
- for (auto thread : waiting_threads_copy)
- thread->ReleaseWaitObject(this);
+ waiting_threads.clear();
- ASSERT_MSG(waiting_threads.empty(), "failed to awaken all waiting threads!");
+ HLE::Reschedule(__func__);
}
HandleTable::HandleTable() {
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index a5a0f480..64595f75 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -140,12 +140,6 @@ public:
*/
void RemoveWaitingThread(Thread* thread);
- /**
- * Wake up the next thread waiting on this object
- * @return Pointer to the thread that was resumed, nullptr if no threads are waiting
- */
- SharedPtr<Thread> WakeupNextThread();
-
/// Wake up all threads waiting on this object
void WakeupAllWaitingThreads();
diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp
index 6aa73df8..edb97d32 100644
--- a/src/core/hle/kernel/mutex.cpp
+++ b/src/core/hle/kernel/mutex.cpp
@@ -23,12 +23,7 @@ static void ResumeWaitingThread(Mutex* mutex) {
// Reset mutex lock thread handle, nothing is waiting
mutex->lock_count = 0;
mutex->holding_thread = nullptr;
-
- // Find the next waiting thread for the mutex...
- auto next_thread = mutex->WakeupNextThread();
- if (next_thread != nullptr) {
- mutex->Acquire(next_thread);
- }
+ mutex->WakeupAllWaitingThreads();
}
void ReleaseThreadMutexes(Thread* thread) {
@@ -94,8 +89,6 @@ void Mutex::Release() {
ResumeWaitingThread(this);
}
}
-
- HLE::Reschedule(__func__);
}
} // namespace
diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h
index 201ec0db..1b8249c7 100644
--- a/src/core/hle/kernel/resource_limit.h
+++ b/src/core/hle/kernel/resource_limit.h
@@ -81,13 +81,13 @@ public:
s32 max_timers = 0;
s32 max_shared_mems = 0;
s32 max_address_arbiters = 0;
-
+
/// Max CPU time that the processes in this category can utilize
s32 max_cpu_time = 0;
- // TODO(Subv): Increment these in their respective Kernel::T::Create functions, keeping in mind that
- // APPLICATION resource limits should not be affected by the objects created by service modules.
- // Currently we have no way of distinguishing if a Create was called by the running application,
+ // TODO(Subv): Increment these in their respective Kernel::T::Create functions, keeping in mind that
+ // APPLICATION resource limits should not be affected by the objects created by service modules.
+ // Currently we have no way of distinguishing if a Create was called by the running application,
// or by a service module. Approach this once we have separated the service modules into their own processes
/// Current memory that the processes in this category are using
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp
index dbb4c9b7..4b359ed0 100644
--- a/src/core/hle/kernel/semaphore.cpp
+++ b/src/core/hle/kernel/semaphore.cpp
@@ -42,19 +42,13 @@ void Semaphore::Acquire() {
ResultVal<s32> Semaphore::Release(s32 release_count) {
if (max_count - available_count < release_count)
- return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel,
+ return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel,
ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
s32 previous_count = available_count;
available_count += release_count;
- // Notify some of the threads that the semaphore has been released
- // stop once the semaphore is full again or there are no more waiting threads
- while (!ShouldWait() && WakeupNextThread() != nullptr) {
- Acquire();
- }
-
- HLE::Reschedule(__func__);
+ WakeupAllWaitingThreads();
return MakeResult<s32>(previous_count);
}
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 690d33b5..4729a7fe 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -13,6 +13,7 @@
#include "common/thread_queue_list.h"
#include "core/arm/arm_interface.h"
+#include "core/arm/skyeye_common/armdefs.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/hle.h"
@@ -100,7 +101,7 @@ void Thread::Stop() {
}
status = THREADSTATUS_DEAD;
-
+
WakeupAllWaitingThreads();
// Clean up any dangling references in objects that this thread was waiting for
@@ -169,7 +170,7 @@ static void PriorityBoostStarvedThreads() {
}
}
-/**
+/**
* Switches the CPU's active thread context to that of the specified thread
* @param new_thread The thread to switch to
*/
@@ -193,8 +194,22 @@ static void SwitchContext(Thread* new_thread) {
if (new_thread) {
DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY, "Thread must be ready to become running.");
+ // Cancel any outstanding wakeup events for this thread
+ CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->callback_handle);
+
current_thread = new_thread;
+ // If the thread was waited by a svcWaitSynch call, step back PC by one instruction to rerun
+ // the SVC when the thread wakes up. This is necessary to ensure that the thread can acquire
+ // the requested wait object(s) before continuing.
+ if (new_thread->waitsynch_waited) {
+ // CPSR flag indicates CPU mode
+ bool thumb_mode = (new_thread->context.cpsr & TBIT) != 0;
+
+ // SVC instruction is 2 bytes for THUMB, 4 bytes for ARM
+ new_thread->context.pc -= thumb_mode ? 2 : 4;
+ }
+
ready_queue.remove(new_thread->current_priority, new_thread);
new_thread->status = THREADSTATUS_RUNNING;
@@ -243,6 +258,7 @@ void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wa
thread->wait_set_output = wait_set_output;
thread->wait_all = wait_all;
thread->wait_objects = std::move(wait_objects);
+ thread->waitsynch_waited = true;
thread->status = THREADSTATUS_WAIT_SYNCH;
}
@@ -268,6 +284,8 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
return;
}
+ thread->waitsynch_waited = false;
+
if (thread->status == THREADSTATUS_WAIT_SYNCH) {
thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS,
ErrorSummary::StatusChanged, ErrorLevel::Info));
@@ -288,63 +306,20 @@ void Thread::WakeAfterDelay(s64 nanoseconds) {
CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, callback_handle);
}
-void Thread::ReleaseWaitObject(WaitObject* wait_object) {
- if (status != THREADSTATUS_WAIT_SYNCH || wait_objects.empty()) {
- LOG_CRITICAL(Kernel, "thread is not waiting on any objects!");
- return;
- }
-
- // Remove this thread from the waiting object's thread list
- wait_object->RemoveWaitingThread(this);
-
- unsigned index = 0;
- bool wait_all_failed = false; // Will be set to true if any object is unavailable
-
- // Iterate through all waiting objects to check availability...
- for (auto itr = wait_objects.begin(); itr != wait_objects.end(); ++itr) {
- if ((*itr)->ShouldWait())
- wait_all_failed = true;
-
- // The output should be the last index of wait_object
- if (*itr == wait_object)
- index = itr - wait_objects.begin();
- }
-
- // If we are waiting on all objects...
- if (wait_all) {
- // Resume the thread only if all are available...
- if (!wait_all_failed) {
- SetWaitSynchronizationResult(RESULT_SUCCESS);
- SetWaitSynchronizationOutput(-1);
-
- ResumeFromWait();
- }
- } else {
- // Otherwise, resume
- SetWaitSynchronizationResult(RESULT_SUCCESS);
-
- if (wait_set_output)
- SetWaitSynchronizationOutput(index);
-
- ResumeFromWait();
- }
-}
-
void Thread::ResumeFromWait() {
- // Cancel any outstanding wakeup events for this thread
- CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle);
-
switch (status) {
case THREADSTATUS_WAIT_SYNCH:
- // Remove this thread from all other WaitObjects
- for (auto wait_object : wait_objects)
- wait_object->RemoveWaitingThread(this);
- break;
case THREADSTATUS_WAIT_ARB:
case THREADSTATUS_WAIT_SLEEP:
break;
- case THREADSTATUS_RUNNING:
+
case THREADSTATUS_READY:
+ // If the thread is waiting on multiple wait objects, it might be awoken more than once
+ // before actually resuming. We can ignore subsequent wakeups if the thread status has
+ // already been set to THREADSTATUS_READY.
+ return;
+
+ case THREADSTATUS_RUNNING:
DEBUG_ASSERT_MSG(false, "Thread with object id %u has already resumed.", GetObjectId());
return;
case THREADSTATUS_DEAD:
@@ -353,7 +328,7 @@ void Thread::ResumeFromWait() {
GetObjectId());
return;
}
-
+
ready_queue.push_back(current_priority, this);
status = THREADSTATUS_READY;
}
@@ -415,6 +390,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
thread->callback_handle = wakeup_callback_handle_table.Create(thread).MoveFrom();
thread->owner_process = g_current_process;
thread->tls_index = -1;
+ thread->waitsynch_waited = false;
// Find the next available TLS index, and mark it as used
auto& used_tls_slots = Kernel::g_current_process->used_tls_slots;
@@ -504,7 +480,7 @@ void Reschedule() {
} else if (next) {
LOG_TRACE(Kernel, "context switch idle -> %u", next->GetObjectId());
}
-
+
SwitchContext(next);
}
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 38992817..b8160bb2 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -94,12 +94,6 @@ public:
* @return The thread's ID
*/
u32 GetThreadId() const { return thread_id; }
-
- /**
- * Release an acquired wait object
- * @param wait_object WaitObject to release
- */
- void ReleaseWaitObject(WaitObject* wait_object);
/**
* Resumes a thread from waiting
@@ -152,6 +146,8 @@ public:
s32 tls_index; ///< Index of the Thread Local Storage of the thread
+ bool waitsynch_waited; ///< Set to true if the last svcWaitSynch call caused the thread to wait
+
/// Mutexes currently held by this thread, which will be released when it exits.
boost::container::flat_set<SharedPtr<Mutex>> held_mutexes;
@@ -163,12 +159,12 @@ public:
std::string name;
+ /// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
+ Handle callback_handle;
+
private:
Thread();
~Thread() override;
-
- /// Handle used as userdata to reference this object when inserting into the CoreTiming queue.
- Handle callback_handle;
};
/**
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp
index 25d066bf..8aa4110a 100644
--- a/src/core/hle/kernel/timer.cpp
+++ b/src/core/hle/kernel/timer.cpp
@@ -88,7 +88,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) {
if (timer->interval_delay != 0) {
// Reschedule the timer with the interval delay
u64 interval_microseconds = timer->interval_delay / 1000;
- CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late,
+ CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late,
timer_callback_event_type, timer_handle);
}
}
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
new file mode 100644
index 00000000..b2dd2154
--- /dev/null
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -0,0 +1,245 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/assert.h"
+
+#include "core/hle/kernel/vm_manager.h"
+#include "core/memory_setup.h"
+
+namespace Kernel {
+
+bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const {
+ ASSERT(base + size == next.base);
+ if (permissions != next.permissions ||
+ meminfo_state != next.meminfo_state ||
+ type != next.type) {
+ return false;
+ }
+ if (type == VMAType::AllocatedMemoryBlock &&
+ (backing_block != next.backing_block || offset + size != next.offset)) {
+ return false;
+ }
+ if (type == VMAType::BackingMemory && backing_memory + size != next.backing_memory) {
+ return false;
+ }
+ if (type == VMAType::MMIO && paddr + size != next.paddr) {
+ return false;
+ }
+ return true;
+}
+
+VMManager::VMManager() {
+ Reset();
+}
+
+void VMManager::Reset() {
+ vma_map.clear();
+
+ // Initialize the map with a single free region covering the entire managed space.
+ VirtualMemoryArea initial_vma;
+ initial_vma.size = MAX_ADDRESS;
+ vma_map.emplace(initial_vma.base, initial_vma);
+
+ UpdatePageTableForVMA(initial_vma);
+}
+
+VMManager::VMAHandle VMManager::FindVMA(VAddr target) const {
+ return std::prev(vma_map.upper_bound(target));
+}
+
+ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target,
+ std::shared_ptr<std::vector<u8>> block, u32 offset, u32 size, MemoryState state) {
+ ASSERT(block != nullptr);
+ ASSERT(offset + size <= block->size());
+
+ // This is the appropriately sized VMA that will turn into our allocation.
+ CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size));
+ VirtualMemoryArea& final_vma = vma_handle->second;
+ ASSERT(final_vma.size == size);
+
+ final_vma.type = VMAType::AllocatedMemoryBlock;
+ final_vma.permissions = VMAPermission::ReadWrite;
+ final_vma.meminfo_state = state;
+ final_vma.backing_block = block;
+ final_vma.offset = offset;
+ UpdatePageTableForVMA(final_vma);
+
+ return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
+}
+
+ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8 * memory, u32 size, MemoryState state) {
+ ASSERT(memory != nullptr);
+
+ // This is the appropriately sized VMA that will turn into our allocation.
+ CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size));
+ VirtualMemoryArea& final_vma = vma_handle->second;
+ ASSERT(final_vma.size == size);
+
+ final_vma.type = VMAType::BackingMemory;
+ final_vma.permissions = VMAPermission::ReadWrite;
+ final_vma.meminfo_state = state;
+ final_vma.backing_memory = memory;
+ UpdatePageTableForVMA(final_vma);
+
+ return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
+}
+
+ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state) {
+ // This is the appropriately sized VMA that will turn into our allocation.
+ CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size));
+ VirtualMemoryArea& final_vma = vma_handle->second;
+ ASSERT(final_vma.size == size);
+
+ final_vma.type = VMAType::MMIO;
+ final_vma.permissions = VMAPermission::ReadWrite;
+ final_vma.meminfo_state = state;
+ final_vma.paddr = paddr;
+ UpdatePageTableForVMA(final_vma);
+
+ return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
+}
+
+void VMManager::Unmap(VMAHandle vma_handle) {
+ VMAIter iter = StripIterConstness(vma_handle);
+
+ VirtualMemoryArea& vma = iter->second;
+ vma.type = VMAType::Free;
+ vma.permissions = VMAPermission::None;
+ vma.meminfo_state = MemoryState::Free;
+
+ vma.backing_block = nullptr;
+ vma.offset = 0;
+ vma.backing_memory = nullptr;
+ vma.paddr = 0;
+
+ UpdatePageTableForVMA(vma);
+
+ MergeAdjacent(iter);
+}
+
+void VMManager::Reprotect(VMAHandle vma_handle, VMAPermission new_perms) {
+ VMAIter iter = StripIterConstness(vma_handle);
+
+ VirtualMemoryArea& vma = iter->second;
+ vma.permissions = new_perms;
+ UpdatePageTableForVMA(vma);
+
+ MergeAdjacent(iter);
+}
+
+VMManager::VMAIter VMManager::StripIterConstness(const VMAHandle & iter) {
+ // This uses a neat C++ trick to convert a const_iterator to a regular iterator, given
+ // non-const access to its container.
+ return vma_map.erase(iter, iter); // Erases an empty range of elements
+}
+
+ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u32 size) {
+ ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: %8X", size);
+ ASSERT_MSG((base & Memory::PAGE_MASK) == 0, "non-page aligned base: %08X", base);
+
+ VMAIter vma_handle = StripIterConstness(FindVMA(base));
+ if (vma_handle == vma_map.end()) {
+ // Target address is outside the range managed by the kernel
+ return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS,
+ ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E01BF5
+ }
+
+ VirtualMemoryArea& vma = vma_handle->second;
+ if (vma.type != VMAType::Free) {
+ // Region is already allocated
+ return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS,
+ ErrorSummary::InvalidState, ErrorLevel::Usage); // 0xE0A01BF5
+ }
+
+ u32 start_in_vma = base - vma.base;
+ u32 end_in_vma = start_in_vma + size;
+
+ if (end_in_vma > vma.size) {
+ // Requested allocation doesn't fit inside VMA
+ return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS,
+ ErrorSummary::InvalidState, ErrorLevel::Usage); // 0xE0A01BF5
+ }
+
+ if (end_in_vma != vma.size) {
+ // Split VMA at the end of the allocated region
+ SplitVMA(vma_handle, end_in_vma);
+ }
+ if (start_in_vma != 0) {
+ // Split VMA at the start of the allocated region
+ vma_handle = SplitVMA(vma_handle, start_in_vma);
+ }
+
+ return MakeResult<VMAIter>(vma_handle);
+}
+
+VMManager::VMAIter VMManager::SplitVMA(VMAIter vma_handle, u32 offset_in_vma) {
+ VirtualMemoryArea& old_vma = vma_handle->second;
+ VirtualMemoryArea new_vma = old_vma; // Make a copy of the VMA
+
+ // For now, don't allow no-op VMA splits (trying to split at a boundary) because it's probably
+ // a bug. This restriction might be removed later.
+ ASSERT(offset_in_vma < old_vma.size);
+ ASSERT(offset_in_vma > 0);
+
+ old_vma.size = offset_in_vma;
+ new_vma.base += offset_in_vma;
+ new_vma.size -= offset_in_vma;
+
+ switch (new_vma.type) {
+ case VMAType::Free:
+ break;
+ case VMAType::AllocatedMemoryBlock:
+ new_vma.offset += offset_in_vma;
+ break;
+ case VMAType::BackingMemory:
+ new_vma.backing_memory += offset_in_vma;
+ break;
+ case VMAType::MMIO:
+ new_vma.paddr += offset_in_vma;
+ break;
+ }
+
+ ASSERT(old_vma.CanBeMergedWith(new_vma));
+
+ return vma_map.emplace_hint(std::next(vma_handle), new_vma.base, new_vma);
+}
+
+VMManager::VMAIter VMManager::MergeAdjacent(VMAIter iter) {
+ VMAIter next_vma = std::next(iter);
+ if (next_vma != vma_map.end() && iter->second.CanBeMergedWith(next_vma->second)) {
+ iter->second.size += next_vma->second.size;
+ vma_map.erase(next_vma);
+ }
+
+ if (iter != vma_map.begin()) {
+ VMAIter prev_vma = std::prev(iter);
+ if (prev_vma->second.CanBeMergedWith(iter->second)) {
+ prev_vma->second.size += iter->second.size;
+ vma_map.erase(iter);
+ iter = prev_vma;
+ }
+ }
+
+ return iter;
+}
+
+void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
+ switch (vma.type) {
+ case VMAType::Free:
+ Memory::UnmapRegion(vma.base, vma.size);
+ break;
+ case VMAType::AllocatedMemoryBlock:
+ Memory::MapMemoryRegion(vma.base, vma.size, vma.backing_block->data() + vma.offset);
+ break;
+ case VMAType::BackingMemory:
+ Memory::MapMemoryRegion(vma.base, vma.size, vma.backing_memory);
+ break;
+ case VMAType::MMIO:
+ // TODO(yuriks): Add support for MMIO handlers.
+ Memory::MapIoRegion(vma.base, vma.size);
+ break;
+ }
+}
+
+}
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
new file mode 100644
index 00000000..22b72460
--- /dev/null
+++ b/src/core/hle/kernel/vm_manager.h
@@ -0,0 +1,200 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "common/common_types.h"
+
+#include "core/hle/result.h"
+
+namespace Kernel {
+
+enum class VMAType : u8 {
+ /// VMA represents an unmapped region of the address space.
+ Free,
+ /// VMA is backed by a ref-counted allocate memory block.
+ AllocatedMemoryBlock,
+ /// VMA is backed by a raw, unmanaged pointer.
+ BackingMemory,
+ /// VMA is mapped to MMIO registers at a fixed PAddr.
+ MMIO,
+ // TODO(yuriks): Implement MemoryAlias to support MAP/UNMAP
+};
+
+/// Permissions for mapped memory blocks
+enum class VMAPermission : u8 {
+ None = 0,
+ Read = 1,
+ Write = 2,
+ Execute = 4,
+
+ ReadWrite = Read | Write,
+ ReadExecute = Read | Execute,
+ WriteExecute = Write | Execute,
+ ReadWriteExecute = Read | Write | Execute,
+};
+
+/// Set of values returned in MemoryInfo.state by svcQueryMemory.
+enum class MemoryState : u8 {
+ Free = 0,
+ Reserved = 1,
+ IO = 2,
+ Static = 3,
+ Code = 4,
+ Private = 5,
+ Shared = 6,
+ Continuous = 7,
+ Aliased = 8,
+ Alias = 9,
+ AliasCode = 10,
+ Locked = 11,
+};
+
+/**
+ * Represents a VMA in an address space. A VMA is a contiguous region of virtual addressing space
+ * with homogeneous attributes across its extents. In this particular implementation each VMA is
+ * also backed by a single host memory allocation.
+ */
+struct VirtualMemoryArea {
+ /// Virtual base address of the region.
+ VAddr base = 0;
+ /// Size of the region.
+ u32 size = 0;
+
+ VMAType type = VMAType::Free;
+ VMAPermission permissions = VMAPermission::None;
+ /// Tag returned by svcQueryMemory. Not otherwise used.
+ MemoryState meminfo_state = MemoryState::Free;
+
+ // Settings for type = AllocatedMemoryBlock
+ /// Memory block backing this VMA.
+ std::shared_ptr<std::vector<u8>> backing_block = nullptr;
+ /// Offset into the backing_memory the mapping starts from.
+ u32 offset = 0;
+
+ // Settings for type = BackingMemory
+ /// Pointer backing this VMA. It will not be destroyed or freed when the VMA is removed.
+ u8* backing_memory = nullptr;
+
+ // Settings for type = MMIO
+ /// Physical address of the register area this VMA maps to.
+ PAddr paddr = 0;
+
+ /// Tests if this area can be merged to the right with `next`.
+ bool CanBeMergedWith(const VirtualMemoryArea& next) const;
+};
+
+/**
+ * Manages a process' virtual addressing space. This class maintains a list of allocated and free
+ * regions in the address space, along with their attributes, and allows kernel clients to
+ * manipulate it, adjusting the page table to match.
+ *
+ * This is similar in idea and purpose to the VM manager present in operating system kernels, with
+ * the main difference being that it doesn't have to support swapping or memory mapping of files.
+ * The implementation is also simplified by not having to allocate page frames. See these articles
+ * about the Linux kernel for an explantion of the concept and implementation:
+ * - http://duartes.org/gustavo/blog/post/how-the-kernel-manages-your-memory/
+ * - http://duartes.org/gustavo/blog/post/page-cache-the-affair-between-memory-and-files/
+ */
+class VMManager {
+ // TODO(yuriks): Make page tables switchable to support multiple VMManagers
+public:
+ /**
+ * The maximum amount of address space managed by the kernel. Addresses above this are never used.
+ * @note This is the limit used by the New 3DS kernel. Old 3DS used 0x20000000.
+ */
+ static const u32 MAX_ADDRESS = 0x40000000;
+
+ /**
+ * A map covering the entirety of the managed address space, keyed by the `base` field of each
+ * VMA. It must always be modified by splitting or merging VMAs, so that the invariant
+ * `elem.base + elem.size == next.base` is preserved, and mergeable regions must always be
+ * merged when possible so that no two similar and adjacent regions exist that have not been
+ * merged.
+ */
+ std::map<VAddr, VirtualMemoryArea> vma_map;
+ using VMAHandle = decltype(vma_map)::const_iterator;
+
+ VMManager();
+
+ /// Clears the address space map, re-initializing with a single free area.
+ void Reset();
+
+ /// Finds the VMA in which the given address is included in, or `vma_map.end()`.
+ VMAHandle FindVMA(VAddr target) const;
+
+ // TODO(yuriks): Should these functions actually return the handle?
+
+ /**
+ * Maps part of a ref-counted block of memory at a given address.
+ *
+ * @param target The guest address to start the mapping at.
+ * @param block The block to be mapped.
+ * @param offset Offset into `block` to map from.
+ * @param size Size of the mapping.
+ * @param state MemoryState tag to attach to the VMA.
+ */
+ ResultVal<VMAHandle> MapMemoryBlock(VAddr target, std::shared_ptr<std::vector<u8>> block,
+ u32 offset, u32 size, MemoryState state);
+
+ /**
+ * Maps an unmanaged host memory pointer at a given address.
+ *
+ * @param target The guest address to start the mapping at.
+ * @param memory The memory to be mapped.
+ * @param size Size of the mapping.
+ * @param state MemoryState tag to attach to the VMA.
+ */
+ ResultVal<VMAHandle> MapBackingMemory(VAddr target, u8* memory, u32 size, MemoryState state);
+
+ /**
+ * Maps a memory-mapped IO region at a given address.
+ *
+ * @param target The guest address to start the mapping at.
+ * @param paddr The physical address where the registers are present.
+ * @param size Size of the mapping.
+ * @param state MemoryState tag to attach to the VMA.
+ */
+ ResultVal<VMAHandle> MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state);
+
+ /// Unmaps the given VMA.
+ void Unmap(VMAHandle vma);
+
+ /// Changes the permissions of the given VMA.
+ void Reprotect(VMAHandle vma, VMAPermission new_perms);
+
+private:
+ using VMAIter = decltype(vma_map)::iterator;
+
+ /// Converts a VMAHandle to a mutable VMAIter.
+ VMAIter StripIterConstness(const VMAHandle& iter);
+
+ /**
+ * Carves a VMA of a specific size at the specified address by splitting Free VMAs while doing
+ * the appropriate error checking.
+ */
+ ResultVal<VMAIter> CarveVMA(VAddr base, u32 size);
+
+ /**
+ * Splits a VMA in two, at the specified offset.
+ * @returns the right side of the split, with the original iterator becoming the left side.
+ */
+ VMAIter SplitVMA(VMAIter vma, u32 offset_in_vma);
+
+ /**
+ * Checks for and merges the specified VMA with adjacent ones if possible.
+ * @returns the merged VMA or the original if no merging was possible.
+ */
+ VMAIter MergeAdjacent(VMAIter vma);
+
+ /// Updates the pages corresponding to this VMA so they match the VMA's attributes.
+ void UpdatePageTableForVMA(const VirtualMemoryArea& vma);
+};
+
+}
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
new file mode 100644
index 00000000..57dc1ece
--- /dev/null
+++ b/src/core/hle/service/am/am.cpp
@@ -0,0 +1,55 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/logging/log.h"
+
+#include "core/hle/service/service.h"
+#include "core/hle/service/am/am_app.h"
+#include "core/hle/service/am/am_net.h"
+#include "core/hle/service/am/am_sys.h"
+
+#include "core/hle/hle.h"
+#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/shared_memory.h"
+
+namespace Service {
+namespace AM {
+
+void TitleIDListGetTotal(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 media_type = cmd_buff[1] & 0xFF;
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = 0;
+
+ LOG_WARNING(Service_AM, "(STUBBED) media_type %u", media_type);
+}
+
+void GetTitleIDList(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+ u32 num_titles = cmd_buff[1];
+ u32 media_type = cmd_buff[2] & 0xFF;
+ u32 addr = cmd_buff[4];
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = 0;
+
+ LOG_WARNING(Service_AM, "(STUBBED) Requested %u titles from media type %u", num_titles, media_type);
+}
+
+void Init() {
+ using namespace Kernel;
+
+ AddService(new AM_APP_Interface);
+ AddService(new AM_NET_Interface);
+ AddService(new AM_SYS_Interface);
+}
+
+void Shutdown() {
+
+}
+
+} // namespace AM
+
+} // namespace Service
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
new file mode 100644
index 00000000..063b8bd0
--- /dev/null
+++ b/src/core/hle/service/am/am.h
@@ -0,0 +1,47 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace AM {
+
+/**
+ * AM::TitleIDListGetTotal service function
+ * Gets the number of installed titles in the requested media type
+ * Inputs:
+ * 0 : Command header (0x00010040)
+ * 1 : Media type to load the titles from
+ * Outputs:
+ * 1 : Result, 0 on success, otherwise error code
+ * 2 : The number of titles in the requested media type
+ */
+void TitleIDListGetTotal(Service::Interface* self);
+
+/**
+ * AM::GetTitleIDList service function
+ * Loads information about the desired number of titles from the desired media type into an array
+ * Inputs:
+ * 0 : Command header (0x00020082)
+ * 1 : The maximum number of titles to load
+ * 2 : Media type to load the titles from
+ * 3 : Descriptor of the output buffer pointer
+ * 4 : Address of the output buffer
+ * Outputs:
+ * 1 : Result, 0 on success, otherwise error code
+ * 2 : The number of titles loaded from the requested media type
+ */
+void GetTitleIDList(Service::Interface* self);
+
+/// Initialize AM service
+void Init();
+
+/// Shutdown AM service
+void Shutdown();
+
+} // namespace AM
+} // namespace Service
diff --git a/src/core/hle/service/am/am_app.cpp b/src/core/hle/service/am/am_app.cpp
new file mode 100644
index 00000000..c6fc81bc
--- /dev/null
+++ b/src/core/hle/service/am/am_app.cpp
@@ -0,0 +1,20 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/hle.h"
+#include "core/hle/service/am/am.h"
+#include "core/hle/service/am/am_app.h"
+
+namespace Service {
+namespace AM {
+
+// Empty arrays are illegal -- commented out until an entry is added.
+//const Interface::FunctionInfo FunctionTable[] = { };
+
+AM_APP_Interface::AM_APP_Interface() {
+ //Register(FunctionTable);
+}
+
+} // namespace AM
+} // namespace Service
diff --git a/src/core/hle/service/am/am_app.h b/src/core/hle/service/am/am_app.h
new file mode 100644
index 00000000..fd6017d1
--- /dev/null
+++ b/src/core/hle/service/am/am_app.h
@@ -0,0 +1,22 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included..
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace AM {
+
+class AM_APP_Interface : public Service::Interface {
+public:
+ AM_APP_Interface();
+
+ std::string GetPortName() const override {
+ return "am:app";
+ }
+};
+
+} // namespace AM
+} // namespace Service
diff --git a/src/core/hle/service/am_net.cpp b/src/core/hle/service/am/am_net.cpp
index ba2a499f..b1af0e9d 100644
--- a/src/core/hle/service/am_net.cpp
+++ b/src/core/hle/service/am/am_net.cpp
@@ -3,12 +3,11 @@
// Refer to the license.txt file included.
#include "core/hle/hle.h"
-#include "core/hle/service/am_net.h"
+#include "core/hle/service/am/am.h"
+#include "core/hle/service/am/am_net.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace AM_NET
-
-namespace AM_NET {
+namespace Service {
+namespace AM {
const Interface::FunctionInfo FunctionTable[] = {
{0x08010000, nullptr, "OpenTicket"},
@@ -33,11 +32,9 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x081B00C2, nullptr, "InstallTitlesFinish"},
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+AM_NET_Interface::AM_NET_Interface() {
Register(FunctionTable);
}
-} // namespace
+} // namespace AM
+} // namespace Service
diff --git a/src/core/hle/service/am/am_net.h b/src/core/hle/service/am/am_net.h
new file mode 100644
index 00000000..25d2c3f2
--- /dev/null
+++ b/src/core/hle/service/am/am_net.h
@@ -0,0 +1,22 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included..
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace AM {
+
+class AM_NET_Interface : public Service::Interface {
+public:
+ AM_NET_Interface();
+
+ std::string GetPortName() const override {
+ return "am:net";
+ }
+};
+
+} // namespace AM
+} // namespace Service
diff --git a/src/core/hle/service/am/am_sys.cpp b/src/core/hle/service/am/am_sys.cpp
new file mode 100644
index 00000000..864fc14d
--- /dev/null
+++ b/src/core/hle/service/am/am_sys.cpp
@@ -0,0 +1,22 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/hle.h"
+#include "core/hle/service/am/am.h"
+#include "core/hle/service/am/am_sys.h"
+
+namespace Service {
+namespace AM {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010040, TitleIDListGetTotal, "TitleIDListGetTotal"},
+ {0x00020082, GetTitleIDList, "GetTitleIDList"},
+};
+
+AM_SYS_Interface::AM_SYS_Interface() {
+ Register(FunctionTable);
+}
+
+} // namespace AM
+} // namespace Service
diff --git a/src/core/hle/service/am/am_sys.h b/src/core/hle/service/am/am_sys.h
new file mode 100644
index 00000000..b114f1d3
--- /dev/null
+++ b/src/core/hle/service/am/am_sys.h
@@ -0,0 +1,22 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included..
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace AM {
+
+class AM_SYS_Interface : public Service::Interface {
+public:
+ AM_SYS_Interface();
+
+ std::string GetPortName() const override {
+ return "am:sys";
+ }
+};
+
+} // namespace AM
+} // namespace Service
diff --git a/src/core/hle/service/am/am_u.cpp b/src/core/hle/service/am/am_u.cpp
new file mode 100644
index 00000000..6bf84b36
--- /dev/null
+++ b/src/core/hle/service/am/am_u.cpp
@@ -0,0 +1,22 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/hle.h"
+#include "core/hle/service/am/am.h"
+#include "core/hle/service/am/am_u.h"
+
+namespace Service {
+namespace AM {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010040, TitleIDListGetTotal, "TitleIDListGetTotal"},
+ {0x00020082, GetTitleIDList, "GetTitleIDList"},
+};
+
+AM_U_Interface::AM_U_Interface() {
+ Register(FunctionTable);
+}
+
+} // namespace AM
+} // namespace Service
diff --git a/src/core/hle/service/am/am_u.h b/src/core/hle/service/am/am_u.h
new file mode 100644
index 00000000..3b2454b6
--- /dev/null
+++ b/src/core/hle/service/am/am_u.h
@@ -0,0 +1,22 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included..
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace AM {
+
+class AM_U_Interface : public Service::Interface {
+public:
+ AM_U_Interface();
+
+ std::string GetPortName() const override {
+ return "am:u";
+ }
+};
+
+} // namespace AM
+} // namespace Service
diff --git a/src/core/hle/service/am_app.cpp b/src/core/hle/service/am_app.cpp
deleted file mode 100644
index 684b753f..00000000
--- a/src/core/hle/service/am_app.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "core/hle/hle.h"
-#include "core/hle/service/am_app.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace AM_APP
-
-namespace AM_APP {
-
-// Empty arrays are illegal -- commented out until an entry is added.
-//const Interface::FunctionInfo FunctionTable[] = { };
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
- //Register(FunctionTable);
-}
-
-} // namespace
diff --git a/src/core/hle/service/am_app.h b/src/core/hle/service/am_app.h
deleted file mode 100644
index 50dc2f5a..00000000
--- a/src/core/hle/service/am_app.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include "core/hle/service/service.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace AM_APP
-
-namespace AM_APP {
-
-class Interface : public Service::Interface {
-public:
- Interface();
-
- std::string GetPortName() const override {
- return "am:app";
- }
-};
-
-} // namespace
diff --git a/src/core/hle/service/am_net.h b/src/core/hle/service/am_net.h
deleted file mode 100644
index 616c33ee..00000000
--- a/src/core/hle/service/am_net.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include "core/hle/service/service.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace AM_NET
-
-namespace AM_NET {
-
-class Interface : public Service::Interface {
-public:
- Interface();
-
- std::string GetPortName() const override {
- return "am:net";
- }
-};
-
-} // namespace
diff --git a/src/core/hle/service/am_sys.cpp b/src/core/hle/service/am_sys.cpp
deleted file mode 100644
index f9e3fe4b..00000000
--- a/src/core/hle/service/am_sys.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2015 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "common/logging/log.h"
-
-#include "core/hle/hle.h"
-#include "core/hle/service/am_sys.h"
-
-namespace AM_SYS {
-
-/**
- * Gets the number of installed titles in the requested media type
- * Inputs:
- * 0: Command header (0x00010040)
- * 1: Media type to load the titles from
- * Outputs:
- * 1: Result, 0 on success, otherwise error code
- * 2: The number of titles in the requested media type
- */
-static void TitleIDListGetTotal(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- u32 media_type = cmd_buff[1] & 0xFF;
-
- cmd_buff[1] = RESULT_SUCCESS.raw;
- cmd_buff[2] = 0;
- LOG_WARNING(Service_CFG, "(STUBBED) media_type %u", media_type);
-}
-
-/**
- * Loads information about the desired number of titles from the desired media type into an array
- * Inputs:
- * 0: Command header (0x00020082)
- * 1: The maximum number of titles to load
- * 2: Media type to load the titles from
- * 3: Descriptor of the output buffer pointer
- * 4: Address of the output buffer
- * Outputs:
- * 1: Result, 0 on success, otherwise error code
- * 2: The number of titles loaded from the requested media type
- */
-static void GetTitleIDList(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
- u32 num_titles = cmd_buff[1];
- u32 media_type = cmd_buff[2] & 0xFF;
- u32 addr = cmd_buff[4];
-
- cmd_buff[1] = RESULT_SUCCESS.raw;
- cmd_buff[2] = 0;
- LOG_WARNING(Service_CFG, "(STUBBED) Requested %u titles from media type %u", num_titles, media_type);
-}
-
-const Interface::FunctionInfo FunctionTable[] = {
- {0x00010040, TitleIDListGetTotal, "TitleIDListGetTotal"},
- {0x00020082, GetTitleIDList, "GetTitleIDList"},
-};
-
-Interface::Interface() {
- Register(FunctionTable);
-}
-
-} // namespace
diff --git a/src/core/hle/service/am_sys.h b/src/core/hle/service/am_sys.h
deleted file mode 100644
index bb6178a4..00000000
--- a/src/core/hle/service/am_sys.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2015 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include "core/hle/service/service.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace AM_SYS
-
-namespace AM_SYS {
-
-class Interface : public Service::Interface {
-public:
- Interface();
-
- std::string GetPortName() const override {
- return "am:sys";
- }
-};
-
-} // namespace
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index 3fd4cfb0..5d14f393 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -151,7 +151,7 @@ void SendParameter(Service::Interface* self) {
u32 handle = cmd_buff[6];
u32 size = cmd_buff[7];
u32 in_param_buffer_ptr = cmd_buff[8];
-
+
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
LOG_WARNING(Service_APT, "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X,"
@@ -283,7 +283,7 @@ void Init() {
AddService(new APT_A_Interface);
AddService(new APT_S_Interface);
AddService(new APT_U_Interface);
-
+
// Load the shared system font (if available).
// The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header
// generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h
index e7fa3932..a03e1712 100644
--- a/src/core/hle/service/apt/apt.h
+++ b/src/core/hle/service/apt/apt.h
@@ -63,7 +63,7 @@ void Initialize(Service::Interface* self);
* 4 : Handle to shared font memory
*/
void GetSharedFont(Service::Interface* self);
-
+
/**
* APT::NotifyToWait service function
* Inputs:
@@ -88,7 +88,7 @@ void Enable(Service::Interface* self);
* 4 : Home Menu AppId
* 5 : AppID of currently active app
*/
-void GetAppletManInfo(Service::Interface* self);
+void GetAppletManInfo(Service::Interface* self);
/**
* APT::IsRegistered service function. This returns whether the specified AppID is registered with NS yet.
@@ -100,14 +100,14 @@ void GetAppletManInfo(Service::Interface* self);
* Outputs:
* 0 : Return header
* 1 : Result of function, 0 on success, otherwise error code
- * 2 : Output, 0 = not registered, 1 = registered.
+ * 2 : Output, 0 = not registered, 1 = registered.
*/
void IsRegistered(Service::Interface* self);
void InquireNotification(Service::Interface* self);
/**
- * APT::SendParameter service function. This sets the parameter data state.
+ * APT::SendParameter service function. This sets the parameter data state.
* Inputs:
* 1 : Source AppID
* 2 : Destination AppID
diff --git a/src/core/hle/service/boss/boss.cpp b/src/core/hle/service/boss/boss.cpp
new file mode 100644
index 00000000..d38140f1
--- /dev/null
+++ b/src/core/hle/service/boss/boss.cpp
@@ -0,0 +1,29 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/service.h"
+#include "core/hle/service/boss/boss.h"
+#include "core/hle/service/boss/boss_p.h"
+#include "core/hle/service/boss/boss_u.h"
+
+#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/shared_memory.h"
+#include "core/hle/hle.h"
+
+namespace Service {
+namespace BOSS {
+
+void Init() {
+ using namespace Kernel;
+
+ AddService(new BOSS_P_Interface);
+ AddService(new BOSS_U_Interface);
+}
+
+void Shutdown() {
+}
+
+} // namespace BOSS
+
+} // namespace Service
diff --git a/src/core/hle/service/boss/boss.h b/src/core/hle/service/boss/boss.h
new file mode 100644
index 00000000..a6942ada
--- /dev/null
+++ b/src/core/hle/service/boss/boss.h
@@ -0,0 +1,20 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace BOSS {
+
+/// Initialize BOSS service(s)
+void Init();
+
+/// Shutdown BOSS service(s)
+void Shutdown();
+
+} // namespace BOSS
+} // namespace Service
diff --git a/src/core/hle/service/boss/boss_p.cpp b/src/core/hle/service/boss/boss_p.cpp
new file mode 100644
index 00000000..089f5f18
--- /dev/null
+++ b/src/core/hle/service/boss/boss_p.cpp
@@ -0,0 +1,20 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/hle.h"
+#include "core/hle/service/boss/boss.h"
+#include "core/hle/service/boss/boss_p.h"
+
+namespace Service {
+namespace BOSS {
+
+// Empty arrays are illegal -- commented out until an entry is added.
+// const Interface::FunctionInfo FunctionTable[] = { };
+
+BOSS_P_Interface::BOSS_P_Interface() {
+ //Register(FunctionTable);
+}
+
+} // namespace BOSS
+} // namespace Service
diff --git a/src/core/hle/service/boss/boss_p.h b/src/core/hle/service/boss/boss_p.h
new file mode 100644
index 00000000..32112c25
--- /dev/null
+++ b/src/core/hle/service/boss/boss_p.h
@@ -0,0 +1,22 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included..
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace BOSS {
+
+class BOSS_P_Interface : public Service::Interface {
+public:
+ BOSS_P_Interface();
+
+ std::string GetPortName() const override {
+ return "boss:P";
+ }
+};
+
+} // namespace BOSS
+} // namespace Service
diff --git a/src/core/hle/service/boss/boss_u.cpp b/src/core/hle/service/boss/boss_u.cpp
new file mode 100644
index 00000000..ed978b96
--- /dev/null
+++ b/src/core/hle/service/boss/boss_u.cpp
@@ -0,0 +1,21 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/hle.h"
+#include "core/hle/service/boss/boss.h"
+#include "core/hle/service/boss/boss_u.h"
+
+namespace Service {
+namespace BOSS {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00020100, nullptr, "GetStorageInfo"},
+};
+
+BOSS_U_Interface::BOSS_U_Interface() {
+ Register(FunctionTable);
+}
+
+} // namespace BOSS
+} // namespace Service
diff --git a/src/core/hle/service/boss/boss_u.h b/src/core/hle/service/boss/boss_u.h
new file mode 100644
index 00000000..d047d8cf
--- /dev/null
+++ b/src/core/hle/service/boss/boss_u.h
@@ -0,0 +1,22 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included..
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace BOSS {
+
+class BOSS_U_Interface : public Service::Interface {
+public:
+ BOSS_U_Interface();
+
+ std::string GetPortName() const override {
+ return "boss:U";
+ }
+};
+
+} // namespace BOSS
+} // namespace Service
diff --git a/src/core/hle/service/boss_p.cpp b/src/core/hle/service/boss_p.cpp
deleted file mode 100644
index 8280830e..00000000
--- a/src/core/hle/service/boss_p.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2015 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "core/hle/hle.h"
-#include "core/hle/service/boss_p.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace BOSS_P
-
-namespace BOSS_P {
-
-// Empty arrays are illegal -- commented out until an entry is added.
-// const Interface::FunctionInfo FunctionTable[] = { };
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
- //Register(FunctionTable);
-}
-
-} // namespace
diff --git a/src/core/hle/service/boss_p.h b/src/core/hle/service/boss_p.h
deleted file mode 100644
index 71f1e746..00000000
--- a/src/core/hle/service/boss_p.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2015 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include "core/hle/service/service.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace BOSS_P
-
-namespace BOSS_P {
-
-class Interface : public Service::Interface {
-public:
- Interface();
-
- std::string GetPortName() const override {
- return "boss:P";
- }
-};
-
-} // namespace
diff --git a/src/core/hle/service/boss_u.cpp b/src/core/hle/service/boss_u.cpp
deleted file mode 100644
index 2c322bdf..00000000
--- a/src/core/hle/service/boss_u.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "core/hle/hle.h"
-#include "core/hle/service/boss_u.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace BOSS_U
-
-namespace BOSS_U {
-
-const Interface::FunctionInfo FunctionTable[] = {
- {0x00020100, nullptr, "GetStorageInfo"},
-};
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
- Register(FunctionTable);
-}
-
-} // namespace
diff --git a/src/core/hle/service/boss_u.h b/src/core/hle/service/boss_u.h
deleted file mode 100644
index 2668f2df..00000000
--- a/src/core/hle/service/boss_u.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include "core/hle/service/service.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace BOSS_U
-
-namespace BOSS_U {
-
-class Interface : public Service::Interface {
-public:
- Interface();
-
- std::string GetPortName() const override {
- return "boss:U";
- }
-};
-
-} // namespace
diff --git a/src/core/hle/service/cam/cam.cpp b/src/core/hle/service/cam/cam.cpp
new file mode 100644
index 00000000..4f34b699
--- /dev/null
+++ b/src/core/hle/service/cam/cam.cpp
@@ -0,0 +1,35 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/logging/log.h"
+
+#include "core/hle/service/service.h"
+#include "core/hle/service/cam/cam.h"
+#include "core/hle/service/cam/cam_c.h"
+#include "core/hle/service/cam/cam_q.h"
+#include "core/hle/service/cam/cam_s.h"
+#include "core/hle/service/cam/cam_u.h"
+
+#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/shared_memory.h"
+#include "core/hle/hle.h"
+
+namespace Service {
+namespace CAM {
+
+void Init() {
+ using namespace Kernel;
+
+ AddService(new CAM_C_Interface);
+ AddService(new CAM_Q_Interface);
+ AddService(new CAM_S_Interface);
+ AddService(new CAM_U_Interface);
+}
+
+void Shutdown() {
+}
+
+} // namespace CAM
+
+} // namespace Service
diff --git a/src/core/hle/service/cam/cam.h b/src/core/hle/service/cam/cam.h
new file mode 100644
index 00000000..edd52484
--- /dev/null
+++ b/src/core/hle/service/cam/cam.h
@@ -0,0 +1,20 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace CAM {
+
+/// Initialize CAM service(s)
+void Init();
+
+/// Shutdown CAM service(s)
+void Shutdown();
+
+} // namespace CAM
+} // namespace Service
diff --git a/src/core/hle/service/cam/cam_c.cpp b/src/core/hle/service/cam/cam_c.cpp
new file mode 100644
index 00000000..d35adcb9
--- /dev/null
+++ b/src/core/hle/service/cam/cam_c.cpp
@@ -0,0 +1,20 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/hle.h"
+#include "core/hle/service/cam/cam.h"
+#include "core/hle/service/cam/cam_c.h"
+
+namespace Service {
+namespace CAM {
+
+// Empty arrays are illegal -- commented out until an entry is added.
+//const Interface::FunctionInfo FunctionTable[] = { };
+
+CAM_C_Interface::CAM_C_Interface() {
+ //Register(FunctionTable);
+}
+
+} // namespace CAM
+} // namespace Service
diff --git a/src/core/hle/service/cam/cam_c.h b/src/core/hle/service/cam/cam_c.h
new file mode 100644
index 00000000..6b296c00
--- /dev/null
+++ b/src/core/hle/service/cam/cam_c.h
@@ -0,0 +1,22 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included..
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace CAM {
+
+class CAM_C_Interface : public Service::Interface {
+public:
+ CAM_C_Interface();
+
+ std::string GetPortName() const override {
+ return "cam:c";
+ }
+};
+
+} // namespace CAM
+} // namespace Service
diff --git a/src/core/hle/service/cam/cam_q.cpp b/src/core/hle/service/cam/cam_q.cpp
new file mode 100644
index 00000000..c2760a10
--- /dev/null
+++ b/src/core/hle/service/cam/cam_q.cpp
@@ -0,0 +1,20 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/hle.h"
+#include "core/hle/service/cam/cam.h"
+#include "core/hle/service/cam/cam_q.h"
+
+namespace Service {
+namespace CAM {
+
+// Empty arrays are illegal -- commented out until an entry is added.
+//const Interface::FunctionInfo FunctionTable[] = { };
+
+CAM_Q_Interface::CAM_Q_Interface() {
+ //Register(FunctionTable);
+}
+
+} // namespace CAM
+} // namespace Service
diff --git a/src/core/hle/service/cam/cam_q.h b/src/core/hle/service/cam/cam_q.h
new file mode 100644
index 00000000..07cc1253
--- /dev/null
+++ b/src/core/hle/service/cam/cam_q.h
@@ -0,0 +1,22 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included..
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace CAM {
+
+class CAM_Q_Interface : public Service::Interface {
+public:
+ CAM_Q_Interface();
+
+ std::string GetPortName() const override {
+ return "cam:q";
+ }
+};
+
+} // namespace CAM
+} // namespace Service
diff --git a/src/core/hle/service/cam/cam_s.cpp b/src/core/hle/service/cam/cam_s.cpp
new file mode 100644
index 00000000..aefbf7df
--- /dev/null
+++ b/src/core/hle/service/cam/cam_s.cpp
@@ -0,0 +1,20 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/hle.h"
+#include "core/hle/service/cam/cam.h"
+#include "core/hle/service/cam/cam_s.h"
+
+namespace Service {
+namespace CAM {
+
+// Empty arrays are illegal -- commented out until an entry is added.
+//const Interface::FunctionInfo FunctionTable[] = { };
+
+CAM_S_Interface::CAM_S_Interface() {
+ //Register(FunctionTable);
+}
+
+} // namespace CAM
+} // namespace Service
diff --git a/src/core/hle/service/cam/cam_s.h b/src/core/hle/service/cam/cam_s.h
new file mode 100644
index 00000000..0a5d6fca
--- /dev/null
+++ b/src/core/hle/service/cam/cam_s.h
@@ -0,0 +1,22 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included..
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace CAM {
+
+class CAM_S_Interface : public Service::Interface {
+public:
+ CAM_S_Interface();
+
+ std::string GetPortName() const override {
+ return "cam:s";
+ }
+};
+
+} // namespace CAM
+} // namespace Service
diff --git a/src/core/hle/service/cam/cam_u.cpp b/src/core/hle/service/cam/cam_u.cpp
new file mode 100644
index 00000000..1c6aca95
--- /dev/null
+++ b/src/core/hle/service/cam/cam_u.cpp
@@ -0,0 +1,20 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/hle.h"
+#include "core/hle/service/cam/cam.h"
+#include "core/hle/service/cam/cam_u.h"
+
+namespace Service {
+namespace CAM {
+
+// Empty arrays are illegal -- commented out until an entry is added.
+//const Interface::FunctionInfo FunctionTable[] = { };
+
+CAM_U_Interface::CAM_U_Interface() {
+ //Register(FunctionTable);
+}
+
+} // namespace CAM
+} // namespace Service
diff --git a/src/core/hle/service/cam/cam_u.h b/src/core/hle/service/cam/cam_u.h
new file mode 100644
index 00000000..36926403
--- /dev/null
+++ b/src/core/hle/service/cam/cam_u.h
@@ -0,0 +1,22 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included..
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace CAM {
+
+class CAM_U_Interface : public Service::Interface {
+public:
+ CAM_U_Interface();
+
+ std::string GetPortName() const override {
+ return "cam:u";
+ }
+};
+
+} // namespace CAM
+} // namespace Service
diff --git a/src/core/hle/service/cam_u.cpp b/src/core/hle/service/cam_u.cpp
deleted file mode 100644
index fcfd8771..00000000
--- a/src/core/hle/service/cam_u.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2015 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "core/hle/hle.h"
-#include "core/hle/service/cam_u.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace CAM_U
-
-namespace CAM_U {
-
-// Empty arrays are illegal -- commented out until an entry is added.
-//const Interface::FunctionInfo FunctionTable[] = { };
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
- //Register(FunctionTable);
-}
-
-} // namespace
diff --git a/src/core/hle/service/cam_u.h b/src/core/hle/service/cam_u.h
deleted file mode 100644
index 878c20a8..00000000
--- a/src/core/hle/service/cam_u.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2015 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include "core/hle/service/service.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace CAM_U
-
-namespace CAM_U {
-
-class Interface : public Service::Interface {
-public:
- Interface();
-
- std::string GetPortName() const override {
- return "cam:u";
- }
-};
-
-} // namespace
diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp
new file mode 100644
index 00000000..db0e52b7
--- /dev/null
+++ b/src/core/hle/service/cecd/cecd.cpp
@@ -0,0 +1,31 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/logging/log.h"
+
+#include "core/hle/service/service.h"
+#include "core/hle/service/cecd/cecd.h"
+#include "core/hle/service/cecd/cecd_s.h"
+#include "core/hle/service/cecd/cecd_u.h"
+
+#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/shared_memory.h"
+#include "core/hle/hle.h"
+
+namespace Service {
+namespace CECD {
+
+void Init() {
+ using namespace Kernel;
+
+ AddService(new CECD_S_Interface);
+ AddService(new CECD_U_Interface);
+}
+
+void Shutdown() {
+}
+
+} // namespace CECD
+
+} // namespace Service
diff --git a/src/core/hle/service/cecd/cecd.h b/src/core/hle/service/cecd/cecd.h
new file mode 100644
index 00000000..32fd2045
--- /dev/null
+++ b/src/core/hle/service/cecd/cecd.h
@@ -0,0 +1,20 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace CECD {
+
+/// Initialize CECD service(s)
+void Init();
+
+/// Shutdown CECD service(s)
+void Shutdown();
+
+} // namespace CECD
+} // namespace Service
diff --git a/src/core/hle/service/cecd/cecd_s.cpp b/src/core/hle/service/cecd/cecd_s.cpp
new file mode 100644
index 00000000..72d7e8d4
--- /dev/null
+++ b/src/core/hle/service/cecd/cecd_s.cpp
@@ -0,0 +1,20 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/hle.h"
+#include "core/hle/service/cecd/cecd.h"
+#include "core/hle/service/cecd/cecd_s.h"
+
+namespace Service {
+namespace CECD {
+
+// Empty arrays are illegal -- commented out until an entry is added.
+//const Interface::FunctionInfo FunctionTable[] = { };
+
+CECD_S_Interface::CECD_S_Interface() {
+ //Register(FunctionTable);
+}
+
+} // namespace CECD
+} // namespace Service
diff --git a/src/core/hle/service/cecd_s.h b/src/core/hle/service/cecd/cecd_s.h
index d880d039..df5c0184 100644
--- a/src/core/hle/service/cecd_s.h
+++ b/src/core/hle/service/cecd/cecd_s.h
@@ -6,18 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace CECD_S
+namespace Service {
+namespace CECD {
-namespace CECD_S {
-
-class Interface : public Service::Interface {
+class CECD_S_Interface : public Interface {
public:
- Interface();
+ CECD_S_Interface();
std::string GetPortName() const override {
return "cecd:s";
}
};
-} // namespace
+} // namespace CECD
+} // namespace Service
diff --git a/src/core/hle/service/cecd/cecd_u.cpp b/src/core/hle/service/cecd/cecd_u.cpp
new file mode 100644
index 00000000..0a23bafb
--- /dev/null
+++ b/src/core/hle/service/cecd/cecd_u.cpp
@@ -0,0 +1,20 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/hle.h"
+#include "core/hle/service/cecd/cecd.h"
+#include "core/hle/service/cecd/cecd_u.h"
+
+namespace Service {
+namespace CECD {
+
+// Empty arrays are illegal -- commented out until an entry is added.
+//const Interface::FunctionInfo FunctionTable[] = { };
+
+CECD_U_Interface::CECD_U_Interface() {
+ //Register(FunctionTable);
+}
+
+} // namespace CECD
+} // namespace Service
diff --git a/src/core/hle/service/cecd_u.h b/src/core/hle/service/cecd/cecd_u.h
index e6756413..394030ff 100644
--- a/src/core/hle/service/cecd_u.h
+++ b/src/core/hle/service/cecd/cecd_u.h
@@ -6,18 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace CECD_U
+namespace Service {
+namespace CECD {
-namespace CECD_U {
-
-class Interface : public Service::Interface {
+class CECD_U_Interface : public Interface {
public:
- Interface();
+ CECD_U_Interface();
std::string GetPortName() const override {
return "cecd:u";
}
};
-} // namespace
+} // namespace CECD
+} // namespace Service
diff --git a/src/core/hle/service/cecd_s.cpp b/src/core/hle/service/cecd_s.cpp
deleted file mode 100644
index b298f151..00000000
--- a/src/core/hle/service/cecd_s.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2015 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "core/hle/hle.h"
-#include "core/hle/service/cecd_s.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace CECD_S
-
-namespace CECD_S {
-
-// Empty arrays are illegal -- commented out until an entry is added.
-//const Interface::FunctionInfo FunctionTable[] = { };
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
- //Register(FunctionTable);
-}
-
-} // namespace
diff --git a/src/core/hle/service/cecd_u.cpp b/src/core/hle/service/cecd_u.cpp
deleted file mode 100644
index 9125364b..00000000
--- a/src/core/hle/service/cecd_u.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "core/hle/hle.h"
-#include "core/hle/service/cecd_u.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace CECD_U
-
-namespace CECD_U {
-
-// Empty arrays are illegal -- commented out until an entry is added.
-//const Interface::FunctionInfo FunctionTable[] = { };
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
- //Register(FunctionTable);
-}
-
-} // namespace
diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp
index d4268288..62ad90fd 100644
--- a/src/core/hle/service/cfg/cfg.cpp
+++ b/src/core/hle/service/cfg/cfg.cpp
@@ -315,11 +315,11 @@ void Init() {
AddService(new CFG_I_Interface);
AddService(new CFG_S_Interface);
AddService(new CFG_U_Interface);
-
+
// Open the SystemSaveData archive 0x00010017
FileSys::Path archive_path(cfg_system_savedata_id);
auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path);
-
+
// If the archive didn't exist, create the files inside
if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) {
// Format the archive to create the directories
diff --git a/src/core/hle/service/frd/frd.cpp b/src/core/hle/service/frd/frd.cpp
new file mode 100644
index 00000000..2911ab40
--- /dev/null
+++ b/src/core/hle/service/frd/frd.cpp
@@ -0,0 +1,29 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/service/service.h"
+#include "core/hle/service/frd/frd.h"
+#include "core/hle/service/frd/frd_a.h"
+#include "core/hle/service/frd/frd_u.h"
+
+#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/shared_memory.h"
+#include "core/hle/hle.h"
+
+namespace Service {
+namespace FRD {
+
+void Init() {
+ using namespace Kernel;
+
+ AddService(new FRD_A_Interface);
+ AddService(new FRD_U_Interface);
+}
+
+void Shutdown() {
+}
+
+} // namespace FRD
+
+} // namespace Service
diff --git a/src/core/hle/service/frd/frd.h b/src/core/hle/service/frd/frd.h
new file mode 100644
index 00000000..41f7a2f6
--- /dev/null
+++ b/src/core/hle/service/frd/frd.h
@@ -0,0 +1,20 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace FRD {
+
+/// Initialize FRD service(s)
+void Init();
+
+/// Shutdown FRD service(s)
+void Shutdown();
+
+} // namespace FRD
+} // namespace Service
diff --git a/src/core/hle/service/frd/frd_a.cpp b/src/core/hle/service/frd/frd_a.cpp
new file mode 100644
index 00000000..1c438a33
--- /dev/null
+++ b/src/core/hle/service/frd/frd_a.cpp
@@ -0,0 +1,20 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/hle.h"
+#include "core/hle/service/frd/frd.h"
+#include "core/hle/service/frd/frd_a.h"
+
+namespace Service {
+namespace FRD {
+
+// Empty arrays are illegal -- commented out until an entry is added.
+// const Interface::FunctionInfo FunctionTable[] = { };
+
+FRD_A_Interface::FRD_A_Interface() {
+ //Register(FunctionTable);
+}
+
+} // namespace FRD
+} // namespace Service
diff --git a/src/core/hle/service/frd_a.h b/src/core/hle/service/frd/frd_a.h
index f068c610..006d1cad 100644
--- a/src/core/hle/service/frd_a.h
+++ b/src/core/hle/service/frd/frd_a.h
@@ -6,18 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace FRD_A
+namespace Service {
+namespace FRD {
-namespace FRD_A {
-
-class Interface : public Service::Interface {
+class FRD_A_Interface : public Service::Interface {
public:
- Interface();
+ FRD_A_Interface();
std::string GetPortName() const override {
return "frd:a";
}
};
-} // namespace
+} // namespace FRD
+} // namespace Service
diff --git a/src/core/hle/service/frd_u.cpp b/src/core/hle/service/frd/frd_u.cpp
index 6d2ff1e2..439c7282 100644
--- a/src/core/hle/service/frd_u.cpp
+++ b/src/core/hle/service/frd/frd_u.cpp
@@ -3,12 +3,11 @@
// Refer to the license.txt file included.
#include "core/hle/hle.h"
-#include "core/hle/service/frd_u.h"
+#include "core/hle/service/frd/frd.h"
+#include "core/hle/service/frd/frd_u.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace FRD_U
-
-namespace FRD_U {
+namespace Service {
+namespace FRD {
const Interface::FunctionInfo FunctionTable[] = {
{0x00050000, nullptr, "GetFriendKey"},
@@ -22,11 +21,9 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00320042, nullptr, "SetClientSdkVersion"}
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
+FRD_U_Interface::FRD_U_Interface() {
Register(FunctionTable);
}
-} // namespace
+} // namespace FRD
+} // namespace Service
diff --git a/src/core/hle/service/frd_u.h b/src/core/hle/service/frd/frd_u.h
index ab8897d5..07e43f15 100644
--- a/src/core/hle/service/frd_u.h
+++ b/src/core/hle/service/frd/frd_u.h
@@ -6,18 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace FRD_U
+namespace Service {
+namespace FRD {
-namespace FRD_U {
-
-class Interface : public Service::Interface {
+class FRD_U_Interface : public Service::Interface {
public:
- Interface();
+ FRD_U_Interface();
std::string GetPortName() const override {
return "frd:u";
}
};
-} // namespace
+} // namespace FRD
+} // namespace Service
diff --git a/src/core/hle/service/frd_a.cpp b/src/core/hle/service/frd_a.cpp
deleted file mode 100644
index 56997931..00000000
--- a/src/core/hle/service/frd_a.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2015 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "core/hle/hle.h"
-#include "core/hle/service/frd_a.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace FRD_A
-
-namespace FRD_A {
-
-// Empty arrays are illegal -- commented out until an entry is added.
-// const Interface::FunctionInfo FunctionTable[] = { };
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
- //Register(FunctionTable);
-}
-
-} // namespace
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp
index 6d4a9c7c..4e275cb1 100644
--- a/src/core/hle/service/fs/archive.cpp
+++ b/src/core/hle/service/fs/archive.cpp
@@ -254,7 +254,7 @@ ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archi
CASCADE_RESULT(std::unique_ptr<ArchiveBackend> res, itr->second->Open(archive_path));
- // This should never even happen in the first place with 64-bit handles,
+ // This should never even happen in the first place with 64-bit handles,
while (handle_map.count(next_handle) != 0) {
++next_handle;
}
@@ -406,7 +406,7 @@ ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path) {
return archive_itr->second->Format(path);
}
-ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low) {
+ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size) {
// Construct the binary path to the archive first
FileSys::Path path = FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low);
@@ -421,9 +421,25 @@ ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low) {
}
std::string base_path = FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND);
- std::string extsavedata_path = FileSys::GetExtSaveDataPath(base_path, path);
- if (!FileUtil::CreateFullPath(extsavedata_path))
+ std::string game_path = FileSys::GetExtSaveDataPath(base_path, path);
+ // These two folders are always created with the ExtSaveData
+ std::string user_path = game_path + "user/";
+ std::string boss_path = game_path + "boss/";
+ if (!FileUtil::CreateFullPath(user_path))
+ return ResultCode(-1); // TODO(Subv): Find the right error code
+ if (!FileUtil::CreateFullPath(boss_path))
+ return ResultCode(-1); // TODO(Subv): Find the right error code
+
+ u8* smdh_icon = Memory::GetPointer(icon_buffer);
+ if (!smdh_icon)
return ResultCode(-1); // TODO(Subv): Find the right error code
+
+ // Create the icon
+ FileUtil::IOFile icon_file(game_path + "icon", "wb+");
+ if (!icon_file.IsGood())
+ return ResultCode(-1); // TODO(Subv): Find the right error code
+
+ icon_file.WriteBytes(smdh_icon, icon_size);
return RESULT_SUCCESS;
}
@@ -441,6 +457,7 @@ ResultCode DeleteExtSaveData(MediaType media_type, u32 high, u32 low) {
return ResultCode(-1); // TODO(Subv): Find the right error code
}
+ // Delete all directories (/user, /boss) and the icon file.
std::string base_path = FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND);
std::string extsavedata_path = FileSys::GetExtSaveDataPath(base_path, path);
if (!FileUtil::DeleteDirRecursively(extsavedata_path))
@@ -488,7 +505,7 @@ void ArchiveInit() {
RegisterArchiveType(std::move(sdmc_factory), ArchiveIdCode::SDMC);
else
LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str());
-
+
// Create the SaveData archive
auto savedata_factory = Common::make_unique<FileSys::ArchiveFactory_SaveData>(sdmc_directory);
RegisterArchiveType(std::move(savedata_factory), ArchiveIdCode::SaveData);
@@ -503,7 +520,7 @@ void ArchiveInit() {
if (sharedextsavedata_factory->Initialize())
RegisterArchiveType(std::move(sharedextsavedata_factory), ArchiveIdCode::SharedExtSaveData);
else
- LOG_ERROR(Service_FS, "Can't instantiate SharedExtSaveData archive with path %s",
+ LOG_ERROR(Service_FS, "Can't instantiate SharedExtSaveData archive with path %s",
sharedextsavedata_factory->GetMountPoint().c_str());
// Create the SaveDataCheck archive, basically a small variation of the RomFS archive
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h
index faab0cb7..357b6b09 100644
--- a/src/core/hle/service/fs/archive.h
+++ b/src/core/hle/service/fs/archive.h
@@ -177,9 +177,11 @@ ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path = File
* @param media_type The media type of the archive to create (NAND / SDMC)
* @param high The high word of the extdata id to create
* @param low The low word of the extdata id to create
+ * @param icon_buffer VAddr of the SMDH icon for this ExtSaveData
+ * @param icon_size Size of the SMDH icon
* @return ResultCode 0 on success or the corresponding code on error
*/
-ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low);
+ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size);
/**
* Deletes the SharedExtSaveData archive for the specified extdata ID
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp
index b25c8941..0ad44e55 100644
--- a/src/core/hle/service/fs/fs_user.cpp
+++ b/src/core/hle/service/fs/fs_user.cpp
@@ -434,7 +434,7 @@ static void IsSdmcWriteable(Service::Interface* self) {
}
/**
- * FS_User::FormatSaveData service function,
+ * FS_User::FormatSaveData service function,
* formats the SaveData specified by the input path.
* Inputs:
* 0 : 0x084C0242
@@ -504,9 +504,9 @@ static void FormatThisUserSaveData(Service::Interface* self) {
* 6 : Unknown
* 7 : Unknown
* 8 : Unknown
- * 9 : Unknown
- * 10: Unknown
- * 11: Unknown
+ * 9 : Size of the SMDH icon
+ * 10: (SMDH Size << 4) | 0x0000000A
+ * 11: Pointer to the SMDH icon for the new ExtSaveData
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
@@ -516,14 +516,16 @@ static void CreateExtSaveData(Service::Interface* self) {
MediaType media_type = static_cast<MediaType>(cmd_buff[1] & 0xFF);
u32 save_low = cmd_buff[2];
u32 save_high = cmd_buff[3];
+ u32 icon_size = cmd_buff[9];
+ VAddr icon_buffer = cmd_buff[11];
LOG_WARNING(Service_FS, "(STUBBED) savedata_high=%08X savedata_low=%08X cmd_buff[3]=%08X "
"cmd_buff[4]=%08X cmd_buff[5]=%08X cmd_buff[6]=%08X cmd_buff[7]=%08X cmd_buff[8]=%08X "
- "cmd_buff[9]=%08X cmd_buff[10]=%08X cmd_buff[11]=%08X", save_high, save_low,
- cmd_buff[3], cmd_buff[4], cmd_buff[5], cmd_buff[6], cmd_buff[7], cmd_buff[8], cmd_buff[9],
- cmd_buff[10], cmd_buff[11]);
+ "icon_size=%08X icon_descriptor=%08X icon_buffer=%08X", save_high, save_low,
+ cmd_buff[3], cmd_buff[4], cmd_buff[5], cmd_buff[6], cmd_buff[7], cmd_buff[8], icon_size,
+ cmd_buff[10], icon_buffer);
- cmd_buff[1] = CreateExtSaveData(media_type, save_high, save_low).raw;
+ cmd_buff[1] = CreateExtSaveData(media_type, save_high, save_low, icon_buffer, icon_size).raw;
}
/**
@@ -544,7 +546,7 @@ static void DeleteExtSaveData(Service::Interface* self) {
u32 save_high = cmd_buff[3];
u32 unknown = cmd_buff[4]; // TODO(Subv): Figure out what this is
- LOG_WARNING(Service_FS, "(STUBBED) save_low=%08X save_high=%08X media_type=%08X unknown=%08X",
+ LOG_WARNING(Service_FS, "(STUBBED) save_low=%08X save_high=%08X media_type=%08X unknown=%08X",
save_low, save_high, cmd_buff[1] & 0xFF, unknown);
cmd_buff[1] = DeleteExtSaveData(media_type, save_high, save_low).raw;
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index c56475ae..4b0b4229 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -167,7 +167,7 @@ static void WriteHWRegsWithMask(Service::Interface* self) {
u32* cmd_buff = Kernel::GetCommandBuffer();
u32 reg_addr = cmd_buff[1];
u32 size = cmd_buff[2];
-
+
u32* src_data = (u32*)Memory::GetPointer(cmd_buff[4]);
u32* mask_data = (u32*)Memory::GetPointer(cmd_buff[6]);
@@ -208,21 +208,21 @@ static void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left);
PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right);
if (info.active_fb == 0) {
- WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)), 4,
+ WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)), 4,
&phys_address_left);
- WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)), 4,
+ WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)), 4,
&phys_address_right);
} else {
- WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)), 4,
+ WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)), 4,
&phys_address_left);
- WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)), 4,
+ WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)), 4,
&phys_address_right);
}
- WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)), 4,
+ WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)), 4,
&info.stride);
- WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)), 4,
+ WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)), 4,
&info.format);
- WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), 4,
+ WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), 4,
&info.shown_fb);
}
@@ -374,7 +374,7 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
{
auto& params = command.set_command_list_last;
- WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(command_processor_config.address)),
+ WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(command_processor_config.address)),
Memory::VirtualToPhysicalAddress(params.address) >> 3);
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(command_processor_config.size)), params.size);
@@ -470,7 +470,7 @@ static void SetLcdForceBlack(Service::Interface* self) {
LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_top), data.raw); // Top LCD
LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_bottom), data.raw); // Bottom LCD
-
+
cmd_buff[1] = RESULT_SUCCESS.raw;
}
@@ -496,6 +496,52 @@ static void TriggerCmdReqQueue(Service::Interface* self) {
cmd_buff[1] = 0; // No error
}
+/**
+ * GSP_GPU::ImportDisplayCaptureInfo service function
+ *
+ * Returns information about the current framebuffer state
+ *
+ * Inputs:
+ * 0: Header 0x00180000
+ * Outputs:
+ * 1: Result code
+ * 2: Left framebuffer virtual address for the main screen
+ * 3: Right framebuffer virtual address for the main screen
+ * 4: Main screen framebuffer format
+ * 5: Main screen framebuffer width
+ * 6: Left framebuffer virtual address for the bottom screen
+ * 7: Right framebuffer virtual address for the bottom screen
+ * 8: Bottom screen framebuffer format
+ * 9: Bottom screen framebuffer width
+ */
+static void ImportDisplayCaptureInfo(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ // TODO(Subv): We're always returning the framebuffer structures for thread_id = 0,
+ // because we only support a single running application at a time.
+ // This should always return the framebuffer data that is currently displayed on the screen.
+
+ u32 thread_id = 0;
+
+ FrameBufferUpdate* top_screen = GetFrameBufferInfo(thread_id, 0);
+ FrameBufferUpdate* bottom_screen = GetFrameBufferInfo(thread_id, 1);
+
+ cmd_buff[2] = top_screen->framebuffer_info[top_screen->index].address_left;
+ cmd_buff[3] = top_screen->framebuffer_info[top_screen->index].address_right;
+ cmd_buff[4] = top_screen->framebuffer_info[top_screen->index].format;
+ cmd_buff[5] = top_screen->framebuffer_info[top_screen->index].stride;
+
+ cmd_buff[6] = bottom_screen->framebuffer_info[bottom_screen->index].address_left;
+ cmd_buff[7] = bottom_screen->framebuffer_info[bottom_screen->index].address_right;
+ cmd_buff[8] = bottom_screen->framebuffer_info[bottom_screen->index].format;
+ cmd_buff[9] = bottom_screen->framebuffer_info[bottom_screen->index].stride;
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+
+ LOG_WARNING(Service_GSP, "called");
+}
+
+
const Interface::FunctionInfo FunctionTable[] = {
{0x00010082, WriteHWRegs, "WriteHWRegs"},
{0x00020084, WriteHWRegsWithMask, "WriteHWRegsWithMask"},
@@ -520,7 +566,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00150002, nullptr, "TryAcquireRight"},
{0x00160042, nullptr, "AcquireRight"},
{0x00170000, nullptr, "ReleaseRight"},
- {0x00180000, nullptr, "ImportDisplayCaptureInfo"},
+ {0x00180000, ImportDisplayCaptureInfo, "ImportDisplayCaptureInfo"},
{0x00190000, nullptr, "SaveVramSysArea"},
{0x001A0000, nullptr, "RestoreVramSysArea"},
{0x001B0000, nullptr, "ResetGpuCore"},
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 2d2133b2..c7c1bb5a 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -58,7 +58,7 @@ void Update() {
mem->pad.current_state.hex = state.hex;
mem->pad.index = next_pad_index;
- ++next_touch_index %= mem->pad.entries.size();
+ next_touch_index = (next_touch_index + 1) % mem->pad.entries.size();
// Get the previous Pad state
u32 last_entry_index = (mem->pad.index - 1) % mem->pad.entries.size();
@@ -88,7 +88,7 @@ void Update() {
}
mem->touch.index = next_touch_index;
- ++next_touch_index %= mem->touch.entries.size();
+ next_touch_index = (next_touch_index + 1) % mem->touch.entries.size();
// Get the current touch entry
TouchDataEntry* touch_entry = &mem->touch.entries[mem->touch.index];
@@ -106,7 +106,7 @@ void Update() {
mem->touch.index_reset_ticks_previous = mem->touch.index_reset_ticks;
mem->touch.index_reset_ticks = (s64)CoreTiming::GetTicks();
}
-
+
// Signal both handles when there's an update to Pad or touch
event_pad_or_touch_1->Signal();
event_pad_or_touch_2->Signal();
diff --git a/src/core/hle/service/hid/hid_spvr.cpp b/src/core/hle/service/hid/hid_spvr.cpp
index 02db12ef..532931ae 100644
--- a/src/core/hle/service/hid/hid_spvr.cpp
+++ b/src/core/hle/service/hid/hid_spvr.cpp
@@ -25,6 +25,6 @@ const Interface::FunctionInfo FunctionTable[] = {
HID_SPVR_Interface::HID_SPVR_Interface() {
Register(FunctionTable);
}
-
+
} // namespace HID
} // namespace Service
diff --git a/src/core/hle/service/hid/hid_user.h b/src/core/hle/service/hid/hid_user.h
index 0eeec2c2..baf7fed7 100644
--- a/src/core/hle/service/hid/hid_user.h
+++ b/src/core/hle/service/hid/hid_user.h
@@ -11,7 +11,7 @@
namespace Service {
namespace HID {
-
+
/**
* HID service interface.
*/
diff --git a/src/core/hle/service/news/news.cpp b/src/core/hle/service/news/news.cpp
new file mode 100644
index 00000000..63cbd385
--- /dev/null
+++ b/src/core/hle/service/news/news.cpp
@@ -0,0 +1,31 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/logging/log.h"
+
+#include "core/hle/service/service.h"
+#include "core/hle/service/news/news.h"
+#include "core/hle/service/news/news_s.h"
+#include "core/hle/service/news/news_u.h"
+
+#include "core/hle/hle.h"
+#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/shared_memory.h"
+
+namespace Service {
+namespace NEWS {
+
+void Init() {
+ using namespace Kernel;
+
+ AddService(new NEWS_S_Interface);
+ AddService(new NEWS_U_Interface);
+}
+
+void Shutdown() {
+}
+
+} // namespace NEWS
+
+} // namespace Service
diff --git a/src/core/hle/service/news/news.h b/src/core/hle/service/news/news.h
new file mode 100644
index 00000000..b31ade25
--- /dev/null
+++ b/src/core/hle/service/news/news.h
@@ -0,0 +1,20 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace NEWS {
+
+/// Initialize NEWS service(s)
+void Init();
+
+/// Shutdown NEWS service(s)
+void Shutdown();
+
+} // namespace NEWS
+} // namespace Service
diff --git a/src/core/hle/service/news/news_s.cpp b/src/core/hle/service/news/news_s.cpp
new file mode 100644
index 00000000..2f8c37d9
--- /dev/null
+++ b/src/core/hle/service/news/news_s.cpp
@@ -0,0 +1,21 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/hle.h"
+#include "core/hle/service/news/news.h"
+#include "core/hle/service/news/news_s.h"
+
+namespace Service {
+namespace NEWS {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x000100C6, nullptr, "AddNotification"},
+};
+
+NEWS_S_Interface::NEWS_S_Interface() {
+ Register(FunctionTable);
+}
+
+} // namespace NEWS
+} // namespace Service
diff --git a/src/core/hle/service/news_s.h b/src/core/hle/service/news/news_s.h
index f8b4636d..f58b969a 100644
--- a/src/core/hle/service/news_s.h
+++ b/src/core/hle/service/news/news_s.h
@@ -6,18 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace NEWS_S
+namespace Service {
+namespace NEWS {
-namespace NEWS_S {
-
-class Interface : public Service::Interface {
+class NEWS_S_Interface : public Service::Interface {
public:
- Interface();
+ NEWS_S_Interface();
std::string GetPortName() const override {
return "news:s";
}
};
-} // namespace
+} // namespace NEWS
+} // namespace Service
diff --git a/src/core/hle/service/news/news_u.cpp b/src/core/hle/service/news/news_u.cpp
new file mode 100644
index 00000000..81f45a24
--- /dev/null
+++ b/src/core/hle/service/news/news_u.cpp
@@ -0,0 +1,21 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/hle.h"
+#include "core/hle/service/news/news.h"
+#include "core/hle/service/news/news_u.h"
+
+namespace Service {
+namespace NEWS {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x000100C6, nullptr, "AddNotification"},
+};
+
+NEWS_U_Interface::NEWS_U_Interface() {
+ Register(FunctionTable);
+}
+
+} // namespace NEWS
+} // namespace Service
diff --git a/src/core/hle/service/news_u.h b/src/core/hle/service/news/news_u.h
index 0473cd19..2720053d 100644
--- a/src/core/hle/service/news_u.h
+++ b/src/core/hle/service/news/news_u.h
@@ -6,18 +6,17 @@
#include "core/hle/service/service.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace NEWS_U
+namespace Service {
+namespace NEWS {
-namespace NEWS_U {
-
-class Interface : public Service::Interface {
+class NEWS_U_Interface : public Service::Interface {
public:
- Interface();
+ NEWS_U_Interface();
std::string GetPortName() const override {
return "news:u";
}
};
-} // namespace
+} // namespace NEWS
+} // namespace Service
diff --git a/src/core/hle/service/news_s.cpp b/src/core/hle/service/news_s.cpp
deleted file mode 100644
index 302d588c..00000000
--- a/src/core/hle/service/news_s.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2015 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "core/hle/hle.h"
-#include "core/hle/service/news_s.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace NEWS_S
-
-namespace NEWS_S {
-
-const Interface::FunctionInfo FunctionTable[] = {
- {0x000100C6, nullptr, "AddNotification"},
-};
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
- Register(FunctionTable);
-}
-
-} // namespace
diff --git a/src/core/hle/service/news_u.cpp b/src/core/hle/service/news_u.cpp
deleted file mode 100644
index 7d835aa3..00000000
--- a/src/core/hle/service/news_u.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "core/hle/hle.h"
-#include "core/hle/service/news_u.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace NEWS_U
-
-namespace NEWS_U {
-
-const Interface::FunctionInfo FunctionTable[] = {
- {0x000100C8, nullptr, "AddNotification"},
-};
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
- Register(FunctionTable);
-}
-
-} // namespace
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp
new file mode 100644
index 00000000..73b0ee52
--- /dev/null
+++ b/src/core/hle/service/nim/nim.cpp
@@ -0,0 +1,42 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "common/logging/log.h"
+
+#include "core/hle/service/service.h"
+#include "core/hle/service/nim/nim.h"
+#include "core/hle/service/nim/nim_aoc.h"
+#include "core/hle/service/nim/nim_s.h"
+#include "core/hle/service/nim/nim_u.h"
+
+#include "core/hle/kernel/event.h"
+#include "core/hle/kernel/shared_memory.h"
+#include "core/hle/hle.h"
+
+namespace Service {
+namespace NIM {
+
+void CheckSysUpdateAvailable(Service::Interface* self) {
+ u32* cmd_buff = Kernel::GetCommandBuffer();
+
+ cmd_buff[1] = RESULT_SUCCESS.raw;
+ cmd_buff[2] = 0; // No update available
+
+ LOG_WARNING(Service_NWM, "(STUBBED) called");
+}
+
+void Init() {
+ using namespace Kernel;
+
+ AddService(new NIM_AOC_Interface);
+ AddService(new NIM_S_Interface);
+ AddService(new NIM_U_Interface);
+}
+
+void Shutdown() {
+}
+
+} // namespace NIM
+
+} // namespace Service
diff --git a/src/core/hle/service/nim/nim.h b/src/core/hle/service/nim/nim.h
new file mode 100644
index 00000000..f7635c74
--- /dev/null
+++ b/src/core/hle/service/nim/nim.h
@@ -0,0 +1,30 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include "core/hle/kernel/kernel.h"
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace NIM {
+
+/**
+ * NIM::CheckSysUpdateAvailable service function
+ * Inputs:
+ * 1 : None
+ * Outputs:
+ * 1 : Result of function, 0 on success, otherwise error code
+ * 2 : flag, 0 = no system update available, 1 = system update available.
+ */
+void CheckSysUpdateAvailable(Service::Interface* self);
+
+/// Initialize NIM service(s)
+void Init();
+
+/// Shutdown NIM service(s)
+void Shutdown();
+
+} // namespace NIM
+} // namespace Service
diff --git a/src/core/hle/service/nim_aoc.cpp b/src/core/hle/service/nim/nim_aoc.cpp
index 7a6aea91..e6b1b614 100644
--- a/src/core/hle/service/nim_aoc.cpp
+++ b/src/core/hle/service/nim/nim_aoc.cpp
@@ -3,12 +3,11 @@
// Refer to the license.txt file included.
#include "core/hle/hle.h"
-#include "core/hle/service/nim_aoc.h"
+#include "core/hle/service/nim/nim.h"
+#include "core/hle/service/nim/nim_aoc.h"
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace NIM_AOC
-
-namespace NIM_AOC {
+namespace Service {
+namespace NIM {
const Interface::FunctionInfo FunctionTable[] = {
{0x00030042, nullptr, "SetApplicationId"},
@@ -20,11 +19,10 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00240282, nullptr, "CalculateContentsRequiredSize"},
{0x00250000, nullptr, "RefreshServerTime"},
};
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-Interface::Interface() {
+NIM_AOC_Interface::NIM_AOC_Interface() {
Register(FunctionTable);
}
-} // namespace
+} // namespace NIM
+} // namespace Service
diff --git a/src/core/hle/service/nim/nim_aoc.h b/src/core/hle/service/nim/nim_aoc.h
new file mode 100644
index 00000000..aace45b5
--- /dev/null
+++ b/src/core/hle/service/nim/nim_aoc.h
@@ -0,0 +1,22 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included..
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace NIM {
+
+class NIM_AOC_Interface : public Service::Interface {
+public:
+ NIM_AOC_Interface();
+
+ std::string GetPortName() const override {
+ return "nim:aoc";
+ }
+};
+
+} // namespace NIM
+} // namespace Service
diff --git a/src/core/hle/service/nim/nim_s.cpp b/src/core/hle/service/nim/nim_s.cpp
new file mode 100644
index 00000000..5d8bc059
--- /dev/null
+++ b/src/core/hle/service/nim/nim_s.cpp
@@ -0,0 +1,22 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/hle.h"
+#include "core/hle/service/nim/nim.h"
+#include "core/hle/service/nim/nim_s.h"
+
+namespace Service {
+namespace NIM {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x000A0000, nullptr, "CheckSysupdateAvailableSOAP"},
+};
+
+NIM_S_Interface::NIM_S_Interface() {
+ Register(FunctionTable);
+}
+
+} // namespace NIM
+} // namespace Service
+
diff --git a/src/core/hle/service/nim/nim_s.h b/src/core/hle/service/nim/nim_s.h
new file mode 100644
index 00000000..f4bf73d2
--- /dev/null
+++ b/src/core/hle/service/nim/nim_s.h
@@ -0,0 +1,22 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included..
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace NIM {
+
+class NIM_S_Interface : public Service::Interface {
+public:
+ NIM_S_Interface();
+
+ std::string GetPortName() const override {
+ return "nim:s";
+ }
+};
+
+} // namespace NIM
+} // namespace Service
diff --git a/src/core/hle/service/nim/nim_u.cpp b/src/core/hle/service/nim/nim_u.cpp
new file mode 100644
index 00000000..066570a8
--- /dev/null
+++ b/src/core/hle/service/nim/nim_u.cpp
@@ -0,0 +1,27 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/hle/hle.h"
+#include "core/hle/service/nim/nim.h"
+#include "core/hle/service/nim/nim_u.h"
+
+namespace Service {
+namespace NIM {
+
+const Interface::FunctionInfo FunctionTable[] = {
+ {0x00010000, nullptr, "StartSysUpdate"},
+ {0x00020000, nullptr, "GetUpdateDownloadProgress"},
+ {0x00040000, nullptr, "FinishTitlesInstall"},
+ {0x00050000, nullptr, "CheckForSysUpdateEvent"},
+ {0x00090000, CheckSysUpdateAvailable, "CheckSysUpdateAvailable"},
+ {0x000A0000, nullptr, "GetState"},
+};
+
+NIM_U_Interface::NIM_U_Interface() {
+ Register(FunctionTable);
+}
+
+} // namespace NIM
+} // namespace Service
+
diff --git a/src/core/hle/service/nim/nim_u.h b/src/core/hle/service/nim/nim_u.h
new file mode 100644
index 00000000..bc89dc0f
--- /dev/null
+++ b/src/core/hle/service/nim/nim_u.h
@@ -0,0 +1,22 @@
+// Copyright 2015 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included..
+
+#pragma once
+
+#include "core/hle/service/service.h"
+
+namespace Service {
+namespace NIM {
+
+class NIM_U_Interface : public Service::Interface {
+public:
+ NIM_U_Interface();
+
+ std::string GetPortName() const override {
+ return "nim:u";
+ }
+};
+
+} // namespace NIM
+} // namespace Service
diff --git a/src/core/hle/service/nim_aoc.h b/src/core/hle/service/nim_aoc.h
deleted file mode 100644
index aeb71eed..00000000
--- a/src/core/hle/service/nim_aoc.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2014 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include "core/hle/service/service.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace NIM_AOC
-
-namespace NIM_AOC {
-
-class Interface : public Service::Interface {
-public:
- Interface();
-
- std::string GetPortName() const override {
- return "nim:aoc";
- }
-};
-
-} // namespace
diff --git a/src/core/hle/service/nim_u.cpp b/src/core/hle/service/nim_u.cpp
deleted file mode 100644
index 5f13bd98..00000000
--- a/src/core/hle/service/nim_u.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2015 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#include "common/logging/log.h"
-
-#include "core/hle/hle.h"
-#include "core/hle/service/nim_u.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace NIM_U
-
-namespace NIM_U {
-
-/**
- * NIM_U::CheckSysUpdateAvailable service function
- * Inputs:
- * 1 : None
- * Outputs:
- * 1 : Result of function, 0 on success, otherwise error code
- * 2 : flag, 0 = no system update available, 1 = system update available.
- */
-static void CheckSysUpdateAvailable(Service::Interface* self) {
- u32* cmd_buff = Kernel::GetCommandBuffer();
-
- cmd_buff[1] = RESULT_SUCCESS.raw;
- cmd_buff[2] = 0; // No update available
-
- LOG_WARNING(Service_NWM, "(STUBBED) called");
-}
-
-const Interface::FunctionInfo FunctionTable[] = {
- {0x00010000, nullptr, "StartSysUpdate"},
- {0x00020000, nullptr, "GetUpdateDownloadProgress"},
- {0x00040000, nullptr, "FinishTitlesInstall"},
- {0x00050000, nullptr, "CheckForSysUpdateEvent"},
- {0x00090000, CheckSysUpdateAvailable, "CheckSysUpdateAvailable"},
- {0x000A0000, nullptr, "GetState"},
-};
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Interface class
-
-Interface::Interface() {
- Register(FunctionTable);
-}
-
-} // namespace
diff --git a/src/core/hle/service/nim_u.h b/src/core/hle/service/nim_u.h
deleted file mode 100644
index 57a1f6ac..00000000
--- a/src/core/hle/service/nim_u.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2015 Citra Emulator Project
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include "core/hle/service/service.h"
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Namespace NIM_U
-
-namespace NIM_U {
-
-class Interface : public Service::Interface {
-public:
- Interface();
-
- std::string GetPortName() const override {
- return "nim:u";
- }
-};
-
-} // namespace
diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h
index 493e6a11..b690003c 100644
--- a/src/core/hle/service/ptm/ptm.h
+++ b/src/core/hle/service/ptm/ptm.h
@@ -20,15 +20,15 @@ enum class ChargeLevels : u32 {
CompletelyFull = 5,
};
-/**
+/**
* Represents the gamecoin file structure in the SharedExtData archive
* More information in 3dbrew (http://www.3dbrew.org/wiki/Extdata#Shared_Extdata_0xf000000b_gamecoin.dat)
*/
struct GameCoin {
u32 magic; ///< Magic number: 0x4F00
- u16 total_coins; ///< Total Play Coins
+ u16 total_coins; ///< Total Play Coins
u16 total_coins_on_date; ///< Total Play Coins obtained on the date stored below.
- u32 step_count; ///< Total step count at the time a new Play Coin was obtained.
+ u32 step_count; ///< Total step count at the time a new Play Coin was obtained.
u32 last_step_count; ///< Step count for the day the last Play Coin was obtained
u16 year;
u8 month;
diff --git a/src/core/hle/service/ptm/ptm_play.cpp b/src/core/hle/service/ptm/ptm_play.cpp
index 48e68a3d..7bb99019 100644
--- a/src/core/hle/service/ptm/ptm_play.cpp
+++ b/src/core/hle/service/ptm/ptm_play.cpp
@@ -18,6 +18,6 @@ const Interface::FunctionInfo FunctionTable[] = {
PTM_Play_Interface::PTM_Play_Interface() {
Register(FunctionTable);
}
-
+
} // namespace PTM
} // namespace Service \ No newline at end of file
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 64185c62..d681cc3d 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -8,29 +8,15 @@
#include "core/hle/service/service.h"
#include "core/hle/service/ac_u.h"
#include "core/hle/service/act_u.h"
-#include "core/hle/service/am_app.h"
-#include "core/hle/service/am_net.h"
-#include "core/hle/service/am_sys.h"
-#include "core/hle/service/boss_p.h"
-#include "core/hle/service/boss_u.h"
-#include "core/hle/service/cam_u.h"
-#include "core/hle/service/cecd_u.h"
-#include "core/hle/service/cecd_s.h"
#include "core/hle/service/csnd_snd.h"
#include "core/hle/service/dsp_dsp.h"
#include "core/hle/service/err_f.h"
-#include "core/hle/service/frd_a.h"
-#include "core/hle/service/frd_u.h"
#include "core/hle/service/gsp_gpu.h"
#include "core/hle/service/gsp_lcd.h"
#include "core/hle/service/http_c.h"
#include "core/hle/service/ldr_ro.h"
#include "core/hle/service/mic_u.h"
#include "core/hle/service/ndm_u.h"
-#include "core/hle/service/news_s.h"
-#include "core/hle/service/news_u.h"
-#include "core/hle/service/nim_aoc.h"
-#include "core/hle/service/nim_u.h"
#include "core/hle/service/ns_s.h"
#include "core/hle/service/nwm_uds.h"
#include "core/hle/service/pm_app.h"
@@ -39,11 +25,18 @@
#include "core/hle/service/ssl_c.h"
#include "core/hle/service/y2r_u.h"
+#include "core/hle/service/am/am.h"
#include "core/hle/service/apt/apt.h"
+#include "core/hle/service/boss/boss.h"
+#include "core/hle/service/cam/cam.h"
+#include "core/hle/service/cecd/cecd.h"
+#include "core/hle/service/frd/frd.h"
#include "core/hle/service/fs/archive.h"
#include "core/hle/service/cfg/cfg.h"
#include "core/hle/service/hid/hid.h"
#include "core/hle/service/ir/ir.h"
+#include "core/hle/service/news/news.h"
+#include "core/hle/service/nim/nim.h"
#include "core/hle/service/ptm/ptm.h"
namespace Service {
@@ -52,7 +45,7 @@ std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_por
std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services;
/**
- * Creates a function string for logging, complete with the name (or header code, depending
+ * Creates a function string for logging, complete with the name (or header code, depending
* on what's passed in) the port name, and all the cmd_buff arguments.
*/
static std::string MakeFunctionString(const char* name, const char* port_name, const u32* cmd_buff) {
@@ -111,36 +104,29 @@ void Init() {
AddNamedPort(new ERR_F::Interface);
Service::FS::ArchiveInit();
- Service::CFG::Init();
+ Service::AM::Init();
Service::APT::Init();
- Service::PTM::Init();
+ Service::BOSS::Init();
+ Service::CAM::Init();
+ Service::CECD::Init();
+ Service::CFG::Init();
+ Service::FRD::Init();
Service::HID::Init();
Service::IR::Init();
+ Service::NEWS::Init();
+ Service::NIM::Init();
+ Service::PTM::Init();
AddService(new AC_U::Interface);
AddService(new ACT_U::Interface);
- AddService(new AM_APP::Interface);
- AddService(new AM_NET::Interface);
- AddService(new AM_SYS::Interface);
- AddService(new BOSS_P::Interface);
- AddService(new BOSS_U::Interface);
- AddService(new CAM_U::Interface);
- AddService(new CECD_S::Interface);
- AddService(new CECD_U::Interface);
AddService(new CSND_SND::Interface);
AddService(new DSP_DSP::Interface);
- AddService(new FRD_A::Interface);
- AddService(new FRD_U::Interface);
AddService(new GSP_GPU::Interface);
AddService(new GSP_LCD::Interface);
AddService(new HTTP_C::Interface);
AddService(new LDR_RO::Interface);
AddService(new MIC_U::Interface);
AddService(new NDM_U::Interface);
- AddService(new NEWS_S::Interface);
- AddService(new NEWS_U::Interface);
- AddService(new NIM_AOC::Interface);
- AddService(new NIM_U::Interface);
AddService(new NS_S::Interface);
AddService(new NWM_UDS::Interface);
AddService(new PM_APP::Interface);
@@ -153,11 +139,19 @@ void Init() {
/// Shutdown ServiceManager
void Shutdown() {
+
+ Service::PTM::Shutdown();
+ Service::NIM::Shutdown();
+ Service::NEWS::Shutdown();
Service::IR::Shutdown();
Service::HID::Shutdown();
- Service::PTM::Shutdown();
- Service::APT::Shutdown();
+ Service::FRD::Shutdown();
Service::CFG::Shutdown();
+ Service::CECD::Shutdown();
+ Service::CAM::Shutdown();
+ Service::BOSS::Shutdown();
+ Service::APT::Shutdown();
+ Service::AM::Shutdown();
Service::FS::ArchiveShutdown();
g_srv_services.clear();
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp
index 39b8d65f..1e0f5df9 100644
--- a/src/core/hle/service/soc_u.cpp
+++ b/src/core/hle/service/soc_u.cpp
@@ -139,7 +139,7 @@ static int TranslateError(int error) {
auto found = error_map.find(error);
if (found != error_map.end())
return -found->second;
-
+
return error;
}
@@ -346,7 +346,7 @@ static void Bind(Service::Interface* self) {
sockaddr sock_addr = CTRSockAddr::ToPlatform(*ctr_sock_addr);
int res = ::bind(socket_handle, &sock_addr, std::max<u32>(sizeof(sock_addr), len));
-
+
int result = 0;
if (res != 0)
result = TranslateError(GET_ERRNO);
@@ -360,14 +360,14 @@ static void Fcntl(Service::Interface* self) {
u32 socket_handle = cmd_buffer[1];
u32 ctr_cmd = cmd_buffer[2];
u32 ctr_arg = cmd_buffer[3];
-
+
int result = 0;
u32 posix_ret = 0; // TODO: Check what hardware returns for F_SETFL (unspecified by POSIX)
SCOPE_EXIT({
cmd_buffer[1] = result;
cmd_buffer[2] = posix_ret;
});
-
+
if (ctr_cmd == 3) { // F_GETFL
#if EMU_PLATFORM == PLATFORM_WINDOWS
posix_ret = 0;
@@ -404,11 +404,11 @@ static void Fcntl(Service::Interface* self) {
posix_ret = -1;
return;
}
-
+
flags &= ~O_NONBLOCK;
if (ctr_arg & 4) // O_NONBLOCK
flags |= O_NONBLOCK;
-
+
int ret = ::fcntl(socket_handle, F_SETFL, flags);
if (ret == SOCKET_ERROR_VALUE) {
result = TranslateError(GET_ERRNO);
@@ -439,8 +439,8 @@ static void Listen(Service::Interface* self) {
}
static void Accept(Service::Interface* self) {
- // TODO(Subv): Calling this function on a blocking socket will block the emu thread,
- // preventing graceful shutdown when closing the emulator, this can be fixed by always
+ // TODO(Subv): Calling this function on a blocking socket will block the emu thread,
+ // preventing graceful shutdown when closing the emulator, this can be fixed by always
// performing nonblocking operations and spinlock until the data is available
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 socket_handle = cmd_buffer[1];
@@ -448,7 +448,7 @@ static void Accept(Service::Interface* self) {
sockaddr addr;
socklen_t addr_len = sizeof(addr);
u32 ret = static_cast<u32>(::accept(socket_handle, &addr, &addr_len));
-
+
if ((s32)ret != SOCKET_ERROR_VALUE)
open_sockets[ret] = { ret, true };
@@ -525,8 +525,8 @@ static void SendTo(Service::Interface* self) {
}
static void RecvFrom(Service::Interface* self) {
- // TODO(Subv): Calling this function on a blocking socket will block the emu thread,
- // preventing graceful shutdown when closing the emulator, this can be fixed by always
+ // TODO(Subv): Calling this function on a blocking socket will block the emu thread,
+ // preventing graceful shutdown when closing the emulator, this can be fixed by always
// performing nonblocking operations and spinlock until the data is available
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 socket_handle = cmd_buffer[1];
@@ -568,7 +568,7 @@ static void Poll(Service::Interface* self) {
pollfd* platform_pollfd = new pollfd[nfds];
for (unsigned current_fds = 0; current_fds < nfds; ++current_fds)
platform_pollfd[current_fds] = CTRPollFD::ToPlatform(input_fds[current_fds]);
-
+
int ret = ::poll(platform_pollfd, nfds, timeout);
// Now update the output pollfd structure
@@ -630,7 +630,7 @@ static void GetPeerName(Service::Interface* self) {
socklen_t len = cmd_buffer[2];
CTRSockAddr* ctr_dest_addr = reinterpret_cast<CTRSockAddr*>(Memory::GetPointer(cmd_buffer[0x104 >> 2]));
-
+
sockaddr dest_addr;
socklen_t dest_addr_len = sizeof(dest_addr);
int ret = ::getpeername(socket_handle, &dest_addr, &dest_addr_len);
@@ -651,8 +651,8 @@ static void GetPeerName(Service::Interface* self) {
}
static void Connect(Service::Interface* self) {
- // TODO(Subv): Calling this function on a blocking socket will block the emu thread,
- // preventing graceful shutdown when closing the emulator, this can be fixed by always
+ // TODO(Subv): Calling this function on a blocking socket will block the emu thread,
+ // preventing graceful shutdown when closing the emulator, this can be fixed by always
// performing nonblocking operations and spinlock until the data is available
u32* cmd_buffer = Kernel::GetCommandBuffer();
u32 socket_handle = cmd_buffer[1];
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index 347d241f..6cde4fc8 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -40,9 +40,6 @@ const ResultCode ERR_NOT_FOUND(ErrorDescription::NotFound, ErrorModule::Kernel,
const ResultCode ERR_PORT_NAME_TOO_LONG(ErrorDescription(30), ErrorModule::OS,
ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E0181E
-/// An invalid result code that is meant to be overwritten when a thread resumes from waiting
-const ResultCode RESULT_INVALID(0xDEADC0DE);
-
enum ControlMemoryOperation {
MEMORY_OPERATION_HEAP = 0x00000003,
MEMORY_OPERATION_GSP_HEAP = 0x00010003,
@@ -143,6 +140,10 @@ static ResultCode CloseHandle(Handle handle) {
/// Wait for a handle to synchronize, timeout after the specified nanoseconds
static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) {
auto object = Kernel::g_handle_table.GetWaitObject(handle);
+ Kernel::Thread* thread = Kernel::GetCurrentThread();
+
+ thread->waitsynch_waited = false;
+
if (object == nullptr)
return ERR_INVALID_HANDLE;
@@ -154,14 +155,14 @@ static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) {
// Check for next thread to schedule
if (object->ShouldWait()) {
- object->AddWaitingThread(Kernel::GetCurrentThread());
+ object->AddWaitingThread(thread);
Kernel::WaitCurrentThread_WaitSynchronization({ object }, false, false);
// Create an event to wake the thread up after the specified nanosecond delay has passed
- Kernel::GetCurrentThread()->WakeAfterDelay(nano_seconds);
+ thread->WakeAfterDelay(nano_seconds);
// NOTE: output of this SVC will be set later depending on how the thread resumes
- return RESULT_INVALID;
+ return HLE::RESULT_INVALID;
}
object->Acquire();
@@ -173,6 +174,9 @@ static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) {
static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) {
bool wait_thread = !wait_all;
int handle_index = 0;
+ Kernel::Thread* thread = Kernel::GetCurrentThread();
+ bool was_waiting = thread->waitsynch_waited;
+ thread->waitsynch_waited = false;
// Check if 'handles' is invalid
if (handles == nullptr)
@@ -190,6 +194,9 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou
// necessary
if (handle_count != 0) {
bool selected = false; // True once an object has been selected
+
+ Kernel::SharedPtr<Kernel::WaitObject> wait_object;
+
for (int i = 0; i < handle_count; ++i) {
auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
if (object == nullptr)
@@ -204,10 +211,11 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou
wait_thread = true;
} else {
// Do not wait on this object, check if this object should be selected...
- if (!wait_all && !selected) {
+ if (!wait_all && (!selected || (wait_object == object && was_waiting))) {
// Do not wait the thread
wait_thread = false;
handle_index = i;
+ wait_object = object;
selected = true;
}
}
@@ -228,7 +236,7 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou
// Actually wait the current thread on each object if we decided to wait...
std::vector<SharedPtr<Kernel::WaitObject>> wait_objects;
wait_objects.reserve(handle_count);
-
+
for (int i = 0; i < handle_count; ++i) {
auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
object->AddWaitingThread(Kernel::GetCurrentThread());
@@ -241,7 +249,7 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou
Kernel::GetCurrentThread()->WakeAfterDelay(nano_seconds);
// NOTE: output of this SVC will be set later depending on how the thread resumes
- return RESULT_INVALID;
+ return HLE::RESULT_INVALID;
}
// Acquire objects if we did not wait...
@@ -261,7 +269,7 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou
// TODO(bunnei): If 'wait_all' is true, this is probably wrong. However, real hardware does
// not seem to set it to any meaningful value.
- *out = wait_all ? 0 : handle_index;
+ *out = handle_count != 0 ? (wait_all ? -1 : handle_index) : 0;
return RESULT_SUCCESS;
}
@@ -475,7 +483,7 @@ static ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle) {
return ERR_INVALID_HANDLE;
const SharedPtr<Kernel::Process> process = thread->owner_process;
-
+
ASSERT_MSG(process != nullptr, "Invalid parent process for thread=0x%08X", thread_handle);
*process_id = process->process_id;
@@ -654,6 +662,8 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32
using Kernel::MemoryPermission;
SharedPtr<SharedMemory> shared_memory = SharedMemory::Create(size,
(MemoryPermission)my_permission, (MemoryPermission)other_permission);
+ // Map the SharedMemory to the specified address
+ shared_memory->base_address = addr;
CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory)));
LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr);