Merge branch 'master' into feature/savestates-2

This commit is contained in:
Hamish Milne 2020-03-07 21:23:08 +00:00
commit da3ab3d56e
80 changed files with 7297 additions and 2608 deletions

View file

@ -83,7 +83,7 @@ bool HandleTable::IsValid(Handle handle) const {
std::shared_ptr<Object> HandleTable::GetGeneric(Handle handle) const {
if (handle == CurrentThread) {
return SharedFrom(kernel.GetThreadManager().GetCurrentThread());
return SharedFrom(kernel.GetCurrentThreadManager().GetCurrentThread());
} else if (handle == CurrentProcess) {
return kernel.GetCurrentProcess();
}

View file

@ -20,22 +20,30 @@ namespace Kernel {
/// Initialize the kernel
KernelSystem::KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing,
std::function<void()> prepare_reschedule_callback, u32 system_mode)
std::function<void()> prepare_reschedule_callback, u32 system_mode,
u32 num_cores, u8 n3ds_mode)
: memory(memory), timing(timing),
prepare_reschedule_callback(std::move(prepare_reschedule_callback)) {
for (auto i = 0; i < memory_regions.size(); i++) {
memory_regions[i] = std::make_shared<MemoryRegionInfo>();
}
MemoryInit(system_mode);
MemoryInit(system_mode, n3ds_mode);
resource_limits = std::make_unique<ResourceLimitList>(*this);
thread_manager = std::make_unique<ThreadManager>(*this);
for (u32 core_id = 0; core_id < num_cores; ++core_id) {
thread_managers.push_back(std::make_unique<ThreadManager>(*this, core_id));
}
timer_manager = std::make_unique<TimerManager>(timing);
ipc_recorder = std::make_unique<IPCDebugger::Recorder>();
stored_processes.assign(num_cores, nullptr);
next_thread_id = 1;
}
/// Shutdown the kernel
KernelSystem::~KernelSystem() = default;
KernelSystem::~KernelSystem() {
ResetThreadIDs();
};
ResourceLimitList& KernelSystem::ResourceLimit() {
return *resource_limits;
@ -58,6 +66,15 @@ void KernelSystem::SetCurrentProcess(std::shared_ptr<Process> process) {
SetCurrentMemoryPageTable(process->vm_manager.page_table);
}
void KernelSystem::SetCurrentProcessForCPU(std::shared_ptr<Process> process, u32 core_id) {
if (current_cpu->GetID() == core_id) {
current_process = process;
SetCurrentMemoryPageTable(process->vm_manager.page_table);
} else {
stored_processes[core_id] = process;
}
}
void KernelSystem::SetCurrentMemoryPageTable(std::shared_ptr<Memory::PageTable> page_table) {
memory.SetCurrentPageTable(page_table);
if (current_cpu != nullptr) {
@ -65,17 +82,39 @@ void KernelSystem::SetCurrentMemoryPageTable(std::shared_ptr<Memory::PageTable>
}
}
void KernelSystem::SetCPU(std::shared_ptr<ARM_Interface> cpu) {
void KernelSystem::SetCPUs(std::vector<std::shared_ptr<ARM_Interface>> cpus) {
ASSERT(cpus.size() == thread_managers.size());
u32 i = 0;
for (const auto& cpu : cpus) {
thread_managers[i++]->SetCPU(*cpu);
}
}
void KernelSystem::SetRunningCPU(std::shared_ptr<ARM_Interface> cpu) {
if (current_process) {
stored_processes[current_cpu->GetID()] = current_process;
}
current_cpu = cpu;
thread_manager->SetCPU(*cpu);
timing.SetCurrentTimer(cpu->GetID());
if (stored_processes[current_cpu->GetID()]) {
SetCurrentProcess(stored_processes[current_cpu->GetID()]);
}
}
ThreadManager& KernelSystem::GetThreadManager() {
return *thread_manager;
ThreadManager& KernelSystem::GetThreadManager(u32 core_id) {
return *thread_managers[core_id];
}
const ThreadManager& KernelSystem::GetThreadManager() const {
return *thread_manager;
const ThreadManager& KernelSystem::GetThreadManager(u32 core_id) const {
return *thread_managers[core_id];
}
ThreadManager& KernelSystem::GetCurrentThreadManager() {
return *thread_managers[current_cpu->GetID()];
}
const ThreadManager& KernelSystem::GetCurrentThreadManager() const {
return *thread_managers[current_cpu->GetID()];
}
TimerManager& KernelSystem::GetTimerManager() {
@ -106,6 +145,14 @@ void KernelSystem::AddNamedPort(std::string name, std::shared_ptr<ClientPort> po
named_ports.emplace(std::move(name), std::move(port));
}
u32 KernelSystem::NewThreadId() {
return next_thread_id++;
}
void KernelSystem::ResetThreadIDs() {
next_thread_id = 0;
}
template <class Archive>
void KernelSystem::serialize(Archive& ar, const unsigned int file_version) {
ar& memory_regions;
@ -118,9 +165,14 @@ void KernelSystem::serialize(Archive& ar, const unsigned int file_version) {
ar& next_process_id;
ar& process_list;
ar& current_process;
ar&* thread_manager.get();
// NB: core count checked in 'core'
for (auto& thread_manager : thread_managers) {
ar&* thread_manager.get();
}
ar& config_mem_handler;
ar& shared_page_handler;
ar& stored_processes;
ar& next_thread_id;
// Deliberately don't include debugger info to allow debugging through loads
}

View file

@ -88,7 +88,8 @@ enum class MemoryRegion : u16 {
class KernelSystem {
public:
explicit KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing,
std::function<void()> prepare_reschedule_callback, u32 system_mode);
std::function<void()> prepare_reschedule_callback, u32 system_mode,
u32 num_cores, u8 n3ds_mode);
~KernelSystem();
using PortPair = std::pair<std::shared_ptr<ServerPort>, std::shared_ptr<ClientPort>>;
@ -214,13 +215,19 @@ public:
std::shared_ptr<Process> GetCurrentProcess() const;
void SetCurrentProcess(std::shared_ptr<Process> process);
void SetCurrentProcessForCPU(std::shared_ptr<Process> process, u32 core_id);
void SetCurrentMemoryPageTable(std::shared_ptr<Memory::PageTable> page_table);
void SetCPU(std::shared_ptr<ARM_Interface> cpu);
void SetCPUs(std::vector<std::shared_ptr<ARM_Interface>> cpu);
ThreadManager& GetThreadManager();
const ThreadManager& GetThreadManager() const;
void SetRunningCPU(std::shared_ptr<ARM_Interface> cpu);
ThreadManager& GetThreadManager(u32 core_id);
const ThreadManager& GetThreadManager(u32 core_id) const;
ThreadManager& GetCurrentThreadManager();
const ThreadManager& GetCurrentThreadManager() const;
TimerManager& GetTimerManager();
const TimerManager& GetTimerManager() const;
@ -246,6 +253,10 @@ public:
prepare_reschedule_callback();
}
u32 NewThreadId();
void ResetThreadIDs();
/// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort
std::unordered_map<std::string, std::shared_ptr<ClientPort>> named_ports;
@ -256,7 +267,7 @@ public:
Core::Timing& timing;
private:
void MemoryInit(u32 mem_type);
void MemoryInit(u32 mem_type, u8 n3ds_mode);
std::function<void()> prepare_reschedule_callback;
@ -280,14 +291,17 @@ private:
std::vector<std::shared_ptr<Process>> process_list;
std::shared_ptr<Process> current_process;
std::vector<std::shared_ptr<Process>> stored_processes;
std::unique_ptr<ThreadManager> thread_manager;
std::vector<std::unique_ptr<ThreadManager>> thread_managers;
std::shared_ptr<ConfigMem::Handler> config_mem_handler;
std::shared_ptr<SharedPage::Handler> shared_page_handler;
std::unique_ptr<IPCDebugger::Recorder> ipc_recorder;
u32 next_thread_id;
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version);

View file

@ -19,6 +19,7 @@
#include "core/hle/kernel/vm_manager.h"
#include "core/hle/result.h"
#include "core/memory.h"
#include "core/settings.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
@ -40,11 +41,32 @@ static const u32 memory_region_sizes[8][3] = {
{0x0B200000, 0x02E00000, 0x02000000}, // 7
};
void KernelSystem::MemoryInit(u32 mem_type) {
// TODO(yuriks): On the n3DS, all o3DS configurations (<=5) are forced to 6 instead.
ASSERT_MSG(mem_type <= 5, "New 3DS memory configuration aren't supported yet!");
namespace MemoryMode {
enum N3DSMode : u8 {
Mode6 = 1,
Mode7 = 2,
Mode6_2 = 3,
};
}
void KernelSystem::MemoryInit(u32 mem_type, u8 n3ds_mode) {
ASSERT(mem_type != 1);
const bool is_new_3ds = Settings::values.is_new_3ds;
u32 reported_mem_type = mem_type;
if (is_new_3ds) {
if (n3ds_mode == MemoryMode::Mode6 || n3ds_mode == MemoryMode::Mode6_2) {
mem_type = 6;
reported_mem_type = 6;
} else if (n3ds_mode == MemoryMode::Mode7) {
mem_type = 7;
reported_mem_type = 7;
} else {
// On the N3ds, all O3ds configurations (<=5) are forced to 6 instead.
mem_type = 6;
}
}
// The kernel allocation regions (APPLICATION, SYSTEM and BASE) are laid out in sequence, with
// the sizes specified in the memory_region_sizes table.
VAddr base = 0;
@ -55,14 +77,12 @@ void KernelSystem::MemoryInit(u32 mem_type) {
}
// We must've allocated the entire FCRAM by the end
ASSERT(base == Memory::FCRAM_SIZE);
ASSERT(base == (is_new_3ds ? Memory::FCRAM_N3DS_SIZE : Memory::FCRAM_SIZE));
config_mem_handler = std::make_shared<ConfigMem::Handler>();
auto& config_mem = config_mem_handler->GetConfigMem();
config_mem.app_mem_type = mem_type;
// app_mem_malloc does not always match the configured size for memory_region[0]: in case the
// n3DS type override is in effect it reports the size the game expects, not the real one.
config_mem.app_mem_alloc = memory_region_sizes[mem_type][0];
config_mem.app_mem_type = reported_mem_type;
config_mem.app_mem_alloc = memory_region_sizes[reported_mem_type][0];
config_mem.sys_mem_alloc = memory_regions[1]->size;
config_mem.base_mem_alloc = memory_regions[2]->size;

View file

@ -39,7 +39,7 @@ std::shared_ptr<Mutex> KernelSystem::CreateMutex(bool initial_locked, std::strin
// Acquire mutex with current thread if initialized as locked
if (initial_locked)
mutex->Acquire(thread_manager->GetCurrentThread());
mutex->Acquire(thread_managers[current_cpu->GetID()]->GetCurrentThread());
return mutex;
}

View file

@ -70,7 +70,7 @@ Handler::Handler(Core::Timing& timing) : timing(timing) {
using namespace std::placeholders;
update_time_event = timing.RegisterEvent("SharedPage::UpdateTimeCallback",
std::bind(&Handler::UpdateTimeCallback, this, _1, _2));
timing.ScheduleEvent(0, update_time_event);
timing.ScheduleEvent(0, update_time_event, 0, 0);
float slidestate = Settings::values.factor_3d / 100.0f;
shared_page.sliderstate_3d = static_cast<float_le>(slidestate);

View file

@ -280,12 +280,12 @@ void SVC::ExitProcess() {
current_process->status = ProcessStatus::Exited;
// Stop all the process threads that are currently waiting for objects.
auto& thread_list = kernel.GetThreadManager().GetThreadList();
auto& thread_list = kernel.GetCurrentThreadManager().GetThreadList();
for (auto& thread : thread_list) {
if (thread->owner_process != current_process)
continue;
if (thread.get() == kernel.GetThreadManager().GetCurrentThread())
if (thread.get() == kernel.GetCurrentThreadManager().GetCurrentThread())
continue;
// TODO(Subv): When are the other running/ready threads terminated?
@ -297,7 +297,7 @@ void SVC::ExitProcess() {
}
// Kill the current thread
kernel.GetThreadManager().GetCurrentThread()->Stop();
kernel.GetCurrentThreadManager().GetCurrentThread()->Stop();
system.PrepareReschedule();
}
@ -388,7 +388,7 @@ ResultCode SVC::SendSyncRequest(Handle handle) {
system.PrepareReschedule();
auto thread = SharedFrom(kernel.GetThreadManager().GetCurrentThread());
auto thread = SharedFrom(kernel.GetCurrentThreadManager().GetCurrentThread());
if (kernel.GetIPCRecorder().IsEnabled()) {
kernel.GetIPCRecorder().RegisterRequest(session, thread);
@ -476,7 +476,7 @@ private:
/// Wait for a handle to synchronize, timeout after the specified nanoseconds
ResultCode SVC::WaitSynchronization1(Handle handle, s64 nano_seconds) {
auto object = kernel.GetCurrentProcess()->handle_table.Get<WaitObject>(handle);
Thread* thread = kernel.GetThreadManager().GetCurrentThread();
Thread* thread = kernel.GetCurrentThreadManager().GetCurrentThread();
if (object == nullptr)
return ERR_INVALID_HANDLE;
@ -514,7 +514,7 @@ ResultCode SVC::WaitSynchronization1(Handle handle, s64 nano_seconds) {
/// Wait for the given handles to synchronize, timeout after the specified nanoseconds
ResultCode SVC::WaitSynchronizationN(s32* out, VAddr handles_address, s32 handle_count,
bool wait_all, s64 nano_seconds) {
Thread* thread = kernel.GetThreadManager().GetCurrentThread();
Thread* thread = kernel.GetCurrentThreadManager().GetCurrentThread();
if (!Memory::IsValidVirtualAddress(*kernel.GetCurrentProcess(), handles_address))
return ERR_INVALID_POINTER;
@ -684,7 +684,7 @@ ResultCode SVC::ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_co
// We are also sending a command reply.
// Do not send a reply if the command id in the command buffer is 0xFFFF.
Thread* thread = kernel.GetThreadManager().GetCurrentThread();
Thread* thread = kernel.GetCurrentThreadManager().GetCurrentThread();
u32 cmd_buff_header = memory.Read32(thread->GetCommandBufferAddress());
IPC::Header header{cmd_buff_header};
if (reply_target != 0 && header.command_id != 0xFFFF) {
@ -791,7 +791,7 @@ ResultCode SVC::ArbitrateAddress(Handle handle, u32 address, u32 type, u32 value
return ERR_INVALID_HANDLE;
auto res =
arbiter->ArbitrateAddress(SharedFrom(kernel.GetThreadManager().GetCurrentThread()),
arbiter->ArbitrateAddress(SharedFrom(kernel.GetCurrentThreadManager().GetCurrentThread()),
static_cast<ArbitrationType>(type), address, value, nanoseconds);
// TODO(Subv): Identify in which specific cases this call should cause a reschedule.
@ -912,14 +912,19 @@ ResultCode SVC::CreateThread(Handle* out_handle, u32 entry_point, u32 arg, VAddr
break;
case ThreadProcessorIdAll:
LOG_INFO(Kernel_SVC,
"Newly created thread is allowed to be run in any Core, unimplemented.");
"Newly created thread is allowed to be run in any Core, for now run in core 0.");
processor_id = ThreadProcessorId0;
break;
case ThreadProcessorId1:
LOG_ERROR(Kernel_SVC,
"Newly created thread must run in the SysCore (Core1), unimplemented.");
case ThreadProcessorId2:
case ThreadProcessorId3:
// TODO: Check and log for: When processorid==0x2 and the process is not a BASE mem-region
// process, exheader kernel-flags bitmask 0x2000 must be set (otherwise error 0xD9001BEA is
// returned). When processorid==0x3 and the process is not a BASE mem-region process, error
// 0xD9001BEA is returned. These are the only restriction checks done by the kernel for
// processorid.
break;
default:
// TODO(bunnei): Implement support for other processor IDs
ASSERT_MSG(false, "Unsupported thread processor ID: {}", processor_id);
break;
}
@ -945,9 +950,9 @@ ResultCode SVC::CreateThread(Handle* out_handle, u32 entry_point, u32 arg, VAddr
/// Called when a thread exits
void SVC::ExitThread() {
LOG_TRACE(Kernel_SVC, "called, pc=0x{:08X}", system.CPU().GetPC());
LOG_TRACE(Kernel_SVC, "called, pc=0x{:08X}", system.GetRunningCore().GetPC());
kernel.GetThreadManager().ExitCurrentThread();
kernel.GetCurrentThreadManager().ExitCurrentThread();
system.PrepareReschedule();
}
@ -993,7 +998,7 @@ ResultCode SVC::SetThreadPriority(Handle handle, u32 priority) {
/// Create a mutex
ResultCode SVC::CreateMutex(Handle* out_handle, u32 initial_locked) {
std::shared_ptr<Mutex> mutex = kernel.CreateMutex(initial_locked != 0);
mutex->name = fmt::format("mutex-{:08x}", system.CPU().GetReg(14));
mutex->name = fmt::format("mutex-{:08x}", system.GetRunningCore().GetReg(14));
CASCADE_RESULT(*out_handle, kernel.GetCurrentProcess()->handle_table.Create(std::move(mutex)));
LOG_TRACE(Kernel_SVC, "called initial_locked={} : created handle=0x{:08X}",
@ -1010,7 +1015,7 @@ ResultCode SVC::ReleaseMutex(Handle handle) {
if (mutex == nullptr)
return ERR_INVALID_HANDLE;
return mutex->Release(kernel.GetThreadManager().GetCurrentThread());
return mutex->Release(kernel.GetCurrentThreadManager().GetCurrentThread());
}
/// Get the ID of the specified process
@ -1060,7 +1065,7 @@ ResultCode SVC::GetThreadId(u32* thread_id, Handle handle) {
ResultCode SVC::CreateSemaphore(Handle* out_handle, s32 initial_count, s32 max_count) {
CASCADE_RESULT(std::shared_ptr<Semaphore> semaphore,
kernel.CreateSemaphore(initial_count, max_count));
semaphore->name = fmt::format("semaphore-{:08x}", system.CPU().GetReg(14));
semaphore->name = fmt::format("semaphore-{:08x}", system.GetRunningCore().GetReg(14));
CASCADE_RESULT(*out_handle,
kernel.GetCurrentProcess()->handle_table.Create(std::move(semaphore)));
@ -1130,8 +1135,9 @@ ResultCode SVC::QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, u32 ad
/// Create an event
ResultCode SVC::CreateEvent(Handle* out_handle, u32 reset_type) {
std::shared_ptr<Event> evt = kernel.CreateEvent(
static_cast<ResetType>(reset_type), fmt::format("event-{:08x}", system.CPU().GetReg(14)));
std::shared_ptr<Event> evt =
kernel.CreateEvent(static_cast<ResetType>(reset_type),
fmt::format("event-{:08x}", system.GetRunningCore().GetReg(14)));
CASCADE_RESULT(*out_handle, kernel.GetCurrentProcess()->handle_table.Create(std::move(evt)));
LOG_TRACE(Kernel_SVC, "called reset_type=0x{:08X} : created handle=0x{:08X}", reset_type,
@ -1173,8 +1179,9 @@ ResultCode SVC::ClearEvent(Handle handle) {
/// Creates a timer
ResultCode SVC::CreateTimer(Handle* out_handle, u32 reset_type) {
std::shared_ptr<Timer> timer = kernel.CreateTimer(
static_cast<ResetType>(reset_type), fmt ::format("timer-{:08x}", system.CPU().GetReg(14)));
std::shared_ptr<Timer> timer =
kernel.CreateTimer(static_cast<ResetType>(reset_type),
fmt ::format("timer-{:08x}", system.GetRunningCore().GetReg(14)));
CASCADE_RESULT(*out_handle, kernel.GetCurrentProcess()->handle_table.Create(std::move(timer)));
LOG_TRACE(Kernel_SVC, "called reset_type=0x{:08X} : created handle=0x{:08X}", reset_type,
@ -1228,7 +1235,7 @@ ResultCode SVC::CancelTimer(Handle handle) {
void SVC::SleepThread(s64 nanoseconds) {
LOG_TRACE(Kernel_SVC, "called nanoseconds={}", nanoseconds);
ThreadManager& thread_manager = kernel.GetThreadManager();
ThreadManager& thread_manager = kernel.GetCurrentThreadManager();
// Don't attempt to yield execution if there are no available threads to run,
// this way we avoid a useless reschedule to the idle thread.
@ -1246,10 +1253,11 @@ void SVC::SleepThread(s64 nanoseconds) {
/// This returns the total CPU ticks elapsed since the CPU was powered-on
s64 SVC::GetSystemTick() {
s64 result = system.CoreTiming().GetTicks();
// TODO: Use globalTicks here?
s64 result = system.GetRunningCore().GetTimer()->GetTicks();
// Advance time to defeat dumb games (like Cubic Ninja) that busy-wait for the frame to end.
// Measured time between two calls on a 9.2 o3DS with Ninjhax 1.1b
system.CoreTiming().AddTicks(150);
system.GetRunningCore().GetTimer()->AddTicks(150);
return result;
}
@ -1611,11 +1619,11 @@ void SVC::CallSVC(u32 immediate) {
SVC::SVC(Core::System& system) : system(system), kernel(system.Kernel()), memory(system.Memory()) {}
u32 SVC::GetReg(std::size_t n) {
return system.CPU().GetReg(static_cast<int>(n));
return system.GetRunningCore().GetReg(static_cast<int>(n));
}
void SVC::SetReg(std::size_t n, u32 value) {
system.CPU().SetReg(static_cast<int>(n), value);
system.GetRunningCore().SetReg(static_cast<int>(n), value);
}
SVCContext::SVCContext(Core::System& system) : impl(std::make_unique<SVC>(system)) {}

View file

@ -62,13 +62,10 @@ void Thread::Acquire(Thread* thread) {
ASSERT_MSG(!ShouldWait(thread), "object unavailable!");
}
u32 ThreadManager::NewThreadId() {
return next_thread_id++;
}
Thread::Thread(KernelSystem& kernel)
: WaitObject(kernel), context(kernel.GetThreadManager().NewContext()),
thread_manager(kernel.GetThreadManager()) {}
Thread::Thread(KernelSystem& kernel, u32 core_id)
: WaitObject(kernel), context(kernel.GetThreadManager(core_id).NewContext()),
core_id(core_id),
thread_manager(kernel.GetThreadManager(core_id)) {}
Thread::~Thread() {}
Thread* ThreadManager::GetCurrentThread() const {
@ -113,7 +110,7 @@ void ThreadManager::SwitchContext(Thread* new_thread) {
// Save context for previous thread
if (previous_thread) {
previous_thread->last_running_ticks = timing.GetTicks();
previous_thread->last_running_ticks = timing.GetGlobalTicks();
cpu->SaveContext(previous_thread->context);
if (previous_thread->status == ThreadStatus::Running) {
@ -140,7 +137,7 @@ void ThreadManager::SwitchContext(Thread* new_thread) {
new_thread->status = ThreadStatus::Running;
if (previous_process != current_thread->owner_process) {
kernel.SetCurrentProcess(current_thread->owner_process);
kernel.SetCurrentProcessForCPU(current_thread->owner_process, cpu->GetID());
}
cpu->LoadContext(new_thread->context);
@ -153,7 +150,7 @@ void ThreadManager::SwitchContext(Thread* new_thread) {
}
Thread* ThreadManager::PopNextReadyThread() {
Thread* next;
Thread* next = nullptr;
Thread* thread = GetCurrentThread();
if (thread && thread->status == ThreadStatus::Running) {
@ -337,22 +334,22 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(
ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
}
auto thread{std::make_shared<Thread>(*this)};
auto thread{std::make_shared<Thread>(*this, processor_id)};
thread_manager->thread_list.push_back(thread);
thread_manager->ready_queue.prepare(priority);
thread_managers[processor_id]->thread_list.push_back(thread);
thread_managers[processor_id]->ready_queue.prepare(priority);
thread->thread_id = thread_manager->NewThreadId();
thread->thread_id = NewThreadId();
thread->status = ThreadStatus::Dormant;
thread->entry_point = entry_point;
thread->stack_top = stack_top;
thread->nominal_priority = thread->current_priority = priority;
thread->last_running_ticks = timing.GetTicks();
thread->last_running_ticks = timing.GetGlobalTicks();
thread->processor_id = processor_id;
thread->wait_objects.clear();
thread->wait_address = 0;
thread->name = std::move(name);
thread_manager->wakeup_callback_table[thread->thread_id] = thread.get();
thread_managers[processor_id]->wakeup_callback_table[thread->thread_id] = thread.get();
thread->owner_process = owner_process;
// Find the next available TLS index, and mark it as used
@ -397,7 +394,7 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(
// to initialize the context
ResetThreadContext(thread->context, stack_top, entry_point, arg);
thread_manager->ready_queue.push_back(thread->current_priority, thread.get());
thread_managers[processor_id]->ready_queue.push_back(thread->current_priority, thread.get());
thread->status = ThreadStatus::Ready;
return MakeResult<std::shared_ptr<Thread>>(std::move(thread));
@ -463,6 +460,9 @@ void ThreadManager::Reschedule() {
LOG_TRACE(Kernel, "context switch {} -> idle", cur->GetObjectId());
} else if (next) {
LOG_TRACE(Kernel, "context switch idle -> {}", next->GetObjectId());
} else {
LOG_TRACE(Kernel, "context switch idle -> idle, do nothing");
return;
}
SwitchContext(next);
@ -489,11 +489,10 @@ VAddr Thread::GetCommandBufferAddress() const {
return GetTLSAddress() + command_header_offset;
}
ThreadManager::ThreadManager(Kernel::KernelSystem& kernel) : kernel(kernel) {
ThreadWakeupEventType =
kernel.timing.RegisterEvent("ThreadWakeupCallback", [this](u64 thread_id, s64 cycle_late) {
ThreadWakeupCallback(thread_id, cycle_late);
});
ThreadManager::ThreadManager(Kernel::KernelSystem& kernel, u32 core_id) : kernel(kernel) {
ThreadWakeupEventType = kernel.timing.RegisterEvent(
"ThreadWakeupCallback_" + std::to_string(core_id),
[this](u64 thread_id, s64 cycle_late) { ThreadWakeupCallback(thread_id, cycle_late); });
}
ThreadManager::~ThreadManager() {

View file

@ -38,7 +38,9 @@ enum ThreadProcessorId : s32 {
ThreadProcessorIdAll = -1, ///< Run thread on either core
ThreadProcessorId0 = 0, ///< Run thread on core 0 (AppCore)
ThreadProcessorId1 = 1, ///< Run thread on core 1 (SysCore)
ThreadProcessorIdMax = 2, ///< Processor ID must be less than this
ThreadProcessorId2 = 2, ///< Run thread on core 2 (additional n3ds core)
ThreadProcessorId3 = 3, ///< Run thread on core 3 (additional n3ds core)
ThreadProcessorIdMax = 4, ///< Processor ID must be less than this
};
enum class ThreadStatus {
@ -75,15 +77,9 @@ private:
class ThreadManager {
public:
explicit ThreadManager(Kernel::KernelSystem& kernel);
explicit ThreadManager(Kernel::KernelSystem& kernel, u32 core_id);
~ThreadManager();
/**
* Creates a new thread ID
* @return The new thread ID
*/
u32 NewThreadId();
/**
* Gets the current thread
*/
@ -150,7 +146,6 @@ private:
Kernel::KernelSystem& kernel;
ARM_Interface* cpu;
u32 next_thread_id = 1;
std::shared_ptr<Thread> current_thread;
Common::ThreadQueueList<Thread*, ThreadPrioLowest + 1> ready_queue;
std::unordered_map<u64, Thread*> wakeup_callback_table;
@ -167,7 +162,6 @@ private:
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) {
ar& next_thread_id;
ar& current_thread;
ar& ready_queue;
ar& wakeup_callback_table;
@ -177,7 +171,7 @@ private:
class Thread final : public WaitObject {
public:
explicit Thread(KernelSystem&);
explicit Thread(KernelSystem&, u32 core_id);
~Thread() override;
std::string GetName() const override {
@ -329,6 +323,8 @@ public:
// available. In case of a timeout, the object will be nullptr.
std::shared_ptr<WakeupCallback> wakeup_callback;
const u32 core_id;
private:
ThreadManager& thread_manager;
@ -351,4 +347,20 @@ std::shared_ptr<Thread> SetupMainThread(KernelSystem& kernel, u32 entry_point, u
} // namespace Kernel
BOOST_CLASS_EXPORT_KEY(Kernel::Thread)
CONSTRUCT_KERNEL_OBJECT(Kernel::Thread)
namespace boost::serialization {
template <class Archive>
inline void save_construct_data(Archive& ar, const Kernel::Thread* t,
const unsigned int file_version) {
ar << t->core_id;
}
template <class Archive>
inline void load_construct_data(Archive& ar, Kernel::Thread* t, const unsigned int file_version) {
u32 core_id;
ar >> core_id;
::new (t) Kernel::Thread(Core::Global<Kernel::KernelSystem>(), core_id);
}
} // namespace boost::serialization

View file

@ -6,9 +6,7 @@
#include <array>
#include <atomic>
#ifndef _MSC_VER
#include <cstddef>
#endif
#include <memory>
#include "common/bit_field.h"
#include "common/common_funcs.h"
@ -177,10 +175,6 @@ struct GyroscopeCalibrateParam {
} x, y, z;
};
// TODO: MSVC does not support using offsetof() on non-static data members even though this
// is technically allowed since C++11. This macro should be enabled once MSVC adds
// support for that.
#ifndef _MSC_VER
#define ASSERT_REG_POSITION(field_name, position) \
static_assert(offsetof(SharedMem, field_name) == position * 4, \
"Field " #field_name " has invalid position")
@ -189,7 +183,6 @@ ASSERT_REG_POSITION(pad.index_reset_ticks, 0x0);
ASSERT_REG_POSITION(touch.index_reset_ticks, 0x2A);
#undef ASSERT_REG_POSITION
#endif // !defined(_MSC_VER)
struct DirectionState {
bool up;

View file

@ -2,9 +2,14 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <atomic>
#ifdef ENABLE_WEB_SERVICE
#include <LUrlParser.h>
#endif
#include <cryptopp/aes.h>
#include <cryptopp/modes.h>
#include "common/archives.h"
#include "common/assert.h"
#include "core/core.h"
#include "core/file_sys/archive_ncch.h"
#include "core/file_sys/file_backend.h"
@ -52,6 +57,82 @@ const ResultCode ERROR_WRONG_CERT_HANDLE = // 0xD8A0A0C9
const ResultCode ERROR_CERT_ALREADY_SET = // 0xD8A0A03D
ResultCode(61, ErrorModule::HTTP, ErrorSummary::InvalidState, ErrorLevel::Permanent);
void Context::MakeRequest() {
ASSERT(state == RequestState::NotStarted);
#ifdef ENABLE_WEB_SERVICE
LUrlParser::clParseURL parsedUrl = LUrlParser::clParseURL::ParseURL(url);
int port;
std::unique_ptr<httplib::Client> client;
if (parsedUrl.m_Scheme == "http") {
if (!parsedUrl.GetPort(&port)) {
port = 80;
}
// TODO(B3N30): Support for setting timeout
// Figure out what the default timeout on 3DS is
client = std::make_unique<httplib::Client>(parsedUrl.m_Host.c_str(), port);
} else {
if (!parsedUrl.GetPort(&port)) {
port = 443;
}
// TODO(B3N30): Support for setting timeout
// Figure out what the default timeout on 3DS is
auto ssl_client = std::make_unique<httplib::SSLClient>(parsedUrl.m_Host, port);
SSL_CTX* ctx = ssl_client->ssl_context();
client = std::move(ssl_client);
if (auto client_cert = ssl_config.client_cert_ctx.lock()) {
SSL_CTX_use_certificate_ASN1(ctx, client_cert->certificate.size(),
client_cert->certificate.data());
SSL_CTX_use_PrivateKey_ASN1(EVP_PKEY_RSA, ctx, client_cert->private_key.data(),
client_cert->private_key.size());
}
// TODO(B3N30): Check for SSLOptions-Bits and set the verify method accordingly
// https://www.3dbrew.org/wiki/SSL_Services#SSLOpt
// Hack: Since for now RootCerts are not implemented we set the VerifyMode to None.
SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
}
state = RequestState::InProgress;
static const std::unordered_map<RequestMethod, std::string> request_method_strings{
{RequestMethod::Get, "GET"}, {RequestMethod::Post, "POST"},
{RequestMethod::Head, "HEAD"}, {RequestMethod::Put, "PUT"},
{RequestMethod::Delete, "DELETE"}, {RequestMethod::PostEmpty, "POST"},
{RequestMethod::PutEmpty, "PUT"},
};
httplib::Request request;
request.method = request_method_strings.at(method);
request.path = url;
// TODO(B3N30): Add post data body
request.progress = [this](u64 current, u64 total) -> bool {
// TODO(B3N30): Is there a state that shows response header are available
current_download_size_bytes = current;
total_download_size_bytes = total;
return true;
};
for (const auto& header : headers) {
request.headers.emplace(header.name, header.value);
}
if (!client->send(request, response)) {
LOG_ERROR(Service_HTTP, "Request failed");
state = RequestState::TimedOut;
} else {
LOG_DEBUG(Service_HTTP, "Request successful");
// TODO(B3N30): Verify this state on HW
state = RequestState::ReadyToDownloadContent;
}
#else
LOG_ERROR(Service_HTTP, "Tried to make request but WebServices is not enabled in this build");
state = RequestState::TimedOut;
#endif
}
void HTTP_C::Initialize(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x1, 1, 4);
const u32 shmem_size = rp.Pop<u32>();
@ -156,7 +237,15 @@ void HTTP_C::BeginRequest(Kernel::HLERequestContext& ctx) {
auto itr = contexts.find(context_handle);
ASSERT(itr != contexts.end());
// TODO(B3N30): Make the request
// On a 3DS BeginRequest and BeginRequestAsync will push the Request to a worker queue.
// You can only enqueue 8 requests at the same time.
// trying to enqueue any more will either fail (BeginRequestAsync), or block (BeginRequest)
// Note that you only can have 8 Contexts at a time. So this difference shouldn't matter
// Then there are 3? worker threads that pop the requests from the queue and send them
// For now make every request async in it's own thread.
itr->second.request_future =
std::async(std::launch::async, &Context::MakeRequest, std::ref(itr->second));
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(RESULT_SUCCESS);
@ -201,7 +290,15 @@ void HTTP_C::BeginRequestAsync(Kernel::HLERequestContext& ctx) {
auto itr = contexts.find(context_handle);
ASSERT(itr != contexts.end());
// TODO(B3N30): Make the request
// On a 3DS BeginRequest and BeginRequestAsync will push the Request to a worker queue.
// You can only enqueue 8 requests at the same time.
// trying to enqueue any more will either fail (BeginRequestAsync), or block (BeginRequest)
// Note that you only can have 8 Contexts at a time. So this difference shouldn't matter
// Then there are 3? worker threads that pop the requests from the queue and send them
// For now make every request async in it's own thread.
itr->second.request_future =
std::async(std::launch::async, &Context::MakeRequest, std::ref(itr->second));
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(RESULT_SUCCESS);
@ -264,7 +361,7 @@ void HTTP_C::CreateContext(Kernel::HLERequestContext& ctx) {
return;
}
contexts.emplace(++context_counter, Context());
contexts.try_emplace(++context_counter);
contexts[context_counter].url = std::move(url);
contexts[context_counter].method = method;
contexts[context_counter].state = RequestState::NotStarted;
@ -311,10 +408,9 @@ void HTTP_C::CloseContext(Kernel::HLERequestContext& ctx) {
}
// TODO(Subv): What happens if you try to close a context that's currently being used?
ASSERT(itr->second.state == RequestState::NotStarted);
// TODO(Subv): Make sure that only the session that created the context can close it.
// Note that this will block if a request is still in progress
contexts.erase(itr);
session_data->num_http_contexts--;

View file

@ -4,6 +4,7 @@
#pragma once
#include <future>
#include <memory>
#include <string>
#include <unordered_map>
@ -15,6 +16,12 @@
#include <boost/serialization/unordered_map.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/weak_ptr.hpp>
#ifdef ENABLE_WEB_SERVICE
#if defined(__ANDROID__)
#include <ifaddrs.h>
#endif
#include <httplib.h>
#endif
#include "core/hle/kernel/shared_memory.h"
#include "core/hle/service/service.h"
@ -113,8 +120,7 @@ public:
Context(const Context&) = delete;
Context& operator=(const Context&) = delete;
Context(Context&& other) = default;
Context& operator=(Context&&) = default;
void MakeRequest();
struct Proxy {
std::string url;
@ -195,14 +201,21 @@ public:
u32 session_id;
std::string url;
RequestMethod method;
RequestState state = RequestState::NotStarted;
boost::optional<Proxy> proxy;
boost::optional<BasicAuth> basic_auth;
std::atomic<RequestState> state = RequestState::NotStarted;
std::optional<Proxy> proxy;
std::optional<BasicAuth> basic_auth;
SSLConfig ssl_config{};
u32 socket_buffer_size;
std::vector<RequestHeader> headers;
std::vector<PostData> post_data;
std::future<void> request_future;
std::atomic<u64> current_download_size_bytes;
std::atomic<u64> total_download_size_bytes;
#ifdef ENABLE_WEB_SERVICE
httplib::Response response;
#endif
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
@ -219,6 +232,7 @@ private:
ar& post_data;
}
friend class boost::serialization::access;
};
struct SessionData : public Kernel::SessionRequestHandler::SessionDataBase {

View file

@ -55,7 +55,7 @@ VAddr CROHelper::SegmentTagToAddress(SegmentTag segment_tag) const {
return 0;
SegmentEntry entry;
GetEntry(memory, segment_tag.segment_index, entry);
GetEntry(system.Memory(), segment_tag.segment_index, entry);
if (segment_tag.offset_into_segment >= entry.size)
return 0;
@ -71,12 +71,12 @@ ResultCode CROHelper::ApplyRelocation(VAddr target_address, RelocationType reloc
break;
case RelocationType::AbsoluteAddress:
case RelocationType::AbsoluteAddress2:
memory.Write32(target_address, symbol_address + addend);
cpu.InvalidateCacheRange(target_address, sizeof(u32));
system.Memory().Write32(target_address, symbol_address + addend);
system.InvalidateCacheRange(target_address, sizeof(u32));
break;
case RelocationType::RelativeAddress:
memory.Write32(target_address, symbol_address + addend - target_future_address);
cpu.InvalidateCacheRange(target_address, sizeof(u32));
system.Memory().Write32(target_address, symbol_address + addend - target_future_address);
system.InvalidateCacheRange(target_address, sizeof(u32));
break;
case RelocationType::ThumbBranch:
case RelocationType::ArmBranch:
@ -98,8 +98,8 @@ ResultCode CROHelper::ClearRelocation(VAddr target_address, RelocationType reloc
case RelocationType::AbsoluteAddress:
case RelocationType::AbsoluteAddress2:
case RelocationType::RelativeAddress:
memory.Write32(target_address, 0);
cpu.InvalidateCacheRange(target_address, sizeof(u32));
system.Memory().Write32(target_address, 0);
system.InvalidateCacheRange(target_address, sizeof(u32));
break;
case RelocationType::ThumbBranch:
case RelocationType::ArmBranch:
@ -121,7 +121,8 @@ ResultCode CROHelper::ApplyRelocationBatch(VAddr batch, u32 symbol_address, bool
VAddr relocation_address = batch;
while (true) {
RelocationEntry relocation;
memory.ReadBlock(process, relocation_address, &relocation, sizeof(RelocationEntry));
system.Memory().ReadBlock(process, relocation_address, &relocation,
sizeof(RelocationEntry));
VAddr relocation_target = SegmentTagToAddress(relocation.target_position);
if (relocation_target == 0) {
@ -142,9 +143,9 @@ ResultCode CROHelper::ApplyRelocationBatch(VAddr batch, u32 symbol_address, bool
}
RelocationEntry relocation;
memory.ReadBlock(process, batch, &relocation, sizeof(RelocationEntry));
system.Memory().ReadBlock(process, batch, &relocation, sizeof(RelocationEntry));
relocation.is_batch_resolved = reset ? 0 : 1;
memory.WriteBlock(process, batch, &relocation, sizeof(RelocationEntry));
system.Memory().WriteBlock(process, batch, &relocation, sizeof(RelocationEntry));
return RESULT_SUCCESS;
}
@ -154,13 +155,13 @@ VAddr CROHelper::FindExportNamedSymbol(const std::string& name) const {
std::size_t len = name.size();
ExportTreeEntry entry;
GetEntry(memory, 0, entry);
GetEntry(system.Memory(), 0, entry);
ExportTreeEntry::Child next;
next.raw = entry.left.raw;
u32 found_id;
while (true) {
GetEntry(memory, next.next_index, entry);
GetEntry(system.Memory(), next.next_index, entry);
if (next.is_end) {
found_id = entry.export_table_index;
@ -186,9 +187,9 @@ VAddr CROHelper::FindExportNamedSymbol(const std::string& name) const {
u32 export_strings_size = GetField(ExportStringsSize);
ExportNamedSymbolEntry symbol_entry;
GetEntry(memory, found_id, symbol_entry);
GetEntry(system.Memory(), found_id, symbol_entry);
if (memory.ReadCString(symbol_entry.name_offset, export_strings_size) != name)
if (system.Memory().ReadCString(symbol_entry.name_offset, export_strings_size) != name)
return 0;
return SegmentTagToAddress(symbol_entry.symbol_position);
@ -279,7 +280,7 @@ ResultVal<VAddr> CROHelper::RebaseSegmentTable(u32 cro_size, VAddr data_segment_
u32 segment_num = GetField(SegmentNum);
for (u32 i = 0; i < segment_num; ++i) {
SegmentEntry segment;
GetEntry(memory, i, segment);
GetEntry(system.Memory(), i, segment);
if (segment.type == SegmentType::Data) {
if (segment.size != 0) {
if (segment.size > data_segment_size)
@ -298,7 +299,7 @@ ResultVal<VAddr> CROHelper::RebaseSegmentTable(u32 cro_size, VAddr data_segment_
if (segment.offset > module_address + cro_size)
return CROFormatError(0x19);
}
SetEntry(memory, i, segment);
SetEntry(system.Memory(), i, segment);
}
return MakeResult<u32>(prev_data_segment + module_address);
}
@ -310,7 +311,7 @@ ResultCode CROHelper::RebaseExportNamedSymbolTable() {
u32 export_named_symbol_num = GetField(ExportNamedSymbolNum);
for (u32 i = 0; i < export_named_symbol_num; ++i) {
ExportNamedSymbolEntry entry;
GetEntry(memory, i, entry);
GetEntry(system.Memory(), i, entry);
if (entry.name_offset != 0) {
entry.name_offset += module_address;
@ -320,7 +321,7 @@ ResultCode CROHelper::RebaseExportNamedSymbolTable() {
}
}
SetEntry(memory, i, entry);
SetEntry(system.Memory(), i, entry);
}
return RESULT_SUCCESS;
}
@ -329,7 +330,7 @@ ResultCode CROHelper::VerifyExportTreeTable() const {
u32 tree_num = GetField(ExportTreeNum);
for (u32 i = 0; i < tree_num; ++i) {
ExportTreeEntry entry;
GetEntry(memory, i, entry);
GetEntry(system.Memory(), i, entry);
if (entry.left.next_index >= tree_num || entry.right.next_index >= tree_num) {
return CROFormatError(0x11);
@ -353,7 +354,7 @@ ResultCode CROHelper::RebaseImportModuleTable() {
u32 module_num = GetField(ImportModuleNum);
for (u32 i = 0; i < module_num; ++i) {
ImportModuleEntry entry;
GetEntry(memory, i, entry);
GetEntry(system.Memory(), i, entry);
if (entry.name_offset != 0) {
entry.name_offset += module_address;
@ -379,7 +380,7 @@ ResultCode CROHelper::RebaseImportModuleTable() {
}
}
SetEntry(memory, i, entry);
SetEntry(system.Memory(), i, entry);
}
return RESULT_SUCCESS;
}
@ -395,7 +396,7 @@ ResultCode CROHelper::RebaseImportNamedSymbolTable() {
u32 num = GetField(ImportNamedSymbolNum);
for (u32 i = 0; i < num; ++i) {
ImportNamedSymbolEntry entry;
GetEntry(memory, i, entry);
GetEntry(system.Memory(), i, entry);
if (entry.name_offset != 0) {
entry.name_offset += module_address;
@ -413,7 +414,7 @@ ResultCode CROHelper::RebaseImportNamedSymbolTable() {
}
}
SetEntry(memory, i, entry);
SetEntry(system.Memory(), i, entry);
}
return RESULT_SUCCESS;
}
@ -427,7 +428,7 @@ ResultCode CROHelper::RebaseImportIndexedSymbolTable() {
u32 num = GetField(ImportIndexedSymbolNum);
for (u32 i = 0; i < num; ++i) {
ImportIndexedSymbolEntry entry;
GetEntry(memory, i, entry);
GetEntry(system.Memory(), i, entry);
if (entry.relocation_batch_offset != 0) {
entry.relocation_batch_offset += module_address;
@ -437,7 +438,7 @@ ResultCode CROHelper::RebaseImportIndexedSymbolTable() {
}
}
SetEntry(memory, i, entry);
SetEntry(system.Memory(), i, entry);
}
return RESULT_SUCCESS;
}
@ -451,7 +452,7 @@ ResultCode CROHelper::RebaseImportAnonymousSymbolTable() {
u32 num = GetField(ImportAnonymousSymbolNum);
for (u32 i = 0; i < num; ++i) {
ImportAnonymousSymbolEntry entry;
GetEntry(memory, i, entry);
GetEntry(system.Memory(), i, entry);
if (entry.relocation_batch_offset != 0) {
entry.relocation_batch_offset += module_address;
@ -461,7 +462,7 @@ ResultCode CROHelper::RebaseImportAnonymousSymbolTable() {
}
}
SetEntry(memory, i, entry);
SetEntry(system.Memory(), i, entry);
}
return RESULT_SUCCESS;
}
@ -476,14 +477,14 @@ ResultCode CROHelper::ResetExternalRelocations() {
ExternalRelocationEntry relocation;
// Verifies that the last relocation is the end of a batch
GetEntry(memory, external_relocation_num - 1, relocation);
GetEntry(system.Memory(), external_relocation_num - 1, relocation);
if (!relocation.is_batch_end) {
return CROFormatError(0x12);
}
bool batch_begin = true;
for (u32 i = 0; i < external_relocation_num; ++i) {
GetEntry(memory, i, relocation);
GetEntry(system.Memory(), i, relocation);
VAddr relocation_target = SegmentTagToAddress(relocation.target_position);
if (relocation_target == 0) {
@ -500,7 +501,7 @@ ResultCode CROHelper::ResetExternalRelocations() {
if (batch_begin) {
// resets to unresolved state
relocation.is_batch_resolved = 0;
SetEntry(memory, i, relocation);
SetEntry(system.Memory(), i, relocation);
}
// if current is an end, then the next is a beginning
@ -516,7 +517,7 @@ ResultCode CROHelper::ClearExternalRelocations() {
bool batch_begin = true;
for (u32 i = 0; i < external_relocation_num; ++i) {
GetEntry(memory, i, relocation);
GetEntry(system.Memory(), i, relocation);
VAddr relocation_target = SegmentTagToAddress(relocation.target_position);
if (relocation_target == 0) {
@ -532,7 +533,7 @@ ResultCode CROHelper::ClearExternalRelocations() {
if (batch_begin) {
// resets to unresolved state
relocation.is_batch_resolved = 0;
SetEntry(memory, i, relocation);
SetEntry(system.Memory(), i, relocation);
}
// if current is an end, then the next is a beginning
@ -548,13 +549,13 @@ ResultCode CROHelper::ApplyStaticAnonymousSymbolToCRS(VAddr crs_address) {
static_relocation_table_offset +
GetField(StaticRelocationNum) * sizeof(StaticRelocationEntry);
CROHelper crs(crs_address, process, memory, cpu);
CROHelper crs(crs_address, process, system);
u32 offset_export_num = GetField(StaticAnonymousSymbolNum);
LOG_INFO(Service_LDR, "CRO \"{}\" exports {} static anonymous symbols", ModuleName(),
offset_export_num);
for (u32 i = 0; i < offset_export_num; ++i) {
StaticAnonymousSymbolEntry entry;
GetEntry(memory, i, entry);
GetEntry(system.Memory(), i, entry);
u32 batch_address = entry.relocation_batch_offset + module_address;
if (batch_address < static_relocation_table_offset ||
@ -579,7 +580,7 @@ ResultCode CROHelper::ApplyInternalRelocations(u32 old_data_segment_address) {
u32 internal_relocation_num = GetField(InternalRelocationNum);
for (u32 i = 0; i < internal_relocation_num; ++i) {
InternalRelocationEntry relocation;
GetEntry(memory, i, relocation);
GetEntry(system.Memory(), i, relocation);
VAddr target_addressB = SegmentTagToAddress(relocation.target_position);
if (target_addressB == 0) {
return CROFormatError(0x15);
@ -587,7 +588,7 @@ ResultCode CROHelper::ApplyInternalRelocations(u32 old_data_segment_address) {
VAddr target_address;
SegmentEntry target_segment;
GetEntry(memory, relocation.target_position.segment_index, target_segment);
GetEntry(system.Memory(), relocation.target_position.segment_index, target_segment);
if (target_segment.type == SegmentType::Data) {
// If the relocation is to the .data segment, we need to relocate it in the old buffer
@ -602,7 +603,7 @@ ResultCode CROHelper::ApplyInternalRelocations(u32 old_data_segment_address) {
}
SegmentEntry symbol_segment;
GetEntry(memory, relocation.symbol_segment, symbol_segment);
GetEntry(system.Memory(), relocation.symbol_segment, symbol_segment);
LOG_TRACE(Service_LDR, "Internally relocates 0x{:08X} with 0x{:08X}", target_address,
symbol_segment.offset);
ResultCode result = ApplyRelocation(target_address, relocation.type, relocation.addend,
@ -619,7 +620,7 @@ ResultCode CROHelper::ClearInternalRelocations() {
u32 internal_relocation_num = GetField(InternalRelocationNum);
for (u32 i = 0; i < internal_relocation_num; ++i) {
InternalRelocationEntry relocation;
GetEntry(memory, i, relocation);
GetEntry(system.Memory(), i, relocation);
VAddr target_address = SegmentTagToAddress(relocation.target_position);
if (target_address == 0) {
@ -639,13 +640,13 @@ void CROHelper::UnrebaseImportAnonymousSymbolTable() {
u32 num = GetField(ImportAnonymousSymbolNum);
for (u32 i = 0; i < num; ++i) {
ImportAnonymousSymbolEntry entry;
GetEntry(memory, i, entry);
GetEntry(system.Memory(), i, entry);
if (entry.relocation_batch_offset != 0) {
entry.relocation_batch_offset -= module_address;
}
SetEntry(memory, i, entry);
SetEntry(system.Memory(), i, entry);
}
}
@ -653,13 +654,13 @@ void CROHelper::UnrebaseImportIndexedSymbolTable() {
u32 num = GetField(ImportIndexedSymbolNum);
for (u32 i = 0; i < num; ++i) {
ImportIndexedSymbolEntry entry;
GetEntry(memory, i, entry);
GetEntry(system.Memory(), i, entry);
if (entry.relocation_batch_offset != 0) {
entry.relocation_batch_offset -= module_address;
}
SetEntry(memory, i, entry);
SetEntry(system.Memory(), i, entry);
}
}
@ -667,7 +668,7 @@ void CROHelper::UnrebaseImportNamedSymbolTable() {
u32 num = GetField(ImportNamedSymbolNum);
for (u32 i = 0; i < num; ++i) {
ImportNamedSymbolEntry entry;
GetEntry(memory, i, entry);
GetEntry(system.Memory(), i, entry);
if (entry.name_offset != 0) {
entry.name_offset -= module_address;
@ -677,7 +678,7 @@ void CROHelper::UnrebaseImportNamedSymbolTable() {
entry.relocation_batch_offset -= module_address;
}
SetEntry(memory, i, entry);
SetEntry(system.Memory(), i, entry);
}
}
@ -685,7 +686,7 @@ void CROHelper::UnrebaseImportModuleTable() {
u32 module_num = GetField(ImportModuleNum);
for (u32 i = 0; i < module_num; ++i) {
ImportModuleEntry entry;
GetEntry(memory, i, entry);
GetEntry(system.Memory(), i, entry);
if (entry.name_offset != 0) {
entry.name_offset -= module_address;
@ -699,7 +700,7 @@ void CROHelper::UnrebaseImportModuleTable() {
entry.import_anonymous_symbol_table_offset -= module_address;
}
SetEntry(memory, i, entry);
SetEntry(system.Memory(), i, entry);
}
}
@ -707,13 +708,13 @@ void CROHelper::UnrebaseExportNamedSymbolTable() {
u32 export_named_symbol_num = GetField(ExportNamedSymbolNum);
for (u32 i = 0; i < export_named_symbol_num; ++i) {
ExportNamedSymbolEntry entry;
GetEntry(memory, i, entry);
GetEntry(system.Memory(), i, entry);
if (entry.name_offset != 0) {
entry.name_offset -= module_address;
}
SetEntry(memory, i, entry);
SetEntry(system.Memory(), i, entry);
}
}
@ -721,7 +722,7 @@ void CROHelper::UnrebaseSegmentTable() {
u32 segment_num = GetField(SegmentNum);
for (u32 i = 0; i < segment_num; ++i) {
SegmentEntry segment;
GetEntry(memory, i, segment);
GetEntry(system.Memory(), i, segment);
if (segment.type == SegmentType::BSS) {
segment.offset = 0;
@ -729,7 +730,7 @@ void CROHelper::UnrebaseSegmentTable() {
segment.offset -= module_address;
}
SetEntry(memory, i, segment);
SetEntry(system.Memory(), i, segment);
}
}
@ -751,17 +752,17 @@ ResultCode CROHelper::ApplyImportNamedSymbol(VAddr crs_address) {
u32 symbol_import_num = GetField(ImportNamedSymbolNum);
for (u32 i = 0; i < symbol_import_num; ++i) {
ImportNamedSymbolEntry entry;
GetEntry(memory, i, entry);
GetEntry(system.Memory(), i, entry);
VAddr relocation_addr = entry.relocation_batch_offset;
ExternalRelocationEntry relocation_entry;
memory.ReadBlock(process, relocation_addr, &relocation_entry,
sizeof(ExternalRelocationEntry));
system.Memory().ReadBlock(process, relocation_addr, &relocation_entry,
sizeof(ExternalRelocationEntry));
if (!relocation_entry.is_batch_resolved) {
ResultCode result = ForEachAutoLinkCRO(
process, memory, cpu, crs_address, [&](CROHelper source) -> ResultVal<bool> {
process, system, crs_address, [&](CROHelper source) -> ResultVal<bool> {
std::string symbol_name =
memory.ReadCString(entry.name_offset, import_strings_size);
system.Memory().ReadCString(entry.name_offset, import_strings_size);
u32 symbol_address = source.FindExportNamedSymbol(symbol_name);
if (symbol_address != 0) {
@ -794,11 +795,11 @@ ResultCode CROHelper::ResetImportNamedSymbol() {
u32 symbol_import_num = GetField(ImportNamedSymbolNum);
for (u32 i = 0; i < symbol_import_num; ++i) {
ImportNamedSymbolEntry entry;
GetEntry(memory, i, entry);
GetEntry(system.Memory(), i, entry);
VAddr relocation_addr = entry.relocation_batch_offset;
ExternalRelocationEntry relocation_entry;
memory.ReadBlock(process, relocation_addr, &relocation_entry,
sizeof(ExternalRelocationEntry));
system.Memory().ReadBlock(process, relocation_addr, &relocation_entry,
sizeof(ExternalRelocationEntry));
ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true);
if (result.IsError()) {
@ -815,11 +816,11 @@ ResultCode CROHelper::ResetImportIndexedSymbol() {
u32 import_num = GetField(ImportIndexedSymbolNum);
for (u32 i = 0; i < import_num; ++i) {
ImportIndexedSymbolEntry entry;
GetEntry(memory, i, entry);
GetEntry(system.Memory(), i, entry);
VAddr relocation_addr = entry.relocation_batch_offset;
ExternalRelocationEntry relocation_entry;
memory.ReadBlock(process, relocation_addr, &relocation_entry,
sizeof(ExternalRelocationEntry));
system.Memory().ReadBlock(process, relocation_addr, &relocation_entry,
sizeof(ExternalRelocationEntry));
ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true);
if (result.IsError()) {
@ -836,11 +837,11 @@ ResultCode CROHelper::ResetImportAnonymousSymbol() {
u32 import_num = GetField(ImportAnonymousSymbolNum);
for (u32 i = 0; i < import_num; ++i) {
ImportAnonymousSymbolEntry entry;
GetEntry(memory, i, entry);
GetEntry(system.Memory(), i, entry);
VAddr relocation_addr = entry.relocation_batch_offset;
ExternalRelocationEntry relocation_entry;
memory.ReadBlock(process, relocation_addr, &relocation_entry,
sizeof(ExternalRelocationEntry));
system.Memory().ReadBlock(process, relocation_addr, &relocation_entry,
sizeof(ExternalRelocationEntry));
ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true);
if (result.IsError()) {
@ -857,19 +858,20 @@ ResultCode CROHelper::ApplyModuleImport(VAddr crs_address) {
u32 import_module_num = GetField(ImportModuleNum);
for (u32 i = 0; i < import_module_num; ++i) {
ImportModuleEntry entry;
GetEntry(memory, i, entry);
std::string want_cro_name = memory.ReadCString(entry.name_offset, import_strings_size);
GetEntry(system.Memory(), i, entry);
std::string want_cro_name =
system.Memory().ReadCString(entry.name_offset, import_strings_size);
ResultCode result = ForEachAutoLinkCRO(
process, memory, cpu, crs_address, [&](CROHelper source) -> ResultVal<bool> {
process, system, crs_address, [&](CROHelper source) -> ResultVal<bool> {
if (want_cro_name == source.ModuleName()) {
LOG_INFO(Service_LDR, "CRO \"{}\" imports {} indexed symbols from \"{}\"",
ModuleName(), entry.import_indexed_symbol_num, source.ModuleName());
for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) {
ImportIndexedSymbolEntry im;
entry.GetImportIndexedSymbolEntry(process, memory, j, im);
entry.GetImportIndexedSymbolEntry(process, system.Memory(), j, im);
ExportIndexedSymbolEntry ex;
source.GetEntry(memory, im.index, ex);
source.GetEntry(system.Memory(), im.index, ex);
u32 symbol_address = source.SegmentTagToAddress(ex.symbol_position);
LOG_TRACE(Service_LDR, " Imports 0x{:08X}", symbol_address);
ResultCode result =
@ -884,7 +886,7 @@ ResultCode CROHelper::ApplyModuleImport(VAddr crs_address) {
ModuleName(), entry.import_anonymous_symbol_num, source.ModuleName());
for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) {
ImportAnonymousSymbolEntry im;
entry.GetImportAnonymousSymbolEntry(process, memory, j, im);
entry.GetImportAnonymousSymbolEntry(process, system.Memory(), j, im);
u32 symbol_address = source.SegmentTagToAddress(im.symbol_position);
LOG_TRACE(Service_LDR, " Imports 0x{:08X}", symbol_address);
ResultCode result =
@ -913,15 +915,15 @@ ResultCode CROHelper::ApplyExportNamedSymbol(CROHelper target) {
u32 target_symbol_import_num = target.GetField(ImportNamedSymbolNum);
for (u32 i = 0; i < target_symbol_import_num; ++i) {
ImportNamedSymbolEntry entry;
target.GetEntry(memory, i, entry);
target.GetEntry(system.Memory(), i, entry);
VAddr relocation_addr = entry.relocation_batch_offset;
ExternalRelocationEntry relocation_entry;
memory.ReadBlock(process, relocation_addr, &relocation_entry,
sizeof(ExternalRelocationEntry));
system.Memory().ReadBlock(process, relocation_addr, &relocation_entry,
sizeof(ExternalRelocationEntry));
if (!relocation_entry.is_batch_resolved) {
std::string symbol_name =
memory.ReadCString(entry.name_offset, target_import_strings_size);
system.Memory().ReadCString(entry.name_offset, target_import_strings_size);
u32 symbol_address = FindExportNamedSymbol(symbol_name);
if (symbol_address != 0) {
LOG_TRACE(Service_LDR, " exports symbol \"{}\"", symbol_name);
@ -944,15 +946,15 @@ ResultCode CROHelper::ResetExportNamedSymbol(CROHelper target) {
u32 target_symbol_import_num = target.GetField(ImportNamedSymbolNum);
for (u32 i = 0; i < target_symbol_import_num; ++i) {
ImportNamedSymbolEntry entry;
target.GetEntry(memory, i, entry);
target.GetEntry(system.Memory(), i, entry);
VAddr relocation_addr = entry.relocation_batch_offset;
ExternalRelocationEntry relocation_entry;
memory.ReadBlock(process, relocation_addr, &relocation_entry,
sizeof(ExternalRelocationEntry));
system.Memory().ReadBlock(process, relocation_addr, &relocation_entry,
sizeof(ExternalRelocationEntry));
if (relocation_entry.is_batch_resolved) {
std::string symbol_name =
memory.ReadCString(entry.name_offset, target_import_strings_size);
system.Memory().ReadCString(entry.name_offset, target_import_strings_size);
u32 symbol_address = FindExportNamedSymbol(symbol_name);
if (symbol_address != 0) {
LOG_TRACE(Service_LDR, " unexports symbol \"{}\"", symbol_name);
@ -974,18 +976,19 @@ ResultCode CROHelper::ApplyModuleExport(CROHelper target) {
u32 target_import_module_num = target.GetField(ImportModuleNum);
for (u32 i = 0; i < target_import_module_num; ++i) {
ImportModuleEntry entry;
target.GetEntry(memory, i, entry);
target.GetEntry(system.Memory(), i, entry);
if (memory.ReadCString(entry.name_offset, target_import_string_size) != module_name)
if (system.Memory().ReadCString(entry.name_offset, target_import_string_size) !=
module_name)
continue;
LOG_INFO(Service_LDR, "CRO \"{}\" exports {} indexed symbols to \"{}\"", module_name,
entry.import_indexed_symbol_num, target.ModuleName());
for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) {
ImportIndexedSymbolEntry im;
entry.GetImportIndexedSymbolEntry(process, memory, j, im);
entry.GetImportIndexedSymbolEntry(process, system.Memory(), j, im);
ExportIndexedSymbolEntry ex;
GetEntry(memory, im.index, ex);
GetEntry(system.Memory(), im.index, ex);
u32 symbol_address = SegmentTagToAddress(ex.symbol_position);
LOG_TRACE(Service_LDR, " exports symbol 0x{:08X}", symbol_address);
ResultCode result =
@ -1000,7 +1003,7 @@ ResultCode CROHelper::ApplyModuleExport(CROHelper target) {
entry.import_anonymous_symbol_num, target.ModuleName());
for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) {
ImportAnonymousSymbolEntry im;
entry.GetImportAnonymousSymbolEntry(process, memory, j, im);
entry.GetImportAnonymousSymbolEntry(process, system.Memory(), j, im);
u32 symbol_address = SegmentTagToAddress(im.symbol_position);
LOG_TRACE(Service_LDR, " exports symbol 0x{:08X}", symbol_address);
ResultCode result =
@ -1023,16 +1026,17 @@ ResultCode CROHelper::ResetModuleExport(CROHelper target) {
u32 target_import_module_num = target.GetField(ImportModuleNum);
for (u32 i = 0; i < target_import_module_num; ++i) {
ImportModuleEntry entry;
target.GetEntry(memory, i, entry);
target.GetEntry(system.Memory(), i, entry);
if (memory.ReadCString(entry.name_offset, target_import_string_size) != module_name)
if (system.Memory().ReadCString(entry.name_offset, target_import_string_size) !=
module_name)
continue;
LOG_DEBUG(Service_LDR, "CRO \"{}\" unexports indexed symbols to \"{}\"", module_name,
target.ModuleName());
for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) {
ImportIndexedSymbolEntry im;
entry.GetImportIndexedSymbolEntry(process, memory, j, im);
entry.GetImportIndexedSymbolEntry(process, system.Memory(), j, im);
ResultCode result =
target.ApplyRelocationBatch(im.relocation_batch_offset, unresolved_symbol, true);
if (result.IsError()) {
@ -1045,7 +1049,7 @@ ResultCode CROHelper::ResetModuleExport(CROHelper target) {
target.ModuleName());
for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) {
ImportAnonymousSymbolEntry im;
entry.GetImportAnonymousSymbolEntry(process, memory, j, im);
entry.GetImportAnonymousSymbolEntry(process, system.Memory(), j, im);
ResultCode result =
target.ApplyRelocationBatch(im.relocation_batch_offset, unresolved_symbol, true);
if (result.IsError()) {
@ -1063,15 +1067,16 @@ ResultCode CROHelper::ApplyExitRelocations(VAddr crs_address) {
u32 symbol_import_num = GetField(ImportNamedSymbolNum);
for (u32 i = 0; i < symbol_import_num; ++i) {
ImportNamedSymbolEntry entry;
GetEntry(memory, i, entry);
GetEntry(system.Memory(), i, entry);
VAddr relocation_addr = entry.relocation_batch_offset;
ExternalRelocationEntry relocation_entry;
memory.ReadBlock(process, relocation_addr, &relocation_entry,
sizeof(ExternalRelocationEntry));
system.Memory().ReadBlock(process, relocation_addr, &relocation_entry,
sizeof(ExternalRelocationEntry));
if (memory.ReadCString(entry.name_offset, import_strings_size) == "__aeabi_atexit") {
if (system.Memory().ReadCString(entry.name_offset, import_strings_size) ==
"__aeabi_atexit") {
ResultCode result = ForEachAutoLinkCRO(
process, memory, cpu, crs_address, [&](CROHelper source) -> ResultVal<bool> {
process, system, crs_address, [&](CROHelper source) -> ResultVal<bool> {
u32 symbol_address = source.FindExportNamedSymbol("nnroAeabiAtexit_");
if (symbol_address != 0) {
@ -1126,7 +1131,8 @@ ResultCode CROHelper::Rebase(VAddr crs_address, u32 cro_size, VAddr data_segment
return result;
}
result = VerifyStringTableLength(memory, GetField(ModuleNameOffset), GetField(ModuleNameSize));
result = VerifyStringTableLength(system.Memory(), GetField(ModuleNameOffset),
GetField(ModuleNameSize));
if (result.IsError()) {
LOG_ERROR(Service_LDR, "Error verifying module name {:08X}", result.raw);
return result;
@ -1155,8 +1161,8 @@ ResultCode CROHelper::Rebase(VAddr crs_address, u32 cro_size, VAddr data_segment
return result;
}
result =
VerifyStringTableLength(memory, GetField(ExportStringsOffset), GetField(ExportStringsSize));
result = VerifyStringTableLength(system.Memory(), GetField(ExportStringsOffset),
GetField(ExportStringsSize));
if (result.IsError()) {
LOG_ERROR(Service_LDR, "Error verifying export strings {:08X}", result.raw);
return result;
@ -1192,8 +1198,8 @@ ResultCode CROHelper::Rebase(VAddr crs_address, u32 cro_size, VAddr data_segment
return result;
}
result =
VerifyStringTableLength(memory, GetField(ImportStringsOffset), GetField(ImportStringsSize));
result = VerifyStringTableLength(system.Memory(), GetField(ImportStringsOffset),
GetField(ImportStringsSize));
if (result.IsError()) {
LOG_ERROR(Service_LDR, "Error verifying import strings {:08X}", result.raw);
return result;
@ -1266,11 +1272,11 @@ ResultCode CROHelper::Link(VAddr crs_address, bool link_on_load_bug_fix) {
// so we do the same
if (GetField(SegmentNum) >= 2) { // means we have .data segment
SegmentEntry entry;
GetEntry(memory, 2, entry);
GetEntry(system.Memory(), 2, entry);
ASSERT(entry.type == SegmentType::Data);
data_segment_address = entry.offset;
entry.offset = GetField(DataOffset);
SetEntry(memory, 2, entry);
SetEntry(system.Memory(), 2, entry);
}
}
SCOPE_EXIT({
@ -1278,9 +1284,9 @@ ResultCode CROHelper::Link(VAddr crs_address, bool link_on_load_bug_fix) {
if (link_on_load_bug_fix) {
if (GetField(SegmentNum) >= 2) {
SegmentEntry entry;
GetEntry(memory, 2, entry);
GetEntry(system.Memory(), 2, entry);
entry.offset = data_segment_address;
SetEntry(memory, 2, entry);
SetEntry(system.Memory(), 2, entry);
}
}
});
@ -1301,7 +1307,7 @@ ResultCode CROHelper::Link(VAddr crs_address, bool link_on_load_bug_fix) {
}
// Exports symbols to other modules
result = ForEachAutoLinkCRO(process, memory, cpu, crs_address,
result = ForEachAutoLinkCRO(process, system, crs_address,
[this](CROHelper target) -> ResultVal<bool> {
ResultCode result = ApplyExportNamedSymbol(target);
if (result.IsError())
@ -1346,7 +1352,7 @@ ResultCode CROHelper::Unlink(VAddr crs_address) {
// Resets all symbols in other modules imported from this module
// Note: the RO service seems only searching in auto-link modules
result = ForEachAutoLinkCRO(process, memory, cpu, crs_address,
result = ForEachAutoLinkCRO(process, system, crs_address,
[this](CROHelper target) -> ResultVal<bool> {
ResultCode result = ResetExportNamedSymbol(target);
if (result.IsError())
@ -1387,13 +1393,13 @@ void CROHelper::InitCRS() {
}
void CROHelper::Register(VAddr crs_address, bool auto_link) {
CROHelper crs(crs_address, process, memory, cpu);
CROHelper head(auto_link ? crs.NextModule() : crs.PreviousModule(), process, memory, cpu);
CROHelper crs(crs_address, process, system);
CROHelper head(auto_link ? crs.NextModule() : crs.PreviousModule(), process, system);
if (head.module_address) {
// there are already CROs registered
// register as the new tail
CROHelper tail(head.PreviousModule(), process, memory, cpu);
CROHelper tail(head.PreviousModule(), process, system);
// link with the old tail
ASSERT(tail.NextModule() == 0);
@ -1419,11 +1425,11 @@ void CROHelper::Register(VAddr crs_address, bool auto_link) {
}
void CROHelper::Unregister(VAddr crs_address) {
CROHelper crs(crs_address, process, memory, cpu);
CROHelper next_head(crs.NextModule(), process, memory, cpu);
CROHelper previous_head(crs.PreviousModule(), process, memory, cpu);
CROHelper next(NextModule(), process, memory, cpu);
CROHelper previous(PreviousModule(), process, memory, cpu);
CROHelper crs(crs_address, process, system);
CROHelper next_head(crs.NextModule(), process, system);
CROHelper previous_head(crs.PreviousModule(), process, system);
CROHelper next(NextModule(), process, system);
CROHelper previous(PreviousModule(), process, system);
if (module_address == next_head.module_address ||
module_address == previous_head.module_address) {
@ -1517,7 +1523,7 @@ std::tuple<VAddr, u32> CROHelper::GetExecutablePages() const {
u32 segment_num = GetField(SegmentNum);
for (u32 i = 0; i < segment_num; ++i) {
SegmentEntry entry;
GetEntry(memory, i, entry);
GetEntry(system.Memory(), i, entry);
if (entry.type == SegmentType::Code && entry.size != 0) {
VAddr begin = Common::AlignDown(entry.offset, Memory::PAGE_SIZE);
VAddr end = Common::AlignUp(entry.offset + entry.size, Memory::PAGE_SIZE);

View file

@ -33,12 +33,11 @@ static constexpr u32 CRO_HASH_SIZE = 0x80;
class CROHelper final {
public:
// TODO (wwylele): pass in the process handle for memory access
explicit CROHelper(VAddr cro_address, Kernel::Process& process, Memory::MemorySystem& memory,
ARM_Interface& cpu)
: module_address(cro_address), process(process), memory(memory), cpu(cpu) {}
explicit CROHelper(VAddr cro_address, Kernel::Process& process, Core::System& system)
: module_address(cro_address), process(process), system(system) {}
std::string ModuleName() const {
return memory.ReadCString(GetField(ModuleNameOffset), GetField(ModuleNameSize));
return system.Memory().ReadCString(GetField(ModuleNameOffset), GetField(ModuleNameSize));
}
u32 GetFileSize() const {
@ -144,8 +143,7 @@ public:
private:
const VAddr module_address; ///< the virtual address of this module
Kernel::Process& process; ///< the owner process of this module
Memory::MemorySystem& memory;
ARM_Interface& cpu;
Core::System& system;
/**
* Each item in this enum represents a u32 field in the header begin from address+0x80,
@ -403,11 +401,11 @@ private:
}
u32 GetField(HeaderField field) const {
return memory.Read32(Field(field));
return system.Memory().Read32(Field(field));
}
void SetField(HeaderField field, u32 value) {
memory.Write32(Field(field), value);
system.Memory().Write32(Field(field), value);
}
/**
@ -474,12 +472,11 @@ private:
* otherwise error code of the last iteration.
*/
template <typename FunctionObject>
static ResultCode ForEachAutoLinkCRO(Kernel::Process& process, Memory::MemorySystem& memory,
ARM_Interface& cpu, VAddr crs_address,
FunctionObject func) {
static ResultCode ForEachAutoLinkCRO(Kernel::Process& process, Core::System& system,
VAddr crs_address, FunctionObject func) {
VAddr current = crs_address;
while (current != 0) {
CROHelper cro(current, process, memory, cpu);
CROHelper cro(current, process, system);
CASCADE_RESULT(bool next, func(cro));
if (!next)
break;

View file

@ -120,7 +120,7 @@ void RO::Initialize(Kernel::HLERequestContext& ctx) {
return;
}
CROHelper crs(crs_address, *process, system.Memory(), system.CPU());
CROHelper crs(crs_address, *process, system);
crs.InitCRS();
result = crs.Rebase(0, crs_size, 0, 0, 0, 0, true);
@ -254,7 +254,7 @@ void RO::LoadCRO(Kernel::HLERequestContext& ctx, bool link_on_load_bug_fix) {
return;
}
CROHelper cro(cro_address, *process, system.Memory(), system.CPU());
CROHelper cro(cro_address, *process, system);
result = cro.VerifyHash(cro_size, crr_address);
if (result.IsError()) {
@ -318,7 +318,7 @@ void RO::LoadCRO(Kernel::HLERequestContext& ctx, bool link_on_load_bug_fix) {
}
}
system.CPU().InvalidateCacheRange(cro_address, cro_size);
system.InvalidateCacheRange(cro_address, cro_size);
LOG_INFO(Service_LDR, "CRO \"{}\" loaded at 0x{:08X}, fixed_end=0x{:08X}", cro.ModuleName(),
cro_address, cro_address + fix_size);
@ -336,7 +336,7 @@ void RO::UnloadCRO(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_LDR, "called, cro_address=0x{:08X}, zero={}, cro_buffer_ptr=0x{:08X}",
cro_address, zero, cro_buffer_ptr);
CROHelper cro(cro_address, *process, system.Memory(), system.CPU());
CROHelper cro(cro_address, *process, system);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
@ -391,7 +391,7 @@ void RO::UnloadCRO(Kernel::HLERequestContext& ctx) {
LOG_ERROR(Service_LDR, "Error unmapping CRO {:08X}", result.raw);
}
system.CPU().InvalidateCacheRange(cro_address, fixed_size);
system.InvalidateCacheRange(cro_address, fixed_size);
rb.Push(result);
}
@ -403,7 +403,7 @@ void RO::LinkCRO(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_LDR, "called, cro_address=0x{:08X}", cro_address);
CROHelper cro(cro_address, *process, system.Memory(), system.CPU());
CROHelper cro(cro_address, *process, system);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
@ -443,7 +443,7 @@ void RO::UnlinkCRO(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_LDR, "called, cro_address=0x{:08X}", cro_address);
CROHelper cro(cro_address, *process, system.Memory(), system.CPU());
CROHelper cro(cro_address, *process, system);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
@ -492,7 +492,7 @@ void RO::Shutdown(Kernel::HLERequestContext& ctx) {
return;
}
CROHelper crs(slot->loaded_crs, *process, system.Memory(), system.CPU());
CROHelper crs(slot->loaded_crs, *process, system);
crs.Unrebase(true);
ResultCode result = RESULT_SUCCESS;