mirror of
https://github.com/yuzu-emu/yuzu-android.git
synced 2025-06-25 18:57:56 -05:00
Sources: Run clang-format on everything.
This commit is contained in:
@ -23,23 +23,24 @@
|
||||
// Specializes std::hash for AppletId, so that we can use it in std::unordered_map.
|
||||
// Workaround for libstdc++ bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<Service::APT::AppletId> {
|
||||
typedef Service::APT::AppletId argument_type;
|
||||
typedef std::size_t result_type;
|
||||
template <>
|
||||
struct hash<Service::APT::AppletId> {
|
||||
typedef Service::APT::AppletId argument_type;
|
||||
typedef std::size_t result_type;
|
||||
|
||||
result_type operator()(const argument_type& id_code) const {
|
||||
typedef std::underlying_type<argument_type>::type Type;
|
||||
return std::hash<Type>()(static_cast<Type>(id_code));
|
||||
}
|
||||
};
|
||||
result_type operator()(const argument_type& id_code) const {
|
||||
typedef std::underlying_type<argument_type>::type Type;
|
||||
return std::hash<Type>()(static_cast<Type>(id_code));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace HLE {
|
||||
namespace Applets {
|
||||
|
||||
static std::unordered_map<Service::APT::AppletId, std::shared_ptr<Applet>> applets;
|
||||
static u32 applet_update_event = -1; ///< The CoreTiming event identifier for the Applet update callback.
|
||||
static u32 applet_update_event =
|
||||
-1; ///< The CoreTiming event identifier for the Applet update callback.
|
||||
/// The interval at which the Applet update callback will be called, 16.6ms
|
||||
static const u64 applet_update_interval_us = 16666;
|
||||
|
||||
@ -60,7 +61,8 @@ ResultCode Applet::Create(Service::APT::AppletId id) {
|
||||
default:
|
||||
LOG_ERROR(Service_APT, "Could not create applet %u", id);
|
||||
// TODO(Subv): Find the right error code
|
||||
return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotSupported, ErrorLevel::Permanent);
|
||||
return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet,
|
||||
ErrorSummary::NotSupported, ErrorLevel::Permanent);
|
||||
}
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
@ -84,7 +86,7 @@ static void AppletUpdateEvent(u64 applet_id, int cycles_late) {
|
||||
// If the applet is still running after the last update, reschedule the event
|
||||
if (applet->IsRunning()) {
|
||||
CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us) - cycles_late,
|
||||
applet_update_event, applet_id);
|
||||
applet_update_event, applet_id);
|
||||
} else {
|
||||
// Otherwise the applet has terminated, in which case we should clean it up
|
||||
applets[id] = nullptr;
|
||||
@ -96,7 +98,8 @@ ResultCode Applet::Start(const Service::APT::AppletStartupParameter& parameter)
|
||||
if (result.IsError())
|
||||
return result;
|
||||
// Schedule the update event
|
||||
CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us), applet_update_event, static_cast<u64>(id));
|
||||
CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us), applet_update_event,
|
||||
static_cast<u64>(id));
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -116,6 +119,5 @@ void Init() {
|
||||
void Shutdown() {
|
||||
CoreTiming::RemoveEvent(applet_update_event);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
@ -14,8 +14,10 @@ namespace Applets {
|
||||
|
||||
class Applet {
|
||||
public:
|
||||
virtual ~Applet() { }
|
||||
Applet(Service::APT::AppletId id) : id(id) { }
|
||||
virtual ~Applet() {
|
||||
}
|
||||
Applet(Service::APT::AppletId id) : id(id) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of the Applet subclass identified by the parameter.
|
||||
@ -64,7 +66,7 @@ protected:
|
||||
*/
|
||||
virtual ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) = 0;
|
||||
|
||||
Service::APT::AppletId id; ///< Id of this Applet
|
||||
Service::APT::AppletId id; ///< Id of this Applet
|
||||
std::shared_ptr<std::vector<u8>> heap_memory; ///< Heap memory for this Applet
|
||||
};
|
||||
|
||||
@ -76,6 +78,5 @@ void Init();
|
||||
|
||||
/// Shuts down the HLE applets
|
||||
void Shutdown();
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
@ -18,7 +18,8 @@ ResultCode ErrEula::ReceiveParameter(const Service::APT::MessageParameter& param
|
||||
return ResultCode(-1);
|
||||
}
|
||||
|
||||
// The LibAppJustStarted message contains a buffer with the size of the framebuffer shared memory.
|
||||
// The LibAppJustStarted message contains a buffer with the size of the framebuffer shared
|
||||
// memory.
|
||||
// Create the SharedMemory that will hold the framebuffer data
|
||||
Service::APT::CaptureBufferInfo capture_info;
|
||||
ASSERT(sizeof(capture_info) == parameter.buffer.size());
|
||||
@ -30,9 +31,9 @@ ResultCode ErrEula::ReceiveParameter(const Service::APT::MessageParameter& param
|
||||
// Allocate a heap block of the required size for this applet.
|
||||
heap_memory = std::make_shared<std::vector<u8>>(capture_info.size);
|
||||
// Create a SharedMemory that directly points to this heap block.
|
||||
framebuffer_memory = Kernel::SharedMemory::CreateForApplet(heap_memory, 0, heap_memory->size(),
|
||||
MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
|
||||
"ErrEula Memory");
|
||||
framebuffer_memory = Kernel::SharedMemory::CreateForApplet(
|
||||
heap_memory, 0, heap_memory->size(), MemoryPermission::ReadWrite,
|
||||
MemoryPermission::ReadWrite, "ErrEula Memory");
|
||||
|
||||
// Send the response message with the newly created SharedMemory
|
||||
Service::APT::MessageParameter result;
|
||||
@ -49,7 +50,8 @@ ResultCode ErrEula::ReceiveParameter(const Service::APT::MessageParameter& param
|
||||
ResultCode ErrEula::StartImpl(const Service::APT::AppletStartupParameter& parameter) {
|
||||
started = true;
|
||||
|
||||
// TODO(Subv): Set the expected fields in the response buffer before resending it to the application.
|
||||
// TODO(Subv): Set the expected fields in the response buffer before resending it to the
|
||||
// application.
|
||||
// TODO(Subv): Reverse the parameter format for the ErrEula applet
|
||||
|
||||
// Let the application know that we're closing
|
||||
|
@ -12,16 +12,21 @@ namespace Applets {
|
||||
|
||||
class ErrEula final : public Applet {
|
||||
public:
|
||||
explicit ErrEula(Service::APT::AppletId id): Applet(id) { }
|
||||
explicit ErrEula(Service::APT::AppletId id) : Applet(id) {
|
||||
}
|
||||
|
||||
ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override;
|
||||
ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override;
|
||||
void Update() override;
|
||||
bool IsRunning() const override { return started; }
|
||||
bool IsRunning() const override {
|
||||
return started;
|
||||
}
|
||||
|
||||
/// This SharedMemory will be created when we receive the LibAppJustStarted message.
|
||||
/// It holds the framebuffer info retrieved by the application with GSPGPU::ImportDisplayCaptureInfo
|
||||
/// It holds the framebuffer info retrieved by the application with
|
||||
/// GSPGPU::ImportDisplayCaptureInfo
|
||||
Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory;
|
||||
|
||||
private:
|
||||
/// Whether this applet is currently running instead of the host application or not.
|
||||
bool started = false;
|
||||
|
@ -29,7 +29,8 @@ ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& p
|
||||
return ResultCode(-1);
|
||||
}
|
||||
|
||||
// The LibAppJustStarted message contains a buffer with the size of the framebuffer shared memory.
|
||||
// The LibAppJustStarted message contains a buffer with the size of the framebuffer shared
|
||||
// memory.
|
||||
// Create the SharedMemory that will hold the framebuffer data
|
||||
Service::APT::CaptureBufferInfo capture_info;
|
||||
ASSERT(sizeof(capture_info) == parameter.buffer.size());
|
||||
@ -40,9 +41,9 @@ ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& p
|
||||
// Allocate a heap block of the required size for this applet.
|
||||
heap_memory = std::make_shared<std::vector<u8>>(capture_info.size);
|
||||
// Create a SharedMemory that directly points to this heap block.
|
||||
framebuffer_memory = Kernel::SharedMemory::CreateForApplet(heap_memory, 0, heap_memory->size(),
|
||||
MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
|
||||
"MiiSelector Memory");
|
||||
framebuffer_memory = Kernel::SharedMemory::CreateForApplet(
|
||||
heap_memory, 0, heap_memory->size(), MemoryPermission::ReadWrite,
|
||||
MemoryPermission::ReadWrite, "MiiSelector Memory");
|
||||
|
||||
// Send the response message with the newly created SharedMemory
|
||||
Service::APT::MessageParameter result;
|
||||
@ -59,12 +60,14 @@ ResultCode MiiSelector::ReceiveParameter(const Service::APT::MessageParameter& p
|
||||
ResultCode MiiSelector::StartImpl(const Service::APT::AppletStartupParameter& parameter) {
|
||||
started = true;
|
||||
|
||||
// TODO(Subv): Set the expected fields in the response buffer before resending it to the application.
|
||||
// TODO(Subv): Set the expected fields in the response buffer before resending it to the
|
||||
// application.
|
||||
// TODO(Subv): Reverse the parameter format for the Mii Selector
|
||||
|
||||
memcpy(&config, parameter.buffer.data(), parameter.buffer.size());
|
||||
|
||||
// TODO(Subv): Find more about this structure, result code 0 is enough to let most games continue.
|
||||
// TODO(Subv): Find more about this structure, result code 0 is enough to let most games
|
||||
// continue.
|
||||
MiiResult result;
|
||||
memset(&result, 0, sizeof(result));
|
||||
result.result_code = 0;
|
||||
@ -84,6 +87,5 @@ ResultCode MiiSelector::StartImpl(const Service::APT::AppletStartupParameter& pa
|
||||
|
||||
void MiiSelector::Update() {
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
@ -4,8 +4,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
#include "core/hle/applets/applet.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
@ -17,28 +17,30 @@ namespace HLE {
|
||||
namespace Applets {
|
||||
|
||||
struct MiiConfig {
|
||||
u8 unk_000;
|
||||
u8 unk_001;
|
||||
u8 unk_002;
|
||||
u8 unk_003;
|
||||
u8 unk_004;
|
||||
u8 unk_000;
|
||||
u8 unk_001;
|
||||
u8 unk_002;
|
||||
u8 unk_003;
|
||||
u8 unk_004;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
u16 unk_008;
|
||||
INSERT_PADDING_BYTES(0x82);
|
||||
u8 unk_08C;
|
||||
u8 unk_08C;
|
||||
INSERT_PADDING_BYTES(3);
|
||||
u16 unk_090;
|
||||
INSERT_PADDING_BYTES(2);
|
||||
u32 unk_094;
|
||||
u16 unk_098;
|
||||
u8 unk_09A[0x64];
|
||||
u8 unk_0FE;
|
||||
u8 unk_0FF;
|
||||
u8 unk_09A[0x64];
|
||||
u8 unk_0FE;
|
||||
u8 unk_0FF;
|
||||
u32 unk_100;
|
||||
};
|
||||
|
||||
static_assert(sizeof(MiiConfig) == 0x104, "MiiConfig structure has incorrect size");
|
||||
#define ASSERT_REG_POSITION(field_name, position) static_assert(offsetof(MiiConfig, field_name) == position, "Field "#field_name" has invalid position")
|
||||
#define ASSERT_REG_POSITION(field_name, position) \
|
||||
static_assert(offsetof(MiiConfig, field_name) == position, \
|
||||
"Field " #field_name " has invalid position")
|
||||
ASSERT_REG_POSITION(unk_008, 0x08);
|
||||
ASSERT_REG_POSITION(unk_08C, 0x8C);
|
||||
ASSERT_REG_POSITION(unk_090, 0x90);
|
||||
@ -55,22 +57,28 @@ struct MiiResult {
|
||||
INSERT_PADDING_BYTES(2);
|
||||
};
|
||||
static_assert(sizeof(MiiResult) == 0x84, "MiiResult structure has incorrect size");
|
||||
#define ASSERT_REG_POSITION(field_name, position) static_assert(offsetof(MiiResult, field_name) == position, "Field "#field_name" has invalid position")
|
||||
#define ASSERT_REG_POSITION(field_name, position) \
|
||||
static_assert(offsetof(MiiResult, field_name) == position, \
|
||||
"Field " #field_name " has invalid position")
|
||||
ASSERT_REG_POSITION(unk_0C, 0x0C);
|
||||
ASSERT_REG_POSITION(unk_6C, 0x6C);
|
||||
#undef ASSERT_REG_POSITION
|
||||
|
||||
class MiiSelector final : public Applet {
|
||||
public:
|
||||
MiiSelector(Service::APT::AppletId id) : Applet(id), started(false) { }
|
||||
MiiSelector(Service::APT::AppletId id) : Applet(id), started(false) {
|
||||
}
|
||||
|
||||
ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override;
|
||||
ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override;
|
||||
void Update() override;
|
||||
bool IsRunning() const override { return started; }
|
||||
bool IsRunning() const override {
|
||||
return started;
|
||||
}
|
||||
|
||||
/// This SharedMemory will be created when we receive the LibAppJustStarted message.
|
||||
/// It holds the framebuffer info retrieved by the application with GSPGPU::ImportDisplayCaptureInfo
|
||||
/// It holds the framebuffer info retrieved by the application with
|
||||
/// GSPGPU::ImportDisplayCaptureInfo
|
||||
Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory;
|
||||
|
||||
/// Whether this applet is currently running instead of the host application or not.
|
||||
@ -78,6 +86,5 @@ public:
|
||||
|
||||
MiiConfig config;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
@ -12,9 +12,9 @@
|
||||
#include "core/hle/applets/swkbd.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/shared_memory.h"
|
||||
#include "core/hle/service/hid/hid.h"
|
||||
#include "core/hle/service/gsp_gpu.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/gsp_gpu.h"
|
||||
#include "core/hle/service/hid/hid.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
#include "video_core/video_core.h"
|
||||
@ -32,7 +32,8 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con
|
||||
return ResultCode(-1);
|
||||
}
|
||||
|
||||
// The LibAppJustStarted message contains a buffer with the size of the framebuffer shared memory.
|
||||
// The LibAppJustStarted message contains a buffer with the size of the framebuffer shared
|
||||
// memory.
|
||||
// Create the SharedMemory that will hold the framebuffer data
|
||||
Service::APT::CaptureBufferInfo capture_info;
|
||||
ASSERT(sizeof(capture_info) == parameter.buffer.size());
|
||||
@ -43,9 +44,9 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con
|
||||
// Allocate a heap block of the required size for this applet.
|
||||
heap_memory = std::make_shared<std::vector<u8>>(capture_info.size);
|
||||
// Create a SharedMemory that directly points to this heap block.
|
||||
framebuffer_memory = Kernel::SharedMemory::CreateForApplet(heap_memory, 0, heap_memory->size(),
|
||||
MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
|
||||
"SoftwareKeyboard Memory");
|
||||
framebuffer_memory = Kernel::SharedMemory::CreateForApplet(
|
||||
heap_memory, 0, heap_memory->size(), MemoryPermission::ReadWrite,
|
||||
MemoryPermission::ReadWrite, "SoftwareKeyboard Memory");
|
||||
|
||||
// Send the response message with the newly created SharedMemory
|
||||
Service::APT::MessageParameter result;
|
||||
@ -60,10 +61,12 @@ ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter con
|
||||
}
|
||||
|
||||
ResultCode SoftwareKeyboard::StartImpl(Service::APT::AppletStartupParameter const& parameter) {
|
||||
ASSERT_MSG(parameter.buffer.size() == sizeof(config), "The size of the parameter (SoftwareKeyboardConfig) is wrong");
|
||||
ASSERT_MSG(parameter.buffer.size() == sizeof(config),
|
||||
"The size of the parameter (SoftwareKeyboardConfig) is wrong");
|
||||
|
||||
memcpy(&config, parameter.buffer.data(), parameter.buffer.size());
|
||||
text_memory = boost::static_pointer_cast<Kernel::SharedMemory, Kernel::Object>(parameter.object);
|
||||
text_memory =
|
||||
boost::static_pointer_cast<Kernel::SharedMemory, Kernel::Object>(parameter.object);
|
||||
|
||||
// TODO(Subv): Verify if this is the correct behavior
|
||||
memset(text_memory->GetPointer(), 0, text_memory->size);
|
||||
@ -115,6 +118,5 @@ void SoftwareKeyboard::Finalize() {
|
||||
|
||||
started = false;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
@ -4,8 +4,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
|
||||
#include "core/hle/applets/applet.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
@ -53,12 +53,15 @@ static_assert(sizeof(SoftwareKeyboardConfig) == 0x400, "Software Keyboard Config
|
||||
|
||||
class SoftwareKeyboard final : public Applet {
|
||||
public:
|
||||
SoftwareKeyboard(Service::APT::AppletId id) : Applet(id), started(false) { }
|
||||
SoftwareKeyboard(Service::APT::AppletId id) : Applet(id), started(false) {
|
||||
}
|
||||
|
||||
ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override;
|
||||
ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override;
|
||||
void Update() override;
|
||||
bool IsRunning() const override { return started; }
|
||||
bool IsRunning() const override {
|
||||
return started;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a keyboard to the current bottom screen framebuffer.
|
||||
@ -72,7 +75,8 @@ public:
|
||||
void Finalize();
|
||||
|
||||
/// This SharedMemory will be created when we receive the LibAppJustStarted message.
|
||||
/// It holds the framebuffer info retrieved by the application with GSPGPU::ImportDisplayCaptureInfo
|
||||
/// It holds the framebuffer info retrieved by the application with
|
||||
/// GSPGPU::ImportDisplayCaptureInfo
|
||||
Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory;
|
||||
|
||||
/// SharedMemory where the output text will be stored
|
||||
@ -84,6 +88,5 @@ public:
|
||||
/// Whether this applet is currently running instead of the host application or not.
|
||||
bool started;
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
@ -2,8 +2,8 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstring>
|
||||
#include "core/hle/config_mem.h"
|
||||
#include <cstring>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
@ -20,16 +20,16 @@
|
||||
namespace ConfigMem {
|
||||
|
||||
struct ConfigMemDef {
|
||||
u8 kernel_unk; // 0
|
||||
u8 kernel_version_rev; // 1
|
||||
u8 kernel_version_min; // 2
|
||||
u8 kernel_version_maj; // 3
|
||||
u8 kernel_unk; // 0
|
||||
u8 kernel_version_rev; // 1
|
||||
u8 kernel_version_min; // 2
|
||||
u8 kernel_version_maj; // 3
|
||||
u32_le update_flag; // 4
|
||||
u64_le ns_tid; // 8
|
||||
u32_le sys_core_ver; // 10
|
||||
u8 unit_info; // 14
|
||||
u8 boot_firm; // 15
|
||||
u8 prev_firm; // 16
|
||||
u8 unit_info; // 14
|
||||
u8 boot_firm; // 15
|
||||
u8 prev_firm; // 16
|
||||
INSERT_PADDING_BYTES(0x1); // 17
|
||||
u32_le ctr_sdk_ver; // 18
|
||||
INSERT_PADDING_BYTES(0x30 - 0x1C); // 1C
|
||||
@ -39,15 +39,16 @@ struct ConfigMemDef {
|
||||
u32_le sys_mem_alloc; // 44
|
||||
u32_le base_mem_alloc; // 48
|
||||
INSERT_PADDING_BYTES(0x60 - 0x4C); // 4C
|
||||
u8 firm_unk; // 60
|
||||
u8 firm_version_rev; // 61
|
||||
u8 firm_version_min; // 62
|
||||
u8 firm_version_maj; // 63
|
||||
u8 firm_unk; // 60
|
||||
u8 firm_version_rev; // 61
|
||||
u8 firm_version_min; // 62
|
||||
u8 firm_version_maj; // 63
|
||||
u32_le firm_sys_core_ver; // 64
|
||||
u32_le firm_ctr_sdk_ver; // 68
|
||||
INSERT_PADDING_BYTES(0x1000 - 0x6C); // 6C
|
||||
};
|
||||
static_assert(sizeof(ConfigMemDef) == Memory::CONFIG_MEMORY_SIZE, "Config Memory structure size is wrong");
|
||||
static_assert(sizeof(ConfigMemDef) == Memory::CONFIG_MEMORY_SIZE,
|
||||
"Config Memory structure size is wrong");
|
||||
|
||||
extern ConfigMemDef config_mem;
|
||||
|
||||
|
@ -7,14 +7,14 @@
|
||||
#include "common/common_types.h"
|
||||
|
||||
#include "core/arm/arm_interface.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/hle/hle.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/svc.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace HLE {
|
||||
|
||||
#define PARAM(n) Core::g_app_core->GetReg(n)
|
||||
#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);
|
||||
@ -40,28 +40,33 @@ static inline void FuncReturn64(u64 res) {
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Function wrappers that return type ResultCode
|
||||
|
||||
template<ResultCode func(u32, u32, u32, u32)> void Wrap() {
|
||||
template <ResultCode func(u32, u32, u32, u32)>
|
||||
void Wrap() {
|
||||
FuncReturn(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)).raw);
|
||||
}
|
||||
|
||||
template<ResultCode func(u32*, u32, u32, u32, u32, u32)> void Wrap(){
|
||||
template <ResultCode func(u32*, u32, u32, u32, u32, u32)>
|
||||
void Wrap() {
|
||||
u32 param_1 = 0;
|
||||
u32 retval = func(¶m_1, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)).raw;
|
||||
Core::g_app_core->SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template<ResultCode func(u32*, s32, u32, u32, u32, s32)> void Wrap() {
|
||||
template <ResultCode func(u32*, s32, u32, u32, u32, s32)>
|
||||
void Wrap() {
|
||||
u32 param_1 = 0;
|
||||
u32 retval = func(¶m_1, PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4)).raw;
|
||||
Core::g_app_core->SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template<ResultCode func(s32*, u32*, s32, bool, s64)> void Wrap() {
|
||||
template <ResultCode func(s32*, u32*, s32, bool, s64)>
|
||||
void Wrap() {
|
||||
s32 param_1 = 0;
|
||||
s32 retval = func(¶m_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2),
|
||||
(PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0))).raw;
|
||||
(PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0)))
|
||||
.raw;
|
||||
|
||||
if (retval != RESULT_INVALID.raw) {
|
||||
Core::g_app_core->SetReg(1, (u32)param_1);
|
||||
@ -69,18 +74,22 @@ template<ResultCode func(s32*, u32*, s32, bool, s64)> void Wrap() {
|
||||
}
|
||||
}
|
||||
|
||||
template<ResultCode func(u32, u32, u32, u32, s64)> void Wrap() {
|
||||
FuncReturn(func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), (((s64)PARAM(5) << 32) | PARAM(4))).raw);
|
||||
template <ResultCode func(u32, u32, u32, u32, s64)>
|
||||
void Wrap() {
|
||||
FuncReturn(
|
||||
func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), (((s64)PARAM(5) << 32) | PARAM(4))).raw);
|
||||
}
|
||||
|
||||
template<ResultCode func(u32*)> void Wrap(){
|
||||
template <ResultCode func(u32*)>
|
||||
void Wrap() {
|
||||
u32 param_1 = 0;
|
||||
u32 retval = func(¶m_1).raw;
|
||||
Core::g_app_core->SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template<ResultCode func(u32, s64)> void Wrap() {
|
||||
template <ResultCode func(u32, s64)>
|
||||
void Wrap() {
|
||||
s32 retval = func(PARAM(0), (((s64)PARAM(3) << 32) | PARAM(2))).raw;
|
||||
|
||||
if (retval != RESULT_INVALID.raw) {
|
||||
@ -88,7 +97,8 @@ template<ResultCode func(u32, s64)> void Wrap() {
|
||||
}
|
||||
}
|
||||
|
||||
template<ResultCode func(MemoryInfo*, PageInfo*, u32)> void Wrap() {
|
||||
template <ResultCode func(MemoryInfo*, PageInfo*, u32)>
|
||||
void Wrap() {
|
||||
MemoryInfo memory_info = {};
|
||||
PageInfo page_info = {};
|
||||
u32 retval = func(&memory_info, &page_info, PARAM(2)).raw;
|
||||
@ -100,7 +110,8 @@ template<ResultCode func(MemoryInfo*, PageInfo*, u32)> void Wrap() {
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template<ResultCode func(MemoryInfo*, PageInfo*, Handle, u32)> void Wrap() {
|
||||
template <ResultCode func(MemoryInfo*, PageInfo*, Handle, u32)>
|
||||
void Wrap() {
|
||||
MemoryInfo memory_info = {};
|
||||
PageInfo page_info = {};
|
||||
u32 retval = func(&memory_info, &page_info, PARAM(2), PARAM(3)).raw;
|
||||
@ -112,55 +123,65 @@ template<ResultCode func(MemoryInfo*, PageInfo*, Handle, u32)> void Wrap() {
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template<ResultCode func(s32*, u32)> void Wrap(){
|
||||
template <ResultCode func(s32*, u32)>
|
||||
void Wrap() {
|
||||
s32 param_1 = 0;
|
||||
u32 retval = func(¶m_1, PARAM(1)).raw;
|
||||
Core::g_app_core->SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template<ResultCode func(u32, s32)> void Wrap() {
|
||||
template <ResultCode func(u32, s32)>
|
||||
void Wrap() {
|
||||
FuncReturn(func(PARAM(0), (s32)PARAM(1)).raw);
|
||||
}
|
||||
|
||||
template<ResultCode func(u32*, u32)> void Wrap(){
|
||||
template <ResultCode func(u32*, u32)>
|
||||
void Wrap() {
|
||||
u32 param_1 = 0;
|
||||
u32 retval = func(¶m_1, PARAM(1)).raw;
|
||||
Core::g_app_core->SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template<ResultCode func(u32)> void Wrap() {
|
||||
template <ResultCode func(u32)>
|
||||
void Wrap() {
|
||||
FuncReturn(func(PARAM(0)).raw);
|
||||
}
|
||||
|
||||
template<ResultCode func(s64*, u32, u32*, u32)> void Wrap(){
|
||||
FuncReturn(func((s64*)Memory::GetPointer(PARAM(0)), PARAM(1), (u32*)Memory::GetPointer(PARAM(2)),
|
||||
(s32)PARAM(3)).raw);
|
||||
template <ResultCode func(s64*, u32, u32*, u32)>
|
||||
void Wrap() {
|
||||
FuncReturn(func((s64*)Memory::GetPointer(PARAM(0)), PARAM(1),
|
||||
(u32*)Memory::GetPointer(PARAM(2)), (s32)PARAM(3))
|
||||
.raw);
|
||||
}
|
||||
|
||||
template<ResultCode func(u32*, const char*)> void Wrap() {
|
||||
template <ResultCode func(u32*, const char*)>
|
||||
void Wrap() {
|
||||
u32 param_1 = 0;
|
||||
u32 retval = func(¶m_1, (char*)Memory::GetPointer(PARAM(1))).raw;
|
||||
Core::g_app_core->SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template<ResultCode func(u32*, s32, s32)> void Wrap() {
|
||||
template <ResultCode func(u32*, s32, s32)>
|
||||
void Wrap() {
|
||||
u32 param_1 = 0;
|
||||
u32 retval = func(¶m_1, PARAM(1), PARAM(2)).raw;
|
||||
Core::g_app_core->SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template<ResultCode func(s32*, u32, s32)> void Wrap() {
|
||||
template <ResultCode func(s32*, u32, s32)>
|
||||
void Wrap() {
|
||||
s32 param_1 = 0;
|
||||
u32 retval = func(¶m_1, PARAM(1), PARAM(2)).raw;
|
||||
Core::g_app_core->SetReg(1, param_1);
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template<ResultCode func(s64*, u32, s32)> void Wrap() {
|
||||
template <ResultCode func(s64*, u32, s32)>
|
||||
void Wrap() {
|
||||
s64 param_1 = 0;
|
||||
u32 retval = func(¶m_1, PARAM(1), PARAM(2)).raw;
|
||||
Core::g_app_core->SetReg(1, (u32)param_1);
|
||||
@ -168,7 +189,8 @@ template<ResultCode func(s64*, u32, s32)> void Wrap() {
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template<ResultCode func(u32*, u32, u32, u32, u32)> void Wrap() {
|
||||
template <ResultCode func(u32*, u32, u32, u32, u32)>
|
||||
void Wrap() {
|
||||
u32 param_1 = 0;
|
||||
// The last parameter is passed in R0 instead of R4
|
||||
u32 retval = func(¶m_1, PARAM(1), PARAM(2), PARAM(3), PARAM(0)).raw;
|
||||
@ -176,13 +198,15 @@ template<ResultCode func(u32*, u32, u32, u32, u32)> void Wrap() {
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template<ResultCode func(u32, s64, s64)> void Wrap() {
|
||||
template <ResultCode func(u32, s64, s64)>
|
||||
void Wrap() {
|
||||
s64 param1 = ((u64)PARAM(3) << 32) | PARAM(2);
|
||||
s64 param2 = ((u64)PARAM(4) << 32) | PARAM(1);
|
||||
FuncReturn(func(PARAM(0), param1, param2).raw);
|
||||
}
|
||||
|
||||
template<ResultCode func(s64*, Handle, u32)> void Wrap() {
|
||||
template <ResultCode func(s64*, Handle, u32)>
|
||||
void Wrap() {
|
||||
s64 param_1 = 0;
|
||||
u32 retval = func(¶m_1, PARAM(1), PARAM(2)).raw;
|
||||
Core::g_app_core->SetReg(1, (u32)param_1);
|
||||
@ -190,14 +214,18 @@ template<ResultCode func(s64*, Handle, u32)> void Wrap() {
|
||||
FuncReturn(retval);
|
||||
}
|
||||
|
||||
template<ResultCode func(Handle, u32)> void Wrap() {
|
||||
template <ResultCode func(Handle, u32)>
|
||||
void Wrap() {
|
||||
FuncReturn(func(PARAM(0), PARAM(1)).raw);
|
||||
}
|
||||
|
||||
template<ResultCode func(Handle*, Handle*, const char*, u32)> void Wrap() {
|
||||
template <ResultCode func(Handle*, Handle*, const char*, u32)>
|
||||
void Wrap() {
|
||||
Handle param_1 = 0;
|
||||
Handle param_2 = 0;
|
||||
u32 retval = func(¶m_1, ¶m_2, reinterpret_cast<const char*>(Memory::GetPointer(PARAM(2))), PARAM(3)).raw;
|
||||
u32 retval = func(¶m_1, ¶m_2,
|
||||
reinterpret_cast<const char*>(Memory::GetPointer(PARAM(2))), PARAM(3))
|
||||
.raw;
|
||||
// The first out parameter is moved into R2 and the second is moved into R1.
|
||||
Core::g_app_core->SetReg(1, param_2);
|
||||
Core::g_app_core->SetReg(2, param_1);
|
||||
@ -207,29 +235,34 @@ template<ResultCode func(Handle*, Handle*, const char*, u32)> void Wrap() {
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Function wrappers that return type u32
|
||||
|
||||
template<u32 func()> void Wrap() {
|
||||
template <u32 func()>
|
||||
void Wrap() {
|
||||
FuncReturn(func());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Function wrappers that return type s64
|
||||
|
||||
template<s64 func()> void Wrap() {
|
||||
template <s64 func()>
|
||||
void Wrap() {
|
||||
FuncReturn64(func());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
/// Function wrappers that return type void
|
||||
|
||||
template<void func(s64)> void Wrap() {
|
||||
template <void func(s64)>
|
||||
void Wrap() {
|
||||
func(((s64)PARAM(1) << 32) | PARAM(0));
|
||||
}
|
||||
|
||||
template<void func(const char*)> void Wrap() {
|
||||
template <void func(const char*)>
|
||||
void Wrap() {
|
||||
func((char*)Memory::GetPointer(PARAM(0)));
|
||||
}
|
||||
|
||||
template<void func(u8)> void Wrap() {
|
||||
template <void func(u8)>
|
||||
void Wrap() {
|
||||
func((u8)PARAM(0));
|
||||
}
|
||||
|
||||
|
@ -15,13 +15,13 @@
|
||||
namespace {
|
||||
|
||||
bool reschedule; ///< If true, immediately reschedules the CPU to a new thread
|
||||
|
||||
}
|
||||
|
||||
namespace HLE {
|
||||
|
||||
void Reschedule(const char *reason) {
|
||||
DEBUG_ASSERT_MSG(reason != nullptr && strlen(reason) < 256, "Reschedule: Invalid or too long reason.");
|
||||
void Reschedule(const char* reason) {
|
||||
DEBUG_ASSERT_MSG(reason != nullptr && strlen(reason) < 256,
|
||||
"Reschedule: Invalid or too long reason.");
|
||||
|
||||
// TODO(bunnei): It seems that games depend on some CPU execution time elapsing during HLE
|
||||
// routines. This simulates that time by artificially advancing the number of CPU "ticks".
|
||||
|
@ -13,7 +13,7 @@ const Handle INVALID_HANDLE = 0;
|
||||
|
||||
namespace HLE {
|
||||
|
||||
void Reschedule(const char *reason);
|
||||
void Reschedule(const char* reason);
|
||||
bool IsReschedulePending();
|
||||
void DoneRescheduling();
|
||||
|
||||
|
@ -16,8 +16,10 @@
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
AddressArbiter::AddressArbiter() {}
|
||||
AddressArbiter::~AddressArbiter() {}
|
||||
AddressArbiter::AddressArbiter() {
|
||||
}
|
||||
AddressArbiter::~AddressArbiter() {
|
||||
}
|
||||
|
||||
SharedPtr<AddressArbiter> AddressArbiter::Create(std::string name) {
|
||||
SharedPtr<AddressArbiter> address_arbiter(new AddressArbiter);
|
||||
@ -28,7 +30,7 @@ SharedPtr<AddressArbiter> AddressArbiter::Create(std::string name) {
|
||||
}
|
||||
|
||||
ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address, s32 value,
|
||||
u64 nanoseconds) {
|
||||
u64 nanoseconds) {
|
||||
switch (type) {
|
||||
|
||||
// Signal thread(s) waiting for arbitrate address...
|
||||
@ -38,7 +40,7 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address,
|
||||
ArbitrateAllThreads(address);
|
||||
} else {
|
||||
// Resume first N threads
|
||||
for(int i = 0; i < value; i++)
|
||||
for (int i = 0; i < value; i++)
|
||||
ArbitrateHighestPriorityThread(address);
|
||||
}
|
||||
break;
|
||||
@ -55,8 +57,7 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address,
|
||||
GetCurrentThread()->WakeAfterDelay(nanoseconds);
|
||||
}
|
||||
break;
|
||||
case ArbitrationType::DecrementAndWaitIfLessThan:
|
||||
{
|
||||
case ArbitrationType::DecrementAndWaitIfLessThan: {
|
||||
s32 memory_value = Memory::Read32(address);
|
||||
if (memory_value < value) {
|
||||
// Only change the memory value if the thread should wait
|
||||
@ -65,8 +66,7 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address,
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ArbitrationType::DecrementAndWaitIfLessThanWithTimeout:
|
||||
{
|
||||
case ArbitrationType::DecrementAndWaitIfLessThanWithTimeout: {
|
||||
s32 memory_value = Memory::Read32(address);
|
||||
if (memory_value < value) {
|
||||
// Only change the memory value if the thread should wait
|
||||
@ -79,17 +79,19 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address,
|
||||
|
||||
default:
|
||||
LOG_ERROR(Kernel, "unknown type=%d", type);
|
||||
return ResultCode(ErrorDescription::InvalidEnumValue, ErrorModule::Kernel, ErrorSummary::WrongArgument, ErrorLevel::Usage);
|
||||
return ResultCode(ErrorDescription::InvalidEnumValue, ErrorModule::Kernel,
|
||||
ErrorSummary::WrongArgument, ErrorLevel::Usage);
|
||||
}
|
||||
|
||||
HLE::Reschedule(__func__);
|
||||
|
||||
// The calls that use a timeout seem to always return a Timeout error even if they did not put the thread to sleep
|
||||
// The calls that use a timeout seem to always return a Timeout error even if they did not put
|
||||
// the thread to sleep
|
||||
if (type == ArbitrationType::WaitIfLessThanWithTimeout ||
|
||||
type == ArbitrationType::DecrementAndWaitIfLessThanWithTimeout) {
|
||||
|
||||
return ResultCode(ErrorDescription::Timeout, ErrorModule::OS,
|
||||
ErrorSummary::StatusChanged, ErrorLevel::Info);
|
||||
return ResultCode(ErrorDescription::Timeout, ErrorModule::OS, ErrorSummary::StatusChanged,
|
||||
ErrorLevel::Info);
|
||||
}
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
@ -36,13 +36,19 @@ public:
|
||||
*/
|
||||
static SharedPtr<AddressArbiter> Create(std::string name = "Unknown");
|
||||
|
||||
std::string GetTypeName() const override { return "Arbiter"; }
|
||||
std::string GetName() const override { return name; }
|
||||
std::string GetTypeName() const override {
|
||||
return "Arbiter";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::AddressArbiter;
|
||||
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
std::string name; ///< Name of address arbiter object (optional)
|
||||
std::string name; ///< Name of address arbiter object (optional)
|
||||
|
||||
ResultCode ArbitrateAddress(ArbitrationType type, VAddr address, s32 value, u64 nanoseconds);
|
||||
|
||||
|
@ -10,7 +10,9 @@
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
ClientPort::ClientPort() {}
|
||||
ClientPort::~ClientPort() {}
|
||||
ClientPort::ClientPort() {
|
||||
}
|
||||
ClientPort::~ClientPort() {
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -17,16 +17,22 @@ class ServerPort;
|
||||
class ClientPort : public Object {
|
||||
public:
|
||||
friend class ServerPort;
|
||||
std::string GetTypeName() const override { return "ClientPort"; }
|
||||
std::string GetName() const override { return name; }
|
||||
std::string GetTypeName() const override {
|
||||
return "ClientPort";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::ClientPort;
|
||||
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port.
|
||||
u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have
|
||||
u32 active_sessions; ///< Number of currently open sessions to this port
|
||||
std::string name; ///< Name of client port (optional)
|
||||
SharedPtr<ServerPort> server_port; ///< ServerPort associated with this client port.
|
||||
u32 max_sessions; ///< Maximum number of simultaneous sessions the port can have
|
||||
u32 active_sessions; ///< Number of currently open sessions to this port
|
||||
std::string name; ///< Name of client port (optional)
|
||||
|
||||
protected:
|
||||
ClientPort();
|
||||
|
@ -2,20 +2,22 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "common/assert.h"
|
||||
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
Event::Event() {}
|
||||
Event::~Event() {}
|
||||
Event::Event() {
|
||||
}
|
||||
Event::~Event() {
|
||||
}
|
||||
|
||||
SharedPtr<Event> Event::Create(ResetType reset_type, std::string name) {
|
||||
SharedPtr<Event> evt(new Event);
|
||||
|
@ -16,7 +16,6 @@ enum class ResetType {
|
||||
Pulse,
|
||||
};
|
||||
|
||||
|
||||
class Event final : public WaitObject {
|
||||
public:
|
||||
/**
|
||||
@ -26,16 +25,22 @@ public:
|
||||
*/
|
||||
static SharedPtr<Event> Create(ResetType reset_type, std::string name = "Unknown");
|
||||
|
||||
std::string GetTypeName() const override { return "Event"; }
|
||||
std::string GetName() const override { return name; }
|
||||
std::string GetTypeName() const override {
|
||||
return "Event";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::Event;
|
||||
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
ResetType reset_type; ///< Current ResetType
|
||||
ResetType reset_type; ///< Current ResetType
|
||||
|
||||
bool signaled; ///< Whether the event has already been signaled
|
||||
std::string name; ///< Name of event (optional)
|
||||
bool signaled; ///< Whether the event has already been signaled
|
||||
std::string name; ///< Name of event (optional)
|
||||
|
||||
bool ShouldWait() override;
|
||||
void Acquire() override;
|
||||
|
@ -61,7 +61,8 @@ ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) {
|
||||
|
||||
// Overflow count so it fits in the 15 bits dedicated to the generation in the handle.
|
||||
// CTR-OS doesn't use generation 0, so skip straight to 1.
|
||||
if (next_generation >= (1 << 15)) next_generation = 1;
|
||||
if (next_generation >= (1 << 15))
|
||||
next_generation = 1;
|
||||
|
||||
generations[slot] = generation;
|
||||
objects[slot] = std::move(obj);
|
||||
|
@ -23,48 +23,55 @@ class Thread;
|
||||
|
||||
// TODO: Verify code
|
||||
const ResultCode ERR_OUT_OF_HANDLES(ErrorDescription::OutOfMemory, ErrorModule::Kernel,
|
||||
ErrorSummary::OutOfResource, ErrorLevel::Temporary);
|
||||
ErrorSummary::OutOfResource, ErrorLevel::Temporary);
|
||||
// TOOD: Verify code
|
||||
const ResultCode ERR_INVALID_HANDLE(ErrorDescription::InvalidHandle, ErrorModule::Kernel,
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
|
||||
|
||||
enum KernelHandle : Handle {
|
||||
CurrentThread = 0xFFFF8000,
|
||||
CurrentProcess = 0xFFFF8001,
|
||||
CurrentThread = 0xFFFF8000,
|
||||
CurrentProcess = 0xFFFF8001,
|
||||
};
|
||||
|
||||
enum class HandleType : u32 {
|
||||
Unknown = 0,
|
||||
Unknown = 0,
|
||||
|
||||
Session = 2,
|
||||
Event = 3,
|
||||
Mutex = 4,
|
||||
SharedMemory = 5,
|
||||
Redirection = 6,
|
||||
Thread = 7,
|
||||
Process = 8,
|
||||
AddressArbiter = 9,
|
||||
Semaphore = 10,
|
||||
Timer = 11,
|
||||
ResourceLimit = 12,
|
||||
CodeSet = 13,
|
||||
ClientPort = 14,
|
||||
ServerPort = 15,
|
||||
Session = 2,
|
||||
Event = 3,
|
||||
Mutex = 4,
|
||||
SharedMemory = 5,
|
||||
Redirection = 6,
|
||||
Thread = 7,
|
||||
Process = 8,
|
||||
AddressArbiter = 9,
|
||||
Semaphore = 10,
|
||||
Timer = 11,
|
||||
ResourceLimit = 12,
|
||||
CodeSet = 13,
|
||||
ClientPort = 14,
|
||||
ServerPort = 15,
|
||||
};
|
||||
|
||||
enum {
|
||||
DEFAULT_STACK_SIZE = 0x4000,
|
||||
DEFAULT_STACK_SIZE = 0x4000,
|
||||
};
|
||||
|
||||
class Object : NonCopyable {
|
||||
public:
|
||||
virtual ~Object() {}
|
||||
virtual ~Object() {
|
||||
}
|
||||
|
||||
/// Returns a unique identifier for the object. For debugging purposes only.
|
||||
unsigned int GetObjectId() const { return object_id; }
|
||||
unsigned int GetObjectId() const {
|
||||
return object_id;
|
||||
}
|
||||
|
||||
virtual std::string GetTypeName() const { return "[BAD KERNEL OBJECT TYPE]"; }
|
||||
virtual std::string GetName() const { return "[UNKNOWN KERNEL OBJECT]"; }
|
||||
virtual std::string GetTypeName() const {
|
||||
return "[BAD KERNEL OBJECT TYPE]";
|
||||
}
|
||||
virtual std::string GetName() const {
|
||||
return "[UNKNOWN KERNEL OBJECT]";
|
||||
}
|
||||
virtual Kernel::HandleType GetHandleType() const = 0;
|
||||
|
||||
/**
|
||||
@ -122,7 +129,6 @@ using SharedPtr = boost::intrusive_ptr<T>;
|
||||
/// Class that represents a Kernel object that a thread can be waiting on
|
||||
class WaitObject : public Object {
|
||||
public:
|
||||
|
||||
/**
|
||||
* Check if the current thread should wait until the object is available
|
||||
* @return True if the current thread should wait due to this object being unavailable
|
||||
@ -247,8 +253,12 @@ private:
|
||||
*/
|
||||
static const size_t MAX_COUNT = 4096;
|
||||
|
||||
static u16 GetSlot(Handle handle) { return handle >> 15; }
|
||||
static u16 GetGeneration(Handle handle) { return handle & 0x7FFF; }
|
||||
static u16 GetSlot(Handle handle) {
|
||||
return handle >> 15;
|
||||
}
|
||||
static u16 GetGeneration(Handle handle) {
|
||||
return handle & 0x7FFF;
|
||||
}
|
||||
|
||||
/// Stores the Object referenced by the handle or null if the slot is empty.
|
||||
std::array<SharedPtr<Object>, MAX_COUNT> objects;
|
||||
|
@ -31,7 +31,7 @@ static MemoryRegionInfo memory_regions[3];
|
||||
static const u32 memory_region_sizes[8][3] = {
|
||||
// Old 3DS layouts
|
||||
{0x04000000, 0x02C00000, 0x01400000}, // 0
|
||||
{ /* This appears to be unused. */ }, // 1
|
||||
{/* This appears to be unused. */}, // 1
|
||||
{0x06000000, 0x00C00000, 0x01400000}, // 2
|
||||
{0x05000000, 0x01C00000, 0x01400000}, // 3
|
||||
{0x04800000, 0x02400000, 0x01400000}, // 4
|
||||
@ -95,7 +95,6 @@ MemoryRegionInfo* GetMemoryRegion(MemoryRegion region) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Memory {
|
||||
@ -110,9 +109,8 @@ struct MemoryArea {
|
||||
|
||||
// We don't declare the IO regions in here since its handled by other means.
|
||||
static MemoryArea memory_areas[] = {
|
||||
{VRAM_VADDR, VRAM_SIZE, "VRAM"}, // Video memory (VRAM)
|
||||
{VRAM_VADDR, VRAM_SIZE, "VRAM"}, // Video memory (VRAM)
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void Init() {
|
||||
@ -125,15 +123,21 @@ void InitLegacyAddressSpace(Kernel::VMManager& address_space) {
|
||||
|
||||
for (MemoryArea& area : memory_areas) {
|
||||
auto block = std::make_shared<std::vector<u8>>(area.size);
|
||||
address_space.MapMemoryBlock(area.base, std::move(block), 0, area.size, MemoryState::Private).Unwrap();
|
||||
address_space
|
||||
.MapMemoryBlock(area.base, std::move(block), 0, area.size, MemoryState::Private)
|
||||
.Unwrap();
|
||||
}
|
||||
|
||||
auto cfg_mem_vma = address_space.MapBackingMemory(CONFIG_MEMORY_VADDR,
|
||||
(u8*)&ConfigMem::config_mem, CONFIG_MEMORY_SIZE, MemoryState::Shared).MoveFrom();
|
||||
auto cfg_mem_vma = address_space
|
||||
.MapBackingMemory(CONFIG_MEMORY_VADDR, (u8*)&ConfigMem::config_mem,
|
||||
CONFIG_MEMORY_SIZE, MemoryState::Shared)
|
||||
.MoveFrom();
|
||||
address_space.Reprotect(cfg_mem_vma, VMAPermission::Read);
|
||||
|
||||
auto shared_page_vma = address_space.MapBackingMemory(SHARED_PAGE_VADDR,
|
||||
(u8*)&SharedPage::shared_page, SHARED_PAGE_SIZE, MemoryState::Shared).MoveFrom();
|
||||
auto shared_page_vma = address_space
|
||||
.MapBackingMemory(SHARED_PAGE_VADDR, (u8*)&SharedPage::shared_page,
|
||||
SHARED_PAGE_SIZE, MemoryState::Shared)
|
||||
.MoveFrom();
|
||||
address_space.Reprotect(shared_page_vma, VMAPermission::Read);
|
||||
|
||||
AudioCore::AddAddressSpace(address_space);
|
||||
|
@ -25,7 +25,6 @@ struct MemoryRegionInfo {
|
||||
void MemoryInit(u32 mem_type);
|
||||
void MemoryShutdown();
|
||||
MemoryRegionInfo* GetMemoryRegion(MemoryRegion region);
|
||||
|
||||
}
|
||||
|
||||
namespace Memory {
|
||||
|
@ -33,8 +33,10 @@ void ReleaseThreadMutexes(Thread* thread) {
|
||||
thread->held_mutexes.clear();
|
||||
}
|
||||
|
||||
Mutex::Mutex() {}
|
||||
Mutex::~Mutex() {}
|
||||
Mutex::Mutex() {
|
||||
}
|
||||
Mutex::~Mutex() {
|
||||
}
|
||||
|
||||
SharedPtr<Mutex> Mutex::Create(bool initial_locked, std::string name) {
|
||||
SharedPtr<Mutex> mutex(new Mutex);
|
||||
|
@ -24,15 +24,21 @@ public:
|
||||
*/
|
||||
static SharedPtr<Mutex> Create(bool initial_locked, std::string name = "Unknown");
|
||||
|
||||
std::string GetTypeName() const override { return "Mutex"; }
|
||||
std::string GetName() const override { return name; }
|
||||
std::string GetTypeName() const override {
|
||||
return "Mutex";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::Mutex;
|
||||
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
int lock_count; ///< Number of times the mutex has been acquired
|
||||
std::string name; ///< Name of mutex (optional)
|
||||
SharedPtr<Thread> holding_thread; ///< Thread that has acquired the mutex
|
||||
int lock_count; ///< Number of times the mutex has been acquired
|
||||
std::string name; ///< Name of mutex (optional)
|
||||
SharedPtr<Thread> holding_thread; ///< Thread that has acquired the mutex
|
||||
|
||||
bool ShouldWait() override;
|
||||
void Acquire() override;
|
||||
|
@ -26,8 +26,10 @@ SharedPtr<CodeSet> CodeSet::Create(std::string name, u64 program_id) {
|
||||
return codeset;
|
||||
}
|
||||
|
||||
CodeSet::CodeSet() {}
|
||||
CodeSet::~CodeSet() {}
|
||||
CodeSet::CodeSet() {
|
||||
}
|
||||
CodeSet::~CodeSet() {
|
||||
}
|
||||
|
||||
u32 Process::next_process_id;
|
||||
|
||||
@ -60,7 +62,8 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) {
|
||||
|
||||
while (bits && index < svc_access_mask.size()) {
|
||||
svc_access_mask.set(index, bits & 1);
|
||||
++index; bits >>= 1;
|
||||
++index;
|
||||
bits >>= 1;
|
||||
}
|
||||
} else if ((type & 0xFF0) == 0xFE0) { // 0x00FF
|
||||
// Handle table size
|
||||
@ -70,11 +73,11 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) {
|
||||
flags.raw = descriptor & 0xFFFF;
|
||||
} else if ((type & 0xFFE) == 0xFF8) { // 0x001F
|
||||
// Mapped memory range
|
||||
if (i+1 >= len || ((kernel_caps[i+1] >> 20) & 0xFFE) != 0xFF8) {
|
||||
if (i + 1 >= len || ((kernel_caps[i + 1] >> 20) & 0xFFE) != 0xFF8) {
|
||||
LOG_WARNING(Loader, "Incomplete exheader memory range descriptor ignored.");
|
||||
continue;
|
||||
}
|
||||
u32 end_desc = kernel_caps[i+1];
|
||||
u32 end_desc = kernel_caps[i + 1];
|
||||
++i; // Skip over the second descriptor on the next iteration
|
||||
|
||||
AddressMapping mapping;
|
||||
@ -107,23 +110,28 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) {
|
||||
void Process::Run(s32 main_thread_priority, u32 stack_size) {
|
||||
memory_region = GetMemoryRegion(flags.memory_region);
|
||||
|
||||
auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions, MemoryState memory_state) {
|
||||
auto vma = vm_manager.MapMemoryBlock(segment.addr, codeset->memory,
|
||||
segment.offset, segment.size, memory_state).Unwrap();
|
||||
auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions,
|
||||
MemoryState memory_state) {
|
||||
auto vma = vm_manager
|
||||
.MapMemoryBlock(segment.addr, codeset->memory, segment.offset, segment.size,
|
||||
memory_state)
|
||||
.Unwrap();
|
||||
vm_manager.Reprotect(vma, permissions);
|
||||
misc_memory_used += segment.size;
|
||||
memory_region->used += segment.size;
|
||||
};
|
||||
|
||||
// Map CodeSet segments
|
||||
MapSegment(codeset->code, VMAPermission::ReadExecute, MemoryState::Code);
|
||||
MapSegment(codeset->rodata, VMAPermission::Read, MemoryState::Code);
|
||||
MapSegment(codeset->data, VMAPermission::ReadWrite, MemoryState::Private);
|
||||
MapSegment(codeset->code, VMAPermission::ReadExecute, MemoryState::Code);
|
||||
MapSegment(codeset->rodata, VMAPermission::Read, MemoryState::Code);
|
||||
MapSegment(codeset->data, VMAPermission::ReadWrite, MemoryState::Private);
|
||||
|
||||
// Allocate and map stack
|
||||
vm_manager.MapMemoryBlock(Memory::HEAP_VADDR_END - stack_size,
|
||||
std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size, MemoryState::Locked
|
||||
).Unwrap();
|
||||
vm_manager
|
||||
.MapMemoryBlock(Memory::HEAP_VADDR_END - stack_size,
|
||||
std::make_shared<std::vector<u8>>(stack_size, 0), 0, stack_size,
|
||||
MemoryState::Locked)
|
||||
.Unwrap();
|
||||
misc_memory_used += stack_size;
|
||||
memory_region->used += stack_size;
|
||||
|
||||
@ -143,7 +151,8 @@ VAddr Process::GetLinearHeapLimit() const {
|
||||
}
|
||||
|
||||
ResultVal<VAddr> Process::HeapAllocate(VAddr target, u32 size, VMAPermission perms) {
|
||||
if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END || target + size < target) {
|
||||
if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END ||
|
||||
target + size < target) {
|
||||
return ERR_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
@ -166,7 +175,8 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u32 size, VMAPermission per
|
||||
}
|
||||
ASSERT(heap_end - heap_start == heap_memory->size());
|
||||
|
||||
CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, heap_memory, target - heap_start, size, MemoryState::Private));
|
||||
CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, heap_memory, target - heap_start,
|
||||
size, MemoryState::Private));
|
||||
vm_manager.Reprotect(vma, perms);
|
||||
|
||||
heap_used += size;
|
||||
@ -176,7 +186,8 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u32 size, VMAPermission per
|
||||
}
|
||||
|
||||
ResultCode Process::HeapFree(VAddr target, u32 size) {
|
||||
if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END || target + size < target) {
|
||||
if (target < Memory::HEAP_VADDR || target + size > Memory::HEAP_VADDR_END ||
|
||||
target + size < target) {
|
||||
return ERR_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
@ -185,7 +196,8 @@ ResultCode Process::HeapFree(VAddr target, u32 size) {
|
||||
}
|
||||
|
||||
ResultCode result = vm_manager.UnmapRange(target, size);
|
||||
if (result.IsError()) return result;
|
||||
if (result.IsError())
|
||||
return result;
|
||||
|
||||
heap_used -= size;
|
||||
memory_region->used -= size;
|
||||
@ -203,8 +215,8 @@ ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission p
|
||||
target = heap_end;
|
||||
}
|
||||
|
||||
if (target < GetLinearHeapBase() || target + size > GetLinearHeapLimit() ||
|
||||
target > heap_end || target + size < target) {
|
||||
if (target < GetLinearHeapBase() || target + size > GetLinearHeapLimit() || target > heap_end ||
|
||||
target + size < target) {
|
||||
|
||||
return ERR_INVALID_ADDRESS;
|
||||
}
|
||||
@ -220,7 +232,8 @@ ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission p
|
||||
// TODO(yuriks): As is, this lets processes map memory allocated by other processes from the
|
||||
// same region. It is unknown if or how the 3DS kernel checks against this.
|
||||
size_t offset = target - GetLinearHeapBase();
|
||||
CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, linheap_memory, offset, size, MemoryState::Continuous));
|
||||
CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, linheap_memory, offset, size,
|
||||
MemoryState::Continuous));
|
||||
vm_manager.Reprotect(vma, perms);
|
||||
|
||||
linear_heap_used += size;
|
||||
@ -248,7 +261,8 @@ ResultCode Process::LinearFree(VAddr target, u32 size) {
|
||||
}
|
||||
|
||||
ResultCode result = vm_manager.UnmapRange(target, size);
|
||||
if (result.IsError()) return result;
|
||||
if (result.IsError())
|
||||
return result;
|
||||
|
||||
linear_heap_used -= size;
|
||||
memory_region->used -= size;
|
||||
@ -268,9 +282,10 @@ ResultCode Process::LinearFree(VAddr target, u32 size) {
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
Kernel::Process::Process() {}
|
||||
Kernel::Process::~Process() {}
|
||||
Kernel::Process::Process() {
|
||||
}
|
||||
Kernel::Process::~Process() {
|
||||
}
|
||||
|
||||
SharedPtr<Process> g_current_process;
|
||||
|
||||
}
|
||||
|
@ -36,15 +36,18 @@ enum class MemoryRegion : u16 {
|
||||
union ProcessFlags {
|
||||
u16 raw;
|
||||
|
||||
BitField< 0, 1, u16> allow_debug; ///< Allows other processes to attach to and debug this process.
|
||||
BitField< 1, 1, u16> force_debug; ///< Allows this process to attach to processes even if they don't have allow_debug set.
|
||||
BitField< 2, 1, u16> allow_nonalphanum;
|
||||
BitField< 3, 1, u16> shared_page_writable; ///< Shared page is mapped with write permissions.
|
||||
BitField< 4, 1, u16> privileged_priority; ///< Can use priority levels higher than 24.
|
||||
BitField< 5, 1, u16> allow_main_args;
|
||||
BitField< 6, 1, u16> shared_device_mem;
|
||||
BitField< 7, 1, u16> runnable_on_sleep;
|
||||
BitField< 8, 4, MemoryRegion> memory_region; ///< Default region for memory allocations for this process
|
||||
BitField<0, 1, u16>
|
||||
allow_debug; ///< Allows other processes to attach to and debug this process.
|
||||
BitField<1, 1, u16> force_debug; ///< Allows this process to attach to processes even if they
|
||||
/// don't have allow_debug set.
|
||||
BitField<2, 1, u16> allow_nonalphanum;
|
||||
BitField<3, 1, u16> shared_page_writable; ///< Shared page is mapped with write permissions.
|
||||
BitField<4, 1, u16> privileged_priority; ///< Can use priority levels higher than 24.
|
||||
BitField<5, 1, u16> allow_main_args;
|
||||
BitField<6, 1, u16> shared_device_mem;
|
||||
BitField<7, 1, u16> runnable_on_sleep;
|
||||
BitField<8, 4, MemoryRegion>
|
||||
memory_region; ///< Default region for memory allocations for this process
|
||||
BitField<12, 1, u16> loaded_high; ///< Application loaded high (not at 0x00100000).
|
||||
};
|
||||
|
||||
@ -54,11 +57,17 @@ struct MemoryRegionInfo;
|
||||
struct CodeSet final : public Object {
|
||||
static SharedPtr<CodeSet> Create(std::string name, u64 program_id);
|
||||
|
||||
std::string GetTypeName() const override { return "CodeSet"; }
|
||||
std::string GetName() const override { return name; }
|
||||
std::string GetTypeName() const override {
|
||||
return "CodeSet";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::CodeSet;
|
||||
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
/// Name of the process
|
||||
std::string name;
|
||||
@ -85,11 +94,17 @@ class Process final : public Object {
|
||||
public:
|
||||
static SharedPtr<Process> Create(SharedPtr<CodeSet> code_set);
|
||||
|
||||
std::string GetTypeName() const override { return "Process"; }
|
||||
std::string GetName() const override { return codeset->name; }
|
||||
std::string GetTypeName() const override {
|
||||
return "Process";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return codeset->name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::Process;
|
||||
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
static u32 next_process_id;
|
||||
|
||||
@ -124,7 +139,6 @@ public:
|
||||
*/
|
||||
void Run(s32 main_thread_priority, u32 stack_size);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Memory Management
|
||||
|
||||
@ -144,7 +158,8 @@ public:
|
||||
|
||||
/// The Thread Local Storage area is allocated as processes create threads,
|
||||
/// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part
|
||||
/// holds the TLS for a specific thread. This vector contains which parts are in use for each page as a bitmask.
|
||||
/// holds the TLS for a specific thread. This vector contains which parts are in use for each
|
||||
/// page as a bitmask.
|
||||
/// This vector will grow as more pages are allocated for new threads.
|
||||
std::vector<std::bitset<8>> tls_slots;
|
||||
|
||||
@ -164,5 +179,4 @@ private:
|
||||
};
|
||||
|
||||
extern SharedPtr<Process> g_current_process;
|
||||
|
||||
}
|
||||
|
@ -12,8 +12,10 @@ namespace Kernel {
|
||||
|
||||
static SharedPtr<ResourceLimit> resource_limits[4];
|
||||
|
||||
ResourceLimit::ResourceLimit() {}
|
||||
ResourceLimit::~ResourceLimit() {}
|
||||
ResourceLimit::ResourceLimit() {
|
||||
}
|
||||
ResourceLimit::~ResourceLimit() {
|
||||
}
|
||||
|
||||
SharedPtr<ResourceLimit> ResourceLimit::Create(std::string name) {
|
||||
SharedPtr<ResourceLimit> resource_limit(new ResourceLimit);
|
||||
@ -23,70 +25,69 @@ SharedPtr<ResourceLimit> ResourceLimit::Create(std::string name) {
|
||||
}
|
||||
|
||||
SharedPtr<ResourceLimit> ResourceLimit::GetForCategory(ResourceLimitCategory category) {
|
||||
switch (category)
|
||||
{
|
||||
case ResourceLimitCategory::APPLICATION:
|
||||
case ResourceLimitCategory::SYS_APPLET:
|
||||
case ResourceLimitCategory::LIB_APPLET:
|
||||
case ResourceLimitCategory::OTHER:
|
||||
return resource_limits[static_cast<u8>(category)];
|
||||
default:
|
||||
LOG_CRITICAL(Kernel, "Unknown resource limit category");
|
||||
UNREACHABLE();
|
||||
switch (category) {
|
||||
case ResourceLimitCategory::APPLICATION:
|
||||
case ResourceLimitCategory::SYS_APPLET:
|
||||
case ResourceLimitCategory::LIB_APPLET:
|
||||
case ResourceLimitCategory::OTHER:
|
||||
return resource_limits[static_cast<u8>(category)];
|
||||
default:
|
||||
LOG_CRITICAL(Kernel, "Unknown resource limit category");
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
s32 ResourceLimit::GetCurrentResourceValue(u32 resource) const {
|
||||
switch (resource) {
|
||||
case COMMIT:
|
||||
return current_commit;
|
||||
case THREAD:
|
||||
return current_threads;
|
||||
case EVENT:
|
||||
return current_events;
|
||||
case MUTEX:
|
||||
return current_mutexes;
|
||||
case SEMAPHORE:
|
||||
return current_semaphores;
|
||||
case TIMER:
|
||||
return current_timers;
|
||||
case SHARED_MEMORY:
|
||||
return current_shared_mems;
|
||||
case ADDRESS_ARBITER:
|
||||
return current_address_arbiters;
|
||||
case CPU_TIME:
|
||||
return current_cpu_time;
|
||||
default:
|
||||
LOG_ERROR(Kernel, "Unknown resource type=%08X", resource);
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
case COMMIT:
|
||||
return current_commit;
|
||||
case THREAD:
|
||||
return current_threads;
|
||||
case EVENT:
|
||||
return current_events;
|
||||
case MUTEX:
|
||||
return current_mutexes;
|
||||
case SEMAPHORE:
|
||||
return current_semaphores;
|
||||
case TIMER:
|
||||
return current_timers;
|
||||
case SHARED_MEMORY:
|
||||
return current_shared_mems;
|
||||
case ADDRESS_ARBITER:
|
||||
return current_address_arbiters;
|
||||
case CPU_TIME:
|
||||
return current_cpu_time;
|
||||
default:
|
||||
LOG_ERROR(Kernel, "Unknown resource type=%08X", resource);
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
s32 ResourceLimit::GetMaxResourceValue(u32 resource) const {
|
||||
switch (resource) {
|
||||
case COMMIT:
|
||||
return max_commit;
|
||||
case THREAD:
|
||||
return max_threads;
|
||||
case EVENT:
|
||||
return max_events;
|
||||
case MUTEX:
|
||||
return max_mutexes;
|
||||
case SEMAPHORE:
|
||||
return max_semaphores;
|
||||
case TIMER:
|
||||
return max_timers;
|
||||
case SHARED_MEMORY:
|
||||
return max_shared_mems;
|
||||
case ADDRESS_ARBITER:
|
||||
return max_address_arbiters;
|
||||
case CPU_TIME:
|
||||
return max_cpu_time;
|
||||
default:
|
||||
LOG_ERROR(Kernel, "Unknown resource type=%08X", resource);
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
case COMMIT:
|
||||
return max_commit;
|
||||
case THREAD:
|
||||
return max_threads;
|
||||
case EVENT:
|
||||
return max_events;
|
||||
case MUTEX:
|
||||
return max_mutexes;
|
||||
case SEMAPHORE:
|
||||
return max_semaphores;
|
||||
case TIMER:
|
||||
return max_timers;
|
||||
case SHARED_MEMORY:
|
||||
return max_shared_mems;
|
||||
case ADDRESS_ARBITER:
|
||||
return max_address_arbiters;
|
||||
case CPU_TIME:
|
||||
return max_cpu_time;
|
||||
default:
|
||||
LOG_ERROR(Kernel, "Unknown resource type=%08X", resource);
|
||||
UNIMPLEMENTED();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -150,7 +151,6 @@ void ResourceLimitsInit() {
|
||||
}
|
||||
|
||||
void ResourceLimitsShutdown() {
|
||||
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -12,22 +12,22 @@ namespace Kernel {
|
||||
|
||||
enum class ResourceLimitCategory : u8 {
|
||||
APPLICATION = 0,
|
||||
SYS_APPLET = 1,
|
||||
LIB_APPLET = 2,
|
||||
OTHER = 3
|
||||
SYS_APPLET = 1,
|
||||
LIB_APPLET = 2,
|
||||
OTHER = 3
|
||||
};
|
||||
|
||||
enum ResourceTypes {
|
||||
PRIORITY = 0,
|
||||
COMMIT = 1,
|
||||
THREAD = 2,
|
||||
EVENT = 3,
|
||||
MUTEX = 4,
|
||||
SEMAPHORE = 5,
|
||||
TIMER = 6,
|
||||
SHARED_MEMORY = 7,
|
||||
ADDRESS_ARBITER = 8,
|
||||
CPU_TIME = 9,
|
||||
PRIORITY = 0,
|
||||
COMMIT = 1,
|
||||
THREAD = 2,
|
||||
EVENT = 3,
|
||||
MUTEX = 4,
|
||||
SEMAPHORE = 5,
|
||||
TIMER = 6,
|
||||
SHARED_MEMORY = 7,
|
||||
ADDRESS_ARBITER = 8,
|
||||
CPU_TIME = 9,
|
||||
};
|
||||
|
||||
class ResourceLimit final : public Object {
|
||||
@ -44,11 +44,17 @@ public:
|
||||
*/
|
||||
static SharedPtr<ResourceLimit> GetForCategory(ResourceLimitCategory category);
|
||||
|
||||
std::string GetTypeName() const override { return "ResourceLimit"; }
|
||||
std::string GetName() const override { return name; }
|
||||
std::string GetTypeName() const override {
|
||||
return "ResourceLimit";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::ResourceLimit;
|
||||
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current value for the specified resource.
|
||||
@ -85,10 +91,12 @@ public:
|
||||
/// 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
|
||||
// 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
|
||||
// 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
|
||||
s32 current_commit = 0;
|
||||
|
@ -10,11 +10,13 @@
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
Semaphore::Semaphore() {}
|
||||
Semaphore::~Semaphore() {}
|
||||
Semaphore::Semaphore() {
|
||||
}
|
||||
Semaphore::~Semaphore() {
|
||||
}
|
||||
|
||||
ResultVal<SharedPtr<Semaphore>> Semaphore::Create(s32 initial_count, s32 max_count,
|
||||
std::string name) {
|
||||
std::string name) {
|
||||
|
||||
if (initial_count > max_count)
|
||||
return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::Kernel,
|
||||
|
@ -23,17 +23,23 @@ public:
|
||||
* @return The created semaphore
|
||||
*/
|
||||
static ResultVal<SharedPtr<Semaphore>> Create(s32 initial_count, s32 max_count,
|
||||
std::string name = "Unknown");
|
||||
std::string name = "Unknown");
|
||||
|
||||
std::string GetTypeName() const override { return "Semaphore"; }
|
||||
std::string GetName() const override { return name; }
|
||||
std::string GetTypeName() const override {
|
||||
return "Semaphore";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::Semaphore;
|
||||
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have
|
||||
s32 available_count; ///< Number of free slots left in the semaphore
|
||||
std::string name; ///< Name of semaphore (optional)
|
||||
s32 max_count; ///< Maximum number of simultaneous holders the semaphore can have
|
||||
s32 available_count; ///< Number of free slots left in the semaphore
|
||||
std::string name; ///< Name of semaphore (optional)
|
||||
|
||||
bool ShouldWait() override;
|
||||
void Acquire() override;
|
||||
|
@ -13,8 +13,10 @@
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
ServerPort::ServerPort() {}
|
||||
ServerPort::~ServerPort() {}
|
||||
ServerPort::ServerPort() {
|
||||
}
|
||||
ServerPort::~ServerPort() {
|
||||
}
|
||||
|
||||
bool ServerPort::ShouldWait() {
|
||||
// If there are no pending sessions, we wait until a new one is added.
|
||||
@ -25,7 +27,8 @@ void ServerPort::Acquire() {
|
||||
ASSERT_MSG(!ShouldWait(), "object unavailable!");
|
||||
}
|
||||
|
||||
std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> ServerPort::CreatePortPair(u32 max_sessions, std::string name) {
|
||||
std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>>
|
||||
ServerPort::CreatePortPair(u32 max_sessions, std::string name) {
|
||||
SharedPtr<ServerPort> server_port(new ServerPort);
|
||||
SharedPtr<ClientPort> client_port(new ClientPort);
|
||||
|
||||
|
@ -23,17 +23,25 @@ public:
|
||||
* @param name Optional name of the ports
|
||||
* @return The created port tuple
|
||||
*/
|
||||
static std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>> CreatePortPair(u32 max_sessions, std::string name = "UnknownPort");
|
||||
static std::tuple<SharedPtr<ServerPort>, SharedPtr<ClientPort>>
|
||||
CreatePortPair(u32 max_sessions, std::string name = "UnknownPort");
|
||||
|
||||
std::string GetTypeName() const override { return "ServerPort"; }
|
||||
std::string GetName() const override { return name; }
|
||||
std::string GetTypeName() const override {
|
||||
return "ServerPort";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::ServerPort;
|
||||
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
std::string name; ///< Name of port (optional)
|
||||
std::string name; ///< Name of port (optional)
|
||||
|
||||
std::vector<SharedPtr<WaitObject>> pending_sessions; ///< ServerSessions waiting to be accepted by the port
|
||||
std::vector<SharedPtr<WaitObject>>
|
||||
pending_sessions; ///< ServerSessions waiting to be accepted by the port
|
||||
|
||||
bool ShouldWait() override;
|
||||
void Acquire() override;
|
||||
|
@ -7,7 +7,8 @@
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
Session::Session() {}
|
||||
Session::~Session() {}
|
||||
|
||||
Session::Session() {
|
||||
}
|
||||
Session::~Session() {
|
||||
}
|
||||
}
|
||||
|
@ -19,12 +19,13 @@ namespace IPC {
|
||||
enum DescriptorType : u32 {
|
||||
// Buffer related desciptors types (mask : 0x0F)
|
||||
StaticBuffer = 0x02,
|
||||
PXIBuffer = 0x04,
|
||||
PXIBuffer = 0x04,
|
||||
MappedBuffer = 0x08,
|
||||
// Handle related descriptors types (mask : 0x30, but need to check for buffer related descriptors first )
|
||||
CopyHandle = 0x00,
|
||||
MoveHandle = 0x10,
|
||||
CallingPid = 0x20,
|
||||
// Handle related descriptors types (mask : 0x30, but need to check for buffer related
|
||||
// descriptors first )
|
||||
CopyHandle = 0x00,
|
||||
MoveHandle = 0x10,
|
||||
CallingPid = 0x20,
|
||||
};
|
||||
|
||||
/**
|
||||
@ -34,24 +35,28 @@ enum DescriptorType : u32 {
|
||||
* @param translate_params_size Size of the translate parameters in words. Up to 63.
|
||||
* @return The created IPC header.
|
||||
*
|
||||
* Normal parameters are sent directly to the process while the translate parameters might go through modifications and checks by the kernel.
|
||||
* Normal parameters are sent directly to the process while the translate parameters might go
|
||||
* through modifications and checks by the kernel.
|
||||
* The translate parameters are described by headers generated with the IPC::*Desc functions.
|
||||
*
|
||||
* @note While #normal_params is equivalent to the number of normal parameters, #translate_params_size includes the size occupied by the translate parameters headers.
|
||||
* @note While #normal_params is equivalent to the number of normal parameters,
|
||||
* #translate_params_size includes the size occupied by the translate parameters headers.
|
||||
*/
|
||||
constexpr u32 MakeHeader(u16 command_id, unsigned int normal_params, unsigned int translate_params_size) {
|
||||
return (u32(command_id) << 16) | ((u32(normal_params) & 0x3F) << 6) | (u32(translate_params_size) & 0x3F);
|
||||
constexpr u32 MakeHeader(u16 command_id, unsigned int normal_params,
|
||||
unsigned int translate_params_size) {
|
||||
return (u32(command_id) << 16) | ((u32(normal_params) & 0x3F) << 6) |
|
||||
(u32(translate_params_size) & 0x3F);
|
||||
}
|
||||
|
||||
union Header {
|
||||
u32 raw;
|
||||
BitField< 0, 6, u32> translate_params_size;
|
||||
BitField< 6, 6, u32> normal_params;
|
||||
BitField<0, 6, u32> translate_params_size;
|
||||
BitField<6, 6, u32> normal_params;
|
||||
BitField<16, 16, u32> command_id;
|
||||
};
|
||||
|
||||
inline Header ParseHeader(u32 header) {
|
||||
return{ header };
|
||||
return {header};
|
||||
}
|
||||
|
||||
constexpr u32 MoveHandleDesc(u32 num_handles = 1) {
|
||||
@ -80,27 +85,29 @@ constexpr u32 StaticBufferDesc(u32 size, u8 buffer_id) {
|
||||
|
||||
union StaticBufferDescInfo {
|
||||
u32 raw;
|
||||
BitField< 10, 4, u32> buffer_id;
|
||||
BitField< 14, 18, u32> size;
|
||||
BitField<10, 4, u32> buffer_id;
|
||||
BitField<14, 18, u32> size;
|
||||
};
|
||||
|
||||
inline StaticBufferDescInfo ParseStaticBufferDesc(const u32 desc) {
|
||||
return{ desc };
|
||||
return {desc};
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Creates a header describing a buffer to be sent over PXI.
|
||||
* @param size Size of the buffer. Max 0x00FFFFFF.
|
||||
* @param buffer_id The Id of the buffer. Max 0xF.
|
||||
* @param is_read_only true if the buffer is read-only. If false, the buffer is considered to have read-write access.
|
||||
* @param is_read_only true if the buffer is read-only. If false, the buffer is considered to have
|
||||
* read-write access.
|
||||
* @return The created PXI buffer header.
|
||||
*
|
||||
* The next value is a phys-address of a table located in the BASE memregion.
|
||||
*/
|
||||
inline u32 PXIBufferDesc(u32 size, unsigned buffer_id, bool is_read_only) {
|
||||
u32 type = PXIBuffer;
|
||||
if (is_read_only) type |= 0x2;
|
||||
return type | (size << 8) | ((buffer_id & 0xF) << 4);
|
||||
if (is_read_only)
|
||||
type |= 0x2;
|
||||
return type | (size << 8) | ((buffer_id & 0xF) << 4);
|
||||
}
|
||||
|
||||
enum MappedBufferPermissions {
|
||||
@ -115,12 +122,12 @@ constexpr u32 MappedBufferDesc(u32 size, MappedBufferPermissions perms) {
|
||||
|
||||
union MappedBufferDescInfo {
|
||||
u32 raw;
|
||||
BitField< 4, 28, u32> size;
|
||||
BitField< 1, 2, MappedBufferPermissions> perms;
|
||||
BitField<4, 28, u32> size;
|
||||
BitField<1, 2, MappedBufferPermissions> perms;
|
||||
};
|
||||
|
||||
inline MappedBufferDescInfo ParseMappedBufferDesc(const u32 desc) {
|
||||
return{ desc };
|
||||
return {desc};
|
||||
}
|
||||
|
||||
inline DescriptorType GetDescriptorType(u32 descriptor) {
|
||||
@ -153,7 +160,8 @@ static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of
|
||||
* @return Pointer to command buffer
|
||||
*/
|
||||
inline u32* GetCommandBuffer(const int offset = 0) {
|
||||
return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset + offset);
|
||||
return (u32*)Memory::GetPointer(GetCurrentThread()->GetTLSAddress() + kCommandHeaderOffset +
|
||||
offset);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -183,10 +191,14 @@ public:
|
||||
Session();
|
||||
~Session() override;
|
||||
|
||||
std::string GetTypeName() const override { return "Session"; }
|
||||
std::string GetTypeName() const override {
|
||||
return "Session";
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::Session;
|
||||
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles a synchronous call to this session using HLE emulation. Emulated <-> emulated calls
|
||||
@ -205,5 +217,4 @@ public:
|
||||
ASSERT_MSG(!ShouldWait(), "object unavailable!");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -6,17 +6,21 @@
|
||||
|
||||
#include "common/logging/log.h"
|
||||
|
||||
#include "core/memory.h"
|
||||
#include "core/hle/kernel/memory.h"
|
||||
#include "core/hle/kernel/shared_memory.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
SharedMemory::SharedMemory() {}
|
||||
SharedMemory::~SharedMemory() {}
|
||||
SharedMemory::SharedMemory() {
|
||||
}
|
||||
SharedMemory::~SharedMemory() {
|
||||
}
|
||||
|
||||
SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u32 size, MemoryPermission permissions,
|
||||
MemoryPermission other_permissions, VAddr address, MemoryRegion region, std::string name) {
|
||||
SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u32 size,
|
||||
MemoryPermission permissions,
|
||||
MemoryPermission other_permissions, VAddr address,
|
||||
MemoryRegion region, std::string name) {
|
||||
SharedPtr<SharedMemory> shared_memory(new SharedMemory);
|
||||
|
||||
shared_memory->owner_process = owner_process;
|
||||
@ -31,7 +35,8 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u
|
||||
MemoryRegionInfo* memory_region = GetMemoryRegion(region);
|
||||
auto& linheap_memory = memory_region->linear_heap_memory;
|
||||
|
||||
ASSERT_MSG(linheap_memory->size() + size <= memory_region->size, "Not enough space in region to allocate shared memory!");
|
||||
ASSERT_MSG(linheap_memory->size() + size <= memory_region->size,
|
||||
"Not enough space in region to allocate shared memory!");
|
||||
|
||||
shared_memory->backing_block = linheap_memory;
|
||||
shared_memory->backing_block_offset = linheap_memory->size();
|
||||
@ -39,7 +44,8 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u
|
||||
linheap_memory->insert(linheap_memory->end(), size, 0);
|
||||
memory_region->used += size;
|
||||
|
||||
shared_memory->linear_heap_phys_address = Memory::FCRAM_PADDR + memory_region->base + shared_memory->backing_block_offset;
|
||||
shared_memory->linear_heap_phys_address =
|
||||
Memory::FCRAM_PADDR + memory_region->base + shared_memory->backing_block_offset;
|
||||
|
||||
// Increase the amount of used linear heap memory for the owner process.
|
||||
if (shared_memory->owner_process != nullptr) {
|
||||
@ -51,18 +57,20 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u
|
||||
Kernel::g_current_process->vm_manager.RefreshMemoryBlockMappings(linheap_memory.get());
|
||||
}
|
||||
} else {
|
||||
// TODO(Subv): What happens if an application tries to create multiple memory blocks pointing to the same address?
|
||||
// TODO(Subv): What happens if an application tries to create multiple memory blocks
|
||||
// pointing to the same address?
|
||||
auto& vm_manager = shared_memory->owner_process->vm_manager;
|
||||
// The memory is already available and mapped in the owner process.
|
||||
auto vma = vm_manager.FindVMA(address)->second;
|
||||
// Copy it over to our own storage
|
||||
shared_memory->backing_block = std::make_shared<std::vector<u8>>(vma.backing_block->data() + vma.offset,
|
||||
vma.backing_block->data() + vma.offset + size);
|
||||
shared_memory->backing_block = std::make_shared<std::vector<u8>>(
|
||||
vma.backing_block->data() + vma.offset, vma.backing_block->data() + vma.offset + size);
|
||||
shared_memory->backing_block_offset = 0;
|
||||
// Unmap the existing pages
|
||||
vm_manager.UnmapRange(address, size);
|
||||
// Map our own block into the address space
|
||||
vm_manager.MapMemoryBlock(address, shared_memory->backing_block, 0, size, MemoryState::Shared);
|
||||
vm_manager.MapMemoryBlock(address, shared_memory->backing_block, 0, size,
|
||||
MemoryState::Shared);
|
||||
// Reprotect the block with the new permissions
|
||||
vm_manager.ReprotectRange(address, size, ConvertPermissions(permissions));
|
||||
}
|
||||
@ -71,8 +79,11 @@ SharedPtr<SharedMemory> SharedMemory::Create(SharedPtr<Process> owner_process, u
|
||||
return shared_memory;
|
||||
}
|
||||
|
||||
SharedPtr<SharedMemory> SharedMemory::CreateForApplet(std::shared_ptr<std::vector<u8>> heap_block, u32 offset, u32 size,
|
||||
MemoryPermission permissions, MemoryPermission other_permissions, std::string name) {
|
||||
SharedPtr<SharedMemory> SharedMemory::CreateForApplet(std::shared_ptr<std::vector<u8>> heap_block,
|
||||
u32 offset, u32 size,
|
||||
MemoryPermission permissions,
|
||||
MemoryPermission other_permissions,
|
||||
std::string name) {
|
||||
SharedPtr<SharedMemory> shared_memory(new SharedMemory);
|
||||
|
||||
shared_memory->owner_process = nullptr;
|
||||
@ -88,27 +99,31 @@ SharedPtr<SharedMemory> SharedMemory::CreateForApplet(std::shared_ptr<std::vecto
|
||||
}
|
||||
|
||||
ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermission permissions,
|
||||
MemoryPermission other_permissions) {
|
||||
MemoryPermission other_permissions) {
|
||||
|
||||
MemoryPermission own_other_permissions = target_process == owner_process ? this->permissions : this->other_permissions;
|
||||
MemoryPermission own_other_permissions =
|
||||
target_process == owner_process ? this->permissions : this->other_permissions;
|
||||
|
||||
// Automatically allocated memory blocks can only be mapped with other_permissions = DontCare
|
||||
if (base_address == 0 && other_permissions != MemoryPermission::DontCare) {
|
||||
return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
||||
return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS,
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
||||
}
|
||||
|
||||
// Error out if the requested permissions don't match what the creator process allows.
|
||||
if (static_cast<u32>(permissions) & ~static_cast<u32>(own_other_permissions)) {
|
||||
LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, permissions don't match",
|
||||
GetObjectId(), address, name.c_str());
|
||||
return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
||||
return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS,
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
||||
}
|
||||
|
||||
// Heap-backed memory blocks can not be mapped with other_permissions = DontCare
|
||||
if (base_address != 0 && other_permissions == MemoryPermission::DontCare) {
|
||||
LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, permissions don't match",
|
||||
GetObjectId(), address, name.c_str());
|
||||
return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
||||
return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS,
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
||||
}
|
||||
|
||||
// Error out if the provided permissions are not compatible with what the creator process needs.
|
||||
@ -116,12 +131,14 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi
|
||||
static_cast<u32>(this->permissions) & ~static_cast<u32>(other_permissions)) {
|
||||
LOG_ERROR(Kernel, "cannot map id=%u, address=0x%08X name=%s, permissions don't match",
|
||||
GetObjectId(), address, name.c_str());
|
||||
return ResultCode(ErrorDescription::WrongPermission, ErrorModule::OS, ErrorSummary::WrongArgument, ErrorLevel::Permanent);
|
||||
return ResultCode(ErrorDescription::WrongPermission, ErrorModule::OS,
|
||||
ErrorSummary::WrongArgument, ErrorLevel::Permanent);
|
||||
}
|
||||
|
||||
// TODO(Subv): Check for the Shared Device Mem flag in the creator process.
|
||||
/*if (was_created_with_shared_device_mem && address != 0) {
|
||||
return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
||||
return ResultCode(ErrorDescription::InvalidCombination, ErrorModule::OS,
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
||||
}*/
|
||||
|
||||
// TODO(Subv): The same process that created a SharedMemory object
|
||||
@ -144,23 +161,29 @@ ResultCode SharedMemory::Map(Process* target_process, VAddr address, MemoryPermi
|
||||
}
|
||||
|
||||
// Map the memory block into the target process
|
||||
auto result = target_process->vm_manager.MapMemoryBlock(target_address, backing_block, backing_block_offset, size, MemoryState::Shared);
|
||||
auto result = target_process->vm_manager.MapMemoryBlock(
|
||||
target_address, backing_block, backing_block_offset, size, MemoryState::Shared);
|
||||
if (result.Failed()) {
|
||||
LOG_ERROR(Kernel, "cannot map id=%u, target_address=0x%08X name=%s, error mapping to virtual memory",
|
||||
GetObjectId(), target_address, name.c_str());
|
||||
LOG_ERROR(
|
||||
Kernel,
|
||||
"cannot map id=%u, target_address=0x%08X name=%s, error mapping to virtual memory",
|
||||
GetObjectId(), target_address, name.c_str());
|
||||
return result.Code();
|
||||
}
|
||||
|
||||
return target_process->vm_manager.ReprotectRange(target_address, size, ConvertPermissions(permissions));
|
||||
return target_process->vm_manager.ReprotectRange(target_address, size,
|
||||
ConvertPermissions(permissions));
|
||||
}
|
||||
|
||||
ResultCode SharedMemory::Unmap(Process* target_process, VAddr address) {
|
||||
// TODO(Subv): Verify what happens if the application tries to unmap an address that is not mapped to a SharedMemory.
|
||||
// TODO(Subv): Verify what happens if the application tries to unmap an address that is not
|
||||
// mapped to a SharedMemory.
|
||||
return target_process->vm_manager.UnmapRange(address, size);
|
||||
}
|
||||
|
||||
VMAPermission SharedMemory::ConvertPermissions(MemoryPermission permission) {
|
||||
u32 masked_permissions = static_cast<u32>(permission) & static_cast<u32>(MemoryPermission::ReadWriteExecute);
|
||||
u32 masked_permissions =
|
||||
static_cast<u32>(permission) & static_cast<u32>(MemoryPermission::ReadWriteExecute);
|
||||
return static_cast<VMAPermission>(masked_permissions);
|
||||
};
|
||||
|
||||
|
@ -16,15 +16,15 @@ namespace Kernel {
|
||||
|
||||
/// Permissions for mapped shared memory blocks
|
||||
enum class MemoryPermission : u32 {
|
||||
None = 0,
|
||||
Read = (1u << 0),
|
||||
Write = (1u << 1),
|
||||
ReadWrite = (Read | Write),
|
||||
Execute = (1u << 2),
|
||||
ReadExecute = (Read | Execute),
|
||||
WriteExecute = (Write | Execute),
|
||||
None = 0,
|
||||
Read = (1u << 0),
|
||||
Write = (1u << 1),
|
||||
ReadWrite = (Read | Write),
|
||||
Execute = (1u << 2),
|
||||
ReadExecute = (Read | Execute),
|
||||
WriteExecute = (Write | Execute),
|
||||
ReadWriteExecute = (Read | Write | Execute),
|
||||
DontCare = (1u << 28)
|
||||
DontCare = (1u << 28)
|
||||
};
|
||||
|
||||
class SharedMemory final : public Object {
|
||||
@ -34,13 +34,18 @@ public:
|
||||
* @param owner_process Process that created this shared memory object.
|
||||
* @param size Size of the memory block. Must be page-aligned.
|
||||
* @param permissions Permission restrictions applied to the process which created the block.
|
||||
* @param other_permissions Permission restrictions applied to other processes mapping the block.
|
||||
* @param other_permissions Permission restrictions applied to other processes mapping the
|
||||
* block.
|
||||
* @param address The address from which to map the Shared Memory.
|
||||
* @param region If the address is 0, the shared memory will be allocated in this region of the linear heap.
|
||||
* @param region If the address is 0, the shared memory will be allocated in this region of the
|
||||
* linear heap.
|
||||
* @param name Optional object name, used for debugging purposes.
|
||||
*/
|
||||
static SharedPtr<SharedMemory> Create(SharedPtr<Process> owner_process, u32 size, MemoryPermission permissions,
|
||||
MemoryPermission other_permissions, VAddr address = 0, MemoryRegion region = MemoryRegion::BASE, std::string name = "Unknown");
|
||||
static SharedPtr<SharedMemory> Create(SharedPtr<Process> owner_process, u32 size,
|
||||
MemoryPermission permissions,
|
||||
MemoryPermission other_permissions, VAddr address = 0,
|
||||
MemoryRegion region = MemoryRegion::BASE,
|
||||
std::string name = "Unknown");
|
||||
|
||||
/**
|
||||
* Creates a shared memory object from a block of memory managed by an HLE applet.
|
||||
@ -48,17 +53,27 @@ public:
|
||||
* @param offset The offset into the heap block that the SharedMemory will map.
|
||||
* @param size Size of the memory block. Must be page-aligned.
|
||||
* @param permissions Permission restrictions applied to the process which created the block.
|
||||
* @param other_permissions Permission restrictions applied to other processes mapping the block.
|
||||
* @param other_permissions Permission restrictions applied to other processes mapping the
|
||||
* block.
|
||||
* @param name Optional object name, used for debugging purposes.
|
||||
*/
|
||||
static SharedPtr<SharedMemory> CreateForApplet(std::shared_ptr<std::vector<u8>> heap_block, u32 offset, u32 size,
|
||||
MemoryPermission permissions, MemoryPermission other_permissions, std::string name = "Unknown Applet");
|
||||
static SharedPtr<SharedMemory> CreateForApplet(std::shared_ptr<std::vector<u8>> heap_block,
|
||||
u32 offset, u32 size,
|
||||
MemoryPermission permissions,
|
||||
MemoryPermission other_permissions,
|
||||
std::string name = "Unknown Applet");
|
||||
|
||||
std::string GetTypeName() const override { return "SharedMemory"; }
|
||||
std::string GetName() const override { return name; }
|
||||
std::string GetTypeName() const override {
|
||||
return "SharedMemory";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::SharedMemory;
|
||||
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the specified MemoryPermission into the equivalent VMAPermission.
|
||||
@ -73,7 +88,8 @@ public:
|
||||
* @param permissions Memory block map permissions (specified by SVC field)
|
||||
* @param other_permissions Memory block map other permissions (specified by SVC field)
|
||||
*/
|
||||
ResultCode Map(Process* target_process, VAddr address, MemoryPermission permissions, MemoryPermission other_permissions);
|
||||
ResultCode Map(Process* target_process, VAddr address, MemoryPermission permissions,
|
||||
MemoryPermission other_permissions);
|
||||
|
||||
/**
|
||||
* Unmaps a shared memory block from the specified address in system memory
|
||||
@ -94,7 +110,8 @@ public:
|
||||
SharedPtr<Process> owner_process;
|
||||
/// Address of shared memory block in the owner process if specified.
|
||||
VAddr base_address;
|
||||
/// Physical address of the shared memory block in the linear heap if no address was specified during creation.
|
||||
/// Physical address of the shared memory block in the linear heap if no address was specified
|
||||
/// during creation.
|
||||
PAddr linear_heap_phys_address;
|
||||
/// Backing memory for this shared memory block.
|
||||
std::shared_ptr<std::vector<u8>> backing_block;
|
||||
|
@ -18,10 +18,10 @@
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/hle.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/kernel/memory.h"
|
||||
#include "core/hle/kernel/mutex.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
@ -46,7 +46,7 @@ static Kernel::HandleTable wakeup_callback_handle_table;
|
||||
static std::vector<SharedPtr<Thread>> thread_list;
|
||||
|
||||
// Lists only ready thread ids.
|
||||
static Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST+1> ready_queue;
|
||||
static Common::ThreadQueueList<Thread*, THREADPRIO_LOWEST + 1> ready_queue;
|
||||
|
||||
static Thread* current_thread;
|
||||
|
||||
@ -61,8 +61,10 @@ inline static u32 const NewThreadId() {
|
||||
return next_thread_id++;
|
||||
}
|
||||
|
||||
Thread::Thread() {}
|
||||
Thread::~Thread() {}
|
||||
Thread::Thread() {
|
||||
}
|
||||
Thread::~Thread() {
|
||||
}
|
||||
|
||||
Thread* GetCurrentThread() {
|
||||
return current_thread;
|
||||
@ -103,7 +105,7 @@ void Thread::Stop() {
|
||||
|
||||
// Clean up thread from ready queue
|
||||
// This is only needed when the thread is termintated forcefully (SVC TerminateProcess)
|
||||
if (status == THREADSTATUS_READY){
|
||||
if (status == THREADSTATUS_READY) {
|
||||
ready_queue.remove(current_priority, this);
|
||||
}
|
||||
|
||||
@ -119,7 +121,8 @@ void Thread::Stop() {
|
||||
|
||||
// Mark the TLS slot in the thread's page as free.
|
||||
u32 tls_page = (tls_address - Memory::TLS_AREA_VADDR) / Memory::PAGE_SIZE;
|
||||
u32 tls_slot = ((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
|
||||
u32 tls_slot =
|
||||
((tls_address - Memory::TLS_AREA_VADDR) % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE;
|
||||
Kernel::g_current_process->tls_slots[tls_page].reset(tls_slot);
|
||||
|
||||
HLE::Reschedule(__func__);
|
||||
@ -137,7 +140,7 @@ Thread* ArbitrateHighestPriorityThread(u32 address) {
|
||||
if (thread == nullptr)
|
||||
continue;
|
||||
|
||||
if(thread->current_priority <= priority) {
|
||||
if (thread->current_priority <= priority) {
|
||||
highest_priority_thread = thread.get();
|
||||
priority = thread->current_priority;
|
||||
}
|
||||
@ -170,7 +173,7 @@ static void PriorityBoostStarvedThreads() {
|
||||
// on hardware. However, this is almost certainly not perfect, and the real CTR OS scheduler
|
||||
// should probably be reversed to verify this.
|
||||
|
||||
const u64 boost_timeout = 2000000; // Boost threads that have been ready for > this long
|
||||
const u64 boost_timeout = 2000000; // Boost threads that have been ready for > this long
|
||||
|
||||
u64 delta = current_ticks - thread->last_running_ticks;
|
||||
|
||||
@ -193,10 +196,12 @@ static std::tuple<u32*, u32*> GetWaitSynchTimeoutParameterRegister(Thread* threa
|
||||
|
||||
if ((thumb_mode && thumb_inst == 0xDF24) || (!thumb_mode && inst == 0x0F000024)) {
|
||||
// svc #0x24 (WaitSynchronization1)
|
||||
return std::make_tuple(&thread->context.cpu_registers[2], &thread->context.cpu_registers[3]);
|
||||
return std::make_tuple(&thread->context.cpu_registers[2],
|
||||
&thread->context.cpu_registers[3]);
|
||||
} else if ((thumb_mode && thumb_inst == 0xDF25) || (!thumb_mode && inst == 0x0F000025)) {
|
||||
// svc #0x25 (WaitSynchronizationN)
|
||||
return std::make_tuple(&thread->context.cpu_registers[0], &thread->context.cpu_registers[4]);
|
||||
return std::make_tuple(&thread->context.cpu_registers[0],
|
||||
&thread->context.cpu_registers[4]);
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
@ -245,7 +250,8 @@ static void SwitchContext(Thread* new_thread) {
|
||||
|
||||
// Load context of new thread
|
||||
if (new_thread) {
|
||||
DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY, "Thread must be ready to become running.");
|
||||
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);
|
||||
@ -263,7 +269,7 @@ static void SwitchContext(Thread* new_thread) {
|
||||
new_thread->context.pc -= thumb_mode ? 2 : 4;
|
||||
|
||||
// Get the register for timeout parameter
|
||||
u32* timeout_low, *timeout_high;
|
||||
u32 *timeout_low, *timeout_high;
|
||||
std::tie(timeout_low, timeout_high) = GetWaitSynchTimeoutParameterRegister(new_thread);
|
||||
|
||||
// Update the timeout parameter
|
||||
@ -307,7 +313,7 @@ static Thread* PopNextReadyThread() {
|
||||
// Otherwise just keep going with the current thread
|
||||
next = thread;
|
||||
}
|
||||
} else {
|
||||
} else {
|
||||
next = ready_queue.pop_first();
|
||||
}
|
||||
|
||||
@ -321,7 +327,8 @@ void WaitCurrentThread_Sleep() {
|
||||
HLE::Reschedule(__func__);
|
||||
}
|
||||
|
||||
void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wait_objects, bool wait_set_output, bool wait_all) {
|
||||
void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wait_objects,
|
||||
bool wait_set_output, bool wait_all) {
|
||||
Thread* thread = GetCurrentThread();
|
||||
thread->wait_set_output = wait_set_output;
|
||||
thread->wait_all = wait_all;
|
||||
@ -352,7 +359,8 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
|
||||
|
||||
if (thread->status == THREADSTATUS_WAIT_SYNCH || thread->status == THREADSTATUS_WAIT_ARB) {
|
||||
thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS,
|
||||
ErrorSummary::StatusChanged, ErrorLevel::Info));
|
||||
ErrorSummary::StatusChanged,
|
||||
ErrorLevel::Info));
|
||||
|
||||
if (thread->wait_set_output)
|
||||
thread->SetWaitSynchronizationOutput(-1);
|
||||
@ -372,25 +380,25 @@ void Thread::WakeAfterDelay(s64 nanoseconds) {
|
||||
|
||||
void Thread::ResumeFromWait() {
|
||||
switch (status) {
|
||||
case THREADSTATUS_WAIT_SYNCH:
|
||||
case THREADSTATUS_WAIT_ARB:
|
||||
case THREADSTATUS_WAIT_SLEEP:
|
||||
break;
|
||||
case THREADSTATUS_WAIT_SYNCH:
|
||||
case THREADSTATUS_WAIT_ARB:
|
||||
case THREADSTATUS_WAIT_SLEEP:
|
||||
break;
|
||||
|
||||
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_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:
|
||||
// This should never happen, as threads must complete before being stopped.
|
||||
DEBUG_ASSERT_MSG(false, "Thread with object id %u cannot be resumed because it's DEAD.",
|
||||
GetObjectId());
|
||||
return;
|
||||
case THREADSTATUS_RUNNING:
|
||||
DEBUG_ASSERT_MSG(false, "Thread with object id %u has already resumed.", GetObjectId());
|
||||
return;
|
||||
case THREADSTATUS_DEAD:
|
||||
// This should never happen, as threads must complete before being stopped.
|
||||
DEBUG_ASSERT_MSG(false, "Thread with object id %u cannot be resumed because it's DEAD.",
|
||||
GetObjectId());
|
||||
return;
|
||||
}
|
||||
|
||||
ready_queue.push_back(current_priority, this);
|
||||
@ -405,7 +413,8 @@ static void DebugThreadQueue() {
|
||||
if (!thread) {
|
||||
LOG_DEBUG(Kernel, "Current: NO CURRENT THREAD");
|
||||
} else {
|
||||
LOG_DEBUG(Kernel, "0x%02X %u (current)", thread->current_priority, GetCurrentThread()->GetObjectId());
|
||||
LOG_DEBUG(Kernel, "0x%02X %u (current)", thread->current_priority,
|
||||
GetCurrentThread()->GetObjectId());
|
||||
}
|
||||
|
||||
for (auto& t : thread_list) {
|
||||
@ -448,7 +457,8 @@ std::tuple<u32, u32, bool> GetFreeThreadLocalSlot(std::vector<std::bitset<8>>& t
|
||||
* @param entry_point Address of entry point for execution
|
||||
* @param arg User argument for thread
|
||||
*/
|
||||
static void ResetThreadContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg) {
|
||||
static void ResetThreadContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point,
|
||||
u32 arg) {
|
||||
memset(&context, 0, sizeof(Core::ThreadContext));
|
||||
|
||||
context.cpu_registers[0] = arg;
|
||||
@ -458,11 +468,11 @@ static void ResetThreadContext(Core::ThreadContext& context, u32 stack_top, u32
|
||||
}
|
||||
|
||||
ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, s32 priority,
|
||||
u32 arg, s32 processor_id, VAddr stack_top) {
|
||||
u32 arg, s32 processor_id, VAddr stack_top) {
|
||||
if (priority < THREADPRIO_HIGHEST || priority > THREADPRIO_LOWEST) {
|
||||
s32 new_priority = MathUtil::Clamp<s32>(priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST);
|
||||
LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d",
|
||||
name.c_str(), priority, new_priority);
|
||||
LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d", name.c_str(),
|
||||
priority, new_priority);
|
||||
// TODO(bunnei): Clamping to a valid priority is not necessarily correct behavior... Confirm
|
||||
// validity of this
|
||||
priority = new_priority;
|
||||
@ -472,7 +482,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
|
||||
LOG_ERROR(Kernel_SVC, "(name=%s): invalid entry %08x", name.c_str(), entry_point);
|
||||
// TODO: Verify error
|
||||
return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
|
||||
}
|
||||
|
||||
SharedPtr<Thread> thread(new Thread);
|
||||
@ -511,8 +521,10 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
|
||||
auto& linheap_memory = memory_region->linear_heap_memory;
|
||||
|
||||
if (linheap_memory->size() + Memory::PAGE_SIZE > memory_region->size) {
|
||||
LOG_ERROR(Kernel_SVC, "Not enough space in region to allocate a new TLS page for thread");
|
||||
return ResultCode(ErrorDescription::OutOfMemory, ErrorModule::Kernel, ErrorSummary::OutOfResource, ErrorLevel::Permanent);
|
||||
LOG_ERROR(Kernel_SVC,
|
||||
"Not enough space in region to allocate a new TLS page for thread");
|
||||
return ResultCode(ErrorDescription::OutOfMemory, ErrorModule::Kernel,
|
||||
ErrorSummary::OutOfResource, ErrorLevel::Permanent);
|
||||
}
|
||||
|
||||
u32 offset = linheap_memory->size();
|
||||
@ -537,7 +549,8 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
|
||||
|
||||
// Mark the slot as used
|
||||
tls_slots[available_page].set(available_slot);
|
||||
thread->tls_address = Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE + available_slot * Memory::TLS_ENTRY_SIZE;
|
||||
thread->tls_address = Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE +
|
||||
available_slot * Memory::TLS_ENTRY_SIZE;
|
||||
|
||||
// TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
|
||||
// to initialize the context
|
||||
@ -551,10 +564,12 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point,
|
||||
return MakeResult<SharedPtr<Thread>>(std::move(thread));
|
||||
}
|
||||
|
||||
// TODO(peachum): Remove this. Range checking should be done, and an appropriate error should be returned.
|
||||
// TODO(peachum): Remove this. Range checking should be done, and an appropriate error should be
|
||||
// returned.
|
||||
static void ClampPriority(const Thread* thread, s32* priority) {
|
||||
if (*priority < THREADPRIO_HIGHEST || *priority > THREADPRIO_LOWEST) {
|
||||
DEBUG_ASSERT_MSG(false, "Application passed an out of range priority. An error should be returned.");
|
||||
DEBUG_ASSERT_MSG(
|
||||
false, "Application passed an out of range priority. An error should be returned.");
|
||||
|
||||
s32 new_priority = MathUtil::Clamp<s32>(*priority, THREADPRIO_HIGHEST, THREADPRIO_LOWEST);
|
||||
LOG_WARNING(Kernel_SVC, "(name=%s): invalid priority=%d, clamping to %d",
|
||||
@ -586,12 +601,13 @@ SharedPtr<Thread> SetupMainThread(u32 entry_point, s32 priority) {
|
||||
DEBUG_ASSERT(!GetCurrentThread());
|
||||
|
||||
// Initialize new "main" thread
|
||||
auto thread_res = Thread::Create("main", entry_point, priority, 0,
|
||||
THREADPROCESSORID_0, Memory::HEAP_VADDR_END);
|
||||
auto thread_res = Thread::Create("main", entry_point, priority, 0, THREADPROCESSORID_0,
|
||||
Memory::HEAP_VADDR_END);
|
||||
|
||||
SharedPtr<Thread> thread = thread_res.MoveFrom();
|
||||
|
||||
thread->context.fpscr = FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO | FPSCR_IXC; // 0x03C00010
|
||||
thread->context.fpscr =
|
||||
FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO | FPSCR_ROUND_TOZERO | FPSCR_IXC; // 0x03C00010
|
||||
|
||||
// Run new "main" thread
|
||||
SwitchContext(thread.get());
|
||||
|
@ -17,29 +17,29 @@
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
enum ThreadPriority : s32{
|
||||
THREADPRIO_HIGHEST = 0, ///< Highest thread priority
|
||||
THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps
|
||||
THREADPRIO_DEFAULT = 48, ///< Default thread priority for userland apps
|
||||
THREADPRIO_LOWEST = 63, ///< Lowest thread priority
|
||||
enum ThreadPriority : s32 {
|
||||
THREADPRIO_HIGHEST = 0, ///< Highest thread priority
|
||||
THREADPRIO_USERLAND_MAX = 24, ///< Highest thread priority for userland apps
|
||||
THREADPRIO_DEFAULT = 48, ///< Default thread priority for userland apps
|
||||
THREADPRIO_LOWEST = 63, ///< Lowest thread priority
|
||||
};
|
||||
|
||||
enum ThreadProcessorId : s32 {
|
||||
THREADPROCESSORID_DEFAULT = -2, ///< Run thread on default core specified by exheader
|
||||
THREADPROCESSORID_ALL = -1, ///< Run thread on either core
|
||||
THREADPROCESSORID_0 = 0, ///< Run thread on core 0 (AppCore)
|
||||
THREADPROCESSORID_1 = 1, ///< Run thread on core 1 (SysCore)
|
||||
THREADPROCESSORID_MAX = 2, ///< Processor ID must be less than this
|
||||
THREADPROCESSORID_DEFAULT = -2, ///< Run thread on default core specified by exheader
|
||||
THREADPROCESSORID_ALL = -1, ///< Run thread on either core
|
||||
THREADPROCESSORID_0 = 0, ///< Run thread on core 0 (AppCore)
|
||||
THREADPROCESSORID_1 = 1, ///< Run thread on core 1 (SysCore)
|
||||
THREADPROCESSORID_MAX = 2, ///< Processor ID must be less than this
|
||||
};
|
||||
|
||||
enum ThreadStatus {
|
||||
THREADSTATUS_RUNNING, ///< Currently running
|
||||
THREADSTATUS_READY, ///< Ready to run
|
||||
THREADSTATUS_WAIT_ARB, ///< Waiting on an address arbiter
|
||||
THREADSTATUS_WAIT_SLEEP, ///< Waiting due to a SleepThread SVC
|
||||
THREADSTATUS_WAIT_SYNCH, ///< Waiting due to a WaitSynchronization SVC
|
||||
THREADSTATUS_DORMANT, ///< Created but not yet made ready
|
||||
THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated
|
||||
THREADSTATUS_RUNNING, ///< Currently running
|
||||
THREADSTATUS_READY, ///< Ready to run
|
||||
THREADSTATUS_WAIT_ARB, ///< Waiting on an address arbiter
|
||||
THREADSTATUS_WAIT_SLEEP, ///< Waiting due to a SleepThread SVC
|
||||
THREADSTATUS_WAIT_SYNCH, ///< Waiting due to a WaitSynchronization SVC
|
||||
THREADSTATUS_DORMANT, ///< Created but not yet made ready
|
||||
THREADSTATUS_DEAD ///< Run to completion, or forcefully terminated
|
||||
};
|
||||
|
||||
namespace Kernel {
|
||||
@ -60,13 +60,19 @@ public:
|
||||
* @return A shared pointer to the newly created thread
|
||||
*/
|
||||
static ResultVal<SharedPtr<Thread>> Create(std::string name, VAddr entry_point, s32 priority,
|
||||
u32 arg, s32 processor_id, VAddr stack_top);
|
||||
u32 arg, s32 processor_id, VAddr stack_top);
|
||||
|
||||
std::string GetName() const override { return name; }
|
||||
std::string GetTypeName() const override { return "Thread"; }
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
std::string GetTypeName() const override {
|
||||
return "Thread";
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::Thread;
|
||||
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
bool ShouldWait() override;
|
||||
void Acquire() override;
|
||||
@ -75,7 +81,9 @@ public:
|
||||
* Gets the thread's current priority
|
||||
* @return The current thread's priority
|
||||
*/
|
||||
s32 GetPriority() const { return current_priority; }
|
||||
s32 GetPriority() const {
|
||||
return current_priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the thread's current priority
|
||||
@ -93,7 +101,9 @@ public:
|
||||
* Gets the thread's thread ID
|
||||
* @return The thread's ID
|
||||
*/
|
||||
u32 GetThreadId() const { return thread_id; }
|
||||
u32 GetThreadId() const {
|
||||
return thread_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resumes a thread from waiting
|
||||
@ -127,7 +137,9 @@ public:
|
||||
* Returns the Thread Local Storage address of the current thread
|
||||
* @returns VAddr of the thread's TLS
|
||||
*/
|
||||
VAddr GetTLSAddress() const { return tls_address; }
|
||||
VAddr GetTLSAddress() const {
|
||||
return tls_address;
|
||||
}
|
||||
|
||||
Core::ThreadContext context;
|
||||
|
||||
@ -137,8 +149,8 @@ public:
|
||||
u32 entry_point;
|
||||
u32 stack_top;
|
||||
|
||||
s32 nominal_priority; ///< Nominal thread priority, as set by the emulated application
|
||||
s32 current_priority; ///< Current thread priority, can be temporarily changed
|
||||
s32 nominal_priority; ///< Nominal thread priority, as set by the emulated application
|
||||
s32 current_priority; ///< Current thread priority, can be temporarily changed
|
||||
|
||||
u64 last_running_ticks; ///< CPU tick when thread was last running
|
||||
|
||||
@ -151,11 +163,11 @@ public:
|
||||
/// Mutexes currently held by this thread, which will be released when it exits.
|
||||
boost::container::flat_set<SharedPtr<Mutex>> held_mutexes;
|
||||
|
||||
SharedPtr<Process> owner_process; ///< Process that owns this thread
|
||||
SharedPtr<Process> owner_process; ///< Process that owns this thread
|
||||
std::vector<SharedPtr<WaitObject>> wait_objects; ///< Objects that the thread is waiting on
|
||||
VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address
|
||||
bool wait_all; ///< True if the thread is waiting on all objects before resuming
|
||||
bool wait_set_output; ///< True if the output parameter should be set on thread wakeup
|
||||
VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address
|
||||
bool wait_all; ///< True if the thread is waiting on all objects before resuming
|
||||
bool wait_set_output; ///< True if the output parameter should be set on thread wakeup
|
||||
|
||||
std::string name;
|
||||
|
||||
@ -205,10 +217,12 @@ void WaitCurrentThread_Sleep();
|
||||
/**
|
||||
* Waits the current thread from a WaitSynchronization call
|
||||
* @param wait_objects Kernel objects that we are waiting on
|
||||
* @param wait_set_output If true, set the output parameter on thread wakeup (for WaitSynchronizationN only)
|
||||
* @param wait_set_output If true, set the output parameter on thread wakeup (for
|
||||
* WaitSynchronizationN only)
|
||||
* @param wait_all If true, wait on all objects before resuming (for WaitSynchronizationN only)
|
||||
*/
|
||||
void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wait_objects, bool wait_set_output, bool wait_all);
|
||||
void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wait_objects,
|
||||
bool wait_set_output, bool wait_all);
|
||||
|
||||
/**
|
||||
* Waits the current thread from an ArbitrateAddress call
|
||||
|
@ -9,8 +9,8 @@
|
||||
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/timer.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/kernel/timer.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
@ -20,8 +20,10 @@ static int timer_callback_event_type;
|
||||
// us to simply use a pool index or similar.
|
||||
static Kernel::HandleTable timer_callback_handle_table;
|
||||
|
||||
Timer::Timer() {}
|
||||
Timer::~Timer() {}
|
||||
Timer::Timer() {
|
||||
}
|
||||
Timer::~Timer() {
|
||||
}
|
||||
|
||||
SharedPtr<Timer> Timer::Create(ResetType reset_type, std::string name) {
|
||||
SharedPtr<Timer> timer(new Timer);
|
||||
@ -41,7 +43,7 @@ bool Timer::ShouldWait() {
|
||||
}
|
||||
|
||||
void Timer::Acquire() {
|
||||
ASSERT_MSG( !ShouldWait(), "object unavailable!");
|
||||
ASSERT_MSG(!ShouldWait(), "object unavailable!");
|
||||
|
||||
if (reset_type == ResetType::OneShot)
|
||||
signaled = false;
|
||||
@ -55,8 +57,8 @@ void Timer::Set(s64 initial, s64 interval) {
|
||||
interval_delay = interval;
|
||||
|
||||
u64 initial_microseconds = initial / 1000;
|
||||
CoreTiming::ScheduleEvent(usToCycles(initial_microseconds),
|
||||
timer_callback_event_type, callback_handle);
|
||||
CoreTiming::ScheduleEvent(usToCycles(initial_microseconds), timer_callback_event_type,
|
||||
callback_handle);
|
||||
|
||||
HLE::Reschedule(__func__);
|
||||
}
|
||||
@ -73,7 +75,8 @@ void Timer::Clear() {
|
||||
|
||||
/// The timer callback event, called when a timer is fired
|
||||
static void TimerCallback(u64 timer_handle, int cycles_late) {
|
||||
SharedPtr<Timer> timer = timer_callback_handle_table.Get<Timer>(static_cast<Handle>(timer_handle));
|
||||
SharedPtr<Timer> timer =
|
||||
timer_callback_handle_table.Get<Timer>(static_cast<Handle>(timer_handle));
|
||||
|
||||
if (timer == nullptr) {
|
||||
LOG_CRITICAL(Kernel, "Callback fired for invalid timer %08" PRIx64, timer_handle);
|
||||
@ -91,7 +94,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) {
|
||||
// Reschedule the timer with the interval delay
|
||||
u64 interval_microseconds = timer->interval_delay / 1000;
|
||||
CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late,
|
||||
timer_callback_event_type, timer_handle);
|
||||
timer_callback_event_type, timer_handle);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,19 +21,25 @@ public:
|
||||
*/
|
||||
static SharedPtr<Timer> Create(ResetType reset_type, std::string name = "Unknown");
|
||||
|
||||
std::string GetTypeName() const override { return "Timer"; }
|
||||
std::string GetName() const override { return name; }
|
||||
std::string GetTypeName() const override {
|
||||
return "Timer";
|
||||
}
|
||||
std::string GetName() const override {
|
||||
return name;
|
||||
}
|
||||
|
||||
static const HandleType HANDLE_TYPE = HandleType::Timer;
|
||||
HandleType GetHandleType() const override { return HANDLE_TYPE; }
|
||||
HandleType GetHandleType() const override {
|
||||
return HANDLE_TYPE;
|
||||
}
|
||||
|
||||
ResetType reset_type; ///< The ResetType of this timer
|
||||
ResetType reset_type; ///< The ResetType of this timer
|
||||
|
||||
bool signaled; ///< Whether the timer has been signaled or not
|
||||
std::string name; ///< Name of timer (optional)
|
||||
bool signaled; ///< Whether the timer has been signaled or not
|
||||
std::string name; ///< Name of timer (optional)
|
||||
|
||||
u64 initial_delay; ///< The delay until the timer fires for the first time
|
||||
u64 interval_delay; ///< The delay until the timer fires after the first time
|
||||
u64 initial_delay; ///< The delay until the timer fires for the first time
|
||||
u64 interval_delay; ///< The delay until the timer fires after the first time
|
||||
|
||||
bool ShouldWait() override;
|
||||
void Acquire() override;
|
||||
|
@ -15,8 +15,8 @@ namespace Kernel {
|
||||
|
||||
static const char* GetMemoryStateName(MemoryState state) {
|
||||
static const char* names[] = {
|
||||
"Free", "Reserved", "IO", "Static", "Code", "Private", "Shared", "Continuous", "Aliased",
|
||||
"Alias", "AliasCode", "Locked",
|
||||
"Free", "Reserved", "IO", "Static", "Code", "Private",
|
||||
"Shared", "Continuous", "Aliased", "Alias", "AliasCode", "Locked",
|
||||
};
|
||||
|
||||
return names[(int)state];
|
||||
@ -24,13 +24,12 @@ static const char* GetMemoryStateName(MemoryState state) {
|
||||
|
||||
bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const {
|
||||
ASSERT(base + size == next.base);
|
||||
if (permissions != next.permissions ||
|
||||
meminfo_state != next.meminfo_state ||
|
||||
type != next.type) {
|
||||
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)) {
|
||||
(backing_block != next.backing_block || offset + size != next.offset)) {
|
||||
return false;
|
||||
}
|
||||
if (type == VMAType::BackingMemory && backing_memory + size != next.backing_memory) {
|
||||
@ -70,7 +69,9 @@ VMManager::VMAHandle VMManager::FindVMA(VAddr target) const {
|
||||
}
|
||||
|
||||
ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target,
|
||||
std::shared_ptr<std::vector<u8>> block, size_t offset, u32 size, MemoryState state) {
|
||||
std::shared_ptr<std::vector<u8>> block,
|
||||
size_t offset, u32 size,
|
||||
MemoryState state) {
|
||||
ASSERT(block != nullptr);
|
||||
ASSERT(offset + size <= block->size());
|
||||
|
||||
@ -89,7 +90,8 @@ ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target,
|
||||
return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
|
||||
}
|
||||
|
||||
ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8 * memory, u32 size, MemoryState state) {
|
||||
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.
|
||||
@ -106,7 +108,9 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8 * m
|
||||
return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
|
||||
}
|
||||
|
||||
ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state, Memory::MMIORegionPointer mmio_handler) {
|
||||
ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u32 size,
|
||||
MemoryState state,
|
||||
Memory::MMIORegionPointer mmio_handler) {
|
||||
// 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;
|
||||
@ -191,15 +195,16 @@ void VMManager::RefreshMemoryBlockMappings(const std::vector<u8>* block) {
|
||||
void VMManager::LogLayout(Log::Level log_level) const {
|
||||
for (const auto& p : vma_map) {
|
||||
const VirtualMemoryArea& vma = p.second;
|
||||
LOG_GENERIC(Log::Class::Kernel, log_level, "%08X - %08X size: %8X %c%c%c %s",
|
||||
vma.base, vma.base + vma.size, vma.size,
|
||||
(u8)vma.permissions & (u8)VMAPermission::Read ? 'R' : '-',
|
||||
(u8)vma.permissions & (u8)VMAPermission::Write ? 'W' : '-',
|
||||
(u8)vma.permissions & (u8)VMAPermission::Execute ? 'X' : '-', GetMemoryStateName(vma.meminfo_state));
|
||||
LOG_GENERIC(Log::Class::Kernel, log_level, "%08X - %08X size: %8X %c%c%c %s", vma.base,
|
||||
vma.base + vma.size, vma.size,
|
||||
(u8)vma.permissions & (u8)VMAPermission::Read ? 'R' : '-',
|
||||
(u8)vma.permissions & (u8)VMAPermission::Write ? 'W' : '-',
|
||||
(u8)vma.permissions & (u8)VMAPermission::Execute ? 'X' : '-',
|
||||
GetMemoryStateName(vma.meminfo_state));
|
||||
}
|
||||
}
|
||||
|
||||
VMManager::VMAIter VMManager::StripIterConstness(const VMAHandle & 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
|
||||
@ -337,5 +342,4 @@ void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,13 +15,13 @@
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
const ResultCode ERR_INVALID_ADDRESS{ // 0xE0E01BF5
|
||||
ErrorDescription::InvalidAddress, ErrorModule::OS,
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Usage};
|
||||
const ResultCode ERR_INVALID_ADDRESS{// 0xE0E01BF5
|
||||
ErrorDescription::InvalidAddress, ErrorModule::OS,
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Usage};
|
||||
|
||||
const ResultCode ERR_INVALID_ADDRESS_STATE{ // 0xE0A01BF5
|
||||
ErrorDescription::InvalidAddress, ErrorModule::OS,
|
||||
ErrorSummary::InvalidState, ErrorLevel::Usage};
|
||||
const ResultCode ERR_INVALID_ADDRESS_STATE{// 0xE0A01BF5
|
||||
ErrorDescription::InvalidAddress, ErrorModule::OS,
|
||||
ErrorSummary::InvalidState, ErrorLevel::Usage};
|
||||
|
||||
enum class VMAType : u8 {
|
||||
/// VMA represents an unmapped region of the address space.
|
||||
@ -115,7 +115,8 @@ class VMManager final {
|
||||
// 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.
|
||||
* 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;
|
||||
@ -151,7 +152,7 @@ public:
|
||||
* @param state MemoryState tag to attach to the VMA.
|
||||
*/
|
||||
ResultVal<VMAHandle> MapMemoryBlock(VAddr target, std::shared_ptr<std::vector<u8>> block,
|
||||
size_t offset, u32 size, MemoryState state);
|
||||
size_t offset, u32 size, MemoryState state);
|
||||
|
||||
/**
|
||||
* Maps an unmanaged host memory pointer at a given address.
|
||||
@ -172,7 +173,8 @@ public:
|
||||
* @param state MemoryState tag to attach to the VMA.
|
||||
* @param mmio_handler The handler that will implement read and write for this MMIO region.
|
||||
*/
|
||||
ResultVal<VMAHandle> MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state, Memory::MMIORegionPointer mmio_handler);
|
||||
ResultVal<VMAHandle> MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state,
|
||||
Memory::MMIORegionPointer mmio_handler);
|
||||
|
||||
/// Unmaps a range of addresses, splitting VMAs as necessary.
|
||||
ResultCode UnmapRange(VAddr target, u32 size);
|
||||
@ -228,5 +230,4 @@ private:
|
||||
/// Updates the pages corresponding to this VMA so they match the VMA's attributes.
|
||||
void UpdatePageTableForVMA(const VirtualMemoryArea& vma);
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -26,7 +26,8 @@ enum class ErrorDescription : u32 {
|
||||
FS_InvalidOpenFlags = 230,
|
||||
FS_NotAFile = 250,
|
||||
FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive
|
||||
OutofRangeOrMisalignedAddress = 513, // TODO(purpasmart): Check if this name fits its actual usage
|
||||
OutofRangeOrMisalignedAddress =
|
||||
513, // TODO(purpasmart): Check if this name fits its actual usage
|
||||
GPU_FirstInitialization = 519,
|
||||
FS_InvalidPath = 702,
|
||||
InvalidSection = 1000,
|
||||
@ -168,15 +169,15 @@ enum class ErrorSummary : u32 {
|
||||
Success = 0,
|
||||
NothingHappened = 1,
|
||||
WouldBlock = 2,
|
||||
OutOfResource = 3, ///< There are no more kernel resources (memory, table slots) to
|
||||
///< execute the operation.
|
||||
NotFound = 4, ///< A file or resource was not found.
|
||||
OutOfResource = 3, ///< There are no more kernel resources (memory, table slots) to
|
||||
///< execute the operation.
|
||||
NotFound = 4, ///< A file or resource was not found.
|
||||
InvalidState = 5,
|
||||
NotSupported = 6, ///< The operation is not supported or not implemented.
|
||||
InvalidArgument = 7, ///< Returned when a passed argument is invalid in the current runtime
|
||||
///< context. (Invalid handle, out-of-bounds pointer or size, etc.)
|
||||
WrongArgument = 8, ///< Returned when a passed argument is in an incorrect format for use
|
||||
///< with the function. (E.g. Invalid enum value)
|
||||
NotSupported = 6, ///< The operation is not supported or not implemented.
|
||||
InvalidArgument = 7, ///< Returned when a passed argument is invalid in the current runtime
|
||||
///< context. (Invalid handle, out-of-bounds pointer or size, etc.)
|
||||
WrongArgument = 8, ///< Returned when a passed argument is in an incorrect format for use
|
||||
///< with the function. (E.g. Invalid enum value)
|
||||
Canceled = 9,
|
||||
StatusChanged = 10,
|
||||
Internal = 11,
|
||||
@ -208,19 +209,25 @@ union ResultCode {
|
||||
BitField<21, 6, ErrorSummary> summary;
|
||||
BitField<27, 5, ErrorLevel> level;
|
||||
|
||||
// The last bit of `level` is checked by apps and the kernel to determine if a result code is an error
|
||||
// The last bit of `level` is checked by apps and the kernel to determine if a result code is an
|
||||
// error
|
||||
BitField<31, 1, u32> is_error;
|
||||
|
||||
explicit ResultCode(u32 raw) : raw(raw) {}
|
||||
ResultCode(ErrorDescription description_, ErrorModule module_,
|
||||
ErrorSummary summary_, ErrorLevel level_) : raw(0) {
|
||||
explicit ResultCode(u32 raw) : raw(raw) {
|
||||
}
|
||||
ResultCode(ErrorDescription description_, ErrorModule module_, ErrorSummary summary_,
|
||||
ErrorLevel level_)
|
||||
: raw(0) {
|
||||
description.Assign(description_);
|
||||
module.Assign(module_);
|
||||
summary.Assign(summary_);
|
||||
level.Assign(level_);
|
||||
}
|
||||
|
||||
ResultCode& operator=(const ResultCode& o) { raw = o.raw; return *this; }
|
||||
ResultCode& operator=(const ResultCode& o) {
|
||||
raw = o.raw;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool IsSuccess() const {
|
||||
return is_error == 0;
|
||||
@ -246,8 +253,8 @@ const ResultCode RESULT_SUCCESS(0);
|
||||
|
||||
/// Might be returned instead of a dummy success for unimplemented APIs.
|
||||
inline ResultCode UnimplementedFunction(ErrorModule module) {
|
||||
return ResultCode(ErrorDescription::NotImplemented, module,
|
||||
ErrorSummary::NotSupported, ErrorLevel::Permanent);
|
||||
return ResultCode(ErrorDescription::NotImplemented, module, ErrorSummary::NotSupported,
|
||||
ErrorLevel::Permanent);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -285,10 +292,9 @@ inline ResultCode UnimplementedFunction(ErrorModule module) {
|
||||
template <typename T>
|
||||
class ResultVal {
|
||||
public:
|
||||
/// Constructs an empty `ResultVal` with the given error code. The code must not be a success code.
|
||||
ResultVal(ResultCode error_code = ResultCode(-1))
|
||||
: result_code(error_code)
|
||||
{
|
||||
/// Constructs an empty `ResultVal` with the given error code. The code must not be a success
|
||||
/// code.
|
||||
ResultVal(ResultCode error_code = ResultCode(-1)) : result_code(error_code) {
|
||||
ASSERT(error_code.IsError());
|
||||
}
|
||||
|
||||
@ -303,17 +309,13 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
ResultVal(const ResultVal& o)
|
||||
: result_code(o.result_code)
|
||||
{
|
||||
ResultVal(const ResultVal& o) : result_code(o.result_code) {
|
||||
if (!o.empty()) {
|
||||
new (&object) T(o.object);
|
||||
}
|
||||
}
|
||||
|
||||
ResultVal(ResultVal&& o)
|
||||
: result_code(o.result_code)
|
||||
{
|
||||
ResultVal(ResultVal&& o) : result_code(o.result_code) {
|
||||
if (!o.empty()) {
|
||||
new (&object) T(std::move(o.object));
|
||||
}
|
||||
@ -357,19 +359,35 @@ public:
|
||||
}
|
||||
|
||||
/// Returns true if the `ResultVal` contains an error code and no value.
|
||||
bool empty() const { return result_code.IsError(); }
|
||||
bool empty() const {
|
||||
return result_code.IsError();
|
||||
}
|
||||
|
||||
/// Returns true if the `ResultVal` contains a return value.
|
||||
bool Succeeded() const { return result_code.IsSuccess(); }
|
||||
bool Succeeded() const {
|
||||
return result_code.IsSuccess();
|
||||
}
|
||||
/// Returns true if the `ResultVal` contains an error code and no value.
|
||||
bool Failed() const { return empty(); }
|
||||
bool Failed() const {
|
||||
return empty();
|
||||
}
|
||||
|
||||
ResultCode Code() const { return result_code; }
|
||||
ResultCode Code() const {
|
||||
return result_code;
|
||||
}
|
||||
|
||||
const T& operator* () const { return object; }
|
||||
T& operator* () { return object; }
|
||||
const T* operator->() const { return &object; }
|
||||
T* operator->() { return &object; }
|
||||
const T& operator*() const {
|
||||
return object;
|
||||
}
|
||||
T& operator*() {
|
||||
return object;
|
||||
}
|
||||
const T* operator->() const {
|
||||
return &object;
|
||||
}
|
||||
T* operator->() {
|
||||
return &object;
|
||||
}
|
||||
|
||||
/// Returns the value contained in this `ResultVal`, or the supplied default if it is missing.
|
||||
template <typename U>
|
||||
@ -390,7 +408,9 @@ public:
|
||||
private:
|
||||
// A union is used to allocate the storage for the value, while allowing us to construct and
|
||||
// destruct it at will.
|
||||
union { T object; };
|
||||
union {
|
||||
T object;
|
||||
};
|
||||
ResultCode result_code;
|
||||
};
|
||||
|
||||
@ -409,8 +429,8 @@ ResultVal<T> MakeResult(Args&&... args) {
|
||||
* variable declaration. If it fails the return code is returned from the current function. Thus it
|
||||
* can be used to cascade errors out, achieving something akin to exception handling.
|
||||
*/
|
||||
#define CASCADE_RESULT(target, source) \
|
||||
auto CONCAT2(check_result_L, __LINE__) = source; \
|
||||
if (CONCAT2(check_result_L, __LINE__).Failed()) \
|
||||
return CONCAT2(check_result_L, __LINE__).Code(); \
|
||||
target = std::move(*CONCAT2(check_result_L, __LINE__))
|
||||
#define CASCADE_RESULT(target, source) \
|
||||
auto CONCAT2(check_result_L, __LINE__) = source; \
|
||||
if (CONCAT2(check_result_L, __LINE__).Failed()) \
|
||||
return CONCAT2(check_result_L, __LINE__).Code(); \
|
||||
target = std::move(*CONCAT2(check_result_L, __LINE__))
|
||||
|
@ -47,7 +47,7 @@ static void GetWifiStatus(Service::Interface* self) {
|
||||
// it returns a valid result without implementing full functionality.
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
cmd_buff[2] = 0; // Connection type set to none
|
||||
cmd_buff[2] = 0; // Connection type set to none
|
||||
|
||||
LOG_WARNING(Service_AC, "(STUBBED) called");
|
||||
}
|
||||
@ -62,29 +62,29 @@ static void IsConnected(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
cmd_buff[2] = false; // Not connected to ac:u service
|
||||
cmd_buff[2] = false; // Not connected to ac:u service
|
||||
|
||||
LOG_WARNING(Service_AC, "(STUBBED) called");
|
||||
}
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00010000, nullptr, "CreateDefaultConfig"},
|
||||
{0x00040006, nullptr, "ConnectAsync"},
|
||||
{0x00050002, nullptr, "GetConnectResult"},
|
||||
{0x00080004, CloseAsync, "CloseAsync"},
|
||||
{0x00090002, nullptr, "GetCloseResult"},
|
||||
{0x000A0000, nullptr, "GetLastErrorCode"},
|
||||
{0x000D0000, GetWifiStatus, "GetWifiStatus"},
|
||||
{0x000E0042, nullptr, "GetCurrentAPInfo"},
|
||||
{0x00100042, nullptr, "GetCurrentNZoneInfo"},
|
||||
{0x00110042, nullptr, "GetNZoneApNumService"},
|
||||
{0x00240042, nullptr, "AddDenyApType"},
|
||||
{0x00270002, nullptr, "GetInfraPriority"},
|
||||
{0x002D0082, nullptr, "SetRequestEulaVersion"},
|
||||
{0x00300004, nullptr, "RegisterDisconnectEvent"},
|
||||
{0x003C0042, nullptr, "GetAPSSIDList"},
|
||||
{0x003E0042, IsConnected, "IsConnected"},
|
||||
{0x00400042, nullptr, "SetClientVersion"},
|
||||
{0x00010000, nullptr, "CreateDefaultConfig"},
|
||||
{0x00040006, nullptr, "ConnectAsync"},
|
||||
{0x00050002, nullptr, "GetConnectResult"},
|
||||
{0x00080004, CloseAsync, "CloseAsync"},
|
||||
{0x00090002, nullptr, "GetCloseResult"},
|
||||
{0x000A0000, nullptr, "GetLastErrorCode"},
|
||||
{0x000D0000, GetWifiStatus, "GetWifiStatus"},
|
||||
{0x000E0042, nullptr, "GetCurrentAPInfo"},
|
||||
{0x00100042, nullptr, "GetCurrentNZoneInfo"},
|
||||
{0x00110042, nullptr, "GetNZoneApNumService"},
|
||||
{0x00240042, nullptr, "AddDenyApType"},
|
||||
{0x00270002, nullptr, "GetInfraPriority"},
|
||||
{0x002D0082, nullptr, "SetRequestEulaVersion"},
|
||||
{0x00300004, nullptr, "RegisterDisconnectEvent"},
|
||||
{0x003C0042, nullptr, "GetAPSSIDList"},
|
||||
{0x003E0042, IsConnected, "IsConnected"},
|
||||
{0x00400042, nullptr, "SetClientVersion"},
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -6,19 +6,19 @@
|
||||
|
||||
#include "common/logging/log.h"
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/am/am.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/service/am/am_u.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service {
|
||||
namespace AM {
|
||||
|
||||
static std::array<u32, 3> am_content_count = { 0, 0, 0 };
|
||||
static std::array<u32, 3> am_titles_count = { 0, 0, 0 };
|
||||
static std::array<u32, 3> am_titles_list_count = { 0, 0, 0 };
|
||||
static std::array<u32, 3> am_content_count = {0, 0, 0};
|
||||
static std::array<u32, 3> am_titles_count = {0, 0, 0};
|
||||
static std::array<u32, 3> am_titles_list_count = {0, 0, 0};
|
||||
static u32 am_ticket_count = 0;
|
||||
static u32 am_ticket_list_count = 0;
|
||||
|
||||
@ -29,7 +29,8 @@ void GetTitleCount(Service::Interface* self) {
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
cmd_buff[2] = am_titles_count[media_type];
|
||||
LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, title_count=0x%08x", media_type, am_titles_count[media_type]);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, title_count=0x%08x", media_type,
|
||||
am_titles_count[media_type]);
|
||||
}
|
||||
|
||||
void FindContentInfos(Service::Interface* self) {
|
||||
@ -43,8 +44,10 @@ void FindContentInfos(Service::Interface* self) {
|
||||
am_content_count[media_type] = cmd_buff[4];
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, title_id=0x%016llx, content_cound=%u, content_ids_pointer=0x%08x, content_info_pointer=0x%08x",
|
||||
media_type, title_id, am_content_count[media_type], content_ids_pointer, content_info_pointer);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, title_id=0x%016llx, content_cound=%u, "
|
||||
"content_ids_pointer=0x%08x, content_info_pointer=0x%08x",
|
||||
media_type, title_id, am_content_count[media_type], content_ids_pointer,
|
||||
content_info_pointer);
|
||||
}
|
||||
|
||||
void ListContentInfos(Service::Interface* self) {
|
||||
@ -59,8 +62,10 @@ void ListContentInfos(Service::Interface* self) {
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
cmd_buff[2] = am_content_count[media_type];
|
||||
LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, content_count=%u, title_id=0x%016" PRIx64 ", start_index=0x%08x, content_info_pointer=0x%08X",
|
||||
media_type, am_content_count[media_type], title_id, start_index, content_info_pointer);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, content_count=%u, title_id=0x%016" PRIx64
|
||||
", start_index=0x%08x, content_info_pointer=0x%08X",
|
||||
media_type, am_content_count[media_type], title_id, start_index,
|
||||
content_info_pointer);
|
||||
}
|
||||
|
||||
void DeleteContents(Service::Interface* self) {
|
||||
@ -73,8 +78,9 @@ void DeleteContents(Service::Interface* self) {
|
||||
am_content_count[media_type] = cmd_buff[4];
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, title_id=0x%016" PRIx64 ", content_count=%u, content_ids_pointer=0x%08x",
|
||||
media_type, title_id, am_content_count[media_type], content_ids_pointer);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, title_id=0x%016" PRIx64
|
||||
", content_count=%u, content_ids_pointer=0x%08x",
|
||||
media_type, title_id, am_content_count[media_type], content_ids_pointer);
|
||||
}
|
||||
|
||||
void GetTitleList(Service::Interface* self) {
|
||||
@ -87,8 +93,10 @@ void GetTitleList(Service::Interface* self) {
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
cmd_buff[2] = am_titles_list_count[media_type];
|
||||
LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, titles_list_count=0x%08X, title_ids_output_pointer=0x%08X",
|
||||
media_type, am_titles_list_count[media_type], title_ids_output_pointer);
|
||||
LOG_WARNING(
|
||||
Service_AM,
|
||||
"(STUBBED) media_type=%u, titles_list_count=0x%08X, title_ids_output_pointer=0x%08X",
|
||||
media_type, am_titles_list_count[media_type], title_ids_output_pointer);
|
||||
}
|
||||
|
||||
void GetTitleInfo(Service::Interface* self) {
|
||||
@ -101,7 +109,8 @@ void GetTitleInfo(Service::Interface* self) {
|
||||
am_titles_count[media_type] = cmd_buff[2];
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, total_titles=0x%08X, title_id_list_pointer=0x%08X, title_list_pointer=0x%08X",
|
||||
LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, total_titles=0x%08X, "
|
||||
"title_id_list_pointer=0x%08X, title_list_pointer=0x%08X",
|
||||
media_type, am_titles_count[media_type], title_id_list_pointer, title_list_pointer);
|
||||
}
|
||||
|
||||
@ -122,8 +131,9 @@ void ListDataTitleTicketInfos(Service::Interface* self) {
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
cmd_buff[2] = am_ticket_count;
|
||||
LOG_WARNING(Service_AM, "(STUBBED) ticket_count=0x%08X, title_id=0x%016" PRIx64 ", start_index=0x%08X, ticket_info_pointer=0x%08X",
|
||||
am_ticket_count, title_id, start_index, ticket_info_pointer);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) ticket_count=0x%08X, title_id=0x%016" PRIx64
|
||||
", start_index=0x%08X, ticket_info_pointer=0x%08X",
|
||||
am_ticket_count, title_id, start_index, ticket_info_pointer);
|
||||
}
|
||||
|
||||
void GetNumContentInfos(Service::Interface* self) {
|
||||
@ -140,7 +150,7 @@ void DeleteTicket(Service::Interface* self) {
|
||||
u64 title_id = (static_cast<u64>(cmd_buff[2]) << 32) | cmd_buff[1];
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called title_id=0x%016" PRIx64 "",title_id);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called title_id=0x%016" PRIx64 "", title_id);
|
||||
}
|
||||
|
||||
void GetTicketCount(Service::Interface* self) {
|
||||
@ -148,7 +158,7 @@ void GetTicketCount(Service::Interface* self) {
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
cmd_buff[2] = am_ticket_count;
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called ticket_count=0x%08x",am_ticket_count);
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called ticket_count=0x%08x", am_ticket_count);
|
||||
}
|
||||
|
||||
void GetTicketList(Service::Interface* self) {
|
||||
@ -161,8 +171,10 @@ void GetTicketList(Service::Interface* self) {
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
cmd_buff[2] = am_ticket_list_count;
|
||||
LOG_WARNING(Service_AM, "(STUBBED) ticket_list_count=0x%08x, num_of_skip=0x%08x, ticket_list_pointer=0x%08x",
|
||||
am_ticket_list_count, num_of_skip, ticket_list_pointer);
|
||||
LOG_WARNING(
|
||||
Service_AM,
|
||||
"(STUBBED) ticket_list_count=0x%08x, num_of_skip=0x%08x, ticket_list_pointer=0x%08x",
|
||||
am_ticket_list_count, num_of_skip, ticket_list_pointer);
|
||||
}
|
||||
|
||||
void Init() {
|
||||
@ -175,7 +187,6 @@ void Init() {
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
|
||||
}
|
||||
|
||||
} // namespace AM
|
||||
|
@ -9,14 +9,14 @@ namespace Service {
|
||||
namespace AM {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x100100C0, GetNumContentInfos, "GetNumContentInfos"},
|
||||
{0x10020104, FindContentInfos, "FindContentInfos"},
|
||||
{0x10030142, ListContentInfos, "ListContentInfos"},
|
||||
{0x10040102, DeleteContents, "DeleteContents"},
|
||||
{0x10050084, GetDataTitleInfos, "GetDataTitleInfos"},
|
||||
{0x10070102, ListDataTitleTicketInfos, "ListDataTitleTicketInfos"},
|
||||
{0x100900C0, nullptr, "IsDataTitleInUse"},
|
||||
{0x100A0000, nullptr, "IsExternalTitleDatabaseInitialized"},
|
||||
{0x100100C0, GetNumContentInfos, "GetNumContentInfos"},
|
||||
{0x10020104, FindContentInfos, "FindContentInfos"},
|
||||
{0x10030142, ListContentInfos, "ListContentInfos"},
|
||||
{0x10040102, DeleteContents, "DeleteContents"},
|
||||
{0x10050084, GetDataTitleInfos, "GetDataTitleInfos"},
|
||||
{0x10070102, ListDataTitleTicketInfos, "ListDataTitleTicketInfos"},
|
||||
{0x100900C0, nullptr, "IsDataTitleInUse"},
|
||||
{0x100A0000, nullptr, "IsExternalTitleDatabaseInitialized"},
|
||||
};
|
||||
|
||||
AM_APP_Interface::AM_APP_Interface() {
|
||||
|
@ -9,61 +9,61 @@ namespace Service {
|
||||
namespace AM {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00010040, GetTitleCount, "GetTitleCount"},
|
||||
{0x00020082, GetTitleList, "GetTitleList"},
|
||||
{0x00030084, GetTitleInfo, "GetTitleInfo"},
|
||||
{0x000400C0, nullptr, "DeleteApplicationTitle"},
|
||||
{0x000500C0, nullptr, "GetTitleProductCode"},
|
||||
{0x000600C0, nullptr, "GetTitleExtDataId"},
|
||||
{0x00070080, DeleteTicket, "DeleteTicket"},
|
||||
{0x00080000, GetTicketCount, "GetTicketCount"},
|
||||
{0x00090082, GetTicketList, "GetTicketList"},
|
||||
{0x000A0000, nullptr, "GetDeviceID"},
|
||||
{0x000D0084, nullptr, "GetPendingTitleInfo"},
|
||||
{0x000E00C0, nullptr, "DeletePendingTitle"},
|
||||
{0x00140040, nullptr, "FinalizePendingTitles"},
|
||||
{0x00150040, nullptr, "DeleteAllPendingTitles"},
|
||||
{0x00180080, nullptr, "InitializeTitleDatabase"},
|
||||
{0x00190040, nullptr, "ReloadDBS"},
|
||||
{0x001A00C0, nullptr, "GetDSiWareExportSize"},
|
||||
{0x001B0144, nullptr, "ExportDSiWare"},
|
||||
{0x001C0084, nullptr, "ImportDSiWare"},
|
||||
{0x00230080, nullptr, "TitleIDListGetTotal2"},
|
||||
{0x002400C2, nullptr, "GetTitleIDList2"},
|
||||
{0x04010080, nullptr, "InstallFIRM"},
|
||||
{0x04020040, nullptr, "StartInstallCIADB0"},
|
||||
{0x04030000, nullptr, "StartInstallCIADB1"},
|
||||
{0x04040002, nullptr, "AbortCIAInstall"},
|
||||
{0x04050002, nullptr, "CloseCIAFinalizeInstall"},
|
||||
{0x04060002, nullptr, "CloseCIA"},
|
||||
{0x040700C2, nullptr, "FinalizeTitlesInstall"},
|
||||
{0x04080042, nullptr, "GetCiaFileInfo"},
|
||||
{0x040E00C2, nullptr, "InstallTitlesFinish"},
|
||||
{0x040F0000, nullptr, "InstallNATIVEFIRM"},
|
||||
{0x041000C0, nullptr, "DeleteTitle"},
|
||||
{0x04120000, nullptr, "Initialize"},
|
||||
{0x041700C0, nullptr, "MigrateAGBtoSAV"},
|
||||
{0x08010000, nullptr, "OpenTicket"},
|
||||
{0x08020002, nullptr, "TicketAbortInstall"},
|
||||
{0x08030002, nullptr, "TicketFinalizeInstall"},
|
||||
{0x08040100, nullptr, "InstallTitleBegin"},
|
||||
{0x08050000, nullptr, "InstallTitleAbort"},
|
||||
{0x080600C0, nullptr, "InstallTitleResume"},
|
||||
{0x08070000, nullptr, "InstallTitleAbortTMD"},
|
||||
{0x08080000, nullptr, "InstallTitleFinish"},
|
||||
{0x080A0000, nullptr, "OpenTMD"},
|
||||
{0x080B0002, nullptr, "TMDAbortInstall"},
|
||||
{0x080C0042, nullptr, "TMDFinalizeInstall"},
|
||||
{0x080E0040, nullptr, "OpenContentCreate"},
|
||||
{0x080F0002, nullptr, "ContentAbortInstall"},
|
||||
{0x08100040, nullptr, "OpenContentResume"},
|
||||
{0x08120002, nullptr, "ContentFinalizeInstall"},
|
||||
{0x08130000, nullptr, "GetTotalContents"},
|
||||
{0x08140042, nullptr, "GetContentIndexes"},
|
||||
{0x08150044, nullptr, "GetContentsInfo"},
|
||||
{0x08180042, nullptr, "GetCTCert"},
|
||||
{0x08190108, nullptr, "SetCertificates"},
|
||||
{0x081B00C2, nullptr, "InstallTitlesFinish"},
|
||||
{0x00010040, GetTitleCount, "GetTitleCount"},
|
||||
{0x00020082, GetTitleList, "GetTitleList"},
|
||||
{0x00030084, GetTitleInfo, "GetTitleInfo"},
|
||||
{0x000400C0, nullptr, "DeleteApplicationTitle"},
|
||||
{0x000500C0, nullptr, "GetTitleProductCode"},
|
||||
{0x000600C0, nullptr, "GetTitleExtDataId"},
|
||||
{0x00070080, DeleteTicket, "DeleteTicket"},
|
||||
{0x00080000, GetTicketCount, "GetTicketCount"},
|
||||
{0x00090082, GetTicketList, "GetTicketList"},
|
||||
{0x000A0000, nullptr, "GetDeviceID"},
|
||||
{0x000D0084, nullptr, "GetPendingTitleInfo"},
|
||||
{0x000E00C0, nullptr, "DeletePendingTitle"},
|
||||
{0x00140040, nullptr, "FinalizePendingTitles"},
|
||||
{0x00150040, nullptr, "DeleteAllPendingTitles"},
|
||||
{0x00180080, nullptr, "InitializeTitleDatabase"},
|
||||
{0x00190040, nullptr, "ReloadDBS"},
|
||||
{0x001A00C0, nullptr, "GetDSiWareExportSize"},
|
||||
{0x001B0144, nullptr, "ExportDSiWare"},
|
||||
{0x001C0084, nullptr, "ImportDSiWare"},
|
||||
{0x00230080, nullptr, "TitleIDListGetTotal2"},
|
||||
{0x002400C2, nullptr, "GetTitleIDList2"},
|
||||
{0x04010080, nullptr, "InstallFIRM"},
|
||||
{0x04020040, nullptr, "StartInstallCIADB0"},
|
||||
{0x04030000, nullptr, "StartInstallCIADB1"},
|
||||
{0x04040002, nullptr, "AbortCIAInstall"},
|
||||
{0x04050002, nullptr, "CloseCIAFinalizeInstall"},
|
||||
{0x04060002, nullptr, "CloseCIA"},
|
||||
{0x040700C2, nullptr, "FinalizeTitlesInstall"},
|
||||
{0x04080042, nullptr, "GetCiaFileInfo"},
|
||||
{0x040E00C2, nullptr, "InstallTitlesFinish"},
|
||||
{0x040F0000, nullptr, "InstallNATIVEFIRM"},
|
||||
{0x041000C0, nullptr, "DeleteTitle"},
|
||||
{0x04120000, nullptr, "Initialize"},
|
||||
{0x041700C0, nullptr, "MigrateAGBtoSAV"},
|
||||
{0x08010000, nullptr, "OpenTicket"},
|
||||
{0x08020002, nullptr, "TicketAbortInstall"},
|
||||
{0x08030002, nullptr, "TicketFinalizeInstall"},
|
||||
{0x08040100, nullptr, "InstallTitleBegin"},
|
||||
{0x08050000, nullptr, "InstallTitleAbort"},
|
||||
{0x080600C0, nullptr, "InstallTitleResume"},
|
||||
{0x08070000, nullptr, "InstallTitleAbortTMD"},
|
||||
{0x08080000, nullptr, "InstallTitleFinish"},
|
||||
{0x080A0000, nullptr, "OpenTMD"},
|
||||
{0x080B0002, nullptr, "TMDAbortInstall"},
|
||||
{0x080C0042, nullptr, "TMDFinalizeInstall"},
|
||||
{0x080E0040, nullptr, "OpenContentCreate"},
|
||||
{0x080F0002, nullptr, "ContentAbortInstall"},
|
||||
{0x08100040, nullptr, "OpenContentResume"},
|
||||
{0x08120002, nullptr, "ContentFinalizeInstall"},
|
||||
{0x08130000, nullptr, "GetTotalContents"},
|
||||
{0x08140042, nullptr, "GetContentIndexes"},
|
||||
{0x08150044, nullptr, "GetContentsInfo"},
|
||||
{0x08180042, nullptr, "GetCTCert"},
|
||||
{0x08190108, nullptr, "SetCertificates"},
|
||||
{0x081B00C2, nullptr, "InstallTitlesFinish"},
|
||||
};
|
||||
|
||||
AM_NET_Interface::AM_NET_Interface() {
|
||||
|
@ -8,29 +8,27 @@
|
||||
namespace Service {
|
||||
namespace AM {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00010040, GetTitleCount, "GetTitleCount"},
|
||||
{0x00020082, GetTitleList, "GetTitleList"},
|
||||
{0x00030084, GetTitleInfo, "GetTitleInfo"},
|
||||
{0x000400C0, nullptr, "DeleteApplicationTitle"},
|
||||
{0x000500C0, nullptr, "GetTitleProductCode"},
|
||||
{0x000600C0, nullptr, "GetTitleExtDataId"},
|
||||
{0x00070080, DeleteTicket, "DeleteTicket"},
|
||||
{0x00080000, GetTicketCount, "GetTicketCount"},
|
||||
{0x00090082, GetTicketList, "GetTicketList"},
|
||||
{0x000A0000, nullptr, "GetDeviceID"},
|
||||
{0x000D0084, nullptr, "GetPendingTitleInfo"},
|
||||
{0x000E00C0, nullptr, "DeletePendingTitle"},
|
||||
{0x00140040, nullptr, "FinalizePendingTitles"},
|
||||
{0x00150040, nullptr, "DeleteAllPendingTitles"},
|
||||
{0x00180080, nullptr, "InitializeTitleDatabase"},
|
||||
{0x00190040, nullptr, "ReloadDBS"},
|
||||
{0x001A00C0, nullptr, "GetDSiWareExportSize"},
|
||||
{0x001B0144, nullptr, "ExportDSiWare"},
|
||||
{0x001C0084, nullptr, "ImportDSiWare"},
|
||||
{0x00230080, nullptr, "GetPendingTitleCount"},
|
||||
{0x002400C2, nullptr, "GetPendingTitleList"}
|
||||
};
|
||||
const Interface::FunctionInfo FunctionTable[] = {{0x00010040, GetTitleCount, "GetTitleCount"},
|
||||
{0x00020082, GetTitleList, "GetTitleList"},
|
||||
{0x00030084, GetTitleInfo, "GetTitleInfo"},
|
||||
{0x000400C0, nullptr, "DeleteApplicationTitle"},
|
||||
{0x000500C0, nullptr, "GetTitleProductCode"},
|
||||
{0x000600C0, nullptr, "GetTitleExtDataId"},
|
||||
{0x00070080, DeleteTicket, "DeleteTicket"},
|
||||
{0x00080000, GetTicketCount, "GetTicketCount"},
|
||||
{0x00090082, GetTicketList, "GetTicketList"},
|
||||
{0x000A0000, nullptr, "GetDeviceID"},
|
||||
{0x000D0084, nullptr, "GetPendingTitleInfo"},
|
||||
{0x000E00C0, nullptr, "DeletePendingTitle"},
|
||||
{0x00140040, nullptr, "FinalizePendingTitles"},
|
||||
{0x00150040, nullptr, "DeleteAllPendingTitles"},
|
||||
{0x00180080, nullptr, "InitializeTitleDatabase"},
|
||||
{0x00190040, nullptr, "ReloadDBS"},
|
||||
{0x001A00C0, nullptr, "GetDSiWareExportSize"},
|
||||
{0x001B0144, nullptr, "ExportDSiWare"},
|
||||
{0x001C0084, nullptr, "ImportDSiWare"},
|
||||
{0x00230080, nullptr, "GetPendingTitleCount"},
|
||||
{0x002400C2, nullptr, "GetPendingTitleList"}};
|
||||
|
||||
AM_SYS_Interface::AM_SYS_Interface() {
|
||||
Register(FunctionTable);
|
||||
|
@ -8,42 +8,40 @@
|
||||
namespace Service {
|
||||
namespace AM {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00010040, GetTitleCount, "GetTitleCount"},
|
||||
{0x00020082, GetTitleList, "GetTitleList"},
|
||||
{0x00030084, GetTitleInfo, "GetTitleInfo"},
|
||||
{0x000400C0, nullptr, "DeleteApplicationTitle"},
|
||||
{0x000500C0, nullptr, "GetTitleProductCode"},
|
||||
{0x000600C0, nullptr, "GetTitleExtDataId"},
|
||||
{0x00070080, DeleteTicket, "DeleteTicket"},
|
||||
{0x00080000, GetTicketCount, "GetTicketCount"},
|
||||
{0x00090082, GetTicketList, "GetTicketList"},
|
||||
{0x000A0000, nullptr, "GetDeviceID"},
|
||||
{0x000D0084, nullptr, "GetPendingTitleInfo"},
|
||||
{0x000E00C0, nullptr, "DeletePendingTitle"},
|
||||
{0x00140040, nullptr, "FinalizePendingTitles"},
|
||||
{0x00150040, nullptr, "DeleteAllPendingTitles"},
|
||||
{0x00180080, nullptr, "InitializeTitleDatabase"},
|
||||
{0x00190040, nullptr, "ReloadDBS"},
|
||||
{0x001A00C0, nullptr, "GetDSiWareExportSize"},
|
||||
{0x001B0144, nullptr, "ExportDSiWare"},
|
||||
{0x001C0084, nullptr, "ImportDSiWare"},
|
||||
{0x00230080, nullptr, "TitleIDListGetTotal2"},
|
||||
{0x002400C2, nullptr, "GetTitleIDList2"},
|
||||
{0x04010080, nullptr, "InstallFIRM"},
|
||||
{0x04020040, nullptr, "StartInstallCIADB0"},
|
||||
{0x04030000, nullptr, "StartInstallCIADB1"},
|
||||
{0x04040002, nullptr, "AbortCIAInstall"},
|
||||
{0x04050002, nullptr, "CloseCIAFinalizeInstall"},
|
||||
{0x04060002, nullptr, "CloseCIA"},
|
||||
{0x040700C2, nullptr, "FinalizeTitlesInstall"},
|
||||
{0x04080042, nullptr, "GetCiaFileInfo"},
|
||||
{0x040E00C2, nullptr, "InstallTitlesFinish"},
|
||||
{0x040F0000, nullptr, "InstallNATIVEFIRM"},
|
||||
{0x041000C0, nullptr, "DeleteTitle"},
|
||||
{0x04120000, nullptr, "Initialize"},
|
||||
{0x041700C0, nullptr, "MigrateAGBtoSAV"}
|
||||
};
|
||||
const Interface::FunctionInfo FunctionTable[] = {{0x00010040, GetTitleCount, "GetTitleCount"},
|
||||
{0x00020082, GetTitleList, "GetTitleList"},
|
||||
{0x00030084, GetTitleInfo, "GetTitleInfo"},
|
||||
{0x000400C0, nullptr, "DeleteApplicationTitle"},
|
||||
{0x000500C0, nullptr, "GetTitleProductCode"},
|
||||
{0x000600C0, nullptr, "GetTitleExtDataId"},
|
||||
{0x00070080, DeleteTicket, "DeleteTicket"},
|
||||
{0x00080000, GetTicketCount, "GetTicketCount"},
|
||||
{0x00090082, GetTicketList, "GetTicketList"},
|
||||
{0x000A0000, nullptr, "GetDeviceID"},
|
||||
{0x000D0084, nullptr, "GetPendingTitleInfo"},
|
||||
{0x000E00C0, nullptr, "DeletePendingTitle"},
|
||||
{0x00140040, nullptr, "FinalizePendingTitles"},
|
||||
{0x00150040, nullptr, "DeleteAllPendingTitles"},
|
||||
{0x00180080, nullptr, "InitializeTitleDatabase"},
|
||||
{0x00190040, nullptr, "ReloadDBS"},
|
||||
{0x001A00C0, nullptr, "GetDSiWareExportSize"},
|
||||
{0x001B0144, nullptr, "ExportDSiWare"},
|
||||
{0x001C0084, nullptr, "ImportDSiWare"},
|
||||
{0x00230080, nullptr, "TitleIDListGetTotal2"},
|
||||
{0x002400C2, nullptr, "GetTitleIDList2"},
|
||||
{0x04010080, nullptr, "InstallFIRM"},
|
||||
{0x04020040, nullptr, "StartInstallCIADB0"},
|
||||
{0x04030000, nullptr, "StartInstallCIADB1"},
|
||||
{0x04040002, nullptr, "AbortCIAInstall"},
|
||||
{0x04050002, nullptr, "CloseCIAFinalizeInstall"},
|
||||
{0x04060002, nullptr, "CloseCIA"},
|
||||
{0x040700C2, nullptr, "FinalizeTitlesInstall"},
|
||||
{0x04080042, nullptr, "GetCiaFileInfo"},
|
||||
{0x040E00C2, nullptr, "InstallTitlesFinish"},
|
||||
{0x040F0000, nullptr, "InstallNATIVEFIRM"},
|
||||
{0x041000C0, nullptr, "DeleteTitle"},
|
||||
{0x04120000, nullptr, "Initialize"},
|
||||
{0x041700C0, nullptr, "MigrateAGBtoSAV"}};
|
||||
|
||||
AM_U_Interface::AM_U_Interface() {
|
||||
Register(FunctionTable);
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include "common/logging/log.h"
|
||||
|
||||
#include "core/hle/applets/applet.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/apt/apt.h"
|
||||
#include "core/hle/service/apt/apt_a.h"
|
||||
#include "core/hle/service/apt/apt_s.h"
|
||||
@ -15,6 +14,7 @@
|
||||
#include "core/hle/service/apt/bcfnt/bcfnt.h"
|
||||
#include "core/hle/service/fs/archive.h"
|
||||
#include "core/hle/service/ptm/ptm.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/kernel/mutex.h"
|
||||
@ -30,7 +30,7 @@ static bool shared_font_relocated = false;
|
||||
|
||||
static Kernel::SharedPtr<Kernel::Mutex> lock;
|
||||
static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event
|
||||
static Kernel::SharedPtr<Kernel::Event> parameter_event; ///< APT parameter event
|
||||
static Kernel::SharedPtr<Kernel::Event> parameter_event; ///< APT parameter event
|
||||
|
||||
static u32 cpu_percent; ///< CPU time available to the running application
|
||||
|
||||
@ -51,7 +51,7 @@ void SendParameter(const MessageParameter& parameter) {
|
||||
void Initialize(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
u32 app_id = cmd_buff[1];
|
||||
u32 flags = cmd_buff[2];
|
||||
u32 flags = cmd_buff[2];
|
||||
|
||||
cmd_buff[2] = IPC::CopyHandleDesc(2);
|
||||
cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom();
|
||||
@ -75,20 +75,24 @@ void GetSharedFont(Service::Interface* self) {
|
||||
if (!shared_font_mem) {
|
||||
LOG_ERROR(Service_APT, "shared font file missing - go dump it from your 3ds");
|
||||
cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2);
|
||||
cmd_buff[1] = -1; // TODO: Find the right error code
|
||||
cmd_buff[1] = -1; // TODO: Find the right error code
|
||||
return;
|
||||
}
|
||||
|
||||
// The shared font has to be relocated to the new address before being passed to the application.
|
||||
VAddr target_address = Memory::PhysicalToVirtualAddress(shared_font_mem->linear_heap_phys_address);
|
||||
// The shared font has to be relocated to the new address before being passed to the
|
||||
// application.
|
||||
VAddr target_address =
|
||||
Memory::PhysicalToVirtualAddress(shared_font_mem->linear_heap_phys_address);
|
||||
if (!shared_font_relocated) {
|
||||
BCFNT::RelocateSharedFont(shared_font_mem, target_address);
|
||||
shared_font_relocated = true;
|
||||
}
|
||||
cmd_buff[0] = IPC::MakeHeader(0x44, 2, 2);
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
// Since the SharedMemory interface doesn't provide the address at which the memory was allocated,
|
||||
// the real APT service calculates this address by scanning the entire address space (using svcQueryMemory)
|
||||
// Since the SharedMemory interface doesn't provide the address at which the memory was
|
||||
// allocated,
|
||||
// the real APT service calculates this address by scanning the entire address space (using
|
||||
// svcQueryMemory)
|
||||
// and searches for an allocation of the same size as the Shared Font.
|
||||
cmd_buff[2] = target_address;
|
||||
cmd_buff[3] = IPC::CopyHandleDesc();
|
||||
@ -112,18 +116,19 @@ void GetLockHandle(Service::Interface* self) {
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
|
||||
cmd_buff[2] = applet_attributes; // Applet Attributes, this value is passed to Enable.
|
||||
cmd_buff[3] = 0; // Least significant bit = power button state
|
||||
cmd_buff[3] = 0; // Least significant bit = power button state
|
||||
cmd_buff[4] = IPC::CopyHandleDesc();
|
||||
cmd_buff[5] = Kernel::g_handle_table.Create(lock).MoveFrom();
|
||||
|
||||
LOG_WARNING(Service_APT, "(STUBBED) called handle=0x%08X applet_attributes=0x%08X", cmd_buff[5], applet_attributes);
|
||||
LOG_WARNING(Service_APT, "(STUBBED) called handle=0x%08X applet_attributes=0x%08X", cmd_buff[5],
|
||||
applet_attributes);
|
||||
}
|
||||
|
||||
void Enable(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
u32 attributes = cmd_buff[1];
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
parameter_event->Signal(); // Let the application know that it has been started
|
||||
parameter_event->Signal(); // Let the application know that it has been started
|
||||
LOG_WARNING(Service_APT, "(STUBBED) called attributes=0x%08X", attributes);
|
||||
}
|
||||
|
||||
@ -133,7 +138,7 @@ void GetAppletManInfo(Service::Interface* self) {
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
cmd_buff[2] = 0;
|
||||
cmd_buff[3] = 0;
|
||||
cmd_buff[4] = static_cast<u32>(AppletId::HomeMenu); // Home menu AppID
|
||||
cmd_buff[4] = static_cast<u32>(AppletId::HomeMenu); // Home menu AppID
|
||||
cmd_buff[5] = static_cast<u32>(AppletId::Application); // TODO(purpasmart96): Do this correctly
|
||||
|
||||
LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk);
|
||||
@ -159,23 +164,24 @@ void IsRegistered(Service::Interface* self) {
|
||||
void InquireNotification(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
u32 app_id = cmd_buff[1];
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
cmd_buff[2] = static_cast<u32>(SignalType::None); // Signal type
|
||||
LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id);
|
||||
}
|
||||
|
||||
void SendParameter(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
u32 src_app_id = cmd_buff[1];
|
||||
u32 dst_app_id = cmd_buff[2];
|
||||
u32 signal_type = cmd_buff[3];
|
||||
u32 buffer_size = cmd_buff[4];
|
||||
u32 value = cmd_buff[5];
|
||||
u32 handle = cmd_buff[6];
|
||||
u32 size = cmd_buff[7];
|
||||
u32 buffer = cmd_buff[8];
|
||||
u32 src_app_id = cmd_buff[1];
|
||||
u32 dst_app_id = cmd_buff[2];
|
||||
u32 signal_type = cmd_buff[3];
|
||||
u32 buffer_size = cmd_buff[4];
|
||||
u32 value = cmd_buff[5];
|
||||
u32 handle = cmd_buff[6];
|
||||
u32 size = cmd_buff[7];
|
||||
u32 buffer = cmd_buff[8];
|
||||
|
||||
std::shared_ptr<HLE::Applets::Applet> dest_applet = HLE::Applets::Applet::Get(static_cast<AppletId>(dst_app_id));
|
||||
std::shared_ptr<HLE::Applets::Applet> dest_applet =
|
||||
HLE::Applets::Applet::Get(static_cast<AppletId>(dst_app_id));
|
||||
|
||||
if (dest_applet == nullptr) {
|
||||
LOG_ERROR(Service_APT, "Unknown applet id=0x%08X", dst_app_id);
|
||||
@ -193,9 +199,11 @@ void SendParameter(Service::Interface* self) {
|
||||
|
||||
cmd_buff[1] = dest_applet->ReceiveParameter(param).raw;
|
||||
|
||||
LOG_WARNING(Service_APT, "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X,"
|
||||
"buffer_size=0x%08X, value=0x%08X, handle=0x%08X, size=0x%08X, in_param_buffer_ptr=0x%08X",
|
||||
src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, buffer);
|
||||
LOG_WARNING(
|
||||
Service_APT,
|
||||
"(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X,"
|
||||
"buffer_size=0x%08X, value=0x%08X, handle=0x%08X, size=0x%08X, in_param_buffer_ptr=0x%08X",
|
||||
src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, buffer);
|
||||
}
|
||||
|
||||
void ReceiveParameter(Service::Interface* self) {
|
||||
@ -206,7 +214,7 @@ void ReceiveParameter(Service::Interface* self) {
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
cmd_buff[2] = next_parameter.sender_id;
|
||||
cmd_buff[3] = next_parameter.signal; // Signal type
|
||||
cmd_buff[3] = next_parameter.signal; // Signal type
|
||||
cmd_buff[4] = next_parameter.buffer.size(); // Parameter buffer size
|
||||
cmd_buff[5] = 0x10;
|
||||
cmd_buff[6] = 0;
|
||||
@ -228,7 +236,7 @@ void GlanceParameter(Service::Interface* self) {
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
cmd_buff[2] = next_parameter.sender_id;
|
||||
cmd_buff[3] = next_parameter.signal; // Signal type
|
||||
cmd_buff[3] = next_parameter.signal; // Signal type
|
||||
cmd_buff[4] = next_parameter.buffer.size(); // Parameter buffer size
|
||||
cmd_buff[5] = 0x10;
|
||||
cmd_buff[6] = 0;
|
||||
@ -237,32 +245,34 @@ void GlanceParameter(Service::Interface* self) {
|
||||
cmd_buff[7] = (next_parameter.buffer.size() << 14) | 2;
|
||||
cmd_buff[8] = buffer;
|
||||
|
||||
Memory::WriteBlock(buffer, next_parameter.buffer.data(), std::min(static_cast<size_t>(buffer_size), next_parameter.buffer.size()));
|
||||
Memory::WriteBlock(buffer, next_parameter.buffer.data(),
|
||||
std::min(static_cast<size_t>(buffer_size), next_parameter.buffer.size()));
|
||||
|
||||
LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
|
||||
}
|
||||
|
||||
void CancelParameter(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
u32 flag1 = cmd_buff[1];
|
||||
u32 unk = cmd_buff[2];
|
||||
u32 flag2 = cmd_buff[3];
|
||||
u32 flag1 = cmd_buff[1];
|
||||
u32 unk = cmd_buff[2];
|
||||
u32 flag2 = cmd_buff[3];
|
||||
u32 app_id = cmd_buff[4];
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
cmd_buff[2] = 1; // Set to Success
|
||||
cmd_buff[2] = 1; // Set to Success
|
||||
|
||||
LOG_WARNING(Service_APT, "(STUBBED) called flag1=0x%08X, unk=0x%08X, flag2=0x%08X, app_id=0x%08X",
|
||||
flag1, unk, flag2, app_id);
|
||||
LOG_WARNING(Service_APT,
|
||||
"(STUBBED) called flag1=0x%08X, unk=0x%08X, flag2=0x%08X, app_id=0x%08X", flag1,
|
||||
unk, flag2, app_id);
|
||||
}
|
||||
|
||||
void PrepareToStartApplication(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
u32 title_info1 = cmd_buff[1];
|
||||
u32 title_info2 = cmd_buff[2];
|
||||
u32 title_info3 = cmd_buff[3];
|
||||
u32 title_info4 = cmd_buff[4];
|
||||
u32 flags = cmd_buff[5];
|
||||
u32 title_info1 = cmd_buff[1];
|
||||
u32 title_info2 = cmd_buff[2];
|
||||
u32 title_info3 = cmd_buff[3];
|
||||
u32 title_info4 = cmd_buff[4];
|
||||
u32 flags = cmd_buff[5];
|
||||
|
||||
if (flags & 0x00000100) {
|
||||
unknown_ns_state_field = 1;
|
||||
@ -270,25 +280,28 @@ void PrepareToStartApplication(Service::Interface* self) {
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
|
||||
LOG_WARNING(Service_APT, "(STUBBED) called title_info1=0x%08X, title_info2=0x%08X, title_info3=0x%08X,"
|
||||
"title_info4=0x%08X, flags=0x%08X", title_info1, title_info2, title_info3, title_info4, flags);
|
||||
LOG_WARNING(Service_APT,
|
||||
"(STUBBED) called title_info1=0x%08X, title_info2=0x%08X, title_info3=0x%08X,"
|
||||
"title_info4=0x%08X, flags=0x%08X",
|
||||
title_info1, title_info2, title_info3, title_info4, flags);
|
||||
}
|
||||
|
||||
void StartApplication(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
u32 buffer1_size = cmd_buff[1];
|
||||
u32 buffer2_size = cmd_buff[2];
|
||||
u32 flag = cmd_buff[3];
|
||||
u32 size1 = cmd_buff[4];
|
||||
u32 buffer1_ptr = cmd_buff[5];
|
||||
u32 size2 = cmd_buff[6];
|
||||
u32 buffer2_ptr = cmd_buff[7];
|
||||
u32 flag = cmd_buff[3];
|
||||
u32 size1 = cmd_buff[4];
|
||||
u32 buffer1_ptr = cmd_buff[5];
|
||||
u32 size2 = cmd_buff[6];
|
||||
u32 buffer2_ptr = cmd_buff[7];
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
|
||||
LOG_WARNING(Service_APT, "(STUBBED) called buffer1_size=0x%08X, buffer2_size=0x%08X, flag=0x%08X,"
|
||||
"size1=0x%08X, buffer1_ptr=0x%08X, size2=0x%08X, buffer2_ptr=0x%08X",
|
||||
buffer1_size, buffer2_size, flag, size1, buffer1_ptr, size2, buffer2_ptr);
|
||||
LOG_WARNING(Service_APT,
|
||||
"(STUBBED) called buffer1_size=0x%08X, buffer2_size=0x%08X, flag=0x%08X,"
|
||||
"size1=0x%08X, buffer1_ptr=0x%08X, size2=0x%08X, buffer2_ptr=0x%08X",
|
||||
buffer1_size, buffer2_size, flag, size1, buffer1_ptr, size2, buffer2_ptr);
|
||||
}
|
||||
|
||||
void AppletUtility(Service::Interface* self) {
|
||||
@ -303,14 +316,15 @@ void AppletUtility(Service::Interface* self) {
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
|
||||
LOG_WARNING(Service_APT, "(STUBBED) called command=0x%08X, buffer1_size=0x%08X, buffer2_size=0x%08X, "
|
||||
"buffer1_addr=0x%08X, buffer2_addr=0x%08X", command, buffer1_size, buffer2_size,
|
||||
buffer1_addr, buffer2_addr);
|
||||
LOG_WARNING(Service_APT,
|
||||
"(STUBBED) called command=0x%08X, buffer1_size=0x%08X, buffer2_size=0x%08X, "
|
||||
"buffer1_addr=0x%08X, buffer2_addr=0x%08X",
|
||||
command, buffer1_size, buffer2_size, buffer1_addr, buffer2_addr);
|
||||
}
|
||||
|
||||
void SetAppCpuTimeLimit(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
u32 value = cmd_buff[1];
|
||||
u32 value = cmd_buff[1];
|
||||
cpu_percent = cmd_buff[2];
|
||||
|
||||
if (value != 1) {
|
||||
@ -393,7 +407,8 @@ void SetScreenCapPostPermission(Service::Interface* self) {
|
||||
|
||||
cmd_buff[0] = IPC::MakeHeader(0x55, 1, 0);
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u", screen_capture_post_permission);
|
||||
LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u",
|
||||
screen_capture_post_permission);
|
||||
}
|
||||
|
||||
void GetScreenCapPostPermission(Service::Interface* self) {
|
||||
@ -402,7 +417,8 @@ void GetScreenCapPostPermission(Service::Interface* self) {
|
||||
cmd_buff[0] = IPC::MakeHeader(0x56, 2, 0);
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
cmd_buff[2] = static_cast<u32>(screen_capture_post_permission);
|
||||
LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u", screen_capture_post_permission);
|
||||
LOG_WARNING(Service_APT, "(STUBBED) screen_capture_post_permission=%u",
|
||||
screen_capture_post_permission);
|
||||
}
|
||||
|
||||
void GetAppletInfo(Service::Interface* self) {
|
||||
@ -418,7 +434,8 @@ void GetAppletInfo(Service::Interface* self) {
|
||||
cmd_buff[7] = 0; // Applet Attributes
|
||||
} else {
|
||||
cmd_buff[1] = ResultCode(ErrorDescription::NotFound, ErrorModule::Applet,
|
||||
ErrorSummary::NotFound, ErrorLevel::Status).raw;
|
||||
ErrorSummary::NotFound, ErrorLevel::Status)
|
||||
.raw;
|
||||
}
|
||||
LOG_WARNING(Service_APT, "(stubbed) called appid=%u", app_id);
|
||||
}
|
||||
@ -429,11 +446,15 @@ void GetStartupArgument(Service::Interface* self) {
|
||||
StartupArgumentType startup_argument_type = static_cast<StartupArgumentType>(cmd_buff[2]);
|
||||
|
||||
if (parameter_size >= 0x300) {
|
||||
LOG_ERROR(Service_APT, "Parameter size is outside the valid range (capped to 0x300): parameter_size=0x%08x", parameter_size);
|
||||
LOG_ERROR(
|
||||
Service_APT,
|
||||
"Parameter size is outside the valid range (capped to 0x300): parameter_size=0x%08x",
|
||||
parameter_size);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_WARNING(Service_APT,"(stubbed) called startup_argument_type=%u , parameter_size=0x%08x , parameter_value=0x%08x",
|
||||
LOG_WARNING(Service_APT, "(stubbed) called startup_argument_type=%u , parameter_size=0x%08x , "
|
||||
"parameter_value=0x%08x",
|
||||
startup_argument_type, parameter_size, Memory::Read32(cmd_buff[41]));
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
@ -484,8 +505,10 @@ void Init() {
|
||||
if (file.IsOpen()) {
|
||||
// Create shared font memory object
|
||||
using Kernel::MemoryPermission;
|
||||
shared_font_mem = Kernel::SharedMemory::Create(nullptr, 0x332000, // 3272 KB
|
||||
MemoryPermission::ReadWrite, MemoryPermission::Read, 0, Kernel::MemoryRegion::SYSTEM, "APT:SharedFont");
|
||||
shared_font_mem =
|
||||
Kernel::SharedMemory::Create(nullptr, 0x332000, // 3272 KB
|
||||
MemoryPermission::ReadWrite, MemoryPermission::Read, 0,
|
||||
Kernel::MemoryRegion::SYSTEM, "APT:SharedFont");
|
||||
// Read shared font data
|
||||
file.ReadBytes(shared_font_mem->GetPointer(), file.GetSize());
|
||||
} else {
|
||||
@ -497,7 +520,8 @@ void Init() {
|
||||
|
||||
cpu_percent = 0;
|
||||
unknown_ns_state_field = 0;
|
||||
screen_capture_post_permission = ScreencapPostPermission::CleanThePermission; // TODO(JamePeng): verify the initial value
|
||||
screen_capture_post_permission =
|
||||
ScreencapPostPermission::CleanThePermission; // TODO(JamePeng): verify the initial value
|
||||
|
||||
// TODO(bunnei): Check if these are created in Initialize or on APT process startup.
|
||||
notification_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "APT_U:Notification");
|
||||
|
@ -46,58 +46,58 @@ static_assert(sizeof(CaptureBufferInfo) == 0x20, "CaptureBufferInfo struct has i
|
||||
|
||||
/// Signals used by APT functions
|
||||
enum class SignalType : u32 {
|
||||
None = 0x0,
|
||||
AppJustStarted = 0x1,
|
||||
None = 0x0,
|
||||
AppJustStarted = 0x1,
|
||||
LibAppJustStarted = 0x2,
|
||||
LibAppFinished = 0x3,
|
||||
LibAppClosed = 0xA,
|
||||
ReturningToApp = 0xB,
|
||||
ExitingApp = 0xC,
|
||||
LibAppFinished = 0x3,
|
||||
LibAppClosed = 0xA,
|
||||
ReturningToApp = 0xB,
|
||||
ExitingApp = 0xC,
|
||||
};
|
||||
|
||||
/// App Id's used by APT functions
|
||||
enum class AppletId : u32 {
|
||||
HomeMenu = 0x101,
|
||||
AlternateMenu = 0x103,
|
||||
Camera = 0x110,
|
||||
FriendsList = 0x112,
|
||||
GameNotes = 0x113,
|
||||
InternetBrowser = 0x114,
|
||||
InstructionManual = 0x115,
|
||||
Notifications = 0x116,
|
||||
Miiverse = 0x117,
|
||||
MiiversePost = 0x118,
|
||||
AmiiboSettings = 0x119,
|
||||
SoftwareKeyboard1 = 0x201,
|
||||
Ed1 = 0x202,
|
||||
PnoteApp = 0x204,
|
||||
SnoteApp = 0x205,
|
||||
Error = 0x206,
|
||||
Mint = 0x207,
|
||||
Extrapad = 0x208,
|
||||
Memolib = 0x209,
|
||||
Application = 0x300,
|
||||
AnyLibraryApplet = 0x400,
|
||||
SoftwareKeyboard2 = 0x401,
|
||||
Ed2 = 0x402,
|
||||
PnoteApp2 = 0x404,
|
||||
SnoteApp2 = 0x405,
|
||||
Error2 = 0x406,
|
||||
Mint2 = 0x407,
|
||||
Extrapad2 = 0x408,
|
||||
Memolib2 = 0x409,
|
||||
HomeMenu = 0x101,
|
||||
AlternateMenu = 0x103,
|
||||
Camera = 0x110,
|
||||
FriendsList = 0x112,
|
||||
GameNotes = 0x113,
|
||||
InternetBrowser = 0x114,
|
||||
InstructionManual = 0x115,
|
||||
Notifications = 0x116,
|
||||
Miiverse = 0x117,
|
||||
MiiversePost = 0x118,
|
||||
AmiiboSettings = 0x119,
|
||||
SoftwareKeyboard1 = 0x201,
|
||||
Ed1 = 0x202,
|
||||
PnoteApp = 0x204,
|
||||
SnoteApp = 0x205,
|
||||
Error = 0x206,
|
||||
Mint = 0x207,
|
||||
Extrapad = 0x208,
|
||||
Memolib = 0x209,
|
||||
Application = 0x300,
|
||||
AnyLibraryApplet = 0x400,
|
||||
SoftwareKeyboard2 = 0x401,
|
||||
Ed2 = 0x402,
|
||||
PnoteApp2 = 0x404,
|
||||
SnoteApp2 = 0x405,
|
||||
Error2 = 0x406,
|
||||
Mint2 = 0x407,
|
||||
Extrapad2 = 0x408,
|
||||
Memolib2 = 0x409,
|
||||
};
|
||||
|
||||
enum class StartupArgumentType : u32 {
|
||||
OtherApp = 0,
|
||||
Restart = 1,
|
||||
OtherApp = 0,
|
||||
Restart = 1,
|
||||
OtherMedia = 2,
|
||||
};
|
||||
|
||||
enum class ScreencapPostPermission : u32 {
|
||||
CleanThePermission = 0, //TODO(JamePeng): verify what "zero" means
|
||||
NoExplicitSetting = 1,
|
||||
EnableScreenshotPostingToMiiverse = 2,
|
||||
CleanThePermission = 0, // TODO(JamePeng): verify what "zero" means
|
||||
NoExplicitSetting = 1,
|
||||
EnableScreenshotPostingToMiiverse = 2,
|
||||
DisableScreenshotPostingToMiiverse = 3
|
||||
};
|
||||
|
||||
@ -182,9 +182,12 @@ void GetAppletManInfo(Service::Interface* self);
|
||||
void GetAppletInfo(Service::Interface* self);
|
||||
|
||||
/**
|
||||
* APT::IsRegistered service function. This returns whether the specified AppID is registered with NS yet.
|
||||
* An AppID is "registered" once the process associated with the AppID uses APT:Enable. Home Menu uses this
|
||||
* command to determine when the launched process is running and to determine when to stop using GSP etc,
|
||||
* APT::IsRegistered service function. This returns whether the specified AppID is registered with
|
||||
* NS yet.
|
||||
* An AppID is "registered" once the process associated with the AppID uses APT:Enable. Home Menu
|
||||
* uses this
|
||||
* command to determine when the launched process is running and to determine when to stop using GSP
|
||||
* etc,
|
||||
* while displaying the "Nintendo 3DS" loading screen.
|
||||
* Inputs:
|
||||
* 1 : AppID
|
||||
@ -260,9 +263,11 @@ void GlanceParameter(Service::Interface* self);
|
||||
* clears the flag which indicates that parameter data is available
|
||||
* (same flag cleared by APT:ReceiveParameter).
|
||||
* Inputs:
|
||||
* 1 : Flag, when non-zero NS will compare the word after this one with a field in the NS state.
|
||||
* 1 : Flag, when non-zero NS will compare the word after this one with a field in the NS
|
||||
* state.
|
||||
* 2 : Unknown, this is the same as the first unknown field returned by APT:ReceiveParameter.
|
||||
* 3 : Flag, when non-zero NS will compare the word after this one with a field in the NS state.
|
||||
* 3 : Flag, when non-zero NS will compare the word after this one with a field in the NS
|
||||
* state.
|
||||
* 4 : AppID
|
||||
* Outputs:
|
||||
* 0 : Return header
|
||||
|
@ -9,35 +9,34 @@ namespace Service {
|
||||
namespace APT {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00010040, GetLockHandle, "GetLockHandle?"},
|
||||
{0x00020080, Initialize, "Initialize?"},
|
||||
{0x00030040, Enable, "Enable?"},
|
||||
{0x00040040, nullptr, "Finalize?"},
|
||||
{0x00050040, GetAppletManInfo, "GetAppletManInfo"},
|
||||
{0x00060040, GetAppletInfo, "GetAppletInfo"},
|
||||
{0x00090040, IsRegistered, "IsRegistered"},
|
||||
{0x000B0040, InquireNotification, "InquireNotification"},
|
||||
{0x000C0104, SendParameter, "SendParameter"},
|
||||
{0x000D0080, ReceiveParameter, "ReceiveParameter"},
|
||||
{0x000E0080, GlanceParameter, "GlanceParameter"},
|
||||
{0x000F0100, CancelParameter, "CancelParameter"},
|
||||
{0x00150140, PrepareToStartApplication, "PrepareToStartApplication"},
|
||||
{0x00160040, PreloadLibraryApplet, "PreloadLibraryApplet"},
|
||||
{0x00180040, PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"},
|
||||
{0x001E0084, StartLibraryApplet, "StartLibraryApplet"},
|
||||
{0x003B0040, nullptr, "CancelLibraryApplet?"},
|
||||
{0x003E0080, nullptr, "ReplySleepQuery"},
|
||||
{0x00430040, NotifyToWait, "NotifyToWait?"},
|
||||
{0x00440000, GetSharedFont, "GetSharedFont?"},
|
||||
{0x004B00C2, AppletUtility, "AppletUtility?"},
|
||||
{0x004F0080, SetAppCpuTimeLimit, "SetAppCpuTimeLimit"},
|
||||
{0x00500040, GetAppCpuTimeLimit, "GetAppCpuTimeLimit"},
|
||||
{0x00510080, GetStartupArgument, "GetStartupArgument"},
|
||||
{0x00550040, SetScreenCapPostPermission, "SetScreenCapPostPermission"},
|
||||
{0x00560000, GetScreenCapPostPermission, "GetScreenCapPostPermission"},
|
||||
{0x01010000, CheckNew3DSApp, "CheckNew3DSApp"},
|
||||
{0x01020000, CheckNew3DS, "CheckNew3DS"}
|
||||
};
|
||||
{0x00010040, GetLockHandle, "GetLockHandle?"},
|
||||
{0x00020080, Initialize, "Initialize?"},
|
||||
{0x00030040, Enable, "Enable?"},
|
||||
{0x00040040, nullptr, "Finalize?"},
|
||||
{0x00050040, GetAppletManInfo, "GetAppletManInfo"},
|
||||
{0x00060040, GetAppletInfo, "GetAppletInfo"},
|
||||
{0x00090040, IsRegistered, "IsRegistered"},
|
||||
{0x000B0040, InquireNotification, "InquireNotification"},
|
||||
{0x000C0104, SendParameter, "SendParameter"},
|
||||
{0x000D0080, ReceiveParameter, "ReceiveParameter"},
|
||||
{0x000E0080, GlanceParameter, "GlanceParameter"},
|
||||
{0x000F0100, CancelParameter, "CancelParameter"},
|
||||
{0x00150140, PrepareToStartApplication, "PrepareToStartApplication"},
|
||||
{0x00160040, PreloadLibraryApplet, "PreloadLibraryApplet"},
|
||||
{0x00180040, PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"},
|
||||
{0x001E0084, StartLibraryApplet, "StartLibraryApplet"},
|
||||
{0x003B0040, nullptr, "CancelLibraryApplet?"},
|
||||
{0x003E0080, nullptr, "ReplySleepQuery"},
|
||||
{0x00430040, NotifyToWait, "NotifyToWait?"},
|
||||
{0x00440000, GetSharedFont, "GetSharedFont?"},
|
||||
{0x004B00C2, AppletUtility, "AppletUtility?"},
|
||||
{0x004F0080, SetAppCpuTimeLimit, "SetAppCpuTimeLimit"},
|
||||
{0x00500040, GetAppCpuTimeLimit, "GetAppCpuTimeLimit"},
|
||||
{0x00510080, GetStartupArgument, "GetStartupArgument"},
|
||||
{0x00550040, SetScreenCapPostPermission, "SetScreenCapPostPermission"},
|
||||
{0x00560000, GetScreenCapPostPermission, "GetScreenCapPostPermission"},
|
||||
{0x01010000, CheckNew3DSApp, "CheckNew3DSApp"},
|
||||
{0x01020000, CheckNew3DS, "CheckNew3DS"}};
|
||||
|
||||
APT_A_Interface::APT_A_Interface() {
|
||||
Register(FunctionTable);
|
||||
|
@ -9,95 +9,94 @@ namespace Service {
|
||||
namespace APT {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00010040, GetLockHandle, "GetLockHandle"},
|
||||
{0x00020080, Initialize, "Initialize"},
|
||||
{0x00030040, Enable, "Enable"},
|
||||
{0x00040040, nullptr, "Finalize"},
|
||||
{0x00050040, GetAppletManInfo, "GetAppletManInfo"},
|
||||
{0x00060040, GetAppletInfo, "GetAppletInfo"},
|
||||
{0x00070000, nullptr, "GetLastSignaledAppletId"},
|
||||
{0x00080000, nullptr, "CountRegisteredApplet"},
|
||||
{0x00090040, nullptr, "IsRegistered"},
|
||||
{0x000A0040, nullptr, "GetAttribute"},
|
||||
{0x000B0040, InquireNotification, "InquireNotification"},
|
||||
{0x000C0104, nullptr, "SendParameter"},
|
||||
{0x000D0080, ReceiveParameter, "ReceiveParameter"},
|
||||
{0x000E0080, GlanceParameter, "GlanceParameter"},
|
||||
{0x000F0100, nullptr, "CancelParameter"},
|
||||
{0x001000C2, nullptr, "DebugFunc"},
|
||||
{0x001100C0, nullptr, "MapProgramIdForDebug"},
|
||||
{0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"},
|
||||
{0x00130000, nullptr, "GetPreparationState"},
|
||||
{0x00140040, nullptr, "SetPreparationState"},
|
||||
{0x00010040, GetLockHandle, "GetLockHandle"},
|
||||
{0x00020080, Initialize, "Initialize"},
|
||||
{0x00030040, Enable, "Enable"},
|
||||
{0x00040040, nullptr, "Finalize"},
|
||||
{0x00050040, GetAppletManInfo, "GetAppletManInfo"},
|
||||
{0x00060040, GetAppletInfo, "GetAppletInfo"},
|
||||
{0x00070000, nullptr, "GetLastSignaledAppletId"},
|
||||
{0x00080000, nullptr, "CountRegisteredApplet"},
|
||||
{0x00090040, nullptr, "IsRegistered"},
|
||||
{0x000A0040, nullptr, "GetAttribute"},
|
||||
{0x000B0040, InquireNotification, "InquireNotification"},
|
||||
{0x000C0104, nullptr, "SendParameter"},
|
||||
{0x000D0080, ReceiveParameter, "ReceiveParameter"},
|
||||
{0x000E0080, GlanceParameter, "GlanceParameter"},
|
||||
{0x000F0100, nullptr, "CancelParameter"},
|
||||
{0x001000C2, nullptr, "DebugFunc"},
|
||||
{0x001100C0, nullptr, "MapProgramIdForDebug"},
|
||||
{0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"},
|
||||
{0x00130000, nullptr, "GetPreparationState"},
|
||||
{0x00140040, nullptr, "SetPreparationState"},
|
||||
{0x00150140, PrepareToStartApplication, "PrepareToStartApplication"},
|
||||
{0x00160040, PreloadLibraryApplet, "PreloadLibraryApplet"},
|
||||
{0x00170040, nullptr, "FinishPreloadingLibraryApplet"},
|
||||
{0x00180040, PrepareToStartLibraryApplet,"PrepareToStartLibraryApplet"},
|
||||
{0x00190040, nullptr, "PrepareToStartSystemApplet"},
|
||||
{0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"},
|
||||
{0x001B00C4, nullptr, "StartApplication"},
|
||||
{0x001C0000, nullptr, "WakeupApplication"},
|
||||
{0x001D0000, nullptr, "CancelApplication"},
|
||||
{0x001E0084, nullptr, "StartLibraryApplet"},
|
||||
{0x001F0084, nullptr, "StartSystemApplet"},
|
||||
{0x00200044, nullptr, "StartNewestHomeMenu"},
|
||||
{0x00210000, nullptr, "OrderToCloseApplication"},
|
||||
{0x00220040, nullptr, "PrepareToCloseApplication"},
|
||||
{0x00230040, nullptr, "PrepareToJumpToApplication"},
|
||||
{0x00240044, nullptr, "JumpToApplication"},
|
||||
{0x002500C0, nullptr, "PrepareToCloseLibraryApplet"},
|
||||
{0x00260000, nullptr, "PrepareToCloseSystemApplet"},
|
||||
{0x00270044, nullptr, "CloseApplication"},
|
||||
{0x00280044, nullptr, "CloseLibraryApplet"},
|
||||
{0x00290044, nullptr, "CloseSystemApplet"},
|
||||
{0x002A0000, nullptr, "OrderToCloseSystemApplet"},
|
||||
{0x002B0000, nullptr, "PrepareToJumpToHomeMenu"},
|
||||
{0x002C0044, nullptr, "JumpToHomeMenu"},
|
||||
{0x002D0000, nullptr, "PrepareToLeaveHomeMenu"},
|
||||
{0x002E0044, nullptr, "LeaveHomeMenu"},
|
||||
{0x002F0040, nullptr, "PrepareToLeaveResidentApplet"},
|
||||
{0x00300044, nullptr, "LeaveResidentApplet"},
|
||||
{0x00310100, nullptr, "PrepareToDoApplicationJump"},
|
||||
{0x00320084, nullptr, "DoApplicationJump"},
|
||||
{0x00330000, nullptr, "GetProgramIdOnApplicationJump"},
|
||||
{0x00340084, nullptr, "SendDeliverArg"},
|
||||
{0x00350080, nullptr, "ReceiveDeliverArg"},
|
||||
{0x00360040, nullptr, "LoadSysMenuArg"},
|
||||
{0x00370042, nullptr, "StoreSysMenuArg"},
|
||||
{0x00380040, nullptr, "PreloadResidentApplet"},
|
||||
{0x00390040, nullptr, "PrepareToStartResidentApplet"},
|
||||
{0x003A0044, nullptr, "StartResidentApplet"},
|
||||
{0x003B0040, nullptr, "CancelLibraryApplet"},
|
||||
{0x003C0042, nullptr, "SendDspSleep"},
|
||||
{0x003D0042, nullptr, "SendDspWakeUp"},
|
||||
{0x003E0080, nullptr, "ReplySleepQuery"},
|
||||
{0x003F0040, nullptr, "ReplySleepNotificationComplete"},
|
||||
{0x00400042, nullptr, "SendCaptureBufferInfo"},
|
||||
{0x00410040, nullptr, "ReceiveCaptureBufferInfo"},
|
||||
{0x00420080, nullptr, "SleepSystem"},
|
||||
{0x00430040, NotifyToWait, "NotifyToWait"},
|
||||
{0x00440000, GetSharedFont, "GetSharedFont"},
|
||||
{0x00450040, nullptr, "GetWirelessRebootInfo"},
|
||||
{0x00460104, nullptr, "Wrap"},
|
||||
{0x00470104, nullptr, "Unwrap"},
|
||||
{0x00480100, nullptr, "GetProgramInfo"},
|
||||
{0x00490180, nullptr, "Reboot"},
|
||||
{0x004A0040, nullptr, "GetCaptureInfo"},
|
||||
{0x004B00C2, AppletUtility, "AppletUtility"},
|
||||
{0x004C0000, nullptr, "SetFatalErrDispMode"},
|
||||
{0x004D0080, nullptr, "GetAppletProgramInfo"},
|
||||
{0x004E0000, nullptr, "HardwareResetAsync"},
|
||||
{0x004F0080, SetAppCpuTimeLimit, "SetAppCpuTimeLimit"},
|
||||
{0x00500040, GetAppCpuTimeLimit, "GetAppCpuTimeLimit"},
|
||||
{0x00510080, GetStartupArgument, "GetStartupArgument"},
|
||||
{0x00520104, nullptr, "Wrap1"},
|
||||
{0x00530104, nullptr, "Unwrap1"},
|
||||
{0x00160040, PreloadLibraryApplet, "PreloadLibraryApplet"},
|
||||
{0x00170040, nullptr, "FinishPreloadingLibraryApplet"},
|
||||
{0x00180040, PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"},
|
||||
{0x00190040, nullptr, "PrepareToStartSystemApplet"},
|
||||
{0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"},
|
||||
{0x001B00C4, nullptr, "StartApplication"},
|
||||
{0x001C0000, nullptr, "WakeupApplication"},
|
||||
{0x001D0000, nullptr, "CancelApplication"},
|
||||
{0x001E0084, nullptr, "StartLibraryApplet"},
|
||||
{0x001F0084, nullptr, "StartSystemApplet"},
|
||||
{0x00200044, nullptr, "StartNewestHomeMenu"},
|
||||
{0x00210000, nullptr, "OrderToCloseApplication"},
|
||||
{0x00220040, nullptr, "PrepareToCloseApplication"},
|
||||
{0x00230040, nullptr, "PrepareToJumpToApplication"},
|
||||
{0x00240044, nullptr, "JumpToApplication"},
|
||||
{0x002500C0, nullptr, "PrepareToCloseLibraryApplet"},
|
||||
{0x00260000, nullptr, "PrepareToCloseSystemApplet"},
|
||||
{0x00270044, nullptr, "CloseApplication"},
|
||||
{0x00280044, nullptr, "CloseLibraryApplet"},
|
||||
{0x00290044, nullptr, "CloseSystemApplet"},
|
||||
{0x002A0000, nullptr, "OrderToCloseSystemApplet"},
|
||||
{0x002B0000, nullptr, "PrepareToJumpToHomeMenu"},
|
||||
{0x002C0044, nullptr, "JumpToHomeMenu"},
|
||||
{0x002D0000, nullptr, "PrepareToLeaveHomeMenu"},
|
||||
{0x002E0044, nullptr, "LeaveHomeMenu"},
|
||||
{0x002F0040, nullptr, "PrepareToLeaveResidentApplet"},
|
||||
{0x00300044, nullptr, "LeaveResidentApplet"},
|
||||
{0x00310100, nullptr, "PrepareToDoApplicationJump"},
|
||||
{0x00320084, nullptr, "DoApplicationJump"},
|
||||
{0x00330000, nullptr, "GetProgramIdOnApplicationJump"},
|
||||
{0x00340084, nullptr, "SendDeliverArg"},
|
||||
{0x00350080, nullptr, "ReceiveDeliverArg"},
|
||||
{0x00360040, nullptr, "LoadSysMenuArg"},
|
||||
{0x00370042, nullptr, "StoreSysMenuArg"},
|
||||
{0x00380040, nullptr, "PreloadResidentApplet"},
|
||||
{0x00390040, nullptr, "PrepareToStartResidentApplet"},
|
||||
{0x003A0044, nullptr, "StartResidentApplet"},
|
||||
{0x003B0040, nullptr, "CancelLibraryApplet"},
|
||||
{0x003C0042, nullptr, "SendDspSleep"},
|
||||
{0x003D0042, nullptr, "SendDspWakeUp"},
|
||||
{0x003E0080, nullptr, "ReplySleepQuery"},
|
||||
{0x003F0040, nullptr, "ReplySleepNotificationComplete"},
|
||||
{0x00400042, nullptr, "SendCaptureBufferInfo"},
|
||||
{0x00410040, nullptr, "ReceiveCaptureBufferInfo"},
|
||||
{0x00420080, nullptr, "SleepSystem"},
|
||||
{0x00430040, NotifyToWait, "NotifyToWait"},
|
||||
{0x00440000, GetSharedFont, "GetSharedFont"},
|
||||
{0x00450040, nullptr, "GetWirelessRebootInfo"},
|
||||
{0x00460104, nullptr, "Wrap"},
|
||||
{0x00470104, nullptr, "Unwrap"},
|
||||
{0x00480100, nullptr, "GetProgramInfo"},
|
||||
{0x00490180, nullptr, "Reboot"},
|
||||
{0x004A0040, nullptr, "GetCaptureInfo"},
|
||||
{0x004B00C2, AppletUtility, "AppletUtility"},
|
||||
{0x004C0000, nullptr, "SetFatalErrDispMode"},
|
||||
{0x004D0080, nullptr, "GetAppletProgramInfo"},
|
||||
{0x004E0000, nullptr, "HardwareResetAsync"},
|
||||
{0x004F0080, SetAppCpuTimeLimit, "SetAppCpuTimeLimit"},
|
||||
{0x00500040, GetAppCpuTimeLimit, "GetAppCpuTimeLimit"},
|
||||
{0x00510080, GetStartupArgument, "GetStartupArgument"},
|
||||
{0x00520104, nullptr, "Wrap1"},
|
||||
{0x00530104, nullptr, "Unwrap1"},
|
||||
{0x00550040, SetScreenCapPostPermission, "SetScreenCapPostPermission"},
|
||||
{0x00560000, GetScreenCapPostPermission, "GetScreenCapPostPermission"},
|
||||
{0x00580002, nullptr, "GetProgramID"},
|
||||
{0x01010000, CheckNew3DSApp, "CheckNew3DSApp"},
|
||||
{0x01020000, CheckNew3DS, "CheckNew3DS"}
|
||||
};
|
||||
{0x00580002, nullptr, "GetProgramID"},
|
||||
{0x01010000, CheckNew3DSApp, "CheckNew3DSApp"},
|
||||
{0x01020000, CheckNew3DS, "CheckNew3DS"}};
|
||||
|
||||
APT_S_Interface::APT_S_Interface() {
|
||||
Register(FunctionTable);
|
||||
|
@ -9,95 +9,94 @@ namespace Service {
|
||||
namespace APT {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00010040, GetLockHandle, "GetLockHandle"},
|
||||
{0x00020080, Initialize, "Initialize"},
|
||||
{0x00030040, Enable, "Enable"},
|
||||
{0x00040040, nullptr, "Finalize"},
|
||||
{0x00050040, GetAppletManInfo, "GetAppletManInfo"},
|
||||
{0x00060040, GetAppletInfo, "GetAppletInfo"},
|
||||
{0x00070000, nullptr, "GetLastSignaledAppletId"},
|
||||
{0x00080000, nullptr, "CountRegisteredApplet"},
|
||||
{0x00090040, IsRegistered, "IsRegistered"},
|
||||
{0x000A0040, nullptr, "GetAttribute"},
|
||||
{0x000B0040, InquireNotification, "InquireNotification"},
|
||||
{0x000C0104, SendParameter, "SendParameter"},
|
||||
{0x000D0080, ReceiveParameter, "ReceiveParameter"},
|
||||
{0x000E0080, GlanceParameter, "GlanceParameter"},
|
||||
{0x000F0100, CancelParameter, "CancelParameter"},
|
||||
{0x001000C2, nullptr, "DebugFunc"},
|
||||
{0x001100C0, nullptr, "MapProgramIdForDebug"},
|
||||
{0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"},
|
||||
{0x00130000, nullptr, "GetPreparationState"},
|
||||
{0x00140040, nullptr, "SetPreparationState"},
|
||||
{0x00150140, PrepareToStartApplication, "PrepareToStartApplication"},
|
||||
{0x00160040, PreloadLibraryApplet, "PreloadLibraryApplet"},
|
||||
{0x00170040, nullptr, "FinishPreloadingLibraryApplet"},
|
||||
{0x00180040, PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"},
|
||||
{0x00190040, nullptr, "PrepareToStartSystemApplet"},
|
||||
{0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"},
|
||||
{0x001B00C4, nullptr, "StartApplication"},
|
||||
{0x001C0000, nullptr, "WakeupApplication"},
|
||||
{0x001D0000, nullptr, "CancelApplication"},
|
||||
{0x001E0084, StartLibraryApplet, "StartLibraryApplet"},
|
||||
{0x001F0084, nullptr, "StartSystemApplet"},
|
||||
{0x00200044, nullptr, "StartNewestHomeMenu"},
|
||||
{0x00210000, nullptr, "OrderToCloseApplication"},
|
||||
{0x00220040, nullptr, "PrepareToCloseApplication"},
|
||||
{0x00230040, nullptr, "PrepareToJumpToApplication"},
|
||||
{0x00240044, nullptr, "JumpToApplication"},
|
||||
{0x002500C0, nullptr, "PrepareToCloseLibraryApplet"},
|
||||
{0x00260000, nullptr, "PrepareToCloseSystemApplet"},
|
||||
{0x00270044, nullptr, "CloseApplication"},
|
||||
{0x00280044, nullptr, "CloseLibraryApplet"},
|
||||
{0x00290044, nullptr, "CloseSystemApplet"},
|
||||
{0x002A0000, nullptr, "OrderToCloseSystemApplet"},
|
||||
{0x002B0000, nullptr, "PrepareToJumpToHomeMenu"},
|
||||
{0x002C0044, nullptr, "JumpToHomeMenu"},
|
||||
{0x002D0000, nullptr, "PrepareToLeaveHomeMenu"},
|
||||
{0x002E0044, nullptr, "LeaveHomeMenu"},
|
||||
{0x002F0040, nullptr, "PrepareToLeaveResidentApplet"},
|
||||
{0x00300044, nullptr, "LeaveResidentApplet"},
|
||||
{0x00310100, nullptr, "PrepareToDoApplicationJump"},
|
||||
{0x00320084, nullptr, "DoApplicationJump"},
|
||||
{0x00330000, nullptr, "GetProgramIdOnApplicationJump"},
|
||||
{0x00340084, nullptr, "SendDeliverArg"},
|
||||
{0x00350080, nullptr, "ReceiveDeliverArg"},
|
||||
{0x00360040, nullptr, "LoadSysMenuArg"},
|
||||
{0x00370042, nullptr, "StoreSysMenuArg"},
|
||||
{0x00380040, nullptr, "PreloadResidentApplet"},
|
||||
{0x00390040, nullptr, "PrepareToStartResidentApplet"},
|
||||
{0x003A0044, nullptr, "StartResidentApplet"},
|
||||
{0x003B0040, nullptr, "CancelLibraryApplet"},
|
||||
{0x003C0042, nullptr, "SendDspSleep"},
|
||||
{0x003D0042, nullptr, "SendDspWakeUp"},
|
||||
{0x003E0080, nullptr, "ReplySleepQuery"},
|
||||
{0x003F0040, nullptr, "ReplySleepNotificationComplete"},
|
||||
{0x00400042, nullptr, "SendCaptureBufferInfo"},
|
||||
{0x00410040, nullptr, "ReceiveCaptureBufferInfo"},
|
||||
{0x00420080, nullptr, "SleepSystem"},
|
||||
{0x00430040, NotifyToWait, "NotifyToWait"},
|
||||
{0x00440000, GetSharedFont, "GetSharedFont"},
|
||||
{0x00450040, nullptr, "GetWirelessRebootInfo"},
|
||||
{0x00460104, nullptr, "Wrap"},
|
||||
{0x00470104, nullptr, "Unwrap"},
|
||||
{0x00480100, nullptr, "GetProgramInfo"},
|
||||
{0x00490180, nullptr, "Reboot"},
|
||||
{0x004A0040, nullptr, "GetCaptureInfo"},
|
||||
{0x004B00C2, AppletUtility, "AppletUtility"},
|
||||
{0x004C0000, nullptr, "SetFatalErrDispMode"},
|
||||
{0x004D0080, nullptr, "GetAppletProgramInfo"},
|
||||
{0x004E0000, nullptr, "HardwareResetAsync"},
|
||||
{0x004F0080, SetAppCpuTimeLimit, "SetAppCpuTimeLimit"},
|
||||
{0x00500040, GetAppCpuTimeLimit, "GetAppCpuTimeLimit"},
|
||||
{0x00510080, GetStartupArgument, "GetStartupArgument"},
|
||||
{0x00520104, nullptr, "Wrap1"},
|
||||
{0x00530104, nullptr, "Unwrap1"},
|
||||
{0x00550040, SetScreenCapPostPermission, "SetScreenCapPostPermission"},
|
||||
{0x00560000, GetScreenCapPostPermission, "GetScreenCapPostPermission"},
|
||||
{0x00580002, nullptr, "GetProgramID"},
|
||||
{0x01010000, CheckNew3DSApp, "CheckNew3DSApp"},
|
||||
{0x01020000, CheckNew3DS, "CheckNew3DS"}
|
||||
};
|
||||
{0x00010040, GetLockHandle, "GetLockHandle"},
|
||||
{0x00020080, Initialize, "Initialize"},
|
||||
{0x00030040, Enable, "Enable"},
|
||||
{0x00040040, nullptr, "Finalize"},
|
||||
{0x00050040, GetAppletManInfo, "GetAppletManInfo"},
|
||||
{0x00060040, GetAppletInfo, "GetAppletInfo"},
|
||||
{0x00070000, nullptr, "GetLastSignaledAppletId"},
|
||||
{0x00080000, nullptr, "CountRegisteredApplet"},
|
||||
{0x00090040, IsRegistered, "IsRegistered"},
|
||||
{0x000A0040, nullptr, "GetAttribute"},
|
||||
{0x000B0040, InquireNotification, "InquireNotification"},
|
||||
{0x000C0104, SendParameter, "SendParameter"},
|
||||
{0x000D0080, ReceiveParameter, "ReceiveParameter"},
|
||||
{0x000E0080, GlanceParameter, "GlanceParameter"},
|
||||
{0x000F0100, CancelParameter, "CancelParameter"},
|
||||
{0x001000C2, nullptr, "DebugFunc"},
|
||||
{0x001100C0, nullptr, "MapProgramIdForDebug"},
|
||||
{0x00120040, nullptr, "SetHomeMenuAppletIdForDebug"},
|
||||
{0x00130000, nullptr, "GetPreparationState"},
|
||||
{0x00140040, nullptr, "SetPreparationState"},
|
||||
{0x00150140, PrepareToStartApplication, "PrepareToStartApplication"},
|
||||
{0x00160040, PreloadLibraryApplet, "PreloadLibraryApplet"},
|
||||
{0x00170040, nullptr, "FinishPreloadingLibraryApplet"},
|
||||
{0x00180040, PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"},
|
||||
{0x00190040, nullptr, "PrepareToStartSystemApplet"},
|
||||
{0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"},
|
||||
{0x001B00C4, nullptr, "StartApplication"},
|
||||
{0x001C0000, nullptr, "WakeupApplication"},
|
||||
{0x001D0000, nullptr, "CancelApplication"},
|
||||
{0x001E0084, StartLibraryApplet, "StartLibraryApplet"},
|
||||
{0x001F0084, nullptr, "StartSystemApplet"},
|
||||
{0x00200044, nullptr, "StartNewestHomeMenu"},
|
||||
{0x00210000, nullptr, "OrderToCloseApplication"},
|
||||
{0x00220040, nullptr, "PrepareToCloseApplication"},
|
||||
{0x00230040, nullptr, "PrepareToJumpToApplication"},
|
||||
{0x00240044, nullptr, "JumpToApplication"},
|
||||
{0x002500C0, nullptr, "PrepareToCloseLibraryApplet"},
|
||||
{0x00260000, nullptr, "PrepareToCloseSystemApplet"},
|
||||
{0x00270044, nullptr, "CloseApplication"},
|
||||
{0x00280044, nullptr, "CloseLibraryApplet"},
|
||||
{0x00290044, nullptr, "CloseSystemApplet"},
|
||||
{0x002A0000, nullptr, "OrderToCloseSystemApplet"},
|
||||
{0x002B0000, nullptr, "PrepareToJumpToHomeMenu"},
|
||||
{0x002C0044, nullptr, "JumpToHomeMenu"},
|
||||
{0x002D0000, nullptr, "PrepareToLeaveHomeMenu"},
|
||||
{0x002E0044, nullptr, "LeaveHomeMenu"},
|
||||
{0x002F0040, nullptr, "PrepareToLeaveResidentApplet"},
|
||||
{0x00300044, nullptr, "LeaveResidentApplet"},
|
||||
{0x00310100, nullptr, "PrepareToDoApplicationJump"},
|
||||
{0x00320084, nullptr, "DoApplicationJump"},
|
||||
{0x00330000, nullptr, "GetProgramIdOnApplicationJump"},
|
||||
{0x00340084, nullptr, "SendDeliverArg"},
|
||||
{0x00350080, nullptr, "ReceiveDeliverArg"},
|
||||
{0x00360040, nullptr, "LoadSysMenuArg"},
|
||||
{0x00370042, nullptr, "StoreSysMenuArg"},
|
||||
{0x00380040, nullptr, "PreloadResidentApplet"},
|
||||
{0x00390040, nullptr, "PrepareToStartResidentApplet"},
|
||||
{0x003A0044, nullptr, "StartResidentApplet"},
|
||||
{0x003B0040, nullptr, "CancelLibraryApplet"},
|
||||
{0x003C0042, nullptr, "SendDspSleep"},
|
||||
{0x003D0042, nullptr, "SendDspWakeUp"},
|
||||
{0x003E0080, nullptr, "ReplySleepQuery"},
|
||||
{0x003F0040, nullptr, "ReplySleepNotificationComplete"},
|
||||
{0x00400042, nullptr, "SendCaptureBufferInfo"},
|
||||
{0x00410040, nullptr, "ReceiveCaptureBufferInfo"},
|
||||
{0x00420080, nullptr, "SleepSystem"},
|
||||
{0x00430040, NotifyToWait, "NotifyToWait"},
|
||||
{0x00440000, GetSharedFont, "GetSharedFont"},
|
||||
{0x00450040, nullptr, "GetWirelessRebootInfo"},
|
||||
{0x00460104, nullptr, "Wrap"},
|
||||
{0x00470104, nullptr, "Unwrap"},
|
||||
{0x00480100, nullptr, "GetProgramInfo"},
|
||||
{0x00490180, nullptr, "Reboot"},
|
||||
{0x004A0040, nullptr, "GetCaptureInfo"},
|
||||
{0x004B00C2, AppletUtility, "AppletUtility"},
|
||||
{0x004C0000, nullptr, "SetFatalErrDispMode"},
|
||||
{0x004D0080, nullptr, "GetAppletProgramInfo"},
|
||||
{0x004E0000, nullptr, "HardwareResetAsync"},
|
||||
{0x004F0080, SetAppCpuTimeLimit, "SetAppCpuTimeLimit"},
|
||||
{0x00500040, GetAppCpuTimeLimit, "GetAppCpuTimeLimit"},
|
||||
{0x00510080, GetStartupArgument, "GetStartupArgument"},
|
||||
{0x00520104, nullptr, "Wrap1"},
|
||||
{0x00530104, nullptr, "Unwrap1"},
|
||||
{0x00550040, SetScreenCapPostPermission, "SetScreenCapPostPermission"},
|
||||
{0x00560000, GetScreenCapPostPermission, "GetScreenCapPostPermission"},
|
||||
{0x00580002, nullptr, "GetProgramID"},
|
||||
{0x01010000, CheckNew3DSApp, "CheckNew3DSApp"},
|
||||
{0x01020000, CheckNew3DS, "CheckNew3DS"}};
|
||||
|
||||
APT_U_Interface::APT_U_Interface() {
|
||||
Register(FunctionTable);
|
||||
|
@ -2,10 +2,10 @@
|
||||
// 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/service/service.h"
|
||||
|
||||
namespace Service {
|
||||
namespace BOSS {
|
||||
|
@ -11,7 +11,7 @@ namespace BOSS {
|
||||
// const Interface::FunctionInfo FunctionTable[] = { };
|
||||
|
||||
BOSS_P_Interface::BOSS_P_Interface() {
|
||||
//Register(FunctionTable);
|
||||
// Register(FunctionTable);
|
||||
}
|
||||
|
||||
} // namespace BOSS
|
||||
|
@ -8,10 +8,10 @@ namespace Service {
|
||||
namespace BOSS {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00020100, nullptr, "GetStorageInfo"},
|
||||
{0x000C0082, nullptr, "UnregisterTask"},
|
||||
{0x001E0042, nullptr, "CancelTask"},
|
||||
{0x00330042, nullptr, "StartBgImmediate"},
|
||||
{0x00020100, nullptr, "GetStorageInfo"},
|
||||
{0x000C0082, nullptr, "UnregisterTask"},
|
||||
{0x001E0042, nullptr, "CancelTask"},
|
||||
{0x00330042, nullptr, "StartBgImmediate"},
|
||||
};
|
||||
|
||||
BOSS_U_Interface::BOSS_U_Interface() {
|
||||
|
@ -71,15 +71,15 @@ void GetBufferErrorInterruptEvent(Service::Interface* self) {
|
||||
}
|
||||
|
||||
void SetReceiving(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
|
||||
VAddr dest = cmd_buff[1];
|
||||
u8 port = cmd_buff[2] & 0xFF;
|
||||
VAddr dest = cmd_buff[1];
|
||||
u8 port = cmd_buff[2] & 0xFF;
|
||||
u32 image_size = cmd_buff[3];
|
||||
u16 trans_unit = cmd_buff[4] & 0xFFFF;
|
||||
|
||||
Kernel::Event* completion_event = (Port)port == Port::Cam2 ?
|
||||
completion_event_cam2.get() : completion_event_cam1.get();
|
||||
Kernel::Event* completion_event =
|
||||
(Port)port == Port::Cam2 ? completion_event_cam2.get() : completion_event_cam1.get();
|
||||
|
||||
completion_event->Signal();
|
||||
|
||||
@ -89,36 +89,36 @@ void SetReceiving(Service::Interface* self) {
|
||||
cmd_buff[3] = Kernel::g_handle_table.Create(completion_event).MoveFrom();
|
||||
|
||||
LOG_WARNING(Service_CAM, "(STUBBED) called, addr=0x%X, port=%d, image_size=%d, trans_unit=%d",
|
||||
dest, port, image_size, trans_unit);
|
||||
dest, port, image_size, trans_unit);
|
||||
}
|
||||
|
||||
void SetTransferLines(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
|
||||
u8 port = cmd_buff[1] & 0xFF;
|
||||
u8 port = cmd_buff[1] & 0xFF;
|
||||
u16 transfer_lines = cmd_buff[2] & 0xFFFF;
|
||||
u16 width = cmd_buff[3] & 0xFFFF;
|
||||
u16 height = cmd_buff[4] & 0xFFFF;
|
||||
u16 width = cmd_buff[3] & 0xFFFF;
|
||||
u16 height = cmd_buff[4] & 0xFFFF;
|
||||
|
||||
cmd_buff[0] = IPC::MakeHeader(0x9, 1, 0);
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
|
||||
LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d, lines=%d, width=%d, height=%d",
|
||||
port, transfer_lines, width, height);
|
||||
LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d, lines=%d, width=%d, height=%d", port,
|
||||
transfer_lines, width, height);
|
||||
}
|
||||
|
||||
void GetMaxLines(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
|
||||
u16 width = cmd_buff[1] & 0xFFFF;
|
||||
u16 width = cmd_buff[1] & 0xFFFF;
|
||||
u16 height = cmd_buff[2] & 0xFFFF;
|
||||
|
||||
cmd_buff[0] = IPC::MakeHeader(0xA, 2, 0);
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
cmd_buff[2] = TRANSFER_BYTES / (2 * width);
|
||||
|
||||
LOG_WARNING(Service_CAM, "(STUBBED) called, width=%d, height=%d, lines = %d",
|
||||
width, height, cmd_buff[2]);
|
||||
LOG_WARNING(Service_CAM, "(STUBBED) called, width=%d, height=%d, lines = %d", width, height,
|
||||
cmd_buff[2]);
|
||||
}
|
||||
|
||||
void GetTransferBytes(Service::Interface* self) {
|
||||
@ -136,7 +136,7 @@ void GetTransferBytes(Service::Interface* self) {
|
||||
void SetTrimming(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
|
||||
u8 port = cmd_buff[1] & 0xFF;
|
||||
u8 port = cmd_buff[1] & 0xFF;
|
||||
bool trim = (cmd_buff[2] & 0xFF) != 0;
|
||||
|
||||
cmd_buff[0] = IPC::MakeHeader(0xE, 1, 0);
|
||||
@ -148,17 +148,17 @@ void SetTrimming(Service::Interface* self) {
|
||||
void SetTrimmingParamsCenter(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
|
||||
u8 port = cmd_buff[1] & 0xFF;
|
||||
u8 port = cmd_buff[1] & 0xFF;
|
||||
s16 trimW = cmd_buff[2] & 0xFFFF;
|
||||
s16 trimH = cmd_buff[3] & 0xFFFF;
|
||||
s16 camW = cmd_buff[4] & 0xFFFF;
|
||||
s16 camH = cmd_buff[5] & 0xFFFF;
|
||||
s16 camW = cmd_buff[4] & 0xFFFF;
|
||||
s16 camH = cmd_buff[5] & 0xFFFF;
|
||||
|
||||
cmd_buff[0] = IPC::MakeHeader(0x12, 1, 0);
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
|
||||
LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d, trimW=%d, trimH=%d, camW=%d, camH=%d",
|
||||
port, trimW, trimH, camW, camH);
|
||||
port, trimW, trimH, camW, camH);
|
||||
}
|
||||
|
||||
void Activate(Service::Interface* self) {
|
||||
@ -169,36 +169,35 @@ void Activate(Service::Interface* self) {
|
||||
cmd_buff[0] = IPC::MakeHeader(0x13, 1, 0);
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
|
||||
LOG_WARNING(Service_CAM, "(STUBBED) called, cam_select=%d",
|
||||
cam_select);
|
||||
LOG_WARNING(Service_CAM, "(STUBBED) called, cam_select=%d", cam_select);
|
||||
}
|
||||
|
||||
void FlipImage(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
|
||||
u8 cam_select = cmd_buff[1] & 0xFF;
|
||||
u8 flip = cmd_buff[2] & 0xFF;
|
||||
u8 context = cmd_buff[3] & 0xFF;
|
||||
u8 flip = cmd_buff[2] & 0xFF;
|
||||
u8 context = cmd_buff[3] & 0xFF;
|
||||
|
||||
cmd_buff[0] = IPC::MakeHeader(0x1D, 1, 0);
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
|
||||
LOG_WARNING(Service_CAM, "(STUBBED) called, cam_select=%d, flip=%d, context=%d",
|
||||
cam_select, flip, context);
|
||||
LOG_WARNING(Service_CAM, "(STUBBED) called, cam_select=%d, flip=%d, context=%d", cam_select,
|
||||
flip, context);
|
||||
}
|
||||
|
||||
void SetSize(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
|
||||
u8 cam_select = cmd_buff[1] & 0xFF;
|
||||
u8 size = cmd_buff[2] & 0xFF;
|
||||
u8 context = cmd_buff[3] & 0xFF;
|
||||
u8 size = cmd_buff[2] & 0xFF;
|
||||
u8 context = cmd_buff[3] & 0xFF;
|
||||
|
||||
cmd_buff[0] = IPC::MakeHeader(0x1F, 1, 0);
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
|
||||
LOG_WARNING(Service_CAM, "(STUBBED) called, cam_select=%d, size=%d, context=%d",
|
||||
cam_select, size, context);
|
||||
LOG_WARNING(Service_CAM, "(STUBBED) called, cam_select=%d, size=%d, context=%d", cam_select,
|
||||
size, context);
|
||||
}
|
||||
|
||||
void SetFrameRate(Service::Interface* self) {
|
||||
@ -210,8 +209,8 @@ void SetFrameRate(Service::Interface* self) {
|
||||
cmd_buff[0] = IPC::MakeHeader(0x20, 1, 0);
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
|
||||
LOG_WARNING(Service_CAM, "(STUBBED) called, cam_select=%d, frame_rate=%d",
|
||||
cam_select, frame_rate);
|
||||
LOG_WARNING(Service_CAM, "(STUBBED) called, cam_select=%d, frame_rate=%d", cam_select,
|
||||
frame_rate);
|
||||
}
|
||||
|
||||
void GetStereoCameraCalibrationData(Service::Interface* self) {
|
||||
@ -293,10 +292,14 @@ void Init() {
|
||||
AddService(new CAM_S_Interface);
|
||||
AddService(new CAM_U_Interface);
|
||||
|
||||
completion_event_cam1 = Kernel::Event::Create(ResetType::OneShot, "CAM_U::completion_event_cam1");
|
||||
completion_event_cam2 = Kernel::Event::Create(ResetType::OneShot, "CAM_U::completion_event_cam2");
|
||||
interrupt_error_event = Kernel::Event::Create(ResetType::OneShot, "CAM_U::interrupt_error_event");
|
||||
vsync_interrupt_error_event = Kernel::Event::Create(ResetType::OneShot, "CAM_U::vsync_interrupt_error_event");
|
||||
completion_event_cam1 =
|
||||
Kernel::Event::Create(ResetType::OneShot, "CAM_U::completion_event_cam1");
|
||||
completion_event_cam2 =
|
||||
Kernel::Event::Create(ResetType::OneShot, "CAM_U::completion_event_cam2");
|
||||
interrupt_error_event =
|
||||
Kernel::Event::Create(ResetType::OneShot, "CAM_U::interrupt_error_event");
|
||||
vsync_interrupt_error_event =
|
||||
Kernel::Event::Create(ResetType::OneShot, "CAM_U::vsync_interrupt_error_event");
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
|
@ -14,12 +14,7 @@
|
||||
namespace Service {
|
||||
namespace CAM {
|
||||
|
||||
enum class Port : u8 {
|
||||
None = 0,
|
||||
Cam1 = 1,
|
||||
Cam2 = 2,
|
||||
Both = Cam1 | Cam2
|
||||
};
|
||||
enum class Port : u8 { None = 0, Cam1 = 1, Cam2 = 2, Both = Cam1 | Cam2 };
|
||||
|
||||
enum class CameraSelect : u8 {
|
||||
None = 0,
|
||||
@ -32,28 +27,11 @@ enum class CameraSelect : u8 {
|
||||
All = Out1 | In1 | Out2
|
||||
};
|
||||
|
||||
enum class Effect : u8 {
|
||||
None = 0,
|
||||
Mono = 1,
|
||||
Sepia = 2,
|
||||
Negative = 3,
|
||||
Negafilm = 4,
|
||||
Sepia01 = 5
|
||||
};
|
||||
enum class Effect : u8 { None = 0, Mono = 1, Sepia = 2, Negative = 3, Negafilm = 4, Sepia01 = 5 };
|
||||
|
||||
enum class Context : u8 {
|
||||
None = 0,
|
||||
A = 1,
|
||||
B = 2,
|
||||
Both = A | B
|
||||
};
|
||||
enum class Context : u8 { None = 0, A = 1, B = 2, Both = A | B };
|
||||
|
||||
enum class Flip : u8 {
|
||||
None = 0,
|
||||
Horizontal = 1,
|
||||
Vertical = 2,
|
||||
Reverse = 3
|
||||
};
|
||||
enum class Flip : u8 { None = 0, Horizontal = 1, Vertical = 2, Reverse = 3 };
|
||||
|
||||
enum class Size : u8 {
|
||||
VGA = 0,
|
||||
@ -83,11 +61,7 @@ enum class FrameRate : u8 {
|
||||
Rate_30_To_10 = 12
|
||||
};
|
||||
|
||||
enum class ShutterSoundType : u8 {
|
||||
Normal = 0,
|
||||
Movie = 1,
|
||||
MovieEnd = 2
|
||||
};
|
||||
enum class ShutterSoundType : u8 { Normal = 0, Movie = 1, MovieEnd = 2 };
|
||||
|
||||
enum class WhiteBalance : u8 {
|
||||
BalanceAuto = 0,
|
||||
@ -106,13 +80,7 @@ enum class WhiteBalance : u8 {
|
||||
BalanceShade = Balance7000K
|
||||
};
|
||||
|
||||
enum class PhotoMode : u8 {
|
||||
Normal = 0,
|
||||
Portrait = 1,
|
||||
Landscape = 2,
|
||||
Nightview = 3,
|
||||
Letter0 = 4
|
||||
};
|
||||
enum class PhotoMode : u8 { Normal = 0, Portrait = 1, Landscape = 2, Nightview = 3, Letter0 = 4 };
|
||||
|
||||
enum class LensCorrection : u8 {
|
||||
Off = 0,
|
||||
@ -140,21 +108,18 @@ enum class Contrast : u8 {
|
||||
High = Pattern07
|
||||
};
|
||||
|
||||
enum class OutputFormat : u8 {
|
||||
YUV422 = 0,
|
||||
RGB565 = 1
|
||||
};
|
||||
enum class OutputFormat : u8 { YUV422 = 0, RGB565 = 1 };
|
||||
|
||||
/// Stereo camera calibration data.
|
||||
struct StereoCameraCalibrationData {
|
||||
u8 isValidRotationXY; ///< Bool indicating whether the X and Y rotation data is valid.
|
||||
u8 isValidRotationXY; ///< Bool indicating whether the X and Y rotation data is valid.
|
||||
INSERT_PADDING_BYTES(3);
|
||||
float_le scale; ///< Scale to match the left camera image with the right.
|
||||
float_le rotationZ; ///< Z axis rotation to match the left camera image with the right.
|
||||
float_le translationX; ///< X axis translation to match the left camera image with the right.
|
||||
float_le translationY; ///< Y axis translation to match the left camera image with the right.
|
||||
float_le rotationX; ///< X axis rotation to match the left camera image with the right.
|
||||
float_le rotationY; ///< Y axis rotation to match the left camera image with the right.
|
||||
float_le scale; ///< Scale to match the left camera image with the right.
|
||||
float_le rotationZ; ///< Z axis rotation to match the left camera image with the right.
|
||||
float_le translationX; ///< X axis translation to match the left camera image with the right.
|
||||
float_le translationY; ///< Y axis translation to match the left camera image with the right.
|
||||
float_le rotationX; ///< X axis rotation to match the left camera image with the right.
|
||||
float_le rotationY; ///< Y axis rotation to match the left camera image with the right.
|
||||
float_le angleOfViewRight; ///< Right camera angle of view.
|
||||
float_le angleOfViewLeft; ///< Left camera angle of view.
|
||||
float_le distanceToChart; ///< Distance between cameras and measurement chart.
|
||||
@ -163,7 +128,8 @@ struct StereoCameraCalibrationData {
|
||||
s16_le imageHeight; ///< Image height.
|
||||
INSERT_PADDING_BYTES(16);
|
||||
};
|
||||
static_assert(sizeof(StereoCameraCalibrationData) == 64, "StereoCameraCalibrationData structure size is wrong");
|
||||
static_assert(sizeof(StereoCameraCalibrationData) == 64,
|
||||
"StereoCameraCalibrationData structure size is wrong");
|
||||
|
||||
struct PackageParameterCameraSelect {
|
||||
CameraSelect camera;
|
||||
@ -188,7 +154,8 @@ struct PackageParameterCameraSelect {
|
||||
s16 auto_white_balance_window_height;
|
||||
};
|
||||
|
||||
static_assert(sizeof(PackageParameterCameraSelect) == 28, "PackageParameterCameraSelect structure size is wrong");
|
||||
static_assert(sizeof(PackageParameterCameraSelect) == 28,
|
||||
"PackageParameterCameraSelect structure size is wrong");
|
||||
|
||||
/**
|
||||
* Unknown
|
||||
|
@ -8,10 +8,10 @@ namespace Service {
|
||||
namespace CAM {
|
||||
|
||||
// Empty arrays are illegal -- commented out until an entry is added.
|
||||
//const Interface::FunctionInfo FunctionTable[] = { };
|
||||
// const Interface::FunctionInfo FunctionTable[] = { };
|
||||
|
||||
CAM_C_Interface::CAM_C_Interface() {
|
||||
//Register(FunctionTable);
|
||||
// Register(FunctionTable);
|
||||
}
|
||||
|
||||
} // namespace CAM
|
||||
|
@ -8,10 +8,10 @@ namespace Service {
|
||||
namespace CAM {
|
||||
|
||||
// Empty arrays are illegal -- commented out until an entry is added.
|
||||
//const Interface::FunctionInfo FunctionTable[] = { };
|
||||
// const Interface::FunctionInfo FunctionTable[] = { };
|
||||
|
||||
CAM_Q_Interface::CAM_Q_Interface() {
|
||||
//Register(FunctionTable);
|
||||
// Register(FunctionTable);
|
||||
}
|
||||
|
||||
} // namespace CAM
|
||||
|
@ -8,10 +8,10 @@ namespace Service {
|
||||
namespace CAM {
|
||||
|
||||
// Empty arrays are illegal -- commented out until an entry is added.
|
||||
//const Interface::FunctionInfo FunctionTable[] = { };
|
||||
// const Interface::FunctionInfo FunctionTable[] = { };
|
||||
|
||||
CAM_S_Interface::CAM_S_Interface() {
|
||||
//Register(FunctionTable);
|
||||
// Register(FunctionTable);
|
||||
}
|
||||
|
||||
} // namespace CAM
|
||||
|
@ -9,68 +9,68 @@ namespace Service {
|
||||
namespace CAM {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00010040, StartCapture, "StartCapture"},
|
||||
{0x00020040, StopCapture, "StopCapture"},
|
||||
{0x00030040, nullptr, "IsBusy"},
|
||||
{0x00040040, nullptr, "ClearBuffer"},
|
||||
{0x00050040, GetVsyncInterruptEvent, "GetVsyncInterruptEvent"},
|
||||
{0x00060040, GetBufferErrorInterruptEvent, "GetBufferErrorInterruptEvent"},
|
||||
{0x00070102, SetReceiving, "SetReceiving"},
|
||||
{0x00080040, nullptr, "IsFinishedReceiving"},
|
||||
{0x00090100, SetTransferLines, "SetTransferLines"},
|
||||
{0x000A0080, GetMaxLines, "GetMaxLines"},
|
||||
{0x000B0100, nullptr, "SetTransferBytes"},
|
||||
{0x000C0040, GetTransferBytes, "GetTransferBytes"},
|
||||
{0x000D0080, nullptr, "GetMaxBytes"},
|
||||
{0x000E0080, SetTrimming, "SetTrimming"},
|
||||
{0x000F0040, nullptr, "IsTrimming"},
|
||||
{0x00100140, nullptr, "SetTrimmingParams"},
|
||||
{0x00110040, nullptr, "GetTrimmingParams"},
|
||||
{0x00120140, SetTrimmingParamsCenter, "SetTrimmingParamsCenter"},
|
||||
{0x00130040, Activate, "Activate"},
|
||||
{0x00140080, nullptr, "SwitchContext"},
|
||||
{0x00150080, nullptr, "SetExposure"},
|
||||
{0x00160080, nullptr, "SetWhiteBalance"},
|
||||
{0x00170080, nullptr, "SetWhiteBalanceWithoutBaseUp"},
|
||||
{0x00180080, nullptr, "SetSharpness"},
|
||||
{0x00190080, nullptr, "SetAutoExposure"},
|
||||
{0x001A0040, nullptr, "IsAutoExposure"},
|
||||
{0x001B0080, nullptr, "SetAutoWhiteBalance"},
|
||||
{0x001C0040, nullptr, "IsAutoWhiteBalance"},
|
||||
{0x001D00C0, FlipImage, "FlipImage"},
|
||||
{0x001E0200, nullptr, "SetDetailSize"},
|
||||
{0x001F00C0, SetSize, "SetSize"},
|
||||
{0x00200080, SetFrameRate, "SetFrameRate"},
|
||||
{0x00210080, nullptr, "SetPhotoMode"},
|
||||
{0x002200C0, nullptr, "SetEffect"},
|
||||
{0x00230080, nullptr, "SetContrast"},
|
||||
{0x00240080, nullptr, "SetLensCorrection"},
|
||||
{0x002500C0, nullptr, "SetOutputFormat"},
|
||||
{0x00260140, nullptr, "SetAutoExposureWindow"},
|
||||
{0x00270140, nullptr, "SetAutoWhiteBalanceWindow"},
|
||||
{0x00280080, nullptr, "SetNoiseFilter"},
|
||||
{0x00290080, nullptr, "SynchronizeVsyncTiming"},
|
||||
{0x002A0080, nullptr, "GetLatestVsyncTiming"},
|
||||
{0x002B0000, GetStereoCameraCalibrationData, "GetStereoCameraCalibrationData"},
|
||||
{0x002C0400, nullptr, "SetStereoCameraCalibrationData"},
|
||||
{0x002D00C0, nullptr, "WriteRegisterI2c"},
|
||||
{0x002E00C0, nullptr, "WriteMcuVariableI2c"},
|
||||
{0x002F0080, nullptr, "ReadRegisterI2cExclusive"},
|
||||
{0x00300080, nullptr, "ReadMcuVariableI2cExclusive"},
|
||||
{0x00310180, nullptr, "SetImageQualityCalibrationData"},
|
||||
{0x00320000, nullptr, "GetImageQualityCalibrationData"},
|
||||
{0x003302C0, nullptr, "SetPackageParameterWithoutContext"},
|
||||
{0x00340140, nullptr, "SetPackageParameterWithContext"},
|
||||
{0x003501C0, nullptr, "SetPackageParameterWithContextDetail"},
|
||||
{0x00360000, GetSuitableY2rStandardCoefficient, "GetSuitableY2rStandardCoefficient"},
|
||||
{0x00370202, nullptr, "PlayShutterSoundWithWave"},
|
||||
{0x00380040, PlayShutterSound, "PlayShutterSound"},
|
||||
{0x00390000, DriverInitialize, "DriverInitialize"},
|
||||
{0x003A0000, DriverFinalize, "DriverFinalize"},
|
||||
{0x003B0000, nullptr, "GetActivatedCamera"},
|
||||
{0x003C0000, nullptr, "GetSleepCamera"},
|
||||
{0x003D0040, nullptr, "SetSleepCamera"},
|
||||
{0x003E0040, nullptr, "SetBrightnessSynchronization"},
|
||||
{0x00010040, StartCapture, "StartCapture"},
|
||||
{0x00020040, StopCapture, "StopCapture"},
|
||||
{0x00030040, nullptr, "IsBusy"},
|
||||
{0x00040040, nullptr, "ClearBuffer"},
|
||||
{0x00050040, GetVsyncInterruptEvent, "GetVsyncInterruptEvent"},
|
||||
{0x00060040, GetBufferErrorInterruptEvent, "GetBufferErrorInterruptEvent"},
|
||||
{0x00070102, SetReceiving, "SetReceiving"},
|
||||
{0x00080040, nullptr, "IsFinishedReceiving"},
|
||||
{0x00090100, SetTransferLines, "SetTransferLines"},
|
||||
{0x000A0080, GetMaxLines, "GetMaxLines"},
|
||||
{0x000B0100, nullptr, "SetTransferBytes"},
|
||||
{0x000C0040, GetTransferBytes, "GetTransferBytes"},
|
||||
{0x000D0080, nullptr, "GetMaxBytes"},
|
||||
{0x000E0080, SetTrimming, "SetTrimming"},
|
||||
{0x000F0040, nullptr, "IsTrimming"},
|
||||
{0x00100140, nullptr, "SetTrimmingParams"},
|
||||
{0x00110040, nullptr, "GetTrimmingParams"},
|
||||
{0x00120140, SetTrimmingParamsCenter, "SetTrimmingParamsCenter"},
|
||||
{0x00130040, Activate, "Activate"},
|
||||
{0x00140080, nullptr, "SwitchContext"},
|
||||
{0x00150080, nullptr, "SetExposure"},
|
||||
{0x00160080, nullptr, "SetWhiteBalance"},
|
||||
{0x00170080, nullptr, "SetWhiteBalanceWithoutBaseUp"},
|
||||
{0x00180080, nullptr, "SetSharpness"},
|
||||
{0x00190080, nullptr, "SetAutoExposure"},
|
||||
{0x001A0040, nullptr, "IsAutoExposure"},
|
||||
{0x001B0080, nullptr, "SetAutoWhiteBalance"},
|
||||
{0x001C0040, nullptr, "IsAutoWhiteBalance"},
|
||||
{0x001D00C0, FlipImage, "FlipImage"},
|
||||
{0x001E0200, nullptr, "SetDetailSize"},
|
||||
{0x001F00C0, SetSize, "SetSize"},
|
||||
{0x00200080, SetFrameRate, "SetFrameRate"},
|
||||
{0x00210080, nullptr, "SetPhotoMode"},
|
||||
{0x002200C0, nullptr, "SetEffect"},
|
||||
{0x00230080, nullptr, "SetContrast"},
|
||||
{0x00240080, nullptr, "SetLensCorrection"},
|
||||
{0x002500C0, nullptr, "SetOutputFormat"},
|
||||
{0x00260140, nullptr, "SetAutoExposureWindow"},
|
||||
{0x00270140, nullptr, "SetAutoWhiteBalanceWindow"},
|
||||
{0x00280080, nullptr, "SetNoiseFilter"},
|
||||
{0x00290080, nullptr, "SynchronizeVsyncTiming"},
|
||||
{0x002A0080, nullptr, "GetLatestVsyncTiming"},
|
||||
{0x002B0000, GetStereoCameraCalibrationData, "GetStereoCameraCalibrationData"},
|
||||
{0x002C0400, nullptr, "SetStereoCameraCalibrationData"},
|
||||
{0x002D00C0, nullptr, "WriteRegisterI2c"},
|
||||
{0x002E00C0, nullptr, "WriteMcuVariableI2c"},
|
||||
{0x002F0080, nullptr, "ReadRegisterI2cExclusive"},
|
||||
{0x00300080, nullptr, "ReadMcuVariableI2cExclusive"},
|
||||
{0x00310180, nullptr, "SetImageQualityCalibrationData"},
|
||||
{0x00320000, nullptr, "GetImageQualityCalibrationData"},
|
||||
{0x003302C0, nullptr, "SetPackageParameterWithoutContext"},
|
||||
{0x00340140, nullptr, "SetPackageParameterWithContext"},
|
||||
{0x003501C0, nullptr, "SetPackageParameterWithContextDetail"},
|
||||
{0x00360000, GetSuitableY2rStandardCoefficient, "GetSuitableY2rStandardCoefficient"},
|
||||
{0x00370202, nullptr, "PlayShutterSoundWithWave"},
|
||||
{0x00380040, PlayShutterSound, "PlayShutterSound"},
|
||||
{0x00390000, DriverInitialize, "DriverInitialize"},
|
||||
{0x003A0000, DriverFinalize, "DriverFinalize"},
|
||||
{0x003B0000, nullptr, "GetActivatedCamera"},
|
||||
{0x003C0000, nullptr, "GetSleepCamera"},
|
||||
{0x003D0040, nullptr, "SetSleepCamera"},
|
||||
{0x003E0040, nullptr, "SetBrightnessSynchronization"},
|
||||
};
|
||||
|
||||
CAM_U_Interface::CAM_U_Interface() {
|
||||
|
@ -5,10 +5,10 @@
|
||||
#include "common/logging/log.h"
|
||||
|
||||
#include "core/hle/kernel/event.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/service/service.h"
|
||||
|
||||
namespace Service {
|
||||
namespace CECD {
|
||||
@ -28,7 +28,7 @@ void GetCecStateAbbreviated(Service::Interface* self) {
|
||||
void GetCecInfoEventHandle(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
cmd_buff[3] = Kernel::g_handle_table.Create(cecinfo_event).MoveFrom(); // Event handle
|
||||
|
||||
LOG_WARNING(Service_CECD, "(STUBBED) called");
|
||||
@ -37,7 +37,7 @@ void GetCecInfoEventHandle(Service::Interface* self) {
|
||||
void GetChangeStateEventHandle(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
cmd_buff[3] = Kernel::g_handle_table.Create(change_state_event).MoveFrom(); // Event handle
|
||||
|
||||
LOG_WARNING(Service_CECD, "(STUBBED) called");
|
||||
@ -48,7 +48,8 @@ void Init() {
|
||||
AddService(new CECD_U_Interface);
|
||||
|
||||
cecinfo_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "CECD_U::cecinfo_event");
|
||||
change_state_event = Kernel::Event::Create(Kernel::ResetType::OneShot, "CECD_U::change_state_event");
|
||||
change_state_event =
|
||||
Kernel::Event::Create(Kernel::ResetType::OneShot, "CECD_U::change_state_event");
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
|
@ -11,11 +11,13 @@ class Interface;
|
||||
namespace CECD {
|
||||
|
||||
enum class CecStateAbbreviated {
|
||||
CEC_STATE_ABBREV_IDLE = 1, ///< Corresponds to CEC_STATE_IDLE
|
||||
CEC_STATE_ABBREV_IDLE = 1, ///< Corresponds to CEC_STATE_IDLE
|
||||
CEC_STATE_ABBREV_NOT_LOCAL = 2, ///< Corresponds to CEC_STATEs *FINISH*, *POST, and OVER_BOSS
|
||||
CEC_STATE_ABBREV_SCANNING = 3, ///< Corresponds to CEC_STATE_SCANNING
|
||||
CEC_STATE_ABBREV_WLREADY = 4, ///< Corresponds to CEC_STATE_WIRELESS_READY when some unknown bool is true
|
||||
CEC_STATE_ABBREV_OTHER = 5, ///< Corresponds to CEC_STATEs besides *FINISH*, *POST, and OVER_BOSS and those listed here
|
||||
CEC_STATE_ABBREV_SCANNING = 3, ///< Corresponds to CEC_STATE_SCANNING
|
||||
CEC_STATE_ABBREV_WLREADY =
|
||||
4, ///< Corresponds to CEC_STATE_WIRELESS_READY when some unknown bool is true
|
||||
CEC_STATE_ABBREV_OTHER = 5, ///< Corresponds to CEC_STATEs besides *FINISH*, *POST, and
|
||||
/// OVER_BOSS and those listed here
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -8,10 +8,10 @@ namespace Service {
|
||||
namespace CECD {
|
||||
|
||||
// Empty arrays are illegal -- commented out until an entry is added.
|
||||
//const Interface::FunctionInfo FunctionTable[] = { };
|
||||
// const Interface::FunctionInfo FunctionTable[] = { };
|
||||
|
||||
CECD_S_Interface::CECD_S_Interface() {
|
||||
//Register(FunctionTable);
|
||||
// Register(FunctionTable);
|
||||
}
|
||||
|
||||
} // namespace CECD
|
||||
|
@ -9,10 +9,10 @@ namespace Service {
|
||||
namespace CECD {
|
||||
|
||||
static const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x000E0000, GetCecStateAbbreviated, "GetCecStateAbbreviated"},
|
||||
{0x000F0000, GetCecInfoEventHandle, "GetCecInfoEventHandle"},
|
||||
{0x000E0000, GetCecStateAbbreviated, "GetCecStateAbbreviated"},
|
||||
{0x000F0000, GetCecInfoEventHandle, "GetCecInfoEventHandle"},
|
||||
{0x00100000, GetChangeStateEventHandle, "GetChangeStateEventHandle"},
|
||||
{0x00120104, nullptr, "ReadSavedData"},
|
||||
{0x00120104, nullptr, "ReadSavedData"},
|
||||
};
|
||||
|
||||
CECD_U_Interface::CECD_U_Interface() {
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
#include "core/file_sys/archive_systemsavedata.h"
|
||||
#include "core/file_sys/file_backend.h"
|
||||
#include "core/settings.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/cfg/cfg.h"
|
||||
#include "core/hle/service/cfg/cfg_i.h"
|
||||
@ -19,6 +18,7 @@
|
||||
#include "core/hle/service/cfg/cfg_u.h"
|
||||
#include "core/hle/service/fs/archive.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace Service {
|
||||
namespace CFG {
|
||||
@ -33,25 +33,29 @@ namespace {
|
||||
* contains information about the blocks in the file
|
||||
*/
|
||||
struct SaveFileConfig {
|
||||
u16 total_entries; ///< The total number of set entries in the config file
|
||||
u16 data_entries_offset; ///< The offset where the data for the blocks start, this is hardcoded to 0x455C as per hardware
|
||||
SaveConfigBlockEntry block_entries[CONFIG_FILE_MAX_BLOCK_ENTRIES]; ///< The block headers, the maximum possible value is 1479 as per hardware
|
||||
u32 unknown; ///< This field is unknown, possibly padding, 0 has been observed in hardware
|
||||
u16 total_entries; ///< The total number of set entries in the config file
|
||||
u16 data_entries_offset; ///< The offset where the data for the blocks start, this is hardcoded
|
||||
/// to 0x455C as per hardware
|
||||
SaveConfigBlockEntry block_entries[CONFIG_FILE_MAX_BLOCK_ENTRIES]; ///< The block headers, the
|
||||
/// maximum possible value is
|
||||
/// 1479 as per hardware
|
||||
u32 unknown; ///< This field is unknown, possibly padding, 0 has been observed in hardware
|
||||
};
|
||||
static_assert(sizeof(SaveFileConfig) == 0x455C, "SaveFileConfig header must be exactly 0x455C bytes");
|
||||
static_assert(sizeof(SaveFileConfig) == 0x455C,
|
||||
"SaveFileConfig header must be exactly 0x455C bytes");
|
||||
|
||||
enum ConfigBlockID {
|
||||
StereoCameraSettingsBlockID = 0x00050005,
|
||||
SoundOutputModeBlockID = 0x00070001,
|
||||
ConsoleUniqueIDBlockID = 0x00090001,
|
||||
UsernameBlockID = 0x000A0000,
|
||||
BirthdayBlockID = 0x000A0001,
|
||||
LanguageBlockID = 0x000A0002,
|
||||
CountryInfoBlockID = 0x000B0000,
|
||||
CountryNameBlockID = 0x000B0001,
|
||||
StateNameBlockID = 0x000B0002,
|
||||
EULAVersionBlockID = 0x000D0000,
|
||||
ConsoleModelBlockID = 0x000F0004,
|
||||
SoundOutputModeBlockID = 0x00070001,
|
||||
ConsoleUniqueIDBlockID = 0x00090001,
|
||||
UsernameBlockID = 0x000A0000,
|
||||
BirthdayBlockID = 0x000A0001,
|
||||
LanguageBlockID = 0x000A0002,
|
||||
CountryInfoBlockID = 0x000B0000,
|
||||
CountryNameBlockID = 0x000B0001,
|
||||
StateNameBlockID = 0x000B0002,
|
||||
EULAVersionBlockID = 0x000D0000,
|
||||
ConsoleModelBlockID = 0x000F0004,
|
||||
};
|
||||
|
||||
struct UsernameBlock {
|
||||
@ -68,8 +72,8 @@ struct BirthdayBlock {
|
||||
static_assert(sizeof(BirthdayBlock) == 2, "BirthdayBlock must be exactly 2 bytes");
|
||||
|
||||
struct ConsoleModelInfo {
|
||||
u8 model; ///< The console model (3DS, 2DS, etc)
|
||||
u8 unknown[3]; ///< Unknown data
|
||||
u8 model; ///< The console model (3DS, 2DS, etc)
|
||||
u8 unknown[3]; ///< Unknown data
|
||||
};
|
||||
static_assert(sizeof(ConsoleModelInfo) == 4, "ConsoleModelInfo must be exactly 4 bytes");
|
||||
|
||||
@ -78,36 +82,36 @@ struct ConsoleCountryInfo {
|
||||
u8 country_code; ///< The country code of the console
|
||||
};
|
||||
static_assert(sizeof(ConsoleCountryInfo) == 4, "ConsoleCountryInfo must be exactly 4 bytes");
|
||||
|
||||
}
|
||||
|
||||
static const u64 CFG_SAVE_ID = 0x00010017;
|
||||
static const u64 CONSOLE_UNIQUE_ID = 0xDEADC0DE;
|
||||
static const ConsoleModelInfo CONSOLE_MODEL = { NINTENDO_3DS_XL, { 0, 0, 0 } };
|
||||
static const ConsoleModelInfo CONSOLE_MODEL = {NINTENDO_3DS_XL, {0, 0, 0}};
|
||||
static const u8 CONSOLE_LANGUAGE = LANGUAGE_EN;
|
||||
static const UsernameBlock CONSOLE_USERNAME_BLOCK = { u"CITRA", 0, 0 };
|
||||
static const BirthdayBlock PROFILE_BIRTHDAY = { 3, 25 }; // March 25th, 2014
|
||||
static const UsernameBlock CONSOLE_USERNAME_BLOCK = {u"CITRA", 0, 0};
|
||||
static const BirthdayBlock PROFILE_BIRTHDAY = {3, 25}; // March 25th, 2014
|
||||
static const u8 SOUND_OUTPUT_MODE = SOUND_SURROUND;
|
||||
static const u8 UNITED_STATES_COUNTRY_ID = 49;
|
||||
/// TODO(Subv): Find what the other bytes are
|
||||
static const ConsoleCountryInfo COUNTRY_INFO = { { 0, 0, 0 }, UNITED_STATES_COUNTRY_ID };
|
||||
static const ConsoleCountryInfo COUNTRY_INFO = {{0, 0, 0}, UNITED_STATES_COUNTRY_ID};
|
||||
|
||||
/**
|
||||
* TODO(Subv): Find out what this actually is, these values fix some NaN uniforms in some games,
|
||||
* for example Nintendo Zone
|
||||
* Thanks Normmatt for providing this information
|
||||
*/
|
||||
static const std::array<float, 8> STEREO_CAMERA_SETTINGS = {{
|
||||
62.0f, 289.0f, 76.80000305175781f, 46.08000183105469f,
|
||||
10.0f, 5.0f, 55.58000183105469f, 21.56999969482422f
|
||||
}};
|
||||
static_assert(sizeof(STEREO_CAMERA_SETTINGS) == 0x20, "STEREO_CAMERA_SETTINGS must be exactly 0x20 bytes");
|
||||
static const std::array<float, 8> STEREO_CAMERA_SETTINGS = {
|
||||
{62.0f, 289.0f, 76.80000305175781f, 46.08000183105469f, 10.0f, 5.0f, 55.58000183105469f,
|
||||
21.56999969482422f}};
|
||||
static_assert(sizeof(STEREO_CAMERA_SETTINGS) == 0x20,
|
||||
"STEREO_CAMERA_SETTINGS must be exactly 0x20 bytes");
|
||||
|
||||
static const u32 CONFIG_SAVEFILE_SIZE = 0x8000;
|
||||
static std::array<u8, CONFIG_SAVEFILE_SIZE> cfg_config_file_buffer;
|
||||
|
||||
static Service::FS::ArchiveHandle cfg_system_save_data_archive;
|
||||
static const std::vector<u8> cfg_system_savedata_id = { 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x01, 0x00 };
|
||||
static const std::vector<u8> cfg_system_savedata_id = {0x00, 0x00, 0x00, 0x00,
|
||||
0x17, 0x00, 0x01, 0x00};
|
||||
|
||||
void GetCountryCodeString(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
@ -115,7 +119,9 @@ void GetCountryCodeString(Service::Interface* self) {
|
||||
|
||||
if (country_code_id >= country_codes.size() || 0 == country_codes[country_code_id]) {
|
||||
LOG_ERROR(Service_CFG, "requested country code id=%d is invalid", country_code_id);
|
||||
cmd_buff[1] = ResultCode(ErrorDescription::NotFound, ErrorModule::Config, ErrorSummary::WrongArgument, ErrorLevel::Permanent).raw;
|
||||
cmd_buff[1] = ResultCode(ErrorDescription::NotFound, ErrorModule::Config,
|
||||
ErrorSummary::WrongArgument, ErrorLevel::Permanent)
|
||||
.raw;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -139,8 +145,11 @@ void GetCountryCodeID(Service::Interface* self) {
|
||||
}
|
||||
|
||||
if (0 == country_code_id) {
|
||||
LOG_ERROR(Service_CFG, "requested country code name=%c%c is invalid", country_code & 0xff, country_code >> 8);
|
||||
cmd_buff[1] = ResultCode(ErrorDescription::NotFound, ErrorModule::Config, ErrorSummary::WrongArgument, ErrorLevel::Permanent).raw;
|
||||
LOG_ERROR(Service_CFG, "requested country code name=%c%c is invalid", country_code & 0xff,
|
||||
country_code >> 8);
|
||||
cmd_buff[1] = ResultCode(ErrorDescription::NotFound, ErrorModule::Config,
|
||||
ErrorSummary::WrongArgument, ErrorLevel::Permanent)
|
||||
.raw;
|
||||
cmd_buff[2] = 0xFFFF;
|
||||
return;
|
||||
}
|
||||
@ -185,8 +194,8 @@ void GetSystemModel(Service::Interface* self) {
|
||||
u32 data;
|
||||
|
||||
// TODO(Subv): Find out the correct error codes
|
||||
cmd_buff[1] = Service::CFG::GetConfigInfoBlock(0x000F0004, 4, 0x8,
|
||||
reinterpret_cast<u8*>(&data)).raw;
|
||||
cmd_buff[1] =
|
||||
Service::CFG::GetConfigInfoBlock(0x000F0004, 4, 0x8, reinterpret_cast<u8*>(&data)).raw;
|
||||
cmd_buff[2] = data & 0xFF;
|
||||
}
|
||||
|
||||
@ -195,8 +204,8 @@ void GetModelNintendo2DS(Service::Interface* self) {
|
||||
u32 data;
|
||||
|
||||
// TODO(Subv): Find out the correct error codes
|
||||
cmd_buff[1] = Service::CFG::GetConfigInfoBlock(0x000F0004, 4, 0x8,
|
||||
reinterpret_cast<u8*>(&data)).raw;
|
||||
cmd_buff[1] =
|
||||
Service::CFG::GetConfigInfoBlock(0x000F0004, 4, 0x8, reinterpret_cast<u8*>(&data)).raw;
|
||||
|
||||
u8 model = data & 0xFF;
|
||||
if (model == Service::CFG::NINTENDO_2DS)
|
||||
@ -267,24 +276,29 @@ static ResultVal<void*> GetConfigInfoBlockPointer(u32 block_id, u32 size, u32 fl
|
||||
// Read the header
|
||||
SaveFileConfig* config = reinterpret_cast<SaveFileConfig*>(cfg_config_file_buffer.data());
|
||||
|
||||
auto itr = std::find_if(std::begin(config->block_entries), std::end(config->block_entries),
|
||||
[&](const SaveConfigBlockEntry& entry) {
|
||||
return entry.block_id == block_id;
|
||||
});
|
||||
auto itr =
|
||||
std::find_if(std::begin(config->block_entries), std::end(config->block_entries),
|
||||
[&](const SaveConfigBlockEntry& entry) { return entry.block_id == block_id; });
|
||||
|
||||
if (itr == std::end(config->block_entries)) {
|
||||
LOG_ERROR(Service_CFG, "Config block 0x%X with flags %u and size %u was not found", block_id, flag, size);
|
||||
return ResultCode(ErrorDescription::NotFound, ErrorModule::Config, ErrorSummary::WrongArgument, ErrorLevel::Permanent);
|
||||
LOG_ERROR(Service_CFG, "Config block 0x%X with flags %u and size %u was not found",
|
||||
block_id, flag, size);
|
||||
return ResultCode(ErrorDescription::NotFound, ErrorModule::Config,
|
||||
ErrorSummary::WrongArgument, ErrorLevel::Permanent);
|
||||
}
|
||||
|
||||
if ((itr->flags & flag) == 0) {
|
||||
LOG_ERROR(Service_CFG, "Invalid flag %u for config block 0x%X with size %u", flag, block_id, size);
|
||||
return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::Config, ErrorSummary::WrongArgument, ErrorLevel::Permanent);
|
||||
LOG_ERROR(Service_CFG, "Invalid flag %u for config block 0x%X with size %u", flag, block_id,
|
||||
size);
|
||||
return ResultCode(ErrorDescription::NotAuthorized, ErrorModule::Config,
|
||||
ErrorSummary::WrongArgument, ErrorLevel::Permanent);
|
||||
}
|
||||
|
||||
if (itr->size != size) {
|
||||
LOG_ERROR(Service_CFG, "Invalid size %u for config block 0x%X with flags %u", size, block_id, flag);
|
||||
return ResultCode(ErrorDescription::InvalidSize, ErrorModule::Config, ErrorSummary::WrongArgument, ErrorLevel::Permanent);
|
||||
LOG_ERROR(Service_CFG, "Invalid size %u for config block 0x%X with flags %u", size,
|
||||
block_id, flag);
|
||||
return ResultCode(ErrorDescription::InvalidSize, ErrorModule::Config,
|
||||
ErrorSummary::WrongArgument, ErrorLevel::Permanent);
|
||||
}
|
||||
|
||||
void* pointer;
|
||||
@ -318,7 +332,7 @@ ResultCode CreateConfigInfoBlk(u32 block_id, u16 size, u16 flags, const void* da
|
||||
return ResultCode(-1); // TODO(Subv): Find the right error code
|
||||
|
||||
// Insert the block header with offset 0 for now
|
||||
config->block_entries[config->total_entries] = { block_id, 0, size, flags };
|
||||
config->block_entries[config->total_entries] = {block_id, 0, size, flags};
|
||||
if (size > 4) {
|
||||
u32 offset = config->data_entries_offset;
|
||||
// Perform a search to locate the next offset for the new data
|
||||
@ -326,8 +340,7 @@ ResultCode CreateConfigInfoBlk(u32 block_id, u16 size, u16 flags, const void* da
|
||||
for (int i = config->total_entries - 1; i >= 0; --i) {
|
||||
// Ignore the blocks that don't have a separate data offset
|
||||
if (config->block_entries[i].size > 4) {
|
||||
offset = config->block_entries[i].offset_or_data +
|
||||
config->block_entries[i].size;
|
||||
offset = config->block_entries[i].offset_or_data + config->block_entries[i].size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -336,8 +349,7 @@ ResultCode CreateConfigInfoBlk(u32 block_id, u16 size, u16 flags, const void* da
|
||||
|
||||
// Write the data at the new offset
|
||||
memcpy(&cfg_config_file_buffer[offset], data, size);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// The offset_or_data field in the header contains the data itself if it's 4 bytes or less
|
||||
memcpy(&config->block_entries[config->total_entries].offset_or_data, data, size);
|
||||
}
|
||||
@ -384,28 +396,40 @@ ResultCode FormatConfig() {
|
||||
|
||||
// 0x00030001 - Unknown
|
||||
res = CreateConfigInfoBlk(0x00030001, 0x8, 0xE, zero_buffer);
|
||||
if (!res.IsSuccess()) return res;
|
||||
if (!res.IsSuccess())
|
||||
return res;
|
||||
|
||||
res = CreateConfigInfoBlk(StereoCameraSettingsBlockID, sizeof(STEREO_CAMERA_SETTINGS), 0xE, STEREO_CAMERA_SETTINGS.data());
|
||||
if (!res.IsSuccess()) return res;
|
||||
res = CreateConfigInfoBlk(StereoCameraSettingsBlockID, sizeof(STEREO_CAMERA_SETTINGS), 0xE,
|
||||
STEREO_CAMERA_SETTINGS.data());
|
||||
if (!res.IsSuccess())
|
||||
return res;
|
||||
|
||||
res = CreateConfigInfoBlk(SoundOutputModeBlockID, sizeof(SOUND_OUTPUT_MODE), 0xE, &SOUND_OUTPUT_MODE);
|
||||
if (!res.IsSuccess()) return res;
|
||||
res = CreateConfigInfoBlk(SoundOutputModeBlockID, sizeof(SOUND_OUTPUT_MODE), 0xE,
|
||||
&SOUND_OUTPUT_MODE);
|
||||
if (!res.IsSuccess())
|
||||
return res;
|
||||
|
||||
res = CreateConfigInfoBlk(ConsoleUniqueIDBlockID, sizeof(CONSOLE_UNIQUE_ID), 0xE, &CONSOLE_UNIQUE_ID);
|
||||
if (!res.IsSuccess()) return res;
|
||||
res = CreateConfigInfoBlk(ConsoleUniqueIDBlockID, sizeof(CONSOLE_UNIQUE_ID), 0xE,
|
||||
&CONSOLE_UNIQUE_ID);
|
||||
if (!res.IsSuccess())
|
||||
return res;
|
||||
|
||||
res = CreateConfigInfoBlk(UsernameBlockID, sizeof(CONSOLE_USERNAME_BLOCK), 0xE, &CONSOLE_USERNAME_BLOCK);
|
||||
if (!res.IsSuccess()) return res;
|
||||
res = CreateConfigInfoBlk(UsernameBlockID, sizeof(CONSOLE_USERNAME_BLOCK), 0xE,
|
||||
&CONSOLE_USERNAME_BLOCK);
|
||||
if (!res.IsSuccess())
|
||||
return res;
|
||||
|
||||
res = CreateConfigInfoBlk(BirthdayBlockID, sizeof(PROFILE_BIRTHDAY), 0xE, &PROFILE_BIRTHDAY);
|
||||
if (!res.IsSuccess()) return res;
|
||||
if (!res.IsSuccess())
|
||||
return res;
|
||||
|
||||
res = CreateConfigInfoBlk(LanguageBlockID, sizeof(CONSOLE_LANGUAGE), 0xE, &CONSOLE_LANGUAGE);
|
||||
if (!res.IsSuccess()) return res;
|
||||
if (!res.IsSuccess())
|
||||
return res;
|
||||
|
||||
res = CreateConfigInfoBlk(CountryInfoBlockID, sizeof(COUNTRY_INFO), 0xE, &COUNTRY_INFO);
|
||||
if (!res.IsSuccess()) return res;
|
||||
if (!res.IsSuccess())
|
||||
return res;
|
||||
|
||||
u16_le country_name_buffer[16][0x40] = {};
|
||||
std::u16string region_name = Common::UTF8ToUTF16("Gensokyo");
|
||||
@ -413,34 +437,44 @@ ResultCode FormatConfig() {
|
||||
std::copy(region_name.cbegin(), region_name.cend(), country_name_buffer[i]);
|
||||
}
|
||||
// 0x000B0001 - Localized names for the profile Country
|
||||
res = CreateConfigInfoBlk(CountryNameBlockID, sizeof(country_name_buffer), 0xE, country_name_buffer);
|
||||
if (!res.IsSuccess()) return res;
|
||||
res = CreateConfigInfoBlk(CountryNameBlockID, sizeof(country_name_buffer), 0xE,
|
||||
country_name_buffer);
|
||||
if (!res.IsSuccess())
|
||||
return res;
|
||||
// 0x000B0002 - Localized names for the profile State/Province
|
||||
res = CreateConfigInfoBlk(StateNameBlockID, sizeof(country_name_buffer), 0xE, country_name_buffer);
|
||||
if (!res.IsSuccess()) return res;
|
||||
res = CreateConfigInfoBlk(StateNameBlockID, sizeof(country_name_buffer), 0xE,
|
||||
country_name_buffer);
|
||||
if (!res.IsSuccess())
|
||||
return res;
|
||||
|
||||
// 0x000B0003 - Unknown, related to country/address (zip code?)
|
||||
res = CreateConfigInfoBlk(0x000B0003, 0x4, 0xE, zero_buffer);
|
||||
if (!res.IsSuccess()) return res;
|
||||
if (!res.IsSuccess())
|
||||
return res;
|
||||
|
||||
// 0x000C0000 - Unknown
|
||||
res = CreateConfigInfoBlk(0x000C0000, 0xC0, 0xE, zero_buffer);
|
||||
if (!res.IsSuccess()) return res;
|
||||
if (!res.IsSuccess())
|
||||
return res;
|
||||
|
||||
// 0x000C0001 - Unknown
|
||||
res = CreateConfigInfoBlk(0x000C0001, 0x14, 0xE, zero_buffer);
|
||||
if (!res.IsSuccess()) return res;
|
||||
if (!res.IsSuccess())
|
||||
return res;
|
||||
|
||||
// 0x000D0000 - Accepted EULA version
|
||||
res = CreateConfigInfoBlk(EULAVersionBlockID, 0x4, 0xE, zero_buffer);
|
||||
if (!res.IsSuccess()) return res;
|
||||
if (!res.IsSuccess())
|
||||
return res;
|
||||
|
||||
res = CreateConfigInfoBlk(ConsoleModelBlockID, sizeof(CONSOLE_MODEL), 0xC, &CONSOLE_MODEL);
|
||||
if (!res.IsSuccess()) return res;
|
||||
if (!res.IsSuccess())
|
||||
return res;
|
||||
|
||||
// 0x00170000 - Unknown
|
||||
res = CreateConfigInfoBlk(0x00170000, 0x4, 0xE, zero_buffer);
|
||||
if (!res.IsSuccess()) return res;
|
||||
if (!res.IsSuccess())
|
||||
return res;
|
||||
|
||||
// Save the buffer to the file
|
||||
res = UpdateConfigNANDSavegame();
|
||||
@ -452,15 +486,18 @@ ResultCode FormatConfig() {
|
||||
ResultCode LoadConfigNANDSaveFile() {
|
||||
// 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);
|
||||
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
|
||||
Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SystemSaveData, FileSys::ArchiveFormatInfo(), archive_path);
|
||||
Service::FS::FormatArchive(Service::FS::ArchiveIdCode::SystemSaveData,
|
||||
FileSys::ArchiveFormatInfo(), archive_path);
|
||||
|
||||
// Open it again to get a valid archive now that the folder exists
|
||||
archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path);
|
||||
archive_result =
|
||||
Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path);
|
||||
}
|
||||
|
||||
ASSERT_MSG(archive_result.Succeeded(), "Could not open the CFG SystemSaveData archive!");
|
||||
@ -515,7 +552,7 @@ std::u16string GetUsername() {
|
||||
}
|
||||
|
||||
void SetBirthday(u8 month, u8 day) {
|
||||
BirthdayBlock block = { month, day };
|
||||
BirthdayBlock block = {month, day};
|
||||
SetConfigInfoBlock(BirthdayBlockID, sizeof(block), 4, &block);
|
||||
}
|
||||
|
||||
|
@ -40,16 +40,13 @@ enum SystemLanguage {
|
||||
LANGUAGE_TW = 11
|
||||
};
|
||||
|
||||
enum SoundOutputMode {
|
||||
SOUND_MONO = 0,
|
||||
SOUND_STEREO = 1,
|
||||
SOUND_SURROUND = 2
|
||||
};
|
||||
enum SoundOutputMode { SOUND_MONO = 0, SOUND_STEREO = 1, SOUND_SURROUND = 2 };
|
||||
|
||||
/// Block header in the config savedata file
|
||||
struct SaveConfigBlockEntry {
|
||||
u32 block_id; ///< The id of the current block
|
||||
u32 offset_or_data; ///< This is the absolute offset to the block data if the size is greater than 4 bytes, otherwise it contains the data itself
|
||||
u32 offset_or_data; ///< This is the absolute offset to the block data if the size is greater
|
||||
/// than 4 bytes, otherwise it contains the data itself
|
||||
u16 size; ///< The size of the block
|
||||
u16 flags; ///< The flags of the block, possibly used for access control
|
||||
};
|
||||
@ -244,7 +241,8 @@ ResultCode GetConfigInfoBlock(u32 block_id, u32 size, u32 flag, void* output);
|
||||
ResultCode SetConfigInfoBlock(u32 block_id, u32 size, u32 flag, const void* input);
|
||||
|
||||
/**
|
||||
* Creates a block with the specified id and writes the input data to the cfg savegame buffer in memory.
|
||||
* Creates a block with the specified id and writes the input data to the cfg savegame buffer in
|
||||
* memory.
|
||||
* The config savegame file in the filesystem is not updated.
|
||||
* @param block_id The id of the block we want to create
|
||||
* @param size The size of the block we want to create
|
||||
|
@ -10,49 +10,49 @@ namespace CFG {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
// cfg common
|
||||
{0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"},
|
||||
{0x00020000, SecureInfoGetRegion, "SecureInfoGetRegion"},
|
||||
{0x00030040, GenHashConsoleUnique, "GenHashConsoleUnique"},
|
||||
{0x00040000, GetRegionCanadaUSA, "GetRegionCanadaUSA"},
|
||||
{0x00050000, GetSystemModel, "GetSystemModel"},
|
||||
{0x00060000, GetModelNintendo2DS, "GetModelNintendo2DS"},
|
||||
{0x00070040, nullptr, "WriteToFirstByteCfgSavegame"},
|
||||
{0x00080080, nullptr, "GoThroughTable"},
|
||||
{0x00090040, GetCountryCodeString, "GetCountryCodeString"},
|
||||
{0x000A0040, GetCountryCodeID, "GetCountryCodeID"},
|
||||
{0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"},
|
||||
{0x00020000, SecureInfoGetRegion, "SecureInfoGetRegion"},
|
||||
{0x00030040, GenHashConsoleUnique, "GenHashConsoleUnique"},
|
||||
{0x00040000, GetRegionCanadaUSA, "GetRegionCanadaUSA"},
|
||||
{0x00050000, GetSystemModel, "GetSystemModel"},
|
||||
{0x00060000, GetModelNintendo2DS, "GetModelNintendo2DS"},
|
||||
{0x00070040, nullptr, "WriteToFirstByteCfgSavegame"},
|
||||
{0x00080080, nullptr, "GoThroughTable"},
|
||||
{0x00090040, GetCountryCodeString, "GetCountryCodeString"},
|
||||
{0x000A0040, GetCountryCodeID, "GetCountryCodeID"},
|
||||
// cfg:i
|
||||
{0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"},
|
||||
{0x04020082, SetConfigInfoBlk4, "SetConfigInfoBlk4"},
|
||||
{0x04030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"},
|
||||
{0x04040042, nullptr, "GetLocalFriendCodeSeedData"},
|
||||
{0x04050000, nullptr, "GetLocalFriendCodeSeed"},
|
||||
{0x04060000, SecureInfoGetRegion, "SecureInfoGetRegion"},
|
||||
{0x04070000, nullptr, "SecureInfoGetByte101"},
|
||||
{0x04080042, nullptr, "SecureInfoGetSerialNo"},
|
||||
{0x04090000, nullptr, "UpdateConfigBlk00040003"},
|
||||
{0x08010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"},
|
||||
{0x08020082, SetConfigInfoBlk4, "SetConfigInfoBlk4"},
|
||||
{0x08030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"},
|
||||
{0x080400C2, nullptr, "CreateConfigInfoBlk"},
|
||||
{0x08050000, nullptr, "DeleteConfigNANDSavefile"},
|
||||
{0x08060000, FormatConfig, "FormatConfig"},
|
||||
{0x08080000, nullptr, "UpdateConfigBlk1"},
|
||||
{0x08090000, nullptr, "UpdateConfigBlk2"},
|
||||
{0x080A0000, nullptr, "UpdateConfigBlk3"},
|
||||
{0x080B0082, nullptr, "SetGetLocalFriendCodeSeedData"},
|
||||
{0x080C0042, nullptr, "SetLocalFriendCodeSeedSignature"},
|
||||
{0x080D0000, nullptr, "DeleteCreateNANDLocalFriendCodeSeed"},
|
||||
{0x080E0000, nullptr, "VerifySigLocalFriendCodeSeed"},
|
||||
{0x080F0042, nullptr, "GetLocalFriendCodeSeedData"},
|
||||
{0x08100000, nullptr, "GetLocalFriendCodeSeed"},
|
||||
{0x08110084, nullptr, "SetSecureInfo"},
|
||||
{0x08120000, nullptr, "DeleteCreateNANDSecureInfo"},
|
||||
{0x08130000, nullptr, "VerifySigSecureInfo"},
|
||||
{0x08140042, nullptr, "SecureInfoGetData"},
|
||||
{0x08150042, nullptr, "SecureInfoGetSignature"},
|
||||
{0x08160000, SecureInfoGetRegion, "SecureInfoGetRegion"},
|
||||
{0x08170000, nullptr, "SecureInfoGetByte101"},
|
||||
{0x08180042, nullptr, "SecureInfoGetSerialNo"},
|
||||
{0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"},
|
||||
{0x04020082, SetConfigInfoBlk4, "SetConfigInfoBlk4"},
|
||||
{0x04030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"},
|
||||
{0x04040042, nullptr, "GetLocalFriendCodeSeedData"},
|
||||
{0x04050000, nullptr, "GetLocalFriendCodeSeed"},
|
||||
{0x04060000, SecureInfoGetRegion, "SecureInfoGetRegion"},
|
||||
{0x04070000, nullptr, "SecureInfoGetByte101"},
|
||||
{0x04080042, nullptr, "SecureInfoGetSerialNo"},
|
||||
{0x04090000, nullptr, "UpdateConfigBlk00040003"},
|
||||
{0x08010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"},
|
||||
{0x08020082, SetConfigInfoBlk4, "SetConfigInfoBlk4"},
|
||||
{0x08030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"},
|
||||
{0x080400C2, nullptr, "CreateConfigInfoBlk"},
|
||||
{0x08050000, nullptr, "DeleteConfigNANDSavefile"},
|
||||
{0x08060000, FormatConfig, "FormatConfig"},
|
||||
{0x08080000, nullptr, "UpdateConfigBlk1"},
|
||||
{0x08090000, nullptr, "UpdateConfigBlk2"},
|
||||
{0x080A0000, nullptr, "UpdateConfigBlk3"},
|
||||
{0x080B0082, nullptr, "SetGetLocalFriendCodeSeedData"},
|
||||
{0x080C0042, nullptr, "SetLocalFriendCodeSeedSignature"},
|
||||
{0x080D0000, nullptr, "DeleteCreateNANDLocalFriendCodeSeed"},
|
||||
{0x080E0000, nullptr, "VerifySigLocalFriendCodeSeed"},
|
||||
{0x080F0042, nullptr, "GetLocalFriendCodeSeedData"},
|
||||
{0x08100000, nullptr, "GetLocalFriendCodeSeed"},
|
||||
{0x08110084, nullptr, "SetSecureInfo"},
|
||||
{0x08120000, nullptr, "DeleteCreateNANDSecureInfo"},
|
||||
{0x08130000, nullptr, "VerifySigSecureInfo"},
|
||||
{0x08140042, nullptr, "SecureInfoGetData"},
|
||||
{0x08150042, nullptr, "SecureInfoGetSignature"},
|
||||
{0x08160000, SecureInfoGetRegion, "SecureInfoGetRegion"},
|
||||
{0x08170000, nullptr, "SecureInfoGetByte101"},
|
||||
{0x08180042, nullptr, "SecureInfoGetSerialNo"},
|
||||
};
|
||||
|
||||
CFG_I_Interface::CFG_I_Interface() {
|
||||
|
@ -10,26 +10,26 @@ namespace CFG {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
// cfg common
|
||||
{0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"},
|
||||
{0x00020000, SecureInfoGetRegion, "SecureInfoGetRegion"},
|
||||
{0x00030040, GenHashConsoleUnique, "GenHashConsoleUnique"},
|
||||
{0x00040000, GetRegionCanadaUSA, "GetRegionCanadaUSA"},
|
||||
{0x00050000, GetSystemModel, "GetSystemModel"},
|
||||
{0x00060000, GetModelNintendo2DS, "GetModelNintendo2DS"},
|
||||
{0x00070040, nullptr, "WriteToFirstByteCfgSavegame"},
|
||||
{0x00080080, nullptr, "GoThroughTable"},
|
||||
{0x00090040, GetCountryCodeString, "GetCountryCodeString"},
|
||||
{0x000A0040, GetCountryCodeID, "GetCountryCodeID"},
|
||||
{0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"},
|
||||
{0x00020000, SecureInfoGetRegion, "SecureInfoGetRegion"},
|
||||
{0x00030040, GenHashConsoleUnique, "GenHashConsoleUnique"},
|
||||
{0x00040000, GetRegionCanadaUSA, "GetRegionCanadaUSA"},
|
||||
{0x00050000, GetSystemModel, "GetSystemModel"},
|
||||
{0x00060000, GetModelNintendo2DS, "GetModelNintendo2DS"},
|
||||
{0x00070040, nullptr, "WriteToFirstByteCfgSavegame"},
|
||||
{0x00080080, nullptr, "GoThroughTable"},
|
||||
{0x00090040, GetCountryCodeString, "GetCountryCodeString"},
|
||||
{0x000A0040, GetCountryCodeID, "GetCountryCodeID"},
|
||||
// cfg:s
|
||||
{0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"},
|
||||
{0x04020082, SetConfigInfoBlk4, "SetConfigInfoBlk4"},
|
||||
{0x04030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"},
|
||||
{0x04040042, nullptr, "GetLocalFriendCodeSeedData"},
|
||||
{0x04050000, nullptr, "GetLocalFriendCodeSeed"},
|
||||
{0x04060000, nullptr, "SecureInfoGetRegion"},
|
||||
{0x04070000, nullptr, "SecureInfoGetByte101"},
|
||||
{0x04080042, nullptr, "SecureInfoGetSerialNo"},
|
||||
{0x04090000, nullptr, "UpdateConfigBlk00040003"},
|
||||
{0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"},
|
||||
{0x04020082, SetConfigInfoBlk4, "SetConfigInfoBlk4"},
|
||||
{0x04030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"},
|
||||
{0x04040042, nullptr, "GetLocalFriendCodeSeedData"},
|
||||
{0x04050000, nullptr, "GetLocalFriendCodeSeed"},
|
||||
{0x04060000, nullptr, "SecureInfoGetRegion"},
|
||||
{0x04070000, nullptr, "SecureInfoGetByte101"},
|
||||
{0x04080042, nullptr, "SecureInfoGetSerialNo"},
|
||||
{0x04090000, nullptr, "UpdateConfigBlk00040003"},
|
||||
};
|
||||
|
||||
CFG_S_Interface::CFG_S_Interface() {
|
||||
|
@ -10,16 +10,16 @@ namespace CFG {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
// cfg common
|
||||
{0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"},
|
||||
{0x00020000, SecureInfoGetRegion, "SecureInfoGetRegion"},
|
||||
{0x00030040, GenHashConsoleUnique, "GenHashConsoleUnique"},
|
||||
{0x00040000, GetRegionCanadaUSA, "GetRegionCanadaUSA"},
|
||||
{0x00050000, GetSystemModel, "GetSystemModel"},
|
||||
{0x00060000, GetModelNintendo2DS, "GetModelNintendo2DS"},
|
||||
{0x00070040, nullptr, "WriteToFirstByteCfgSavegame"},
|
||||
{0x00080080, nullptr, "GoThroughTable"},
|
||||
{0x00090040, GetCountryCodeString, "GetCountryCodeString"},
|
||||
{0x000A0040, GetCountryCodeID, "GetCountryCodeID"},
|
||||
{0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"},
|
||||
{0x00020000, SecureInfoGetRegion, "SecureInfoGetRegion"},
|
||||
{0x00030040, GenHashConsoleUnique, "GenHashConsoleUnique"},
|
||||
{0x00040000, GetRegionCanadaUSA, "GetRegionCanadaUSA"},
|
||||
{0x00050000, GetSystemModel, "GetSystemModel"},
|
||||
{0x00060000, GetModelNintendo2DS, "GetModelNintendo2DS"},
|
||||
{0x00070040, nullptr, "WriteToFirstByteCfgSavegame"},
|
||||
{0x00080080, nullptr, "GoThroughTable"},
|
||||
{0x00090040, GetCountryCodeString, "GetCountryCodeString"},
|
||||
{0x000A0040, GetCountryCodeID, "GetCountryCodeID"},
|
||||
};
|
||||
|
||||
CFG_U_Interface::CFG_U_Interface() {
|
||||
|
@ -2,12 +2,12 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/hle/service/csnd_snd.h"
|
||||
#include <cstring>
|
||||
#include "common/alignment.h"
|
||||
#include "core/hle/hle.h"
|
||||
#include "core/hle/kernel/mutex.h"
|
||||
#include "core/hle/kernel/shared_memory.h"
|
||||
#include "core/hle/service/csnd_snd.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Namespace CSND_SND
|
||||
@ -15,18 +15,18 @@
|
||||
namespace CSND_SND {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00010140, Initialize, "Initialize"},
|
||||
{0x00020000, Shutdown, "Shutdown"},
|
||||
{0x00030040, ExecuteType0Commands, "ExecuteType0Commands"},
|
||||
{0x00040080, nullptr, "ExecuteType1Commands"},
|
||||
{0x00050000, AcquireSoundChannels, "AcquireSoundChannels"},
|
||||
{0x00060000, nullptr, "ReleaseSoundChannels"},
|
||||
{0x00070000, nullptr, "AcquireCaptureDevice"},
|
||||
{0x00080040, nullptr, "ReleaseCaptureDevice"},
|
||||
{0x00090082, nullptr, "FlushDataCache"},
|
||||
{0x000A0082, nullptr, "StoreDataCache"},
|
||||
{0x000B0082, nullptr, "InvalidateDataCache"},
|
||||
{0x000C0000, nullptr, "Reset"},
|
||||
{0x00010140, Initialize, "Initialize"},
|
||||
{0x00020000, Shutdown, "Shutdown"},
|
||||
{0x00030040, ExecuteType0Commands, "ExecuteType0Commands"},
|
||||
{0x00040080, nullptr, "ExecuteType1Commands"},
|
||||
{0x00050000, AcquireSoundChannels, "AcquireSoundChannels"},
|
||||
{0x00060000, nullptr, "ReleaseSoundChannels"},
|
||||
{0x00070000, nullptr, "AcquireCaptureDevice"},
|
||||
{0x00080040, nullptr, "ReleaseCaptureDevice"},
|
||||
{0x00090082, nullptr, "FlushDataCache"},
|
||||
{0x000A0082, nullptr, "StoreDataCache"},
|
||||
{0x000B0082, nullptr, "InvalidateDataCache"},
|
||||
{0x000C0000, nullptr, "Reset"},
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -44,9 +44,9 @@ void Initialize(Service::Interface* self) {
|
||||
|
||||
u32 size = Common::AlignUp(cmd_buff[1], Memory::PAGE_SIZE);
|
||||
using Kernel::MemoryPermission;
|
||||
shared_memory = Kernel::SharedMemory::Create(nullptr, size,
|
||||
MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
|
||||
0, Kernel::MemoryRegion::BASE, "CSND:SharedMemory");
|
||||
shared_memory = Kernel::SharedMemory::Create(nullptr, size, MemoryPermission::ReadWrite,
|
||||
MemoryPermission::ReadWrite, 0,
|
||||
Kernel::MemoryRegion::BASE, "CSND:SharedMemory");
|
||||
|
||||
mutex = Kernel::Mutex::Create(false);
|
||||
|
||||
@ -58,7 +58,7 @@ void Initialize(Service::Interface* self) {
|
||||
|
||||
void ExecuteType0Commands(Service::Interface* self) {
|
||||
u32* const cmd_buff = Kernel::GetCommandBuffer();
|
||||
u8* const ptr = shared_memory->GetPointer(cmd_buff[1]);
|
||||
u8* const ptr = shared_memory->GetPointer(cmd_buff[1]);
|
||||
|
||||
if (shared_memory != nullptr && ptr != nullptr) {
|
||||
Type0Command command;
|
||||
|
@ -25,7 +25,7 @@ struct Type0Command {
|
||||
u32 command_id;
|
||||
u32 finished;
|
||||
u32 flags;
|
||||
u8 parameters[20];
|
||||
u8 parameters[20];
|
||||
};
|
||||
|
||||
void Initialize(Service::Interface* self);
|
||||
|
@ -2,11 +2,11 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/dlp/dlp.h"
|
||||
#include "core/hle/service/dlp/dlp_clnt.h"
|
||||
#include "core/hle/service/dlp/dlp_fkcl.h"
|
||||
#include "core/hle/service/dlp/dlp_srvr.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service {
|
||||
namespace DLP {
|
||||
|
@ -8,8 +8,7 @@ namespace Service {
|
||||
namespace DLP {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x000100C3, nullptr, "Initialize"},
|
||||
{0x00110000, nullptr, "GetWirelessRebootPassphrase"},
|
||||
{0x000100C3, nullptr, "Initialize"}, {0x00110000, nullptr, "GetWirelessRebootPassphrase"},
|
||||
};
|
||||
|
||||
DLP_CLNT_Interface::DLP_CLNT_Interface() {
|
||||
|
@ -8,8 +8,7 @@ namespace Service {
|
||||
namespace DLP {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00010083, nullptr, "Initialize"},
|
||||
{0x000F0000, nullptr, "GetWirelessRebootPassphrase"},
|
||||
{0x00010083, nullptr, "Initialize"}, {0x000F0000, nullptr, "GetWirelessRebootPassphrase"},
|
||||
};
|
||||
|
||||
DLP_FKCL_Interface::DLP_FKCL_Interface() {
|
||||
|
@ -2,10 +2,10 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/hle/service/dlp/dlp_srvr.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/dlp/dlp_srvr.h"
|
||||
|
||||
namespace Service {
|
||||
namespace DLP {
|
||||
@ -20,10 +20,10 @@ static void unk_0x000E0040(Interface* self) {
|
||||
}
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00010183, nullptr, "Initialize"},
|
||||
{0x00020000, nullptr, "Finalize"},
|
||||
{0x000800C0, nullptr, "SendWirelessRebootPassphrase"},
|
||||
{0x000E0040, unk_0x000E0040, "unk_0x000E0040"},
|
||||
{0x00010183, nullptr, "Initialize"},
|
||||
{0x00020000, nullptr, "Finalize"},
|
||||
{0x000800C0, nullptr, "SendWirelessRebootPassphrase"},
|
||||
{0x000E0040, unk_0x000E0040, "unk_0x000E0040"},
|
||||
};
|
||||
|
||||
DLP_SRVR_Interface::DLP_SRVR_Interface() {
|
||||
|
@ -23,9 +23,7 @@ namespace DSP_DSP {
|
||||
static Kernel::SharedPtr<Kernel::Event> semaphore_event;
|
||||
|
||||
/// There are three types of interrupts
|
||||
enum class InterruptType {
|
||||
Zero, One, Pipe
|
||||
};
|
||||
enum class InterruptType { Zero, One, Pipe };
|
||||
constexpr size_t NUM_INTERRUPT_TYPE = 3;
|
||||
|
||||
class InterruptEvents final {
|
||||
@ -57,9 +55,8 @@ public:
|
||||
// Actual service implementation only has 6 'slots' for interrupts.
|
||||
constexpr size_t max_number_of_interrupt_events = 6;
|
||||
|
||||
size_t number = std::count_if(pipe.begin(), pipe.end(), [](const auto& evt) {
|
||||
return evt != nullptr;
|
||||
});
|
||||
size_t number =
|
||||
std::count_if(pipe.begin(), pipe.end(), [](const auto& evt) { return evt != nullptr; });
|
||||
|
||||
if (zero != nullptr)
|
||||
number++;
|
||||
@ -105,7 +102,8 @@ static void ConvertProcessAddressFromDspDram(Service::Interface* self) {
|
||||
cmd_buff[0] = IPC::MakeHeader(0xC, 2, 0);
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
|
||||
// TODO(merry): There is a per-region offset missing in this calculation (that seems to be always zero).
|
||||
// TODO(merry): There is a per-region offset missing in this calculation (that seems to be
|
||||
// always zero).
|
||||
cmd_buff[2] = (addr << 1) + (Memory::DSP_RAM_VADDR + 0x40000);
|
||||
|
||||
LOG_DEBUG(Service_DSP, "addr=0x%08X", addr);
|
||||
@ -126,15 +124,15 @@ static void ConvertProcessAddressFromDspDram(Service::Interface* self) {
|
||||
static void LoadComponent(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
|
||||
u32 size = cmd_buff[1];
|
||||
u32 prog_mask = cmd_buff[2];
|
||||
u32 data_mask = cmd_buff[3];
|
||||
u32 desc = cmd_buff[4];
|
||||
u32 buffer = cmd_buff[5];
|
||||
u32 size = cmd_buff[1];
|
||||
u32 prog_mask = cmd_buff[2];
|
||||
u32 data_mask = cmd_buff[3];
|
||||
u32 desc = cmd_buff[4];
|
||||
u32 buffer = cmd_buff[5];
|
||||
|
||||
cmd_buff[0] = IPC::MakeHeader(0x11, 2, 2);
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
cmd_buff[2] = 1; // Pretend that we actually loaded the DSP firmware
|
||||
cmd_buff[2] = 1; // Pretend that we actually loaded the DSP firmware
|
||||
cmd_buff[3] = desc;
|
||||
cmd_buff[4] = buffer;
|
||||
|
||||
@ -145,12 +143,15 @@ static void LoadComponent(Service::Interface* self) {
|
||||
std::vector<u8> component_data(size);
|
||||
Memory::ReadBlock(buffer, component_data.data(), component_data.size());
|
||||
|
||||
LOG_INFO(Service_DSP, "Firmware hash: %#" PRIx64, Common::ComputeHash64(component_data.data(), component_data.size()));
|
||||
LOG_INFO(Service_DSP, "Firmware hash: %#" PRIx64,
|
||||
Common::ComputeHash64(component_data.data(), component_data.size()));
|
||||
// Some versions of the firmware have the location of DSP structures listed here.
|
||||
ASSERT(size > 0x37C);
|
||||
LOG_INFO(Service_DSP, "Structures hash: %#" PRIx64, Common::ComputeHash64(component_data.data() + 0x340, 60));
|
||||
LOG_INFO(Service_DSP, "Structures hash: %#" PRIx64,
|
||||
Common::ComputeHash64(component_data.data() + 0x340, 60));
|
||||
|
||||
LOG_WARNING(Service_DSP, "(STUBBED) called size=0x%X, prog_mask=0x%08X, data_mask=0x%08X, buffer=0x%08X",
|
||||
LOG_WARNING(Service_DSP,
|
||||
"(STUBBED) called size=0x%X, prog_mask=0x%08X, data_mask=0x%08X, buffer=0x%08X",
|
||||
size, prog_mask, data_mask, buffer);
|
||||
}
|
||||
|
||||
@ -187,13 +188,14 @@ static void GetSemaphoreEventHandle(Service::Interface* self) {
|
||||
static void FlushDataCache(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
u32 address = cmd_buff[1];
|
||||
u32 size = cmd_buff[2];
|
||||
u32 size = cmd_buff[2];
|
||||
u32 process = cmd_buff[4];
|
||||
|
||||
cmd_buff[0] = IPC::MakeHeader(0x13, 1, 0);
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
|
||||
LOG_TRACE(Service_DSP, "called address=0x%08X, size=0x%X, process=0x%08X", address, size, process);
|
||||
LOG_TRACE(Service_DSP, "called address=0x%08X, size=0x%X, process=0x%08X", address, size,
|
||||
process);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -224,23 +226,29 @@ static void RegisterInterruptEvents(Service::Interface* self) {
|
||||
auto evt = Kernel::g_handle_table.Get<Kernel::Event>(cmd_buff[4]);
|
||||
|
||||
if (!evt) {
|
||||
LOG_INFO(Service_DSP, "Invalid event handle! type=%u, pipe=%u, event_handle=0x%08X", type_index, pipe_index, event_handle);
|
||||
LOG_INFO(Service_DSP, "Invalid event handle! type=%u, pipe=%u, event_handle=0x%08X",
|
||||
type_index, pipe_index, event_handle);
|
||||
ASSERT(false); // TODO: This should really be handled at an IPC translation layer.
|
||||
}
|
||||
|
||||
if (interrupt_events.HasTooManyEventsRegistered()) {
|
||||
LOG_INFO(Service_DSP, "Ran out of space to register interrupts (Attempted to register type=%u, pipe=%u, event_handle=0x%08X)",
|
||||
LOG_INFO(Service_DSP, "Ran out of space to register interrupts (Attempted to register "
|
||||
"type=%u, pipe=%u, event_handle=0x%08X)",
|
||||
type_index, pipe_index, event_handle);
|
||||
cmd_buff[1] = ResultCode(ErrorDescription::InvalidResultValue, ErrorModule::DSP, ErrorSummary::OutOfResource, ErrorLevel::Status).raw;
|
||||
cmd_buff[1] = ResultCode(ErrorDescription::InvalidResultValue, ErrorModule::DSP,
|
||||
ErrorSummary::OutOfResource, ErrorLevel::Status)
|
||||
.raw;
|
||||
return;
|
||||
}
|
||||
|
||||
interrupt_events.Get(type, pipe) = evt;
|
||||
LOG_INFO(Service_DSP, "Registered type=%u, pipe=%u, event_handle=0x%08X", type_index, pipe_index, event_handle);
|
||||
LOG_INFO(Service_DSP, "Registered type=%u, pipe=%u, event_handle=0x%08X", type_index,
|
||||
pipe_index, event_handle);
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
} else {
|
||||
interrupt_events.Get(type, pipe) = nullptr;
|
||||
LOG_INFO(Service_DSP, "Unregistered interrupt=%u, channel=%u, event_handle=0x%08X", type_index, pipe_index, event_handle);
|
||||
LOG_INFO(Service_DSP, "Unregistered interrupt=%u, channel=%u, event_handle=0x%08X",
|
||||
type_index, pipe_index, event_handle);
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
}
|
||||
}
|
||||
@ -282,13 +290,18 @@ static void WriteProcessPipe(Service::Interface* self) {
|
||||
DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(pipe_index);
|
||||
|
||||
if (IPC::StaticBufferDesc(size, 1) != cmd_buff[3]) {
|
||||
LOG_ERROR(Service_DSP, "IPC static buffer descriptor failed validation (0x%X). pipe=%u, size=0x%X, buffer=0x%08X", cmd_buff[3], pipe_index, size, buffer);
|
||||
LOG_ERROR(Service_DSP, "IPC static buffer descriptor failed validation (0x%X). pipe=%u, "
|
||||
"size=0x%X, buffer=0x%08X",
|
||||
cmd_buff[3], pipe_index, size, buffer);
|
||||
cmd_buff[0] = IPC::MakeHeader(0, 1, 0);
|
||||
cmd_buff[1] = ResultCode(ErrorDescription::OS_InvalidBufferDescriptor, ErrorModule::OS, ErrorSummary::WrongArgument, ErrorLevel::Permanent).raw;
|
||||
cmd_buff[1] = ResultCode(ErrorDescription::OS_InvalidBufferDescriptor, ErrorModule::OS,
|
||||
ErrorSummary::WrongArgument, ErrorLevel::Permanent)
|
||||
.raw;
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT_MSG(Memory::IsValidVirtualAddress(buffer), "Invalid Buffer: pipe=%u, size=0x%X, buffer=0x%08X", pipe, size, buffer);
|
||||
ASSERT_MSG(Memory::IsValidVirtualAddress(buffer),
|
||||
"Invalid Buffer: pipe=%u, size=0x%X, buffer=0x%08X", pipe, size, buffer);
|
||||
|
||||
std::vector<u8> message(size);
|
||||
for (u32 i = 0; i < size; i++) {
|
||||
@ -327,7 +340,9 @@ static void ReadPipeIfPossible(Service::Interface* self) {
|
||||
|
||||
DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(pipe_index);
|
||||
|
||||
ASSERT_MSG(Memory::IsValidVirtualAddress(addr), "Invalid addr: pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X", pipe, unknown, size, addr);
|
||||
ASSERT_MSG(Memory::IsValidVirtualAddress(addr),
|
||||
"Invalid addr: pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X", pipe, unknown,
|
||||
size, addr);
|
||||
|
||||
cmd_buff[0] = IPC::MakeHeader(0x10, 1, 2);
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
@ -343,7 +358,9 @@ static void ReadPipeIfPossible(Service::Interface* self) {
|
||||
cmd_buff[3] = IPC::StaticBufferDesc(size, 0);
|
||||
cmd_buff[4] = addr;
|
||||
|
||||
LOG_DEBUG(Service_DSP, "pipe=%u, unknown=0x%08X, size=0x%X, buffer=0x%08X, return cmd_buff[2]=0x%08X", pipe_index, unknown, size, addr, cmd_buff[2]);
|
||||
LOG_DEBUG(Service_DSP,
|
||||
"pipe=%u, unknown=0x%08X, size=0x%X, buffer=0x%08X, return cmd_buff[2]=0x%08X",
|
||||
pipe_index, unknown, size, addr, cmd_buff[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -367,7 +384,9 @@ static void ReadPipe(Service::Interface* self) {
|
||||
|
||||
DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(pipe_index);
|
||||
|
||||
ASSERT_MSG(Memory::IsValidVirtualAddress(addr), "Invalid addr: pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X", pipe, unknown, size, addr);
|
||||
ASSERT_MSG(Memory::IsValidVirtualAddress(addr),
|
||||
"Invalid addr: pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X", pipe, unknown,
|
||||
size, addr);
|
||||
|
||||
if (DSP::HLE::GetPipeReadableSize(pipe) >= size) {
|
||||
std::vector<u8> response = DSP::HLE::PipeRead(pipe, size);
|
||||
@ -384,7 +403,9 @@ static void ReadPipe(Service::Interface* self) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
LOG_DEBUG(Service_DSP, "pipe=%u, unknown=0x%08X, size=0x%X, buffer=0x%08X, return cmd_buff[2]=0x%08X", pipe_index, unknown, size, addr, cmd_buff[2]);
|
||||
LOG_DEBUG(Service_DSP,
|
||||
"pipe=%u, unknown=0x%08X, size=0x%X, buffer=0x%08X, return cmd_buff[2]=0x%08X",
|
||||
pipe_index, unknown, size, addr, cmd_buff[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -408,7 +429,8 @@ static void GetPipeReadableSize(Service::Interface* self) {
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
cmd_buff[2] = static_cast<u32>(DSP::HLE::GetPipeReadableSize(pipe));
|
||||
|
||||
LOG_DEBUG(Service_DSP, "pipe=%u, unknown=0x%08X, return cmd_buff[2]=0x%08X", pipe_index, unknown, cmd_buff[2]);
|
||||
LOG_DEBUG(Service_DSP, "pipe=%u, unknown=0x%08X, return cmd_buff[2]=0x%08X", pipe_index,
|
||||
unknown, cmd_buff[2]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -443,7 +465,7 @@ static void GetHeadphoneStatus(Service::Interface* self) {
|
||||
|
||||
cmd_buff[0] = IPC::MakeHeader(0x1F, 2, 0);
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
cmd_buff[2] = 0; // Not using headphones
|
||||
cmd_buff[2] = 0; // Not using headphones
|
||||
|
||||
LOG_DEBUG(Service_DSP, "called");
|
||||
}
|
||||
@ -466,7 +488,8 @@ static void RecvData(Service::Interface* self) {
|
||||
|
||||
ASSERT_MSG(register_number == 0, "Unknown register_number %u", register_number);
|
||||
|
||||
// Application reads this after requesting DSP shutdown, to verify the DSP has indeed shutdown or slept.
|
||||
// Application reads this after requesting DSP shutdown, to verify the DSP has indeed shutdown
|
||||
// or slept.
|
||||
|
||||
cmd_buff[0] = IPC::MakeHeader(0x1, 2, 0);
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
@ -512,39 +535,39 @@ static void RecvDataIsReady(Service::Interface* self) {
|
||||
}
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00010040, RecvData, "RecvData"},
|
||||
{0x00020040, RecvDataIsReady, "RecvDataIsReady"},
|
||||
{0x00030080, nullptr, "SendData"},
|
||||
{0x00040040, nullptr, "SendDataIsEmpty"},
|
||||
{0x000500C2, nullptr, "SendFifoEx"},
|
||||
{0x000600C0, nullptr, "RecvFifoEx"},
|
||||
{0x00070040, SetSemaphore, "SetSemaphore"},
|
||||
{0x00080000, nullptr, "GetSemaphore"},
|
||||
{0x00090040, nullptr, "ClearSemaphore"},
|
||||
{0x000A0040, nullptr, "MaskSemaphore"},
|
||||
{0x000B0000, nullptr, "CheckSemaphoreRequest"},
|
||||
{0x00010040, RecvData, "RecvData"},
|
||||
{0x00020040, RecvDataIsReady, "RecvDataIsReady"},
|
||||
{0x00030080, nullptr, "SendData"},
|
||||
{0x00040040, nullptr, "SendDataIsEmpty"},
|
||||
{0x000500C2, nullptr, "SendFifoEx"},
|
||||
{0x000600C0, nullptr, "RecvFifoEx"},
|
||||
{0x00070040, SetSemaphore, "SetSemaphore"},
|
||||
{0x00080000, nullptr, "GetSemaphore"},
|
||||
{0x00090040, nullptr, "ClearSemaphore"},
|
||||
{0x000A0040, nullptr, "MaskSemaphore"},
|
||||
{0x000B0000, nullptr, "CheckSemaphoreRequest"},
|
||||
{0x000C0040, ConvertProcessAddressFromDspDram, "ConvertProcessAddressFromDspDram"},
|
||||
{0x000D0082, WriteProcessPipe, "WriteProcessPipe"},
|
||||
{0x000E00C0, ReadPipe, "ReadPipe"},
|
||||
{0x000F0080, GetPipeReadableSize, "GetPipeReadableSize"},
|
||||
{0x001000C0, ReadPipeIfPossible, "ReadPipeIfPossible"},
|
||||
{0x001100C2, LoadComponent, "LoadComponent"},
|
||||
{0x00120000, nullptr, "UnloadComponent"},
|
||||
{0x00130082, FlushDataCache, "FlushDataCache"},
|
||||
{0x00140082, nullptr, "InvalidateDCache"},
|
||||
{0x00150082, RegisterInterruptEvents, "RegisterInterruptEvents"},
|
||||
{0x00160000, GetSemaphoreEventHandle, "GetSemaphoreEventHandle"},
|
||||
{0x00170040, SetSemaphoreMask, "SetSemaphoreMask"},
|
||||
{0x00180040, nullptr, "GetPhysicalAddress"},
|
||||
{0x00190040, nullptr, "GetVirtualAddress"},
|
||||
{0x001A0042, nullptr, "SetIirFilterI2S1_cmd1"},
|
||||
{0x001B0042, nullptr, "SetIirFilterI2S1_cmd2"},
|
||||
{0x001C0082, nullptr, "SetIirFilterEQ"},
|
||||
{0x001D00C0, nullptr, "ReadMultiEx_SPI2"},
|
||||
{0x001E00C2, nullptr, "WriteMultiEx_SPI2"},
|
||||
{0x001F0000, GetHeadphoneStatus, "GetHeadphoneStatus"},
|
||||
{0x00200040, nullptr, "ForceHeadphoneOut"},
|
||||
{0x00210000, nullptr, "GetIsDspOccupied"},
|
||||
{0x000D0082, WriteProcessPipe, "WriteProcessPipe"},
|
||||
{0x000E00C0, ReadPipe, "ReadPipe"},
|
||||
{0x000F0080, GetPipeReadableSize, "GetPipeReadableSize"},
|
||||
{0x001000C0, ReadPipeIfPossible, "ReadPipeIfPossible"},
|
||||
{0x001100C2, LoadComponent, "LoadComponent"},
|
||||
{0x00120000, nullptr, "UnloadComponent"},
|
||||
{0x00130082, FlushDataCache, "FlushDataCache"},
|
||||
{0x00140082, nullptr, "InvalidateDCache"},
|
||||
{0x00150082, RegisterInterruptEvents, "RegisterInterruptEvents"},
|
||||
{0x00160000, GetSemaphoreEventHandle, "GetSemaphoreEventHandle"},
|
||||
{0x00170040, SetSemaphoreMask, "SetSemaphoreMask"},
|
||||
{0x00180040, nullptr, "GetPhysicalAddress"},
|
||||
{0x00190040, nullptr, "GetVirtualAddress"},
|
||||
{0x001A0042, nullptr, "SetIirFilterI2S1_cmd1"},
|
||||
{0x001B0042, nullptr, "SetIirFilterI2S1_cmd2"},
|
||||
{0x001C0082, nullptr, "SetIirFilterEQ"},
|
||||
{0x001D00C0, nullptr, "ReadMultiEx_SPI2"},
|
||||
{0x001E00C2, nullptr, "WriteMultiEx_SPI2"},
|
||||
{0x001F0000, GetHeadphoneStatus, "GetHeadphoneStatus"},
|
||||
{0x00200040, nullptr, "ForceHeadphoneOut"},
|
||||
{0x00210000, nullptr, "GetIsDspOccupied"},
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -35,70 +35,70 @@ union ErrInfo {
|
||||
u8 specifier;
|
||||
|
||||
struct {
|
||||
u8 specifier; // 0x0
|
||||
u8 rev_high; // 0x1
|
||||
u16 rev_low; // 0x2
|
||||
RSL result_code; // 0x4
|
||||
u32 address; // 0x8
|
||||
INSERT_PADDING_BYTES(4); // 0xC
|
||||
u32 pid_low; // 0x10
|
||||
u32 pid_high; // 0x14
|
||||
u32 aid_low; // 0x18
|
||||
u32 aid_high; // 0x1C
|
||||
u8 specifier; // 0x0
|
||||
u8 rev_high; // 0x1
|
||||
u16 rev_low; // 0x2
|
||||
RSL result_code; // 0x4
|
||||
u32 address; // 0x8
|
||||
INSERT_PADDING_BYTES(4); // 0xC
|
||||
u32 pid_low; // 0x10
|
||||
u32 pid_high; // 0x14
|
||||
u32 aid_low; // 0x18
|
||||
u32 aid_high; // 0x1C
|
||||
} errtype1;
|
||||
|
||||
struct {
|
||||
u8 specifier; // 0x0
|
||||
u8 rev_high; // 0x1
|
||||
u16 rev_low; // 0x2
|
||||
INSERT_PADDING_BYTES(0xC); // 0x4
|
||||
u32 pid_low; // 0x10
|
||||
u32 pid_high; // 0x14
|
||||
u32 aid_low; // 0x18
|
||||
u32 aid_high; // 0x1C
|
||||
u8 error_type; // 0x20
|
||||
INSERT_PADDING_BYTES(3); // 0x21
|
||||
u32 fault_status_reg; // 0x24
|
||||
u32 fault_addr; // 0x28
|
||||
u32 fpexc; // 0x2C
|
||||
u32 finst; // 0x30
|
||||
u32 finst2; // 0x34
|
||||
INSERT_PADDING_BYTES(0x34); // 0x38
|
||||
u32 sp; // 0x6C
|
||||
u32 pc; // 0x70
|
||||
u32 lr; // 0x74
|
||||
u32 cpsr; // 0x78
|
||||
u8 specifier; // 0x0
|
||||
u8 rev_high; // 0x1
|
||||
u16 rev_low; // 0x2
|
||||
INSERT_PADDING_BYTES(0xC); // 0x4
|
||||
u32 pid_low; // 0x10
|
||||
u32 pid_high; // 0x14
|
||||
u32 aid_low; // 0x18
|
||||
u32 aid_high; // 0x1C
|
||||
u8 error_type; // 0x20
|
||||
INSERT_PADDING_BYTES(3); // 0x21
|
||||
u32 fault_status_reg; // 0x24
|
||||
u32 fault_addr; // 0x28
|
||||
u32 fpexc; // 0x2C
|
||||
u32 finst; // 0x30
|
||||
u32 finst2; // 0x34
|
||||
INSERT_PADDING_BYTES(0x34); // 0x38
|
||||
u32 sp; // 0x6C
|
||||
u32 pc; // 0x70
|
||||
u32 lr; // 0x74
|
||||
u32 cpsr; // 0x78
|
||||
} errtype3;
|
||||
|
||||
struct {
|
||||
u8 specifier; // 0x0
|
||||
u8 rev_high; // 0x1
|
||||
u16 rev_low; // 0x2
|
||||
RSL result_code; // 0x4
|
||||
INSERT_PADDING_BYTES(8); // 0x8
|
||||
u32 pid_low; // 0x10
|
||||
u32 pid_high; // 0x14
|
||||
u32 aid_low; // 0x18
|
||||
u32 aid_high; // 0x1C
|
||||
char debug_string1[0x2E]; // 0x20
|
||||
char debug_string2[0x2E]; // 0x4E
|
||||
u8 specifier; // 0x0
|
||||
u8 rev_high; // 0x1
|
||||
u16 rev_low; // 0x2
|
||||
RSL result_code; // 0x4
|
||||
INSERT_PADDING_BYTES(8); // 0x8
|
||||
u32 pid_low; // 0x10
|
||||
u32 pid_high; // 0x14
|
||||
u32 aid_low; // 0x18
|
||||
u32 aid_high; // 0x1C
|
||||
char debug_string1[0x2E]; // 0x20
|
||||
char debug_string2[0x2E]; // 0x4E
|
||||
} errtype4;
|
||||
};
|
||||
|
||||
enum {
|
||||
PrefetchAbort = 0,
|
||||
DataAbort = 1,
|
||||
UndefInstr = 2,
|
||||
VectorFP = 3
|
||||
};
|
||||
enum { PrefetchAbort = 0, DataAbort = 1, UndefInstr = 2, VectorFP = 3 };
|
||||
|
||||
static std::string GetErrInfo3Type(u8 type_code) {
|
||||
switch (type_code) {
|
||||
case PrefetchAbort: return "Prefetch Abort";
|
||||
case DataAbort: return "Data Abort";
|
||||
case UndefInstr: return "Undefined Instruction";
|
||||
case VectorFP: return "Vector Floating Point";
|
||||
default: return "unknown";
|
||||
case PrefetchAbort:
|
||||
return "Prefetch Abort";
|
||||
case DataAbort:
|
||||
return "Data Abort";
|
||||
case UndefInstr:
|
||||
return "Undefined Instruction";
|
||||
case VectorFP:
|
||||
return "Vector Floating Point";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,8 +110,7 @@ static void ThrowFatalError(Service::Interface* self) {
|
||||
|
||||
switch (errinfo->specifier) {
|
||||
case ErrSpecifier0:
|
||||
case ErrSpecifier1:
|
||||
{
|
||||
case ErrSpecifier1: {
|
||||
const auto& errtype = errinfo->errtype1;
|
||||
LOG_CRITICAL(Service_ERR, "PID: 0x%08X_0x%08X", errtype.pid_low, errtype.pid_high);
|
||||
LOG_CRITICAL(Service_ERR, "REV: %d", errtype.rev_low | (errtype.rev_high << 16));
|
||||
@ -119,15 +118,14 @@ static void ThrowFatalError(Service::Interface* self) {
|
||||
LOG_CRITICAL(Service_ERR, "ADR: 0x%08X", errtype.address);
|
||||
|
||||
LOG_CRITICAL(Service_ERR, "RSL: 0x%08X", errtype.result_code.raw);
|
||||
LOG_CRITICAL(Service_ERR, " Level: %u", errtype.result_code.level.Value());
|
||||
LOG_CRITICAL(Service_ERR, " Level: %u", errtype.result_code.level.Value());
|
||||
LOG_CRITICAL(Service_ERR, " Summary: %u", errtype.result_code.summary.Value());
|
||||
LOG_CRITICAL(Service_ERR, " Module: %u", errtype.result_code.module.Value());
|
||||
LOG_CRITICAL(Service_ERR, " Desc: %u", errtype.result_code.description.Value());
|
||||
LOG_CRITICAL(Service_ERR, " Module: %u", errtype.result_code.module.Value());
|
||||
LOG_CRITICAL(Service_ERR, " Desc: %u", errtype.result_code.description.Value());
|
||||
break;
|
||||
}
|
||||
|
||||
case ErrSpecifier3:
|
||||
{
|
||||
case ErrSpecifier3: {
|
||||
const auto& errtype = errinfo->errtype3;
|
||||
LOG_CRITICAL(Service_ERR, "PID: 0x%08X_0x%08X", errtype.pid_low, errtype.pid_high);
|
||||
LOG_CRITICAL(Service_ERR, "REV: %d", errtype.rev_low | (errtype.rev_high << 16));
|
||||
@ -154,18 +152,17 @@ static void ThrowFatalError(Service::Interface* self) {
|
||||
break;
|
||||
}
|
||||
|
||||
case ErrSpecifier4:
|
||||
{
|
||||
case ErrSpecifier4: {
|
||||
const auto& errtype = errinfo->errtype4;
|
||||
LOG_CRITICAL(Service_ERR, "PID: 0x%08X_0x%08X", errtype.pid_low, errtype.pid_high);
|
||||
LOG_CRITICAL(Service_ERR, "REV: %d", errtype.rev_low | (errtype.rev_high << 16));
|
||||
LOG_CRITICAL(Service_ERR, "AID: 0x%08X_0x%08X", errtype.aid_low, errtype.aid_high);
|
||||
|
||||
LOG_CRITICAL(Service_ERR, "RSL: 0x%08X", errtype.result_code.raw);
|
||||
LOG_CRITICAL(Service_ERR, " Level: %u", errtype.result_code.level.Value());
|
||||
LOG_CRITICAL(Service_ERR, " Level: %u", errtype.result_code.level.Value());
|
||||
LOG_CRITICAL(Service_ERR, " Summary: %u", errtype.result_code.summary.Value());
|
||||
LOG_CRITICAL(Service_ERR, " Module: %u", errtype.result_code.module.Value());
|
||||
LOG_CRITICAL(Service_ERR, " Desc: %u", errtype.result_code.description.Value());
|
||||
LOG_CRITICAL(Service_ERR, " Module: %u", errtype.result_code.module.Value());
|
||||
LOG_CRITICAL(Service_ERR, " Desc: %u", errtype.result_code.description.Value());
|
||||
|
||||
LOG_CRITICAL(Service_ERR, "%s", errtype.debug_string1);
|
||||
LOG_CRITICAL(Service_ERR, "%s", errtype.debug_string2);
|
||||
@ -176,9 +173,7 @@ static void ThrowFatalError(Service::Interface* self) {
|
||||
cmd_buff[1] = 0; // No error
|
||||
}
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00010800, ThrowFatalError, "ThrowFatalError"}
|
||||
};
|
||||
const Interface::FunctionInfo FunctionTable[] = {{0x00010800, ThrowFatalError, "ThrowFatalError"}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Interface class
|
||||
|
@ -4,10 +4,10 @@
|
||||
|
||||
#include "common/string_util.h"
|
||||
|
||||
#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/service/service.h"
|
||||
|
||||
namespace Service {
|
||||
namespace FRD {
|
||||
@ -43,7 +43,7 @@ void GetFriendKeyList(Service::Interface* self) {
|
||||
}
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
cmd_buff[2] = 0; // 0 friends
|
||||
cmd_buff[2] = 0; // 0 friends
|
||||
LOG_WARNING(Service_FRD, "(STUBBED) called, unknown=%d, frd_count=%d, frd_key_addr=0x%08X",
|
||||
unknown, frd_count, frd_key_addr);
|
||||
}
|
||||
@ -61,25 +61,27 @@ void GetFriendProfile(Service::Interface* self) {
|
||||
}
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
LOG_WARNING(Service_FRD, "(STUBBED) called, count=%d, frd_key_addr=0x%08X, profiles_addr=0x%08X",
|
||||
count, frd_key_addr, profiles_addr);
|
||||
LOG_WARNING(Service_FRD,
|
||||
"(STUBBED) called, count=%d, frd_key_addr=0x%08X, profiles_addr=0x%08X", count,
|
||||
frd_key_addr, profiles_addr);
|
||||
}
|
||||
|
||||
void GetFriendAttributeFlags(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
|
||||
u32 count = cmd_buff[1];
|
||||
u32 frd_key_addr = cmd_buff[3];
|
||||
u32 count = cmd_buff[1];
|
||||
u32 frd_key_addr = cmd_buff[3];
|
||||
u32 attr_flags_addr = cmd_buff[65];
|
||||
|
||||
for (u32 i = 0; i < count; ++i) {
|
||||
//TODO:(mailwl) figure out AttributeFlag size and zero all buffer. Assume 1 byte
|
||||
// TODO:(mailwl) figure out AttributeFlag size and zero all buffer. Assume 1 byte
|
||||
Memory::Write8(attr_flags_addr + i, 0);
|
||||
}
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
LOG_WARNING(Service_FRD, "(STUBBED) called, count=%d, frd_key_addr=0x%08X, attr_flags_addr=0x%08X",
|
||||
count, frd_key_addr, attr_flags_addr);
|
||||
LOG_WARNING(Service_FRD,
|
||||
"(STUBBED) called, count=%d, frd_key_addr=0x%08X, attr_flags_addr=0x%08X", count,
|
||||
frd_key_addr, attr_flags_addr);
|
||||
}
|
||||
|
||||
void GetMyFriendKey(Service::Interface* self) {
|
||||
|
@ -11,7 +11,7 @@ namespace FRD {
|
||||
// const Interface::FunctionInfo FunctionTable[] = { };
|
||||
|
||||
FRD_A_Interface::FRD_A_Interface() {
|
||||
//Register(FunctionTable);
|
||||
// Register(FunctionTable);
|
||||
}
|
||||
|
||||
} // namespace FRD
|
||||
|
@ -9,59 +9,59 @@ namespace Service {
|
||||
namespace FRD {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00010000, nullptr, "HasLoggedIn"},
|
||||
{0x00020000, nullptr, "IsOnline"},
|
||||
{0x00030000, nullptr, "Login"},
|
||||
{0x00040000, nullptr, "Logout"},
|
||||
{0x00050000, GetMyFriendKey, "GetMyFriendKey"},
|
||||
{0x00060000, nullptr, "GetMyPreference"},
|
||||
{0x00070000, nullptr, "GetMyProfile"},
|
||||
{0x00080000, GetMyPresence, "GetMyPresence"},
|
||||
{0x00090000, GetMyScreenName, "GetMyScreenName"},
|
||||
{0x000A0000, nullptr, "GetMyMii"},
|
||||
{0x000B0000, nullptr, "GetMyLocalAccountId"},
|
||||
{0x000C0000, nullptr, "GetMyPlayingGame"},
|
||||
{0x000D0000, nullptr, "GetMyFavoriteGame"},
|
||||
{0x000E0000, nullptr, "GetMyNcPrincipalId"},
|
||||
{0x000F0000, nullptr, "GetMyComment"},
|
||||
{0x00100040, nullptr, "GetMyPassword"},
|
||||
{0x00110080, GetFriendKeyList, "GetFriendKeyList"},
|
||||
{0x00120042, nullptr, "GetFriendPresence"},
|
||||
{0x00130142, nullptr, "GetFriendScreenName"},
|
||||
{0x00140044, nullptr, "GetFriendMii"},
|
||||
{0x00150042, GetFriendProfile, "GetFriendProfile"},
|
||||
{0x00160042, nullptr, "GetFriendRelationship"},
|
||||
{0x00010000, nullptr, "HasLoggedIn"},
|
||||
{0x00020000, nullptr, "IsOnline"},
|
||||
{0x00030000, nullptr, "Login"},
|
||||
{0x00040000, nullptr, "Logout"},
|
||||
{0x00050000, GetMyFriendKey, "GetMyFriendKey"},
|
||||
{0x00060000, nullptr, "GetMyPreference"},
|
||||
{0x00070000, nullptr, "GetMyProfile"},
|
||||
{0x00080000, GetMyPresence, "GetMyPresence"},
|
||||
{0x00090000, GetMyScreenName, "GetMyScreenName"},
|
||||
{0x000A0000, nullptr, "GetMyMii"},
|
||||
{0x000B0000, nullptr, "GetMyLocalAccountId"},
|
||||
{0x000C0000, nullptr, "GetMyPlayingGame"},
|
||||
{0x000D0000, nullptr, "GetMyFavoriteGame"},
|
||||
{0x000E0000, nullptr, "GetMyNcPrincipalId"},
|
||||
{0x000F0000, nullptr, "GetMyComment"},
|
||||
{0x00100040, nullptr, "GetMyPassword"},
|
||||
{0x00110080, GetFriendKeyList, "GetFriendKeyList"},
|
||||
{0x00120042, nullptr, "GetFriendPresence"},
|
||||
{0x00130142, nullptr, "GetFriendScreenName"},
|
||||
{0x00140044, nullptr, "GetFriendMii"},
|
||||
{0x00150042, GetFriendProfile, "GetFriendProfile"},
|
||||
{0x00160042, nullptr, "GetFriendRelationship"},
|
||||
{0x00170042, GetFriendAttributeFlags, "GetFriendAttributeFlags"},
|
||||
{0x00180044, nullptr, "GetFriendPlayingGame"},
|
||||
{0x00190042, nullptr, "GetFriendFavoriteGame"},
|
||||
{0x001A00C4, nullptr, "GetFriendInfo"},
|
||||
{0x001B0080, nullptr, "IsIncludedInFriendList"},
|
||||
{0x001C0042, nullptr, "UnscrambleLocalFriendCode"},
|
||||
{0x001D0002, nullptr, "UpdateGameModeDescription"},
|
||||
{0x001E02C2, nullptr, "UpdateGameMode"},
|
||||
{0x001F0042, nullptr, "SendInvitation"},
|
||||
{0x00200002, nullptr, "AttachToEventNotification"},
|
||||
{0x00210040, nullptr, "SetNotificationMask"},
|
||||
{0x00220040, nullptr, "GetEventNotification"},
|
||||
{0x00230000, nullptr, "GetLastResponseResult"},
|
||||
{0x00240040, nullptr, "PrincipalIdToFriendCode"},
|
||||
{0x00250080, nullptr, "FriendCodeToPrincipalId"},
|
||||
{0x00260080, nullptr, "IsValidFriendCode"},
|
||||
{0x00270040, nullptr, "ResultToErrorCode"},
|
||||
{0x00280244, nullptr, "RequestGameAuthentication"},
|
||||
{0x00290000, nullptr, "GetGameAuthenticationData"},
|
||||
{0x002A0204, nullptr, "RequestServiceLocator"},
|
||||
{0x002B0000, nullptr, "GetServiceLocatorData"},
|
||||
{0x002C0002, nullptr, "DetectNatProperties"},
|
||||
{0x002D0000, nullptr, "GetNatProperties"},
|
||||
{0x002E0000, nullptr, "GetServerTimeInterval"},
|
||||
{0x002F0040, nullptr, "AllowHalfAwake"},
|
||||
{0x00300000, nullptr, "GetServerTypes"},
|
||||
{0x00310082, nullptr, "GetFriendComment"},
|
||||
{0x00320042, nullptr, "SetClientSdkVersion"},
|
||||
{0x00330000, nullptr, "GetMyApproachContext"},
|
||||
{0x00340046, nullptr, "AddFriendWithApproach"},
|
||||
{0x00350082, nullptr, "DecryptApproachContext"},
|
||||
{0x00180044, nullptr, "GetFriendPlayingGame"},
|
||||
{0x00190042, nullptr, "GetFriendFavoriteGame"},
|
||||
{0x001A00C4, nullptr, "GetFriendInfo"},
|
||||
{0x001B0080, nullptr, "IsIncludedInFriendList"},
|
||||
{0x001C0042, nullptr, "UnscrambleLocalFriendCode"},
|
||||
{0x001D0002, nullptr, "UpdateGameModeDescription"},
|
||||
{0x001E02C2, nullptr, "UpdateGameMode"},
|
||||
{0x001F0042, nullptr, "SendInvitation"},
|
||||
{0x00200002, nullptr, "AttachToEventNotification"},
|
||||
{0x00210040, nullptr, "SetNotificationMask"},
|
||||
{0x00220040, nullptr, "GetEventNotification"},
|
||||
{0x00230000, nullptr, "GetLastResponseResult"},
|
||||
{0x00240040, nullptr, "PrincipalIdToFriendCode"},
|
||||
{0x00250080, nullptr, "FriendCodeToPrincipalId"},
|
||||
{0x00260080, nullptr, "IsValidFriendCode"},
|
||||
{0x00270040, nullptr, "ResultToErrorCode"},
|
||||
{0x00280244, nullptr, "RequestGameAuthentication"},
|
||||
{0x00290000, nullptr, "GetGameAuthenticationData"},
|
||||
{0x002A0204, nullptr, "RequestServiceLocator"},
|
||||
{0x002B0000, nullptr, "GetServiceLocatorData"},
|
||||
{0x002C0002, nullptr, "DetectNatProperties"},
|
||||
{0x002D0000, nullptr, "GetNatProperties"},
|
||||
{0x002E0000, nullptr, "GetServerTimeInterval"},
|
||||
{0x002F0040, nullptr, "AllowHalfAwake"},
|
||||
{0x00300000, nullptr, "GetServerTypes"},
|
||||
{0x00310082, nullptr, "GetFriendComment"},
|
||||
{0x00320042, nullptr, "SetClientSdkVersion"},
|
||||
{0x00330000, nullptr, "GetMyApproachContext"},
|
||||
{0x00340046, nullptr, "AddFriendWithApproach"},
|
||||
{0x00350082, nullptr, "DecryptApproachContext"},
|
||||
};
|
||||
|
||||
FRD_U_Interface::FRD_U_Interface() {
|
||||
|
@ -3,9 +3,9 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <system_error>
|
||||
#include <type_traits>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
@ -25,25 +25,25 @@
|
||||
#include "core/file_sys/directory_backend.h"
|
||||
#include "core/file_sys/file_backend.h"
|
||||
#include "core/hle/hle.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/fs/archive.h"
|
||||
#include "core/hle/service/fs/fs_user.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
// Specializes std::hash for ArchiveIdCode, so that we can use it in std::unordered_map.
|
||||
// Workaroung for libstdc++ bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<Service::FS::ArchiveIdCode> {
|
||||
typedef Service::FS::ArchiveIdCode argument_type;
|
||||
typedef std::size_t result_type;
|
||||
template <>
|
||||
struct hash<Service::FS::ArchiveIdCode> {
|
||||
typedef Service::FS::ArchiveIdCode argument_type;
|
||||
typedef std::size_t result_type;
|
||||
|
||||
result_type operator()(const argument_type& id_code) const {
|
||||
typedef std::underlying_type<argument_type>::type Type;
|
||||
return std::hash<Type>()(static_cast<Type>(id_code));
|
||||
}
|
||||
};
|
||||
result_type operator()(const argument_type& id_code) const {
|
||||
typedef std::underlying_type<argument_type>::type Type;
|
||||
return std::hash<Type>()(static_cast<Type>(id_code));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// TODO(Subv): Confirm length of these strings
|
||||
@ -56,197 +56,193 @@ namespace FS {
|
||||
// TODO: Verify code
|
||||
/// Returned when a function is passed an invalid handle.
|
||||
const ResultCode ERR_INVALID_HANDLE(ErrorDescription::InvalidHandle, ErrorModule::FS,
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
|
||||
|
||||
/// Returned when a function is passed an invalid archive handle.
|
||||
const ResultCode ERR_INVALID_ARCHIVE_HANDLE(ErrorDescription::FS_ArchiveNotMounted, ErrorModule::FS,
|
||||
ErrorSummary::NotFound, ErrorLevel::Status); // 0xC8804465
|
||||
ErrorSummary::NotFound,
|
||||
ErrorLevel::Status); // 0xC8804465
|
||||
|
||||
// Command to access archive file
|
||||
enum class FileCommand : u32 {
|
||||
Dummy1 = 0x000100C6,
|
||||
Control = 0x040100C4,
|
||||
OpenSubFile = 0x08010100,
|
||||
Read = 0x080200C2,
|
||||
Write = 0x08030102,
|
||||
GetSize = 0x08040000,
|
||||
SetSize = 0x08050080,
|
||||
GetAttributes = 0x08060000,
|
||||
SetAttributes = 0x08070040,
|
||||
Close = 0x08080000,
|
||||
Flush = 0x08090000,
|
||||
SetPriority = 0x080A0040,
|
||||
GetPriority = 0x080B0000,
|
||||
OpenLinkFile = 0x080C0000,
|
||||
Dummy1 = 0x000100C6,
|
||||
Control = 0x040100C4,
|
||||
OpenSubFile = 0x08010100,
|
||||
Read = 0x080200C2,
|
||||
Write = 0x08030102,
|
||||
GetSize = 0x08040000,
|
||||
SetSize = 0x08050080,
|
||||
GetAttributes = 0x08060000,
|
||||
SetAttributes = 0x08070040,
|
||||
Close = 0x08080000,
|
||||
Flush = 0x08090000,
|
||||
SetPriority = 0x080A0040,
|
||||
GetPriority = 0x080B0000,
|
||||
OpenLinkFile = 0x080C0000,
|
||||
};
|
||||
|
||||
// Command to access directory
|
||||
enum class DirectoryCommand : u32 {
|
||||
Dummy1 = 0x000100C6,
|
||||
Control = 0x040100C4,
|
||||
Read = 0x08010042,
|
||||
Close = 0x08020000,
|
||||
Dummy1 = 0x000100C6,
|
||||
Control = 0x040100C4,
|
||||
Read = 0x08010042,
|
||||
Close = 0x08020000,
|
||||
};
|
||||
|
||||
File::File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path & path)
|
||||
: path(path), priority(0), backend(std::move(backend)) {}
|
||||
File::File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path)
|
||||
: path(path), priority(0), backend(std::move(backend)) {
|
||||
}
|
||||
|
||||
File::~File() {}
|
||||
File::~File() {
|
||||
}
|
||||
|
||||
ResultVal<bool> File::SyncRequest() {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
FileCommand cmd = static_cast<FileCommand>(cmd_buff[0]);
|
||||
switch (cmd) {
|
||||
|
||||
// Read from file...
|
||||
case FileCommand::Read:
|
||||
{
|
||||
u64 offset = cmd_buff[1] | ((u64)cmd_buff[2]) << 32;
|
||||
u32 length = cmd_buff[3];
|
||||
u32 address = cmd_buff[5];
|
||||
LOG_TRACE(Service_FS, "Read %s %s: offset=0x%llx length=%d address=0x%x",
|
||||
GetTypeName().c_str(), GetName().c_str(), offset, length, address);
|
||||
// Read from file...
|
||||
case FileCommand::Read: {
|
||||
u64 offset = cmd_buff[1] | ((u64)cmd_buff[2]) << 32;
|
||||
u32 length = cmd_buff[3];
|
||||
u32 address = cmd_buff[5];
|
||||
LOG_TRACE(Service_FS, "Read %s %s: offset=0x%llx length=%d address=0x%x",
|
||||
GetTypeName().c_str(), GetName().c_str(), offset, length, address);
|
||||
|
||||
if (offset + length > backend->GetSize()) {
|
||||
LOG_ERROR(Service_FS, "Reading from out of bounds offset=0x%llX length=0x%08X file_size=0x%llX",
|
||||
offset, length, backend->GetSize());
|
||||
}
|
||||
|
||||
std::vector<u8> data(length);
|
||||
ResultVal<size_t> read = backend->Read(offset, data.size(), data.data());
|
||||
if (read.Failed()) {
|
||||
cmd_buff[1] = read.Code().raw;
|
||||
return read.Code();
|
||||
}
|
||||
Memory::WriteBlock(address, data.data(), *read);
|
||||
cmd_buff[2] = static_cast<u32>(*read);
|
||||
break;
|
||||
if (offset + length > backend->GetSize()) {
|
||||
LOG_ERROR(Service_FS,
|
||||
"Reading from out of bounds offset=0x%llX length=0x%08X file_size=0x%llX",
|
||||
offset, length, backend->GetSize());
|
||||
}
|
||||
|
||||
// Write to file...
|
||||
case FileCommand::Write:
|
||||
{
|
||||
u64 offset = cmd_buff[1] | ((u64)cmd_buff[2]) << 32;
|
||||
u32 length = cmd_buff[3];
|
||||
u32 flush = cmd_buff[4];
|
||||
u32 address = cmd_buff[6];
|
||||
LOG_TRACE(Service_FS, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x",
|
||||
GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush);
|
||||
|
||||
std::vector<u8> data(length);
|
||||
Memory::ReadBlock(address, data.data(), data.size());
|
||||
ResultVal<size_t> written = backend->Write(offset, data.size(), flush != 0, data.data());
|
||||
if (written.Failed()) {
|
||||
cmd_buff[1] = written.Code().raw;
|
||||
return written.Code();
|
||||
}
|
||||
cmd_buff[2] = static_cast<u32>(*written);
|
||||
break;
|
||||
std::vector<u8> data(length);
|
||||
ResultVal<size_t> read = backend->Read(offset, data.size(), data.data());
|
||||
if (read.Failed()) {
|
||||
cmd_buff[1] = read.Code().raw;
|
||||
return read.Code();
|
||||
}
|
||||
Memory::WriteBlock(address, data.data(), *read);
|
||||
cmd_buff[2] = static_cast<u32>(*read);
|
||||
break;
|
||||
}
|
||||
|
||||
case FileCommand::GetSize:
|
||||
{
|
||||
LOG_TRACE(Service_FS, "GetSize %s %s", GetTypeName().c_str(), GetName().c_str());
|
||||
u64 size = backend->GetSize();
|
||||
cmd_buff[2] = (u32)size;
|
||||
cmd_buff[3] = size >> 32;
|
||||
break;
|
||||
// Write to file...
|
||||
case FileCommand::Write: {
|
||||
u64 offset = cmd_buff[1] | ((u64)cmd_buff[2]) << 32;
|
||||
u32 length = cmd_buff[3];
|
||||
u32 flush = cmd_buff[4];
|
||||
u32 address = cmd_buff[6];
|
||||
LOG_TRACE(Service_FS, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x",
|
||||
GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush);
|
||||
|
||||
std::vector<u8> data(length);
|
||||
Memory::ReadBlock(address, data.data(), data.size());
|
||||
ResultVal<size_t> written = backend->Write(offset, data.size(), flush != 0, data.data());
|
||||
if (written.Failed()) {
|
||||
cmd_buff[1] = written.Code().raw;
|
||||
return written.Code();
|
||||
}
|
||||
cmd_buff[2] = static_cast<u32>(*written);
|
||||
break;
|
||||
}
|
||||
|
||||
case FileCommand::SetSize:
|
||||
{
|
||||
u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32);
|
||||
LOG_TRACE(Service_FS, "SetSize %s %s size=%llu",
|
||||
GetTypeName().c_str(), GetName().c_str(), size);
|
||||
backend->SetSize(size);
|
||||
break;
|
||||
}
|
||||
case FileCommand::GetSize: {
|
||||
LOG_TRACE(Service_FS, "GetSize %s %s", GetTypeName().c_str(), GetName().c_str());
|
||||
u64 size = backend->GetSize();
|
||||
cmd_buff[2] = (u32)size;
|
||||
cmd_buff[3] = size >> 32;
|
||||
break;
|
||||
}
|
||||
|
||||
case FileCommand::Close:
|
||||
{
|
||||
LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
|
||||
backend->Close();
|
||||
break;
|
||||
}
|
||||
case FileCommand::SetSize: {
|
||||
u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32);
|
||||
LOG_TRACE(Service_FS, "SetSize %s %s size=%llu", GetTypeName().c_str(), GetName().c_str(),
|
||||
size);
|
||||
backend->SetSize(size);
|
||||
break;
|
||||
}
|
||||
|
||||
case FileCommand::Flush:
|
||||
{
|
||||
LOG_TRACE(Service_FS, "Flush");
|
||||
backend->Flush();
|
||||
break;
|
||||
}
|
||||
case FileCommand::Close: {
|
||||
LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
|
||||
backend->Close();
|
||||
break;
|
||||
}
|
||||
|
||||
case FileCommand::OpenLinkFile:
|
||||
{
|
||||
LOG_WARNING(Service_FS, "(STUBBED) File command OpenLinkFile %s", GetName().c_str());
|
||||
cmd_buff[3] = Kernel::g_handle_table.Create(this).ValueOr(INVALID_HANDLE);
|
||||
break;
|
||||
}
|
||||
case FileCommand::Flush: {
|
||||
LOG_TRACE(Service_FS, "Flush");
|
||||
backend->Flush();
|
||||
break;
|
||||
}
|
||||
|
||||
case FileCommand::SetPriority:
|
||||
{
|
||||
priority = cmd_buff[1];
|
||||
LOG_TRACE(Service_FS, "SetPriority %u", priority);
|
||||
break;
|
||||
}
|
||||
case FileCommand::OpenLinkFile: {
|
||||
LOG_WARNING(Service_FS, "(STUBBED) File command OpenLinkFile %s", GetName().c_str());
|
||||
cmd_buff[3] = Kernel::g_handle_table.Create(this).ValueOr(INVALID_HANDLE);
|
||||
break;
|
||||
}
|
||||
|
||||
case FileCommand::GetPriority:
|
||||
{
|
||||
cmd_buff[2] = priority;
|
||||
LOG_TRACE(Service_FS, "GetPriority");
|
||||
break;
|
||||
}
|
||||
case FileCommand::SetPriority: {
|
||||
priority = cmd_buff[1];
|
||||
LOG_TRACE(Service_FS, "SetPriority %u", priority);
|
||||
break;
|
||||
}
|
||||
|
||||
// Unknown command...
|
||||
default:
|
||||
LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd);
|
||||
ResultCode error = UnimplementedFunction(ErrorModule::FS);
|
||||
cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
|
||||
return error;
|
||||
case FileCommand::GetPriority: {
|
||||
cmd_buff[2] = priority;
|
||||
LOG_TRACE(Service_FS, "GetPriority");
|
||||
break;
|
||||
}
|
||||
|
||||
// Unknown command...
|
||||
default:
|
||||
LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd);
|
||||
ResultCode error = UnimplementedFunction(ErrorModule::FS);
|
||||
cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
|
||||
return error;
|
||||
}
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
return MakeResult<bool>(false);
|
||||
}
|
||||
|
||||
Directory::Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path & path)
|
||||
: path(path), backend(std::move(backend)) {}
|
||||
Directory::Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend,
|
||||
const FileSys::Path& path)
|
||||
: path(path), backend(std::move(backend)) {
|
||||
}
|
||||
|
||||
Directory::~Directory() {}
|
||||
Directory::~Directory() {
|
||||
}
|
||||
|
||||
ResultVal<bool> Directory::SyncRequest() {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
DirectoryCommand cmd = static_cast<DirectoryCommand>(cmd_buff[0]);
|
||||
switch (cmd) {
|
||||
|
||||
// Read from directory...
|
||||
case DirectoryCommand::Read:
|
||||
{
|
||||
u32 count = cmd_buff[1];
|
||||
u32 address = cmd_buff[3];
|
||||
std::vector<FileSys::Entry> entries(count);
|
||||
LOG_TRACE(Service_FS, "Read %s %s: count=%d",
|
||||
GetTypeName().c_str(), GetName().c_str(), count);
|
||||
// Read from directory...
|
||||
case DirectoryCommand::Read: {
|
||||
u32 count = cmd_buff[1];
|
||||
u32 address = cmd_buff[3];
|
||||
std::vector<FileSys::Entry> entries(count);
|
||||
LOG_TRACE(Service_FS, "Read %s %s: count=%d", GetTypeName().c_str(), GetName().c_str(),
|
||||
count);
|
||||
|
||||
// Number of entries actually read
|
||||
u32 read = backend->Read(entries.size(), entries.data());
|
||||
cmd_buff[2] = read;
|
||||
Memory::WriteBlock(address, entries.data(), read * sizeof(FileSys::Entry));
|
||||
break;
|
||||
}
|
||||
// Number of entries actually read
|
||||
u32 read = backend->Read(entries.size(), entries.data());
|
||||
cmd_buff[2] = read;
|
||||
Memory::WriteBlock(address, entries.data(), read * sizeof(FileSys::Entry));
|
||||
break;
|
||||
}
|
||||
|
||||
case DirectoryCommand::Close:
|
||||
{
|
||||
LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
|
||||
backend->Close();
|
||||
break;
|
||||
}
|
||||
case DirectoryCommand::Close: {
|
||||
LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str());
|
||||
backend->Close();
|
||||
break;
|
||||
}
|
||||
|
||||
// Unknown command...
|
||||
default:
|
||||
LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd);
|
||||
ResultCode error = UnimplementedFunction(ErrorModule::FS);
|
||||
cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
|
||||
return MakeResult<bool>(false);
|
||||
// Unknown command...
|
||||
default:
|
||||
LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd);
|
||||
ResultCode error = UnimplementedFunction(ErrorModule::FS);
|
||||
cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that.
|
||||
return MakeResult<bool>(false);
|
||||
}
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
return MakeResult<bool>(false);
|
||||
@ -280,8 +276,8 @@ ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archi
|
||||
auto itr = id_code_map.find(id_code);
|
||||
if (itr == id_code_map.end()) {
|
||||
// TODO: Verify error against hardware
|
||||
return ResultCode(ErrorDescription::NotFound, ErrorModule::FS,
|
||||
ErrorSummary::NotFound, ErrorLevel::Permanent);
|
||||
return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, ErrorSummary::NotFound,
|
||||
ErrorLevel::Permanent);
|
||||
}
|
||||
|
||||
CASCADE_RESULT(std::unique_ptr<ArchiveBackend> res, itr->second->Open(archive_path));
|
||||
@ -303,19 +299,22 @@ ResultCode CloseArchive(ArchiveHandle handle) {
|
||||
|
||||
// TODO(yuriks): This might be what the fs:REG service is for. See the Register/Unregister calls in
|
||||
// http://3dbrew.org/wiki/Filesystem_services#ProgramRegistry_service_.22fs:REG.22
|
||||
ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factory, ArchiveIdCode id_code) {
|
||||
ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factory,
|
||||
ArchiveIdCode id_code) {
|
||||
auto result = id_code_map.emplace(id_code, std::move(factory));
|
||||
|
||||
bool inserted = result.second;
|
||||
ASSERT_MSG(inserted, "Tried to register more than one archive with same id code");
|
||||
|
||||
auto& archive = result.first->second;
|
||||
LOG_DEBUG(Service_FS, "Registered archive %s with id code 0x%08X", archive->GetName().c_str(), id_code);
|
||||
LOG_DEBUG(Service_FS, "Registered archive %s with id code 0x%08X", archive->GetName().c_str(),
|
||||
id_code);
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultVal<Kernel::SharedPtr<File>> OpenFileFromArchive(ArchiveHandle archive_handle,
|
||||
const FileSys::Path& path, const FileSys::Mode mode) {
|
||||
const FileSys::Path& path,
|
||||
const FileSys::Mode mode) {
|
||||
ArchiveBackend* archive = GetArchive(archive_handle);
|
||||
if (archive == nullptr)
|
||||
return ERR_INVALID_ARCHIVE_HANDLE;
|
||||
@ -336,8 +335,10 @@ ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Pa
|
||||
return archive->DeleteFile(path);
|
||||
}
|
||||
|
||||
ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path,
|
||||
ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path) {
|
||||
ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle,
|
||||
const FileSys::Path& src_path,
|
||||
ArchiveHandle dest_archive_handle,
|
||||
const FileSys::Path& dest_path) {
|
||||
ArchiveBackend* src_archive = GetArchive(src_archive_handle);
|
||||
ArchiveBackend* dest_archive = GetArchive(dest_archive_handle);
|
||||
if (src_archive == nullptr || dest_archive == nullptr)
|
||||
@ -368,7 +369,8 @@ ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSy
|
||||
ErrorSummary::Canceled, ErrorLevel::Status);
|
||||
}
|
||||
|
||||
ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path, u64 file_size) {
|
||||
ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path,
|
||||
u64 file_size) {
|
||||
ArchiveBackend* archive = GetArchive(archive_handle);
|
||||
if (archive == nullptr)
|
||||
return ERR_INVALID_ARCHIVE_HANDLE;
|
||||
@ -387,8 +389,10 @@ ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSy
|
||||
ErrorSummary::Canceled, ErrorLevel::Status);
|
||||
}
|
||||
|
||||
ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path,
|
||||
ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path) {
|
||||
ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle,
|
||||
const FileSys::Path& src_path,
|
||||
ArchiveHandle dest_archive_handle,
|
||||
const FileSys::Path& dest_path) {
|
||||
ArchiveBackend* src_archive = GetArchive(src_archive_handle);
|
||||
ArchiveBackend* dest_archive = GetArchive(dest_archive_handle);
|
||||
if (src_archive == nullptr || dest_archive == nullptr)
|
||||
@ -409,15 +413,15 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, cons
|
||||
}
|
||||
|
||||
ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle,
|
||||
const FileSys::Path& path) {
|
||||
const FileSys::Path& path) {
|
||||
ArchiveBackend* archive = GetArchive(archive_handle);
|
||||
if (archive == nullptr)
|
||||
return ERR_INVALID_ARCHIVE_HANDLE;
|
||||
|
||||
std::unique_ptr<FileSys::DirectoryBackend> backend = archive->OpenDirectory(path);
|
||||
if (backend == nullptr) {
|
||||
return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS,
|
||||
ErrorSummary::NotFound, ErrorLevel::Permanent);
|
||||
return ResultCode(ErrorDescription::FS_NotFound, ErrorModule::FS, ErrorSummary::NotFound,
|
||||
ErrorLevel::Permanent);
|
||||
}
|
||||
|
||||
auto directory = Kernel::SharedPtr<Directory>(new Directory(std::move(backend), path));
|
||||
@ -431,7 +435,8 @@ ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle) {
|
||||
return MakeResult<u64>(archive->GetFreeBytes());
|
||||
}
|
||||
|
||||
ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::ArchiveFormatInfo& format_info, const FileSys::Path& path) {
|
||||
ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::ArchiveFormatInfo& format_info,
|
||||
const FileSys::Path& path) {
|
||||
auto archive_itr = id_code_map.find(id_code);
|
||||
if (archive_itr == id_code_map.end()) {
|
||||
return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
|
||||
@ -440,7 +445,8 @@ ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::ArchiveFormatInfo
|
||||
return archive_itr->second->Format(path, format_info);
|
||||
}
|
||||
|
||||
ResultVal<FileSys::ArchiveFormatInfo> GetArchiveFormatInfo(ArchiveIdCode id_code, FileSys::Path& archive_path) {
|
||||
ResultVal<FileSys::ArchiveFormatInfo> GetArchiveFormatInfo(ArchiveIdCode id_code,
|
||||
FileSys::Path& archive_path) {
|
||||
auto archive = id_code_map.find(id_code);
|
||||
if (archive == id_code_map.end()) {
|
||||
return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
|
||||
@ -449,11 +455,14 @@ ResultVal<FileSys::ArchiveFormatInfo> GetArchiveFormatInfo(ArchiveIdCode id_code
|
||||
return archive->second->GetFormatInfo(archive_path);
|
||||
}
|
||||
|
||||
ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size, const FileSys::ArchiveFormatInfo& format_info) {
|
||||
ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer,
|
||||
u32 icon_size, const FileSys::ArchiveFormatInfo& format_info) {
|
||||
// Construct the binary path to the archive first
|
||||
FileSys::Path path = FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low);
|
||||
FileSys::Path path =
|
||||
FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low);
|
||||
|
||||
auto archive = id_code_map.find(media_type == MediaType::NAND ? ArchiveIdCode::SharedExtSaveData : ArchiveIdCode::ExtSaveData);
|
||||
auto archive = id_code_map.find(media_type == MediaType::NAND ? ArchiveIdCode::SharedExtSaveData
|
||||
: ArchiveIdCode::ExtSaveData);
|
||||
|
||||
if (archive == id_code_map.end()) {
|
||||
return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
|
||||
@ -476,7 +485,8 @@ ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon
|
||||
|
||||
ResultCode DeleteExtSaveData(MediaType media_type, u32 high, u32 low) {
|
||||
// Construct the binary path to the archive first
|
||||
FileSys::Path path = FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low);
|
||||
FileSys::Path path =
|
||||
FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low);
|
||||
|
||||
std::string media_type_directory;
|
||||
if (media_type == MediaType::NAND) {
|
||||
@ -489,7 +499,8 @@ ResultCode DeleteExtSaveData(MediaType media_type, u32 high, u32 low) {
|
||||
}
|
||||
|
||||
// Delete all directories (/user, /boss) and the icon file.
|
||||
std::string base_path = FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND);
|
||||
std::string base_path =
|
||||
FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND);
|
||||
std::string extsavedata_path = FileSys::GetExtSaveDataPath(base_path, path);
|
||||
if (FileUtil::Exists(extsavedata_path) && !FileUtil::DeleteDirRecursively(extsavedata_path))
|
||||
return ResultCode(-1); // TODO(Subv): Find the right error code
|
||||
@ -530,30 +541,36 @@ void RegisterArchiveTypes() {
|
||||
if (sdmc_factory->Initialize())
|
||||
RegisterArchiveType(std::move(sdmc_factory), ArchiveIdCode::SDMC);
|
||||
else
|
||||
LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str());
|
||||
LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s",
|
||||
sdmc_directory.c_str());
|
||||
|
||||
// Create the SaveData archive
|
||||
auto savedata_factory = std::make_unique<FileSys::ArchiveFactory_SaveData>(sdmc_directory);
|
||||
RegisterArchiveType(std::move(savedata_factory), ArchiveIdCode::SaveData);
|
||||
|
||||
auto extsavedata_factory = std::make_unique<FileSys::ArchiveFactory_ExtSaveData>(sdmc_directory, false);
|
||||
auto extsavedata_factory =
|
||||
std::make_unique<FileSys::ArchiveFactory_ExtSaveData>(sdmc_directory, false);
|
||||
if (extsavedata_factory->Initialize())
|
||||
RegisterArchiveType(std::move(extsavedata_factory), ArchiveIdCode::ExtSaveData);
|
||||
else
|
||||
LOG_ERROR(Service_FS, "Can't instantiate ExtSaveData archive with path %s", extsavedata_factory->GetMountPoint().c_str());
|
||||
LOG_ERROR(Service_FS, "Can't instantiate ExtSaveData archive with path %s",
|
||||
extsavedata_factory->GetMountPoint().c_str());
|
||||
|
||||
auto sharedextsavedata_factory = std::make_unique<FileSys::ArchiveFactory_ExtSaveData>(nand_directory, true);
|
||||
auto sharedextsavedata_factory =
|
||||
std::make_unique<FileSys::ArchiveFactory_ExtSaveData>(nand_directory, true);
|
||||
if (sharedextsavedata_factory->Initialize())
|
||||
RegisterArchiveType(std::move(sharedextsavedata_factory), ArchiveIdCode::SharedExtSaveData);
|
||||
else
|
||||
LOG_ERROR(Service_FS, "Can't instantiate SharedExtSaveData archive with path %s",
|
||||
sharedextsavedata_factory->GetMountPoint().c_str());
|
||||
sharedextsavedata_factory->GetMountPoint().c_str());
|
||||
|
||||
// Create the SaveDataCheck archive, basically a small variation of the RomFS archive
|
||||
auto savedatacheck_factory = std::make_unique<FileSys::ArchiveFactory_SaveDataCheck>(nand_directory);
|
||||
auto savedatacheck_factory =
|
||||
std::make_unique<FileSys::ArchiveFactory_SaveDataCheck>(nand_directory);
|
||||
RegisterArchiveType(std::move(savedatacheck_factory), ArchiveIdCode::SaveDataCheck);
|
||||
|
||||
auto systemsavedata_factory = std::make_unique<FileSys::ArchiveFactory_SystemSaveData>(nand_directory);
|
||||
auto systemsavedata_factory =
|
||||
std::make_unique<FileSys::ArchiveFactory_SystemSaveData>(nand_directory);
|
||||
RegisterArchiveType(std::move(systemsavedata_factory), ArchiveIdCode::SystemSaveData);
|
||||
}
|
||||
|
||||
|
@ -28,21 +28,18 @@ namespace FS {
|
||||
|
||||
/// Supported archive types
|
||||
enum class ArchiveIdCode : u32 {
|
||||
RomFS = 0x00000003,
|
||||
SaveData = 0x00000004,
|
||||
ExtSaveData = 0x00000006,
|
||||
SharedExtSaveData = 0x00000007,
|
||||
SystemSaveData = 0x00000008,
|
||||
SDMC = 0x00000009,
|
||||
SDMCWriteOnly = 0x0000000A,
|
||||
SaveDataCheck = 0x2345678A,
|
||||
RomFS = 0x00000003,
|
||||
SaveData = 0x00000004,
|
||||
ExtSaveData = 0x00000006,
|
||||
SharedExtSaveData = 0x00000007,
|
||||
SystemSaveData = 0x00000008,
|
||||
SDMC = 0x00000009,
|
||||
SDMCWriteOnly = 0x0000000A,
|
||||
SaveDataCheck = 0x2345678A,
|
||||
};
|
||||
|
||||
/// Media types for the archives
|
||||
enum class MediaType : u32 {
|
||||
NAND = 0,
|
||||
SDMC = 1
|
||||
};
|
||||
enum class MediaType : u32 { NAND = 0, SDMC = 1 };
|
||||
|
||||
typedef u64 ArchiveHandle;
|
||||
|
||||
@ -51,11 +48,13 @@ public:
|
||||
File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path);
|
||||
~File();
|
||||
|
||||
std::string GetName() const override { return "Path: " + path.DebugStr(); }
|
||||
std::string GetName() const override {
|
||||
return "Path: " + path.DebugStr();
|
||||
}
|
||||
ResultVal<bool> SyncRequest() override;
|
||||
|
||||
FileSys::Path path; ///< Path of the file
|
||||
u32 priority; ///< Priority of the file. TODO(Subv): Find out what this means
|
||||
u32 priority; ///< Priority of the file. TODO(Subv): Find out what this means
|
||||
std::unique_ptr<FileSys::FileBackend> backend; ///< File backend interface
|
||||
};
|
||||
|
||||
@ -64,10 +63,12 @@ public:
|
||||
Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path);
|
||||
~Directory();
|
||||
|
||||
std::string GetName() const override { return "Directory: " + path.DebugStr(); }
|
||||
std::string GetName() const override {
|
||||
return "Directory: " + path.DebugStr();
|
||||
}
|
||||
ResultVal<bool> SyncRequest() override;
|
||||
|
||||
FileSys::Path path; ///< Path of the directory
|
||||
FileSys::Path path; ///< Path of the directory
|
||||
std::unique_ptr<FileSys::DirectoryBackend> backend; ///< File backend interface
|
||||
};
|
||||
|
||||
@ -90,7 +91,8 @@ ResultCode CloseArchive(ArchiveHandle handle);
|
||||
* @param factory File system backend interface to the archive
|
||||
* @param id_code Id code used to access this type of archive
|
||||
*/
|
||||
ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factory, ArchiveIdCode id_code);
|
||||
ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factory,
|
||||
ArchiveIdCode id_code);
|
||||
|
||||
/**
|
||||
* Open a File from an Archive
|
||||
@ -100,7 +102,8 @@ ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factor
|
||||
* @return The opened File object as a Session
|
||||
*/
|
||||
ResultVal<Kernel::SharedPtr<File>> OpenFileFromArchive(ArchiveHandle archive_handle,
|
||||
const FileSys::Path& path, const FileSys::Mode mode);
|
||||
const FileSys::Path& path,
|
||||
const FileSys::Mode mode);
|
||||
|
||||
/**
|
||||
* Delete a File from an Archive
|
||||
@ -118,8 +121,10 @@ ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Pa
|
||||
* @param dest_path Path to the File inside of the destination Archive
|
||||
* @return Whether rename succeeded
|
||||
*/
|
||||
ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path,
|
||||
ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path);
|
||||
ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle,
|
||||
const FileSys::Path& src_path,
|
||||
ArchiveHandle dest_archive_handle,
|
||||
const FileSys::Path& dest_path);
|
||||
|
||||
/**
|
||||
* Delete a Directory from an Archive
|
||||
@ -136,7 +141,8 @@ ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSy
|
||||
* @param file_size The size of the new file, filled with zeroes
|
||||
* @return File creation result code
|
||||
*/
|
||||
ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path, u64 file_size);
|
||||
ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path,
|
||||
u64 file_size);
|
||||
|
||||
/**
|
||||
* Create a Directory from an Archive
|
||||
@ -154,8 +160,10 @@ ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSy
|
||||
* @param dest_path Path to the Directory inside of the destination Archive
|
||||
* @return Whether rename succeeded
|
||||
*/
|
||||
ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path,
|
||||
ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path);
|
||||
ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle,
|
||||
const FileSys::Path& src_path,
|
||||
ArchiveHandle dest_archive_handle,
|
||||
const FileSys::Path& dest_path);
|
||||
|
||||
/**
|
||||
* Open a Directory from an Archive
|
||||
@ -164,7 +172,7 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, cons
|
||||
* @return The opened Directory object as a Session
|
||||
*/
|
||||
ResultVal<Kernel::SharedPtr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle,
|
||||
const FileSys::Path& path);
|
||||
const FileSys::Path& path);
|
||||
|
||||
/**
|
||||
* Get the free space in an Archive
|
||||
@ -181,7 +189,8 @@ ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle);
|
||||
* @param path The path to the archive, if relevant.
|
||||
* @return ResultCode 0 on success or the corresponding code on error
|
||||
*/
|
||||
ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::ArchiveFormatInfo& format_info, const FileSys::Path& path = FileSys::Path());
|
||||
ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::ArchiveFormatInfo& format_info,
|
||||
const FileSys::Path& path = FileSys::Path());
|
||||
|
||||
/**
|
||||
* Retrieves the format info about the archive of the specified type and path.
|
||||
@ -190,7 +199,8 @@ ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::ArchiveFormatInfo
|
||||
* @param archive_path The path of the archive, if relevant
|
||||
* @return The format info of the archive, or the corresponding error code if failed.
|
||||
*/
|
||||
ResultVal<FileSys::ArchiveFormatInfo> GetArchiveFormatInfo(ArchiveIdCode id_code, FileSys::Path& archive_path);
|
||||
ResultVal<FileSys::ArchiveFormatInfo> GetArchiveFormatInfo(ArchiveIdCode id_code,
|
||||
FileSys::Path& archive_path);
|
||||
|
||||
/**
|
||||
* Creates a blank SharedExtSaveData archive for the specified extdata ID
|
||||
@ -202,7 +212,8 @@ ResultVal<FileSys::ArchiveFormatInfo> GetArchiveFormatInfo(ArchiveIdCode id_code
|
||||
* @param format_info Format information about the new archive
|
||||
* @return ResultCode 0 on success or the corresponding code on error
|
||||
*/
|
||||
ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size, const FileSys::ArchiveFormatInfo& format_info);
|
||||
ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer,
|
||||
u32 icon_size, const FileSys::ArchiveFormatInfo& format_info);
|
||||
|
||||
/**
|
||||
* Deletes the SharedExtSaveData archive for the specified extdata ID
|
||||
|
@ -57,14 +57,16 @@ static void OpenFile(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
|
||||
ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);
|
||||
auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
|
||||
u32 filename_size = cmd_buff[5];
|
||||
FileSys::Mode mode; mode.hex = cmd_buff[6];
|
||||
u32 attributes = cmd_buff[7]; // TODO(Link Mauve): do something with those attributes.
|
||||
u32 filename_ptr = cmd_buff[9];
|
||||
auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
|
||||
u32 filename_size = cmd_buff[5];
|
||||
FileSys::Mode mode;
|
||||
mode.hex = cmd_buff[6];
|
||||
u32 attributes = cmd_buff[7]; // TODO(Link Mauve): do something with those attributes.
|
||||
u32 filename_ptr = cmd_buff[9];
|
||||
FileSys::Path file_path(filename_type, filename_size, filename_ptr);
|
||||
|
||||
LOG_DEBUG(Service_FS, "path=%s, mode=%d attrs=%u", file_path.DebugStr().c_str(), mode.hex, attributes);
|
||||
LOG_DEBUG(Service_FS, "path=%s, mode=%d attrs=%u", file_path.DebugStr().c_str(), mode.hex,
|
||||
attributes);
|
||||
|
||||
ResultVal<SharedPtr<File>> file_res = OpenFileFromArchive(archive_handle, file_path, mode);
|
||||
cmd_buff[1] = file_res.Code().raw;
|
||||
@ -98,24 +100,27 @@ static void OpenFile(Service::Interface* self) {
|
||||
static void OpenFileDirectly(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
|
||||
auto archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[2]);
|
||||
auto archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[2]);
|
||||
auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[3]);
|
||||
u32 archivename_size = cmd_buff[4];
|
||||
auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[5]);
|
||||
u32 filename_size = cmd_buff[6];
|
||||
FileSys::Mode mode; mode.hex = cmd_buff[7];
|
||||
u32 attributes = cmd_buff[8]; // TODO(Link Mauve): do something with those attributes.
|
||||
u32 archivename_ptr = cmd_buff[10];
|
||||
u32 filename_ptr = cmd_buff[12];
|
||||
u32 archivename_size = cmd_buff[4];
|
||||
auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[5]);
|
||||
u32 filename_size = cmd_buff[6];
|
||||
FileSys::Mode mode;
|
||||
mode.hex = cmd_buff[7];
|
||||
u32 attributes = cmd_buff[8]; // TODO(Link Mauve): do something with those attributes.
|
||||
u32 archivename_ptr = cmd_buff[10];
|
||||
u32 filename_ptr = cmd_buff[12];
|
||||
FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr);
|
||||
FileSys::Path file_path(filename_type, filename_size, filename_ptr);
|
||||
|
||||
LOG_DEBUG(Service_FS, "archive_id=0x%08X archive_path=%s file_path=%s, mode=%u attributes=%d",
|
||||
archive_id, archive_path.DebugStr().c_str(), file_path.DebugStr().c_str(), mode.hex, attributes);
|
||||
archive_id, archive_path.DebugStr().c_str(), file_path.DebugStr().c_str(), mode.hex,
|
||||
attributes);
|
||||
|
||||
ResultVal<ArchiveHandle> archive_handle = OpenArchive(archive_id, archive_path);
|
||||
if (archive_handle.Failed()) {
|
||||
LOG_ERROR(Service_FS, "failed to get a handle for archive archive_id=0x%08X archive_path=%s",
|
||||
LOG_ERROR(Service_FS,
|
||||
"failed to get a handle for archive archive_id=0x%08X archive_path=%s",
|
||||
archive_id, archive_path.DebugStr().c_str());
|
||||
cmd_buff[1] = archive_handle.Code().raw;
|
||||
cmd_buff[3] = 0;
|
||||
@ -149,14 +154,14 @@ static void DeleteFile(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
|
||||
ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);
|
||||
auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
|
||||
u32 filename_size = cmd_buff[5];
|
||||
u32 filename_ptr = cmd_buff[7];
|
||||
auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
|
||||
u32 filename_size = cmd_buff[5];
|
||||
u32 filename_ptr = cmd_buff[7];
|
||||
|
||||
FileSys::Path file_path(filename_type, filename_size, filename_ptr);
|
||||
|
||||
LOG_DEBUG(Service_FS, "type=%d size=%d data=%s",
|
||||
filename_type, filename_size, file_path.DebugStr().c_str());
|
||||
LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", filename_type, filename_size,
|
||||
file_path.DebugStr().c_str());
|
||||
|
||||
cmd_buff[1] = DeleteFileFromArchive(archive_handle, file_path).raw;
|
||||
}
|
||||
@ -181,22 +186,26 @@ static void RenameFile(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
|
||||
ArchiveHandle src_archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);
|
||||
auto src_filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
|
||||
u32 src_filename_size = cmd_buff[5];
|
||||
ArchiveHandle dest_archive_handle = MakeArchiveHandle(cmd_buff[6], cmd_buff[7]);;
|
||||
auto dest_filename_type = static_cast<FileSys::LowPathType>(cmd_buff[8]);
|
||||
u32 dest_filename_size = cmd_buff[9];
|
||||
u32 src_filename_ptr = cmd_buff[11];
|
||||
u32 dest_filename_ptr = cmd_buff[13];
|
||||
auto src_filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
|
||||
u32 src_filename_size = cmd_buff[5];
|
||||
ArchiveHandle dest_archive_handle = MakeArchiveHandle(cmd_buff[6], cmd_buff[7]);
|
||||
;
|
||||
auto dest_filename_type = static_cast<FileSys::LowPathType>(cmd_buff[8]);
|
||||
u32 dest_filename_size = cmd_buff[9];
|
||||
u32 src_filename_ptr = cmd_buff[11];
|
||||
u32 dest_filename_ptr = cmd_buff[13];
|
||||
|
||||
FileSys::Path src_file_path(src_filename_type, src_filename_size, src_filename_ptr);
|
||||
FileSys::Path dest_file_path(dest_filename_type, dest_filename_size, dest_filename_ptr);
|
||||
|
||||
LOG_DEBUG(Service_FS, "src_type=%d src_size=%d src_data=%s dest_type=%d dest_size=%d dest_data=%s",
|
||||
LOG_DEBUG(Service_FS,
|
||||
"src_type=%d src_size=%d src_data=%s dest_type=%d dest_size=%d dest_data=%s",
|
||||
src_filename_type, src_filename_size, src_file_path.DebugStr().c_str(),
|
||||
dest_filename_type, dest_filename_size, dest_file_path.DebugStr().c_str());
|
||||
|
||||
cmd_buff[1] = RenameFileBetweenArchives(src_archive_handle, src_file_path, dest_archive_handle, dest_file_path).raw;
|
||||
cmd_buff[1] = RenameFileBetweenArchives(src_archive_handle, src_file_path, dest_archive_handle,
|
||||
dest_file_path)
|
||||
.raw;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -214,14 +223,14 @@ static void DeleteDirectory(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
|
||||
ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);
|
||||
auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
|
||||
u32 dirname_size = cmd_buff[5];
|
||||
u32 dirname_ptr = cmd_buff[7];
|
||||
auto dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
|
||||
u32 dirname_size = cmd_buff[5];
|
||||
u32 dirname_ptr = cmd_buff[7];
|
||||
|
||||
FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr);
|
||||
|
||||
LOG_DEBUG(Service_FS, "type=%d size=%d data=%s",
|
||||
dirname_type, dirname_size, dir_path.DebugStr().c_str());
|
||||
LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size,
|
||||
dir_path.DebugStr().c_str());
|
||||
|
||||
cmd_buff[1] = DeleteDirectoryFromArchive(archive_handle, dir_path).raw;
|
||||
}
|
||||
@ -243,14 +252,15 @@ static void CreateFile(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
|
||||
ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);
|
||||
auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
|
||||
u32 filename_size = cmd_buff[5];
|
||||
u64 file_size = ((u64)cmd_buff[8] << 32) | cmd_buff[7];
|
||||
u32 filename_ptr = cmd_buff[10];
|
||||
auto filename_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
|
||||
u32 filename_size = cmd_buff[5];
|
||||
u64 file_size = ((u64)cmd_buff[8] << 32) | cmd_buff[7];
|
||||
u32 filename_ptr = cmd_buff[10];
|
||||
|
||||
FileSys::Path file_path(filename_type, filename_size, filename_ptr);
|
||||
|
||||
LOG_DEBUG(Service_FS, "type=%d size=%llu data=%s", filename_type, file_size, file_path.DebugStr().c_str());
|
||||
LOG_DEBUG(Service_FS, "type=%d size=%llu data=%s", filename_type, file_size,
|
||||
file_path.DebugStr().c_str());
|
||||
|
||||
cmd_buff[1] = CreateFileInArchive(archive_handle, file_path, file_size).raw;
|
||||
}
|
||||
@ -276,7 +286,8 @@ static void CreateDirectory(Service::Interface* self) {
|
||||
|
||||
FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr);
|
||||
|
||||
LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str());
|
||||
LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size,
|
||||
dir_path.DebugStr().c_str());
|
||||
|
||||
cmd_buff[1] = CreateDirectoryFromArchive(archive_handle, dir_path).raw;
|
||||
}
|
||||
@ -301,22 +312,25 @@ static void RenameDirectory(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
|
||||
ArchiveHandle src_archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]);
|
||||
auto src_dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
|
||||
u32 src_dirname_size = cmd_buff[5];
|
||||
auto src_dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[4]);
|
||||
u32 src_dirname_size = cmd_buff[5];
|
||||
ArchiveHandle dest_archive_handle = MakeArchiveHandle(cmd_buff[6], cmd_buff[7]);
|
||||
auto dest_dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[8]);
|
||||
u32 dest_dirname_size = cmd_buff[9];
|
||||
u32 src_dirname_ptr = cmd_buff[11];
|
||||
u32 dest_dirname_ptr = cmd_buff[13];
|
||||
auto dest_dirname_type = static_cast<FileSys::LowPathType>(cmd_buff[8]);
|
||||
u32 dest_dirname_size = cmd_buff[9];
|
||||
u32 src_dirname_ptr = cmd_buff[11];
|
||||
u32 dest_dirname_ptr = cmd_buff[13];
|
||||
|
||||
FileSys::Path src_dir_path(src_dirname_type, src_dirname_size, src_dirname_ptr);
|
||||
FileSys::Path dest_dir_path(dest_dirname_type, dest_dirname_size, dest_dirname_ptr);
|
||||
|
||||
LOG_DEBUG(Service_FS, "src_type=%d src_size=%d src_data=%s dest_type=%d dest_size=%d dest_data=%s",
|
||||
LOG_DEBUG(Service_FS,
|
||||
"src_type=%d src_size=%d src_data=%s dest_type=%d dest_size=%d dest_data=%s",
|
||||
src_dirname_type, src_dirname_size, src_dir_path.DebugStr().c_str(),
|
||||
dest_dirname_type, dest_dirname_size, dest_dir_path.DebugStr().c_str());
|
||||
|
||||
cmd_buff[1] = RenameDirectoryBetweenArchives(src_archive_handle, src_dir_path, dest_archive_handle, dest_dir_path).raw;
|
||||
cmd_buff[1] = RenameDirectoryBetweenArchives(src_archive_handle, src_dir_path,
|
||||
dest_archive_handle, dest_dir_path)
|
||||
.raw;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -342,7 +356,8 @@ static void OpenDirectory(Service::Interface* self) {
|
||||
|
||||
FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr);
|
||||
|
||||
LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str());
|
||||
LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size,
|
||||
dir_path.DebugStr().c_str());
|
||||
|
||||
ResultVal<SharedPtr<Directory>> dir_res = OpenDirectoryFromArchive(archive_handle, dir_path);
|
||||
cmd_buff[1] = dir_res.Code().raw;
|
||||
@ -370,13 +385,14 @@ static void OpenDirectory(Service::Interface* self) {
|
||||
static void OpenArchive(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
|
||||
auto archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[1]);
|
||||
auto archive_id = static_cast<FS::ArchiveIdCode>(cmd_buff[1]);
|
||||
auto archivename_type = static_cast<FileSys::LowPathType>(cmd_buff[2]);
|
||||
u32 archivename_size = cmd_buff[3];
|
||||
u32 archivename_ptr = cmd_buff[5];
|
||||
u32 archivename_size = cmd_buff[3];
|
||||
u32 archivename_ptr = cmd_buff[5];
|
||||
FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr);
|
||||
|
||||
LOG_DEBUG(Service_FS, "archive_id=0x%08X archive_path=%s", archive_id, archive_path.DebugStr().c_str());
|
||||
LOG_DEBUG(Service_FS, "archive_id=0x%08X archive_path=%s", archive_id,
|
||||
archive_path.DebugStr().c_str());
|
||||
|
||||
ResultVal<ArchiveHandle> handle = OpenArchive(archive_id, archive_path);
|
||||
cmd_buff[1] = handle.Code().raw;
|
||||
@ -385,7 +401,8 @@ static void OpenArchive(Service::Interface* self) {
|
||||
cmd_buff[3] = (*handle >> 32) & 0xFFFFFFFF;
|
||||
} else {
|
||||
cmd_buff[2] = cmd_buff[3] = 0;
|
||||
LOG_ERROR(Service_FS, "failed to get a handle for archive archive_id=0x%08X archive_path=%s",
|
||||
LOG_ERROR(Service_FS,
|
||||
"failed to get a handle for archive archive_id=0x%08X archive_path=%s",
|
||||
archive_id, archive_path.DebugStr().c_str());
|
||||
}
|
||||
}
|
||||
@ -471,7 +488,8 @@ static void FormatSaveData(Service::Interface* self) {
|
||||
if (archive_id != FS::ArchiveIdCode::SaveData) {
|
||||
LOG_ERROR(Service_FS, "tried to format an archive different than SaveData, %u", archive_id);
|
||||
cmd_buff[1] = ResultCode(ErrorDescription::FS_InvalidPath, ErrorModule::FS,
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Usage).raw;
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Usage)
|
||||
.raw;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -571,18 +589,21 @@ static void CreateExtSaveData(Service::Interface* self) {
|
||||
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 "
|
||||
"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);
|
||||
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 "
|
||||
"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);
|
||||
|
||||
FileSys::ArchiveFormatInfo format_info;
|
||||
format_info.number_directories = cmd_buff[5];
|
||||
format_info.number_files = cmd_buff[6];
|
||||
format_info.duplicate_data = false;
|
||||
format_info.total_size = 0;
|
||||
cmd_buff[1] = CreateExtSaveData(media_type, save_high, save_low, icon_buffer, icon_size, format_info).raw;
|
||||
cmd_buff[1] =
|
||||
CreateExtSaveData(media_type, save_high, save_low, icon_buffer, icon_size, format_info).raw;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -604,7 +625,7 @@ static void DeleteExtSaveData(Service::Interface* self) {
|
||||
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",
|
||||
save_low, save_high, cmd_buff[1] & 0xFF, unknown);
|
||||
save_low, save_high, cmd_buff[1] & 0xFF, unknown);
|
||||
|
||||
cmd_buff[1] = DeleteExtSaveData(media_type, save_high, save_low).raw;
|
||||
}
|
||||
@ -662,10 +683,13 @@ static void CreateSystemSaveData(Service::Interface* self) {
|
||||
u32 savedata_high = cmd_buff[1];
|
||||
u32 savedata_low = cmd_buff[2];
|
||||
|
||||
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", savedata_high, savedata_low, cmd_buff[3], cmd_buff[4], cmd_buff[5],
|
||||
cmd_buff[6], cmd_buff[7], cmd_buff[8], cmd_buff[9]);
|
||||
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",
|
||||
savedata_high, savedata_low, cmd_buff[3], cmd_buff[4], cmd_buff[5], cmd_buff[6],
|
||||
cmd_buff[7], cmd_buff[8], cmd_buff[9]);
|
||||
|
||||
cmd_buff[1] = CreateSystemSaveData(savedata_high, savedata_low).raw;
|
||||
}
|
||||
@ -692,10 +716,13 @@ static void CreateLegacySystemSaveData(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
u32 savedata_id = cmd_buff[1];
|
||||
|
||||
LOG_WARNING(Service_FS, "(STUBBED) savedata_id=%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", savedata_id, cmd_buff[3], cmd_buff[4], cmd_buff[5],
|
||||
cmd_buff[6], cmd_buff[7], cmd_buff[8], cmd_buff[9]);
|
||||
LOG_WARNING(
|
||||
Service_FS,
|
||||
"(STUBBED) savedata_id=%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",
|
||||
savedata_id, cmd_buff[3], cmd_buff[4], cmd_buff[5], cmd_buff[6], cmd_buff[7], cmd_buff[8],
|
||||
cmd_buff[9]);
|
||||
|
||||
cmd_buff[0] = IPC::MakeHeader(0x810, 0x1, 0);
|
||||
// With this command, the SystemSaveData always has save_high = 0 (Always created in the NAND)
|
||||
@ -721,8 +748,8 @@ static void InitializeWithSdkVersion(Service::Interface* self) {
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
|
||||
LOG_WARNING(Service_FS, "(STUBBED) called unk1=0x%08X, unk2=0x%08X, unk3=0x%08X",
|
||||
unk1, unk2, unk3);
|
||||
LOG_WARNING(Service_FS, "(STUBBED) called unk1=0x%08X, unk2=0x%08X, unk3=0x%08X", unk1, unk2,
|
||||
unk3);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -834,115 +861,114 @@ static void GetFormatInfo(Service::Interface* self) {
|
||||
}
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x000100C6, nullptr, "Dummy1"},
|
||||
{0x040100C4, nullptr, "Control"},
|
||||
{0x08010002, Initialize, "Initialize"},
|
||||
{0x080201C2, OpenFile, "OpenFile"},
|
||||
{0x08030204, OpenFileDirectly, "OpenFileDirectly"},
|
||||
{0x08040142, DeleteFile, "DeleteFile"},
|
||||
{0x08050244, RenameFile, "RenameFile"},
|
||||
{0x08060142, DeleteDirectory, "DeleteDirectory"},
|
||||
{0x08070142, nullptr, "DeleteDirectoryRecursively"},
|
||||
{0x08080202, CreateFile, "CreateFile"},
|
||||
{0x08090182, CreateDirectory, "CreateDirectory"},
|
||||
{0x080A0244, RenameDirectory, "RenameDirectory"},
|
||||
{0x080B0102, OpenDirectory, "OpenDirectory"},
|
||||
{0x080C00C2, OpenArchive, "OpenArchive"},
|
||||
{0x080D0144, nullptr, "ControlArchive"},
|
||||
{0x080E0080, CloseArchive, "CloseArchive"},
|
||||
{0x080F0180, FormatThisUserSaveData, "FormatThisUserSaveData"},
|
||||
{0x000100C6, nullptr, "Dummy1"},
|
||||
{0x040100C4, nullptr, "Control"},
|
||||
{0x08010002, Initialize, "Initialize"},
|
||||
{0x080201C2, OpenFile, "OpenFile"},
|
||||
{0x08030204, OpenFileDirectly, "OpenFileDirectly"},
|
||||
{0x08040142, DeleteFile, "DeleteFile"},
|
||||
{0x08050244, RenameFile, "RenameFile"},
|
||||
{0x08060142, DeleteDirectory, "DeleteDirectory"},
|
||||
{0x08070142, nullptr, "DeleteDirectoryRecursively"},
|
||||
{0x08080202, CreateFile, "CreateFile"},
|
||||
{0x08090182, CreateDirectory, "CreateDirectory"},
|
||||
{0x080A0244, RenameDirectory, "RenameDirectory"},
|
||||
{0x080B0102, OpenDirectory, "OpenDirectory"},
|
||||
{0x080C00C2, OpenArchive, "OpenArchive"},
|
||||
{0x080D0144, nullptr, "ControlArchive"},
|
||||
{0x080E0080, CloseArchive, "CloseArchive"},
|
||||
{0x080F0180, FormatThisUserSaveData, "FormatThisUserSaveData"},
|
||||
{0x08100200, CreateLegacySystemSaveData, "CreateLegacySystemSaveData"},
|
||||
{0x08110040, nullptr, "DeleteSystemSaveData"},
|
||||
{0x08120080, GetFreeBytes, "GetFreeBytes"},
|
||||
{0x08130000, nullptr, "GetCardType"},
|
||||
{0x08140000, nullptr, "GetSdmcArchiveResource"},
|
||||
{0x08150000, nullptr, "GetNandArchiveResource"},
|
||||
{0x08160000, nullptr, "GetSdmcFatfsError"},
|
||||
{0x08170000, IsSdmcDetected, "IsSdmcDetected"},
|
||||
{0x08180000, IsSdmcWriteable, "IsSdmcWritable"},
|
||||
{0x08190042, nullptr, "GetSdmcCid"},
|
||||
{0x081A0042, nullptr, "GetNandCid"},
|
||||
{0x081B0000, nullptr, "GetSdmcSpeedInfo"},
|
||||
{0x081C0000, nullptr, "GetNandSpeedInfo"},
|
||||
{0x081D0042, nullptr, "GetSdmcLog"},
|
||||
{0x081E0042, nullptr, "GetNandLog"},
|
||||
{0x081F0000, nullptr, "ClearSdmcLog"},
|
||||
{0x08200000, nullptr, "ClearNandLog"},
|
||||
{0x08210000, CardSlotIsInserted, "CardSlotIsInserted"},
|
||||
{0x08220000, nullptr, "CardSlotPowerOn"},
|
||||
{0x08230000, nullptr, "CardSlotPowerOff"},
|
||||
{0x08240000, nullptr, "CardSlotGetCardIFPowerStatus"},
|
||||
{0x08250040, nullptr, "CardNorDirectCommand"},
|
||||
{0x08260080, nullptr, "CardNorDirectCommandWithAddress"},
|
||||
{0x08270082, nullptr, "CardNorDirectRead"},
|
||||
{0x082800C2, nullptr, "CardNorDirectReadWithAddress"},
|
||||
{0x08290082, nullptr, "CardNorDirectWrite"},
|
||||
{0x082A00C2, nullptr, "CardNorDirectWriteWithAddress"},
|
||||
{0x082B00C2, nullptr, "CardNorDirectRead_4xIO"},
|
||||
{0x082C0082, nullptr, "CardNorDirectCpuWriteWithoutVerify"},
|
||||
{0x082D0040, nullptr, "CardNorDirectSectorEraseWithoutVerify"},
|
||||
{0x082E0040, nullptr, "GetProductInfo"},
|
||||
{0x082F0040, nullptr, "GetProgramLaunchInfo"},
|
||||
{0x08300182, nullptr, "CreateExtSaveData"},
|
||||
{0x08310180, nullptr, "CreateSharedExtSaveData"},
|
||||
{0x08320102, nullptr, "ReadExtSaveDataIcon"},
|
||||
{0x08330082, nullptr, "EnumerateExtSaveData"},
|
||||
{0x08340082, nullptr, "EnumerateSharedExtSaveData"},
|
||||
{0x08350080, nullptr, "DeleteExtSaveData"},
|
||||
{0x08360080, nullptr, "DeleteSharedExtSaveData"},
|
||||
{0x08370040, nullptr, "SetCardSpiBaudRate"},
|
||||
{0x08380040, nullptr, "SetCardSpiBusMode"},
|
||||
{0x08390000, nullptr, "SendInitializeInfoTo9"},
|
||||
{0x083A0100, nullptr, "GetSpecialContentIndex"},
|
||||
{0x083B00C2, nullptr, "GetLegacyRomHeader"},
|
||||
{0x083C00C2, nullptr, "GetLegacyBannerData"},
|
||||
{0x083D0100, nullptr, "CheckAuthorityToAccessExtSaveData"},
|
||||
{0x083E00C2, nullptr, "QueryTotalQuotaSize"},
|
||||
{0x083F00C0, nullptr, "GetExtDataBlockSize"},
|
||||
{0x08400040, nullptr, "AbnegateAccessRight"},
|
||||
{0x08410000, nullptr, "DeleteSdmcRoot"},
|
||||
{0x08420040, nullptr, "DeleteAllExtSaveDataOnNand"},
|
||||
{0x08430000, nullptr, "InitializeCtrFileSystem"},
|
||||
{0x08440000, nullptr, "CreateSeed"},
|
||||
{0x084500C2, GetFormatInfo, "GetFormatInfo"},
|
||||
{0x08460102, nullptr, "GetLegacyRomHeader2"},
|
||||
{0x08470180, nullptr, "FormatCtrCardUserSaveData"},
|
||||
{0x08480042, nullptr, "GetSdmcCtrRootPath"},
|
||||
{0x08490040, GetArchiveResource, "GetArchiveResource"},
|
||||
{0x084A0002, nullptr, "ExportIntegrityVerificationSeed"},
|
||||
{0x084B0002, nullptr, "ImportIntegrityVerificationSeed"},
|
||||
{0x084C0242, FormatSaveData, "FormatSaveData"},
|
||||
{0x084D0102, nullptr, "GetLegacySubBannerData"},
|
||||
{0x084E0342, nullptr, "UpdateSha256Context"},
|
||||
{0x084F0102, nullptr, "ReadSpecialFile"},
|
||||
{0x08500040, nullptr, "GetSpecialFileSize"},
|
||||
{0x08510242, CreateExtSaveData, "CreateExtSaveData"},
|
||||
{0x08520100, DeleteExtSaveData, "DeleteExtSaveData"},
|
||||
{0x08530142, nullptr, "ReadExtSaveDataIcon"},
|
||||
{0x085400C0, nullptr, "GetExtDataBlockSize"},
|
||||
{0x08550102, nullptr, "EnumerateExtSaveData"},
|
||||
{0x08560240, CreateSystemSaveData, "CreateSystemSaveData"},
|
||||
{0x08570080, DeleteSystemSaveData, "DeleteSystemSaveData"},
|
||||
{0x08580000, nullptr, "StartDeviceMoveAsSource"},
|
||||
{0x08590200, nullptr, "StartDeviceMoveAsDestination"},
|
||||
{0x085A00C0, nullptr, "SetArchivePriority"},
|
||||
{0x085B0080, nullptr, "GetArchivePriority"},
|
||||
{0x085C00C0, nullptr, "SetCtrCardLatencyParameter"},
|
||||
{0x085D01C0, nullptr, "SetFsCompatibilityInfo"},
|
||||
{0x085E0040, nullptr, "ResetCardCompatibilityParameter"},
|
||||
{0x085F0040, nullptr, "SwitchCleanupInvalidSaveData"},
|
||||
{0x08600042, nullptr, "EnumerateSystemSaveData"},
|
||||
{0x08110040, nullptr, "DeleteSystemSaveData"},
|
||||
{0x08120080, GetFreeBytes, "GetFreeBytes"},
|
||||
{0x08130000, nullptr, "GetCardType"},
|
||||
{0x08140000, nullptr, "GetSdmcArchiveResource"},
|
||||
{0x08150000, nullptr, "GetNandArchiveResource"},
|
||||
{0x08160000, nullptr, "GetSdmcFatfsError"},
|
||||
{0x08170000, IsSdmcDetected, "IsSdmcDetected"},
|
||||
{0x08180000, IsSdmcWriteable, "IsSdmcWritable"},
|
||||
{0x08190042, nullptr, "GetSdmcCid"},
|
||||
{0x081A0042, nullptr, "GetNandCid"},
|
||||
{0x081B0000, nullptr, "GetSdmcSpeedInfo"},
|
||||
{0x081C0000, nullptr, "GetNandSpeedInfo"},
|
||||
{0x081D0042, nullptr, "GetSdmcLog"},
|
||||
{0x081E0042, nullptr, "GetNandLog"},
|
||||
{0x081F0000, nullptr, "ClearSdmcLog"},
|
||||
{0x08200000, nullptr, "ClearNandLog"},
|
||||
{0x08210000, CardSlotIsInserted, "CardSlotIsInserted"},
|
||||
{0x08220000, nullptr, "CardSlotPowerOn"},
|
||||
{0x08230000, nullptr, "CardSlotPowerOff"},
|
||||
{0x08240000, nullptr, "CardSlotGetCardIFPowerStatus"},
|
||||
{0x08250040, nullptr, "CardNorDirectCommand"},
|
||||
{0x08260080, nullptr, "CardNorDirectCommandWithAddress"},
|
||||
{0x08270082, nullptr, "CardNorDirectRead"},
|
||||
{0x082800C2, nullptr, "CardNorDirectReadWithAddress"},
|
||||
{0x08290082, nullptr, "CardNorDirectWrite"},
|
||||
{0x082A00C2, nullptr, "CardNorDirectWriteWithAddress"},
|
||||
{0x082B00C2, nullptr, "CardNorDirectRead_4xIO"},
|
||||
{0x082C0082, nullptr, "CardNorDirectCpuWriteWithoutVerify"},
|
||||
{0x082D0040, nullptr, "CardNorDirectSectorEraseWithoutVerify"},
|
||||
{0x082E0040, nullptr, "GetProductInfo"},
|
||||
{0x082F0040, nullptr, "GetProgramLaunchInfo"},
|
||||
{0x08300182, nullptr, "CreateExtSaveData"},
|
||||
{0x08310180, nullptr, "CreateSharedExtSaveData"},
|
||||
{0x08320102, nullptr, "ReadExtSaveDataIcon"},
|
||||
{0x08330082, nullptr, "EnumerateExtSaveData"},
|
||||
{0x08340082, nullptr, "EnumerateSharedExtSaveData"},
|
||||
{0x08350080, nullptr, "DeleteExtSaveData"},
|
||||
{0x08360080, nullptr, "DeleteSharedExtSaveData"},
|
||||
{0x08370040, nullptr, "SetCardSpiBaudRate"},
|
||||
{0x08380040, nullptr, "SetCardSpiBusMode"},
|
||||
{0x08390000, nullptr, "SendInitializeInfoTo9"},
|
||||
{0x083A0100, nullptr, "GetSpecialContentIndex"},
|
||||
{0x083B00C2, nullptr, "GetLegacyRomHeader"},
|
||||
{0x083C00C2, nullptr, "GetLegacyBannerData"},
|
||||
{0x083D0100, nullptr, "CheckAuthorityToAccessExtSaveData"},
|
||||
{0x083E00C2, nullptr, "QueryTotalQuotaSize"},
|
||||
{0x083F00C0, nullptr, "GetExtDataBlockSize"},
|
||||
{0x08400040, nullptr, "AbnegateAccessRight"},
|
||||
{0x08410000, nullptr, "DeleteSdmcRoot"},
|
||||
{0x08420040, nullptr, "DeleteAllExtSaveDataOnNand"},
|
||||
{0x08430000, nullptr, "InitializeCtrFileSystem"},
|
||||
{0x08440000, nullptr, "CreateSeed"},
|
||||
{0x084500C2, GetFormatInfo, "GetFormatInfo"},
|
||||
{0x08460102, nullptr, "GetLegacyRomHeader2"},
|
||||
{0x08470180, nullptr, "FormatCtrCardUserSaveData"},
|
||||
{0x08480042, nullptr, "GetSdmcCtrRootPath"},
|
||||
{0x08490040, GetArchiveResource, "GetArchiveResource"},
|
||||
{0x084A0002, nullptr, "ExportIntegrityVerificationSeed"},
|
||||
{0x084B0002, nullptr, "ImportIntegrityVerificationSeed"},
|
||||
{0x084C0242, FormatSaveData, "FormatSaveData"},
|
||||
{0x084D0102, nullptr, "GetLegacySubBannerData"},
|
||||
{0x084E0342, nullptr, "UpdateSha256Context"},
|
||||
{0x084F0102, nullptr, "ReadSpecialFile"},
|
||||
{0x08500040, nullptr, "GetSpecialFileSize"},
|
||||
{0x08510242, CreateExtSaveData, "CreateExtSaveData"},
|
||||
{0x08520100, DeleteExtSaveData, "DeleteExtSaveData"},
|
||||
{0x08530142, nullptr, "ReadExtSaveDataIcon"},
|
||||
{0x085400C0, nullptr, "GetExtDataBlockSize"},
|
||||
{0x08550102, nullptr, "EnumerateExtSaveData"},
|
||||
{0x08560240, CreateSystemSaveData, "CreateSystemSaveData"},
|
||||
{0x08570080, DeleteSystemSaveData, "DeleteSystemSaveData"},
|
||||
{0x08580000, nullptr, "StartDeviceMoveAsSource"},
|
||||
{0x08590200, nullptr, "StartDeviceMoveAsDestination"},
|
||||
{0x085A00C0, nullptr, "SetArchivePriority"},
|
||||
{0x085B0080, nullptr, "GetArchivePriority"},
|
||||
{0x085C00C0, nullptr, "SetCtrCardLatencyParameter"},
|
||||
{0x085D01C0, nullptr, "SetFsCompatibilityInfo"},
|
||||
{0x085E0040, nullptr, "ResetCardCompatibilityParameter"},
|
||||
{0x085F0040, nullptr, "SwitchCleanupInvalidSaveData"},
|
||||
{0x08600042, nullptr, "EnumerateSystemSaveData"},
|
||||
{0x08610042, InitializeWithSdkVersion, "InitializeWithSdkVersion"},
|
||||
{0x08620040, SetPriority, "SetPriority"},
|
||||
{0x08630000, GetPriority, "GetPriority"},
|
||||
{0x08640000, nullptr, "GetNandInfo"},
|
||||
{0x08650140, nullptr, "SetSaveDataSecureValue"},
|
||||
{0x086600C0, nullptr, "GetSaveDataSecureValue"},
|
||||
{0x086700C4, nullptr, "ControlSecureSave"},
|
||||
{0x08680000, nullptr, "GetMediaType"},
|
||||
{0x08690000, nullptr, "GetNandEraseCount"},
|
||||
{0x086A0082, nullptr, "ReadNandReport"}
|
||||
};
|
||||
{0x08620040, SetPriority, "SetPriority"},
|
||||
{0x08630000, GetPriority, "GetPriority"},
|
||||
{0x08640000, nullptr, "GetNandInfo"},
|
||||
{0x08650140, nullptr, "SetSaveDataSecureValue"},
|
||||
{0x086600C0, nullptr, "GetSaveDataSecureValue"},
|
||||
{0x086700C4, nullptr, "ControlSecureSave"},
|
||||
{0x08680000, nullptr, "GetMediaType"},
|
||||
{0x08690000, nullptr, "GetNandEraseCount"},
|
||||
{0x086A0082, nullptr, "ReadNandReport"}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Interface class
|
||||
|
@ -5,16 +5,16 @@
|
||||
#include "common/bit_field.h"
|
||||
#include "common/microprofile.h"
|
||||
|
||||
#include "core/memory.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/kernel/shared_memory.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hw/hw.h"
|
||||
#include "core/hw/gpu.h"
|
||||
#include "core/hw/hw.h"
|
||||
#include "core/hw/lcd.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
#include "video_core/gpu_debugger.h"
|
||||
#include "video_core/debug_utils/debug_utils.h"
|
||||
#include "video_core/gpu_debugger.h"
|
||||
|
||||
#include "gsp_gpu.h"
|
||||
|
||||
@ -29,12 +29,16 @@ const static u32 REGS_BEGIN = 0x1EB00000;
|
||||
|
||||
namespace GSP_GPU {
|
||||
|
||||
const ResultCode ERR_GSP_REGS_OUTOFRANGE_OR_MISALIGNED(ErrorDescription::OutofRangeOrMisalignedAddress, ErrorModule::GX,
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E02A01
|
||||
const ResultCode
|
||||
ERR_GSP_REGS_OUTOFRANGE_OR_MISALIGNED(ErrorDescription::OutofRangeOrMisalignedAddress,
|
||||
ErrorModule::GX, ErrorSummary::InvalidArgument,
|
||||
ErrorLevel::Usage); // 0xE0E02A01
|
||||
const ResultCode ERR_GSP_REGS_MISALIGNED(ErrorDescription::MisalignedSize, ErrorModule::GX,
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E02BF2
|
||||
ErrorSummary::InvalidArgument,
|
||||
ErrorLevel::Usage); // 0xE0E02BF2
|
||||
const ResultCode ERR_GSP_REGS_INVALID_SIZE(ErrorDescription::InvalidSize, ErrorModule::GX,
|
||||
ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E02BEC
|
||||
ErrorSummary::InvalidArgument,
|
||||
ErrorLevel::Usage); // 0xE0E02BEC
|
||||
|
||||
/// Event triggered when GSP interrupt has been signalled
|
||||
Kernel::SharedPtr<Kernel::Event> g_interrupt_event;
|
||||
@ -73,7 +77,8 @@ static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) {
|
||||
* @param data Data to be written
|
||||
*/
|
||||
static void WriteSingleHWReg(u32 base_address, u32 data) {
|
||||
DEBUG_ASSERT_MSG((base_address & 3) == 0 && base_address < 0x420000, "Write address out of range or misaligned");
|
||||
DEBUG_ASSERT_MSG((base_address & 3) == 0 && base_address < 0x420000,
|
||||
"Write address out of range or misaligned");
|
||||
HW::Write<u32>(base_address + REGS_BEGIN, data);
|
||||
}
|
||||
|
||||
@ -90,7 +95,8 @@ static ResultCode WriteHWRegs(u32 base_address, u32 size_in_bytes, VAddr data_va
|
||||
const u32 max_size_in_bytes = 0x80;
|
||||
|
||||
if (base_address & 3 || base_address >= 0x420000) {
|
||||
LOG_ERROR(Service_GSP, "Write address was out of range or misaligned! (address=0x%08x, size=0x%08x)",
|
||||
LOG_ERROR(Service_GSP,
|
||||
"Write address was out of range or misaligned! (address=0x%08x, size=0x%08x)",
|
||||
base_address, size_in_bytes);
|
||||
return ERR_GSP_REGS_OUTOFRANGE_OR_MISALIGNED;
|
||||
} else if (size_in_bytes <= max_size_in_bytes) {
|
||||
@ -124,12 +130,14 @@ static ResultCode WriteHWRegs(u32 base_address, u32 size_in_bytes, VAddr data_va
|
||||
* @param masks A pointer to the masks
|
||||
* @return RESULT_SUCCESS if the parameters are valid, error code otherwise
|
||||
*/
|
||||
static ResultCode WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, VAddr data_vaddr, VAddr masks_vaddr) {
|
||||
static ResultCode WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, VAddr data_vaddr,
|
||||
VAddr masks_vaddr) {
|
||||
// This magic number is verified to be done by the gsp module
|
||||
const u32 max_size_in_bytes = 0x80;
|
||||
|
||||
if (base_address & 3 || base_address >= 0x420000) {
|
||||
LOG_ERROR(Service_GSP, "Write address was out of range or misaligned! (address=0x%08x, size=0x%08x)",
|
||||
LOG_ERROR(Service_GSP,
|
||||
"Write address was out of range or misaligned! (address=0x%08x, size=0x%08x)",
|
||||
base_address, size_in_bytes);
|
||||
return ERR_GSP_REGS_OUTOFRANGE_OR_MISALIGNED;
|
||||
} else if (size_in_bytes <= max_size_in_bytes) {
|
||||
@ -214,7 +222,8 @@ static void ReadHWRegs(Service::Interface* self) {
|
||||
|
||||
// TODO: Return proper error codes
|
||||
if (reg_addr + size >= 0x420000) {
|
||||
LOG_ERROR(Service_GSP, "Read address out of range! (address=0x%08x, size=0x%08x)", reg_addr, size);
|
||||
LOG_ERROR(Service_GSP, "Read address out of range! (address=0x%08x, size=0x%08x)", reg_addr,
|
||||
size);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -243,22 +252,34 @@ ResultCode 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) {
|
||||
WriteSingleHWReg(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)),
|
||||
phys_address_left);
|
||||
WriteSingleHWReg(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)),
|
||||
phys_address_right);
|
||||
WriteSingleHWReg(
|
||||
base_address +
|
||||
4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)),
|
||||
phys_address_left);
|
||||
WriteSingleHWReg(
|
||||
base_address +
|
||||
4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)),
|
||||
phys_address_right);
|
||||
} else {
|
||||
WriteSingleHWReg(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)),
|
||||
phys_address_left);
|
||||
WriteSingleHWReg(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)),
|
||||
phys_address_right);
|
||||
WriteSingleHWReg(
|
||||
base_address +
|
||||
4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)),
|
||||
phys_address_left);
|
||||
WriteSingleHWReg(
|
||||
base_address +
|
||||
4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)),
|
||||
phys_address_right);
|
||||
}
|
||||
WriteSingleHWReg(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)),
|
||||
WriteSingleHWReg(base_address +
|
||||
4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)),
|
||||
info.stride);
|
||||
WriteSingleHWReg(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)),
|
||||
info.format);
|
||||
WriteSingleHWReg(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)),
|
||||
info.shown_fb);
|
||||
WriteSingleHWReg(
|
||||
base_address +
|
||||
4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)),
|
||||
info.format);
|
||||
WriteSingleHWReg(
|
||||
base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)),
|
||||
info.shown_fb);
|
||||
|
||||
if (Pica::g_debug_context)
|
||||
Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::BufferSwapped, nullptr);
|
||||
@ -305,15 +326,15 @@ static void SetBufferSwap(Service::Interface* self) {
|
||||
static void FlushDataCache(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
u32 address = cmd_buff[1];
|
||||
u32 size = cmd_buff[2];
|
||||
u32 size = cmd_buff[2];
|
||||
u32 process = cmd_buff[4];
|
||||
|
||||
// TODO(purpasmart96): Verify return header on HW
|
||||
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw; // No error
|
||||
|
||||
LOG_DEBUG(Service_GSP, "(STUBBED) called address=0x%08X, size=0x%08X, process=0x%08X",
|
||||
address, size, process);
|
||||
LOG_DEBUG(Service_GSP, "(STUBBED) called address=0x%08X, size=0x%08X, process=0x%08X", address,
|
||||
size, process);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -356,11 +377,12 @@ static void RegisterInterruptRelayQueue(Service::Interface* self) {
|
||||
// This specific code is required for a successful initialization, rather than 0
|
||||
first_initialization = false;
|
||||
cmd_buff[1] = ResultCode(ErrorDescription::GPU_FirstInitialization, ErrorModule::GX,
|
||||
ErrorSummary::Success, ErrorLevel::Success).raw;
|
||||
ErrorSummary::Success, ErrorLevel::Success)
|
||||
.raw;
|
||||
} else {
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
}
|
||||
cmd_buff[2] = g_thread_id++; // Thread ID
|
||||
cmd_buff[2] = g_thread_id++; // Thread ID
|
||||
cmd_buff[4] = Kernel::g_handle_table.Create(g_shared_memory).MoveFrom(); // GSP shared memory
|
||||
|
||||
g_interrupt_event->Signal(); // TODO(bunnei): Is this correct?
|
||||
@ -416,7 +438,8 @@ void SignalInterrupt(InterruptId interrupt_id) {
|
||||
// Update framebuffer information if requested
|
||||
// TODO(yuriks): Confirm where this code should be called. It is definitely updated without
|
||||
// executing any GSP commands, only waiting on the event.
|
||||
int screen_id = (interrupt_id == InterruptId::PDC0) ? 0 : (interrupt_id == InterruptId::PDC1) ? 1 : -1;
|
||||
int screen_id =
|
||||
(interrupt_id == InterruptId::PDC0) ? 0 : (interrupt_id == InterruptId::PDC1) ? 1 : -1;
|
||||
if (screen_id != -1) {
|
||||
FrameBufferUpdate* info = GetFrameBufferInfo(thread_id, screen_id);
|
||||
if (info->is_dirty) {
|
||||
@ -440,25 +463,27 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
|
||||
switch (command.id) {
|
||||
|
||||
// GX request DMA - typically used for copying memory from GSP heap to VRAM
|
||||
case CommandId::REQUEST_DMA:
|
||||
{
|
||||
case CommandId::REQUEST_DMA: {
|
||||
MICROPROFILE_SCOPE(GPU_GSP_DMA);
|
||||
|
||||
// TODO: Consider attempting rasterizer-accelerated surface blit if that usage is ever possible/likely
|
||||
Memory::RasterizerFlushRegion(Memory::VirtualToPhysicalAddress(command.dma_request.source_address),
|
||||
command.dma_request.size);
|
||||
Memory::RasterizerFlushAndInvalidateRegion(Memory::VirtualToPhysicalAddress(command.dma_request.dest_address),
|
||||
command.dma_request.size);
|
||||
// TODO: Consider attempting rasterizer-accelerated surface blit if that usage is ever
|
||||
// possible/likely
|
||||
Memory::RasterizerFlushRegion(
|
||||
Memory::VirtualToPhysicalAddress(command.dma_request.source_address),
|
||||
command.dma_request.size);
|
||||
Memory::RasterizerFlushAndInvalidateRegion(
|
||||
Memory::VirtualToPhysicalAddress(command.dma_request.dest_address),
|
||||
command.dma_request.size);
|
||||
|
||||
// TODO(Subv): These memory accesses should not go through the application's memory mapping.
|
||||
// They should go through the GSP module's memory mapping.
|
||||
Memory::CopyBlock(command.dma_request.dest_address, command.dma_request.source_address, command.dma_request.size);
|
||||
Memory::CopyBlock(command.dma_request.dest_address, command.dma_request.source_address,
|
||||
command.dma_request.size);
|
||||
SignalInterrupt(InterruptId::DMA);
|
||||
break;
|
||||
}
|
||||
// TODO: This will need some rework in the future. (why?)
|
||||
case CommandId::SUBMIT_GPU_CMDLIST:
|
||||
{
|
||||
case CommandId::SUBMIT_GPU_CMDLIST: {
|
||||
auto& params = command.submit_gpu_cmdlist;
|
||||
|
||||
if (params.do_flush) {
|
||||
@ -468,10 +493,12 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
|
||||
}
|
||||
|
||||
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);
|
||||
Memory::VirtualToPhysicalAddress(params.address) >> 3);
|
||||
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(command_processor_config.size)),
|
||||
params.size);
|
||||
|
||||
// TODO: Not sure if we are supposed to always write this .. seems to trigger processing though
|
||||
// TODO: Not sure if we are supposed to always write this .. seems to trigger processing
|
||||
// though
|
||||
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(command_processor_config.trigger)), 1);
|
||||
|
||||
// TODO(yuriks): Figure out the meaning of the `flags` field.
|
||||
@ -481,67 +508,70 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
|
||||
|
||||
// It's assumed that the two "blocks" behave equivalently.
|
||||
// Presumably this is done simply to allow two memory fills to run in parallel.
|
||||
case CommandId::SET_MEMORY_FILL:
|
||||
{
|
||||
case CommandId::SET_MEMORY_FILL: {
|
||||
auto& params = command.memory_fill;
|
||||
|
||||
if (params.start1 != 0) {
|
||||
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_start)),
|
||||
Memory::VirtualToPhysicalAddress(params.start1) >> 3);
|
||||
Memory::VirtualToPhysicalAddress(params.start1) >> 3);
|
||||
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_end)),
|
||||
Memory::VirtualToPhysicalAddress(params.end1) >> 3);
|
||||
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].value_32bit)), params.value1);
|
||||
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].control)), params.control1);
|
||||
Memory::VirtualToPhysicalAddress(params.end1) >> 3);
|
||||
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].value_32bit)),
|
||||
params.value1);
|
||||
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].control)),
|
||||
params.control1);
|
||||
}
|
||||
|
||||
if (params.start2 != 0) {
|
||||
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_start)),
|
||||
Memory::VirtualToPhysicalAddress(params.start2) >> 3);
|
||||
Memory::VirtualToPhysicalAddress(params.start2) >> 3);
|
||||
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_end)),
|
||||
Memory::VirtualToPhysicalAddress(params.end2) >> 3);
|
||||
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].value_32bit)), params.value2);
|
||||
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].control)), params.control2);
|
||||
Memory::VirtualToPhysicalAddress(params.end2) >> 3);
|
||||
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].value_32bit)),
|
||||
params.value2);
|
||||
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].control)),
|
||||
params.control2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CommandId::SET_DISPLAY_TRANSFER:
|
||||
{
|
||||
case CommandId::SET_DISPLAY_TRANSFER: {
|
||||
auto& params = command.display_transfer;
|
||||
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.input_address)),
|
||||
Memory::VirtualToPhysicalAddress(params.in_buffer_address) >> 3);
|
||||
Memory::VirtualToPhysicalAddress(params.in_buffer_address) >> 3);
|
||||
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.output_address)),
|
||||
Memory::VirtualToPhysicalAddress(params.out_buffer_address) >> 3);
|
||||
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.input_size)), params.in_buffer_size);
|
||||
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.output_size)), params.out_buffer_size);
|
||||
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.flags)), params.flags);
|
||||
Memory::VirtualToPhysicalAddress(params.out_buffer_address) >> 3);
|
||||
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.input_size)),
|
||||
params.in_buffer_size);
|
||||
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.output_size)),
|
||||
params.out_buffer_size);
|
||||
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.flags)),
|
||||
params.flags);
|
||||
WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(display_transfer_config.trigger)), 1);
|
||||
break;
|
||||
}
|
||||
|
||||
case CommandId::SET_TEXTURE_COPY:
|
||||
{
|
||||
case CommandId::SET_TEXTURE_COPY: {
|
||||
auto& params = command.texture_copy;
|
||||
WriteGPURegister((u32)GPU_REG_INDEX(display_transfer_config.input_address),
|
||||
Memory::VirtualToPhysicalAddress(params.in_buffer_address) >> 3);
|
||||
Memory::VirtualToPhysicalAddress(params.in_buffer_address) >> 3);
|
||||
WriteGPURegister((u32)GPU_REG_INDEX(display_transfer_config.output_address),
|
||||
Memory::VirtualToPhysicalAddress(params.out_buffer_address) >> 3);
|
||||
Memory::VirtualToPhysicalAddress(params.out_buffer_address) >> 3);
|
||||
WriteGPURegister((u32)GPU_REG_INDEX(display_transfer_config.texture_copy.size),
|
||||
params.size);
|
||||
params.size);
|
||||
WriteGPURegister((u32)GPU_REG_INDEX(display_transfer_config.texture_copy.input_size),
|
||||
params.in_width_gap);
|
||||
params.in_width_gap);
|
||||
WriteGPURegister((u32)GPU_REG_INDEX(display_transfer_config.texture_copy.output_size),
|
||||
params.out_width_gap);
|
||||
WriteGPURegister((u32)GPU_REG_INDEX(display_transfer_config.flags),
|
||||
params.flags);
|
||||
params.out_width_gap);
|
||||
WriteGPURegister((u32)GPU_REG_INDEX(display_transfer_config.flags), params.flags);
|
||||
|
||||
// NOTE: Actual GSP ORs 1 with current register instead of overwriting. Doesn't seem to matter.
|
||||
// NOTE: Actual GSP ORs 1 with current register instead of overwriting. Doesn't seem to
|
||||
// matter.
|
||||
WriteGPURegister((u32)GPU_REG_INDEX(display_transfer_config.trigger), 1);
|
||||
break;
|
||||
}
|
||||
|
||||
case CommandId::CACHE_FLUSH:
|
||||
{
|
||||
case CommandId::CACHE_FLUSH: {
|
||||
// NOTE: Rasterizer flushing handled elsewhere in CPU read/write and other GPU handlers
|
||||
// Use command.cache_flush.regions to implement this handler
|
||||
break;
|
||||
@ -552,7 +582,8 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
|
||||
}
|
||||
|
||||
if (Pica::g_debug_context)
|
||||
Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::GSPCommandProcessed, (void*)&command);
|
||||
Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::GSPCommandProcessed,
|
||||
(void*)&command);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -575,7 +606,7 @@ static void SetLcdForceBlack(Service::Interface* self) {
|
||||
// the color to black (all zero).
|
||||
data.is_enabled.Assign(enable_black);
|
||||
|
||||
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_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;
|
||||
@ -679,37 +710,37 @@ static void ReleaseRight(Service::Interface* self) {
|
||||
}
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00010082, WriteHWRegs, "WriteHWRegs"},
|
||||
{0x00020084, WriteHWRegsWithMask, "WriteHWRegsWithMask"},
|
||||
{0x00030082, nullptr, "WriteHWRegRepeat"},
|
||||
{0x00040080, ReadHWRegs, "ReadHWRegs"},
|
||||
{0x00050200, SetBufferSwap, "SetBufferSwap"},
|
||||
{0x00060082, nullptr, "SetCommandList"},
|
||||
{0x000700C2, nullptr, "RequestDma"},
|
||||
{0x00080082, FlushDataCache, "FlushDataCache"},
|
||||
{0x00090082, nullptr, "InvalidateDataCache"},
|
||||
{0x000A0044, nullptr, "RegisterInterruptEvents"},
|
||||
{0x000B0040, SetLcdForceBlack, "SetLcdForceBlack"},
|
||||
{0x000C0000, TriggerCmdReqQueue, "TriggerCmdReqQueue"},
|
||||
{0x000D0140, nullptr, "SetDisplayTransfer"},
|
||||
{0x000E0180, nullptr, "SetTextureCopy"},
|
||||
{0x000F0200, nullptr, "SetMemoryFill"},
|
||||
{0x00100040, SetAxiConfigQoSMode, "SetAxiConfigQoSMode"},
|
||||
{0x00110040, nullptr, "SetPerfLogMode"},
|
||||
{0x00120000, nullptr, "GetPerfLog"},
|
||||
{0x00130042, RegisterInterruptRelayQueue, "RegisterInterruptRelayQueue"},
|
||||
{0x00010082, WriteHWRegs, "WriteHWRegs"},
|
||||
{0x00020084, WriteHWRegsWithMask, "WriteHWRegsWithMask"},
|
||||
{0x00030082, nullptr, "WriteHWRegRepeat"},
|
||||
{0x00040080, ReadHWRegs, "ReadHWRegs"},
|
||||
{0x00050200, SetBufferSwap, "SetBufferSwap"},
|
||||
{0x00060082, nullptr, "SetCommandList"},
|
||||
{0x000700C2, nullptr, "RequestDma"},
|
||||
{0x00080082, FlushDataCache, "FlushDataCache"},
|
||||
{0x00090082, nullptr, "InvalidateDataCache"},
|
||||
{0x000A0044, nullptr, "RegisterInterruptEvents"},
|
||||
{0x000B0040, SetLcdForceBlack, "SetLcdForceBlack"},
|
||||
{0x000C0000, TriggerCmdReqQueue, "TriggerCmdReqQueue"},
|
||||
{0x000D0140, nullptr, "SetDisplayTransfer"},
|
||||
{0x000E0180, nullptr, "SetTextureCopy"},
|
||||
{0x000F0200, nullptr, "SetMemoryFill"},
|
||||
{0x00100040, SetAxiConfigQoSMode, "SetAxiConfigQoSMode"},
|
||||
{0x00110040, nullptr, "SetPerfLogMode"},
|
||||
{0x00120000, nullptr, "GetPerfLog"},
|
||||
{0x00130042, RegisterInterruptRelayQueue, "RegisterInterruptRelayQueue"},
|
||||
{0x00140000, UnregisterInterruptRelayQueue, "UnregisterInterruptRelayQueue"},
|
||||
{0x00150002, nullptr, "TryAcquireRight"},
|
||||
{0x00160042, AcquireRight, "AcquireRight"},
|
||||
{0x00170000, ReleaseRight, "ReleaseRight"},
|
||||
{0x00180000, ImportDisplayCaptureInfo, "ImportDisplayCaptureInfo"},
|
||||
{0x00190000, nullptr, "SaveVramSysArea"},
|
||||
{0x001A0000, nullptr, "RestoreVramSysArea"},
|
||||
{0x001B0000, nullptr, "ResetGpuCore"},
|
||||
{0x001C0040, nullptr, "SetLedForceOff"},
|
||||
{0x001D0040, nullptr, "SetTestCommand"},
|
||||
{0x001E0080, nullptr, "SetInternalPriorities"},
|
||||
{0x001F0082, nullptr, "StoreDataCache"},
|
||||
{0x00150002, nullptr, "TryAcquireRight"},
|
||||
{0x00160042, AcquireRight, "AcquireRight"},
|
||||
{0x00170000, ReleaseRight, "ReleaseRight"},
|
||||
{0x00180000, ImportDisplayCaptureInfo, "ImportDisplayCaptureInfo"},
|
||||
{0x00190000, nullptr, "SaveVramSysArea"},
|
||||
{0x001A0000, nullptr, "RestoreVramSysArea"},
|
||||
{0x001B0000, nullptr, "ResetGpuCore"},
|
||||
{0x001C0040, nullptr, "SetLedForceOff"},
|
||||
{0x001D0040, nullptr, "SetTestCommand"},
|
||||
{0x001E0080, nullptr, "SetInternalPriorities"},
|
||||
{0x001F0082, nullptr, "StoreDataCache"},
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -721,9 +752,9 @@ Interface::Interface() {
|
||||
g_interrupt_event = nullptr;
|
||||
|
||||
using Kernel::MemoryPermission;
|
||||
g_shared_memory = Kernel::SharedMemory::Create(nullptr, 0x1000,
|
||||
MemoryPermission::ReadWrite, MemoryPermission::ReadWrite,
|
||||
0, Kernel::MemoryRegion::BASE, "GSP:SharedMemory");
|
||||
g_shared_memory = Kernel::SharedMemory::Create(nullptr, 0x1000, MemoryPermission::ReadWrite,
|
||||
MemoryPermission::ReadWrite, 0,
|
||||
Kernel::MemoryRegion::BASE, "GSP:SharedMemory");
|
||||
|
||||
g_thread_id = 0;
|
||||
gpu_right_acquired = false;
|
||||
|
@ -20,30 +20,30 @@ namespace GSP_GPU {
|
||||
|
||||
/// GSP interrupt ID
|
||||
enum class InterruptId : u8 {
|
||||
PSC0 = 0x00,
|
||||
PSC1 = 0x01,
|
||||
PDC0 = 0x02, // Seems called every vertical screen line
|
||||
PDC1 = 0x03, // Seems called every frame
|
||||
PPF = 0x04,
|
||||
P3D = 0x05,
|
||||
DMA = 0x06,
|
||||
PSC0 = 0x00,
|
||||
PSC1 = 0x01,
|
||||
PDC0 = 0x02, // Seems called every vertical screen line
|
||||
PDC1 = 0x03, // Seems called every frame
|
||||
PPF = 0x04,
|
||||
P3D = 0x05,
|
||||
DMA = 0x06,
|
||||
};
|
||||
|
||||
/// GSP command ID
|
||||
enum class CommandId : u32 {
|
||||
REQUEST_DMA = 0x00,
|
||||
REQUEST_DMA = 0x00,
|
||||
/// Submits a commandlist for execution by the GPU.
|
||||
SUBMIT_GPU_CMDLIST = 0x01,
|
||||
|
||||
// Fills a given memory range with a particular value
|
||||
SET_MEMORY_FILL = 0x02,
|
||||
SET_MEMORY_FILL = 0x02,
|
||||
|
||||
// Copies an image and optionally performs color-conversion or scaling.
|
||||
// This is highly similar to the GameCube's EFB copy feature
|
||||
SET_DISPLAY_TRANSFER = 0x03,
|
||||
SET_DISPLAY_TRANSFER = 0x03,
|
||||
|
||||
// Conceptionally similar to SET_DISPLAY_TRANSFER and presumable uses the same hardware path
|
||||
SET_TEXTURE_COPY = 0x04,
|
||||
SET_TEXTURE_COPY = 0x04,
|
||||
/// Flushes up to 3 cache regions in a single command.
|
||||
CACHE_FLUSH = 0x05,
|
||||
};
|
||||
@ -61,19 +61,18 @@ struct InterruptRelayQueue {
|
||||
u32 missed_PDC0;
|
||||
u32 missed_PDC1;
|
||||
|
||||
InterruptId slot[0x34]; ///< Interrupt ID slots
|
||||
InterruptId slot[0x34]; ///< Interrupt ID slots
|
||||
};
|
||||
static_assert(sizeof(InterruptRelayQueue) == 0x40,
|
||||
"InterruptRelayQueue struct has incorrect size");
|
||||
static_assert(sizeof(InterruptRelayQueue) == 0x40, "InterruptRelayQueue struct has incorrect size");
|
||||
|
||||
struct FrameBufferInfo {
|
||||
BitField<0, 1, u32> active_fb; // 0 = first, 1 = second
|
||||
|
||||
u32 address_left;
|
||||
u32 address_right;
|
||||
u32 stride; // maps to 0x1EF00X90 ?
|
||||
u32 format; // maps to 0x1EF00X70 ?
|
||||
u32 shown_fb; // maps to 0x1EF00X78 ?
|
||||
u32 stride; // maps to 0x1EF00X90 ?
|
||||
u32 format; // maps to 0x1EF00X70 ?
|
||||
u32 shown_fb; // maps to 0x1EF00X78 ?
|
||||
u32 unknown;
|
||||
};
|
||||
static_assert(sizeof(FrameBufferInfo) == 0x1c, "Struct has incorrect size");
|
||||
@ -91,7 +90,8 @@ static_assert(sizeof(FrameBufferUpdate) == 0x40, "Struct has incorrect size");
|
||||
// TODO: Not sure if this padding is correct.
|
||||
// Chances are the second block is stored at offset 0x24 rather than 0x20.
|
||||
#ifndef _MSC_VER
|
||||
static_assert(offsetof(FrameBufferUpdate, framebuffer_info[1]) == 0x20, "FrameBufferInfo element has incorrect alignment");
|
||||
static_assert(offsetof(FrameBufferUpdate, framebuffer_info[1]) == 0x20,
|
||||
"FrameBufferInfo element has incorrect alignment");
|
||||
#endif
|
||||
|
||||
/// GSP command
|
||||
@ -163,13 +163,13 @@ struct CommandBuffer {
|
||||
// Current command index. This index is updated by GSP module after loading the command
|
||||
// data, right before the command is processed. When this index is updated by GSP module,
|
||||
// the total commands field is decreased by one as well.
|
||||
BitField<0,8,u32> index;
|
||||
BitField<0, 8, u32> index;
|
||||
|
||||
// Total commands to process, must not be value 0 when GSP module handles commands. This
|
||||
// must be <=15 when writing a command to shared memory. This is incremented by the
|
||||
// application when writing a command to shared memory, after increasing this value
|
||||
// TriggerCmdReqQueue is only used if this field is value 1.
|
||||
BitField<8,8,u32> number_commands;
|
||||
BitField<8, 8, u32> number_commands;
|
||||
};
|
||||
|
||||
u32 unk[7];
|
||||
|
@ -9,13 +9,11 @@
|
||||
|
||||
namespace GSP_LCD {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x000F0000, nullptr, "PowerOnAllBacklights"},
|
||||
{0x00100000, nullptr, "PowerOffAllBacklights"},
|
||||
{0x00110040, nullptr, "PowerOnBacklight"},
|
||||
{0x00120040, nullptr, "PowerOffBacklight"},
|
||||
{0x00130040, nullptr, "SetLedForceOff"}
|
||||
};
|
||||
const Interface::FunctionInfo FunctionTable[] = {{0x000F0000, nullptr, "PowerOnAllBacklights"},
|
||||
{0x00100000, nullptr, "PowerOffAllBacklights"},
|
||||
{0x00110040, nullptr, "PowerOnBacklight"},
|
||||
{0x00120040, nullptr, "PowerOffBacklight"},
|
||||
{0x00130040, nullptr, "SetLedForceOff"}};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Interface class
|
||||
|
@ -4,13 +4,13 @@
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "common/emu_window.h"
|
||||
#include "common/logging/log.h"
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/hid/hid.h"
|
||||
#include "core/hle/service/hid/hid_spvr.h"
|
||||
#include "core/hle/service/hid/hid_user.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
@ -37,11 +37,14 @@ static u32 next_accelerometer_index;
|
||||
static u32 next_gyroscope_index;
|
||||
|
||||
static int enable_accelerometer_count = 0; // positive means enabled
|
||||
static int enable_gyroscope_count = 0; // positive means enabled
|
||||
static int enable_gyroscope_count = 0; // positive means enabled
|
||||
|
||||
static PadState GetCirclePadDirectionState(s16 circle_pad_x, s16 circle_pad_y) {
|
||||
constexpr float TAN30 = 0.577350269, TAN60 = 1 / TAN30; // 30 degree and 60 degree are angular thresholds for directions
|
||||
constexpr int CIRCLE_PAD_THRESHOLD_SQUARE = 40 * 40; // a circle pad radius greater than 40 will trigger circle pad direction
|
||||
constexpr float TAN30 = 0.577350269,
|
||||
TAN60 =
|
||||
1 / TAN30; // 30 degree and 60 degree are angular thresholds for directions
|
||||
constexpr int CIRCLE_PAD_THRESHOLD_SQUARE =
|
||||
40 * 40; // a circle pad radius greater than 40 will trigger circle pad direction
|
||||
PadState state;
|
||||
state.hex = 0;
|
||||
|
||||
@ -90,7 +93,7 @@ void Update() {
|
||||
PadState old_state = mem->pad.entries[last_entry_index].current_state;
|
||||
|
||||
// Compute bitmask with 1s for bits different from the old state
|
||||
PadState changed = { { (state.hex ^ old_state.hex) } };
|
||||
PadState changed = {{(state.hex ^ old_state.hex)}};
|
||||
|
||||
// Get the current Pad entry
|
||||
PadDataEntry& pad_entry = mem->pad.entries[mem->pad.index];
|
||||
@ -135,11 +138,13 @@ void Update() {
|
||||
// Update accelerometer
|
||||
if (enable_accelerometer_count > 0) {
|
||||
mem->accelerometer.index = next_accelerometer_index;
|
||||
next_accelerometer_index = (next_accelerometer_index + 1) % mem->accelerometer.entries.size();
|
||||
next_accelerometer_index =
|
||||
(next_accelerometer_index + 1) % mem->accelerometer.entries.size();
|
||||
|
||||
AccelerometerDataEntry& accelerometer_entry = mem->accelerometer.entries[mem->accelerometer.index];
|
||||
std::tie(accelerometer_entry.x, accelerometer_entry.y, accelerometer_entry.z)
|
||||
= VideoCore::g_emu_window->GetAccelerometerState();
|
||||
AccelerometerDataEntry& accelerometer_entry =
|
||||
mem->accelerometer.entries[mem->accelerometer.index];
|
||||
std::tie(accelerometer_entry.x, accelerometer_entry.y, accelerometer_entry.z) =
|
||||
VideoCore::g_emu_window->GetAccelerometerState();
|
||||
|
||||
// Make up "raw" entry
|
||||
// TODO(wwylele):
|
||||
@ -167,8 +172,8 @@ void Update() {
|
||||
next_gyroscope_index = (next_gyroscope_index + 1) % mem->gyroscope.entries.size();
|
||||
|
||||
GyroscopeDataEntry& gyroscope_entry = mem->gyroscope.entries[mem->gyroscope.index];
|
||||
std::tie(gyroscope_entry.x, gyroscope_entry.y, gyroscope_entry.z)
|
||||
= VideoCore::g_emu_window->GetGyroscopeState();
|
||||
std::tie(gyroscope_entry.x, gyroscope_entry.y, gyroscope_entry.z) =
|
||||
VideoCore::g_emu_window->GetGyroscopeState();
|
||||
|
||||
// Make up "raw" entry
|
||||
mem->gyroscope.raw_entry.x = gyroscope_entry.x;
|
||||
@ -188,7 +193,7 @@ void Update() {
|
||||
void GetIPCHandles(Service::Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
|
||||
cmd_buff[1] = 0; // No error
|
||||
cmd_buff[1] = 0; // No error
|
||||
cmd_buff[2] = 0x14000000; // IPC Command Structure translate-header
|
||||
// TODO(yuriks): Return error from SendSyncRequest is this fails (part of IPC marshalling)
|
||||
cmd_buff[3] = Kernel::g_handle_table.Create(Service::HID::shared_mem).MoveFrom();
|
||||
@ -259,9 +264,7 @@ void GetGyroscopeLowCalibrateParam(Service::Interface* self) {
|
||||
|
||||
const s16 param_unit = 6700; // an approximate value taken from hw
|
||||
GyroscopeCalibrateParam param = {
|
||||
{ 0, param_unit, -param_unit },
|
||||
{ 0, param_unit, -param_unit },
|
||||
{ 0, param_unit, -param_unit },
|
||||
{0, param_unit, -param_unit}, {0, param_unit, -param_unit}, {0, param_unit, -param_unit},
|
||||
};
|
||||
memcpy(&cmd_buff[2], ¶m, sizeof(param));
|
||||
|
||||
@ -286,9 +289,9 @@ void Init() {
|
||||
AddService(new HID_SPVR_Interface);
|
||||
|
||||
using Kernel::MemoryPermission;
|
||||
shared_mem = SharedMemory::Create(nullptr, 0x1000,
|
||||
MemoryPermission::ReadWrite, MemoryPermission::Read,
|
||||
0, Kernel::MemoryRegion::BASE, "HID:SharedMemory");
|
||||
shared_mem =
|
||||
SharedMemory::Create(nullptr, 0x1000, MemoryPermission::ReadWrite, MemoryPermission::Read,
|
||||
0, Kernel::MemoryRegion::BASE, "HID:SharedMemory");
|
||||
|
||||
next_pad_index = 0;
|
||||
next_touch_index = 0;
|
||||
@ -296,9 +299,9 @@ void Init() {
|
||||
// Create event handles
|
||||
event_pad_or_touch_1 = Event::Create(ResetType::OneShot, "HID:EventPadOrTouch1");
|
||||
event_pad_or_touch_2 = Event::Create(ResetType::OneShot, "HID:EventPadOrTouch2");
|
||||
event_accelerometer = Event::Create(ResetType::OneShot, "HID:EventAccelerometer");
|
||||
event_gyroscope = Event::Create(ResetType::OneShot, "HID:EventGyroscope");
|
||||
event_debug_pad = Event::Create(ResetType::OneShot, "HID:EventDebugPad");
|
||||
event_accelerometer = Event::Create(ResetType::OneShot, "HID:EventAccelerometer");
|
||||
event_gyroscope = Event::Create(ResetType::OneShot, "HID:EventGyroscope");
|
||||
event_debug_pad = Event::Create(ResetType::OneShot, "HID:EventDebugPad");
|
||||
}
|
||||
|
||||
void Shutdown() {
|
||||
|
@ -9,10 +9,10 @@
|
||||
#ifndef _MSC_VER
|
||||
#include <cstddef>
|
||||
#endif
|
||||
#include "core/settings.h"
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace Service {
|
||||
|
||||
@ -103,7 +103,7 @@ struct SharedMem {
|
||||
struct {
|
||||
s64 index_reset_ticks; ///< CPU tick count for when HID module updated entry index 0
|
||||
s64 index_reset_ticks_previous; ///< Previous `index_reset_ticks`
|
||||
u32 index; ///< Index of the last updated pad state entry
|
||||
u32 index; ///< Index of the last updated pad state entry
|
||||
|
||||
INSERT_PADDING_WORDS(0x2);
|
||||
|
||||
@ -121,7 +121,7 @@ struct SharedMem {
|
||||
struct {
|
||||
s64 index_reset_ticks; ///< CPU tick count for when HID module updated entry index 0
|
||||
s64 index_reset_ticks_previous; ///< Previous `index_reset_ticks`
|
||||
u32 index; ///< Index of the last updated touch entry
|
||||
u32 index; ///< Index of the last updated touch entry
|
||||
|
||||
INSERT_PADDING_WORDS(0x1);
|
||||
|
||||
@ -135,7 +135,7 @@ struct SharedMem {
|
||||
struct {
|
||||
s64 index_reset_ticks; ///< CPU tick count for when HID module updated entry index 0
|
||||
s64 index_reset_ticks_previous; ///< Previous `index_reset_ticks`
|
||||
u32 index; ///< Index of the last updated accelerometer entry
|
||||
u32 index; ///< Index of the last updated accelerometer entry
|
||||
|
||||
INSERT_PADDING_WORDS(0x1);
|
||||
|
||||
@ -149,7 +149,7 @@ struct SharedMem {
|
||||
struct {
|
||||
s64 index_reset_ticks; ///< CPU tick count for when HID module updated entry index 0
|
||||
s64 index_reset_ticks_previous; ///< Previous `index_reset_ticks`
|
||||
u32 index; ///< Index of the last updated accelerometer entry
|
||||
u32 index; ///< Index of the last updated accelerometer entry
|
||||
|
||||
INSERT_PADDING_WORDS(0x1);
|
||||
|
||||
@ -176,9 +176,9 @@ struct GyroscopeCalibrateParam {
|
||||
// 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")
|
||||
#define ASSERT_REG_POSITION(field_name, position) \
|
||||
static_assert(offsetof(SharedMem, field_name) == position * 4, \
|
||||
"Field " #field_name " has invalid position")
|
||||
|
||||
ASSERT_REG_POSITION(pad.index_reset_ticks, 0x0);
|
||||
ASSERT_REG_POSITION(touch.index_reset_ticks, 0x2A);
|
||||
@ -187,33 +187,33 @@ ASSERT_REG_POSITION(touch.index_reset_ticks, 0x2A);
|
||||
#endif // !defined(_MSC_VER)
|
||||
|
||||
// Pre-defined PadStates for single button presses
|
||||
const PadState PAD_NONE = {{0}};
|
||||
const PadState PAD_A = {{1u << 0}};
|
||||
const PadState PAD_B = {{1u << 1}};
|
||||
const PadState PAD_SELECT = {{1u << 2}};
|
||||
const PadState PAD_START = {{1u << 3}};
|
||||
const PadState PAD_RIGHT = {{1u << 4}};
|
||||
const PadState PAD_LEFT = {{1u << 5}};
|
||||
const PadState PAD_UP = {{1u << 6}};
|
||||
const PadState PAD_DOWN = {{1u << 7}};
|
||||
const PadState PAD_R = {{1u << 8}};
|
||||
const PadState PAD_L = {{1u << 9}};
|
||||
const PadState PAD_X = {{1u << 10}};
|
||||
const PadState PAD_Y = {{1u << 11}};
|
||||
const PadState PAD_NONE = {{0}};
|
||||
const PadState PAD_A = {{1u << 0}};
|
||||
const PadState PAD_B = {{1u << 1}};
|
||||
const PadState PAD_SELECT = {{1u << 2}};
|
||||
const PadState PAD_START = {{1u << 3}};
|
||||
const PadState PAD_RIGHT = {{1u << 4}};
|
||||
const PadState PAD_LEFT = {{1u << 5}};
|
||||
const PadState PAD_UP = {{1u << 6}};
|
||||
const PadState PAD_DOWN = {{1u << 7}};
|
||||
const PadState PAD_R = {{1u << 8}};
|
||||
const PadState PAD_L = {{1u << 9}};
|
||||
const PadState PAD_X = {{1u << 10}};
|
||||
const PadState PAD_Y = {{1u << 11}};
|
||||
|
||||
const PadState PAD_ZL = {{1u << 14}};
|
||||
const PadState PAD_ZR = {{1u << 15}};
|
||||
const PadState PAD_ZL = {{1u << 14}};
|
||||
const PadState PAD_ZR = {{1u << 15}};
|
||||
|
||||
const PadState PAD_TOUCH = {{1u << 20}};
|
||||
const PadState PAD_TOUCH = {{1u << 20}};
|
||||
|
||||
const PadState PAD_C_RIGHT = {{1u << 24}};
|
||||
const PadState PAD_C_LEFT = {{1u << 25}};
|
||||
const PadState PAD_C_UP = {{1u << 26}};
|
||||
const PadState PAD_C_DOWN = {{1u << 27}};
|
||||
const PadState PAD_C_RIGHT = {{1u << 24}};
|
||||
const PadState PAD_C_LEFT = {{1u << 25}};
|
||||
const PadState PAD_C_UP = {{1u << 26}};
|
||||
const PadState PAD_C_DOWN = {{1u << 27}};
|
||||
const PadState PAD_CIRCLE_RIGHT = {{1u << 28}};
|
||||
const PadState PAD_CIRCLE_LEFT = {{1u << 29}};
|
||||
const PadState PAD_CIRCLE_UP = {{1u << 30}};
|
||||
const PadState PAD_CIRCLE_DOWN = {{1u << 31}};
|
||||
const PadState PAD_CIRCLE_LEFT = {{1u << 29}};
|
||||
const PadState PAD_CIRCLE_UP = {{1u << 30}};
|
||||
const PadState PAD_CIRCLE_DOWN = {{1u << 31}};
|
||||
|
||||
/**
|
||||
* HID::GetIPCHandles service function
|
||||
@ -305,6 +305,5 @@ void Init();
|
||||
|
||||
/// Shutdown HID service
|
||||
void Shutdown();
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -9,16 +9,16 @@ namespace Service {
|
||||
namespace HID {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x000A0000, GetIPCHandles, "GetIPCHandles"},
|
||||
{0x000B0000, nullptr, "StartAnalogStickCalibration"},
|
||||
{0x000E0000, nullptr, "GetAnalogStickCalibrateParam"},
|
||||
{0x00110000, EnableAccelerometer, "EnableAccelerometer"},
|
||||
{0x00120000, DisableAccelerometer, "DisableAccelerometer"},
|
||||
{0x00130000, EnableGyroscopeLow, "EnableGyroscopeLow"},
|
||||
{0x00140000, DisableGyroscopeLow, "DisableGyroscopeLow"},
|
||||
{0x000A0000, GetIPCHandles, "GetIPCHandles"},
|
||||
{0x000B0000, nullptr, "StartAnalogStickCalibration"},
|
||||
{0x000E0000, nullptr, "GetAnalogStickCalibrateParam"},
|
||||
{0x00110000, EnableAccelerometer, "EnableAccelerometer"},
|
||||
{0x00120000, DisableAccelerometer, "DisableAccelerometer"},
|
||||
{0x00130000, EnableGyroscopeLow, "EnableGyroscopeLow"},
|
||||
{0x00140000, DisableGyroscopeLow, "DisableGyroscopeLow"},
|
||||
{0x00150000, GetGyroscopeLowRawToDpsCoefficient, "GetGyroscopeLowRawToDpsCoefficient"},
|
||||
{0x00160000, GetGyroscopeLowCalibrateParam, "GetGyroscopeLowCalibrateParam"},
|
||||
{0x00170000, GetSoundVolume, "GetSoundVolume"},
|
||||
{0x00160000, GetGyroscopeLowCalibrateParam, "GetGyroscopeLowCalibrateParam"},
|
||||
{0x00170000, GetSoundVolume, "GetSoundVolume"},
|
||||
};
|
||||
|
||||
HID_SPVR_Interface::HID_SPVR_Interface() {
|
||||
|
@ -9,16 +9,16 @@ namespace Service {
|
||||
namespace HID {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x000A0000, GetIPCHandles, "GetIPCHandles"},
|
||||
{0x000B0000, nullptr, "StartAnalogStickCalibration"},
|
||||
{0x000E0000, nullptr, "GetAnalogStickCalibrateParam"},
|
||||
{0x00110000, EnableAccelerometer, "EnableAccelerometer"},
|
||||
{0x00120000, DisableAccelerometer, "DisableAccelerometer"},
|
||||
{0x00130000, EnableGyroscopeLow, "EnableGyroscopeLow"},
|
||||
{0x00140000, DisableGyroscopeLow, "DisableGyroscopeLow"},
|
||||
{0x000A0000, GetIPCHandles, "GetIPCHandles"},
|
||||
{0x000B0000, nullptr, "StartAnalogStickCalibration"},
|
||||
{0x000E0000, nullptr, "GetAnalogStickCalibrateParam"},
|
||||
{0x00110000, EnableAccelerometer, "EnableAccelerometer"},
|
||||
{0x00120000, DisableAccelerometer, "DisableAccelerometer"},
|
||||
{0x00130000, EnableGyroscopeLow, "EnableGyroscopeLow"},
|
||||
{0x00140000, DisableGyroscopeLow, "DisableGyroscopeLow"},
|
||||
{0x00150000, GetGyroscopeLowRawToDpsCoefficient, "GetGyroscopeLowRawToDpsCoefficient"},
|
||||
{0x00160000, GetGyroscopeLowCalibrateParam, "GetGyroscopeLowCalibrateParam"},
|
||||
{0x00170000, GetSoundVolume, "GetSoundVolume"},
|
||||
{0x00160000, GetGyroscopeLowCalibrateParam, "GetGyroscopeLowCalibrateParam"},
|
||||
{0x00170000, GetSoundVolume, "GetSoundVolume"},
|
||||
};
|
||||
|
||||
HID_U_Interface::HID_U_Interface() {
|
||||
|
@ -10,56 +10,56 @@
|
||||
namespace HTTP_C {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00010044, nullptr, "Initialize"},
|
||||
{0x00020082, nullptr, "CreateContext"},
|
||||
{0x00030040, nullptr, "CloseContext"},
|
||||
{0x00040040, nullptr, "CancelConnection"},
|
||||
{0x00050040, nullptr, "GetRequestState"},
|
||||
{0x00060040, nullptr, "GetDownloadSizeState"},
|
||||
{0x00070040, nullptr, "GetRequestError"},
|
||||
{0x00080042, nullptr, "InitializeConnectionSession"},
|
||||
{0x00090040, nullptr, "BeginRequest"},
|
||||
{0x000A0040, nullptr, "BeginRequestAsync"},
|
||||
{0x000B0082, nullptr, "ReceiveData"},
|
||||
{0x000C0102, nullptr, "ReceiveDataTimeout"},
|
||||
{0x000D0146, nullptr, "SetProxy"},
|
||||
{0x000E0040, nullptr, "SetProxyDefault"},
|
||||
{0x000F00C4, nullptr, "SetBasicAuthorization"},
|
||||
{0x00100080, nullptr, "SetSocketBufferSize"},
|
||||
{0x001100C4, nullptr, "AddRequestHeader"},
|
||||
{0x001200C4, nullptr, "AddPostDataAscii"},
|
||||
{0x001300C4, nullptr, "AddPostDataBinary"},
|
||||
{0x00140082, nullptr, "AddPostDataRaw"},
|
||||
{0x00150080, nullptr, "SetPostDataType"},
|
||||
{0x001600C4, nullptr, "SendPostDataAscii"},
|
||||
{0x00170144, nullptr, "SendPostDataAsciiTimeout"},
|
||||
{0x001800C4, nullptr, "SendPostDataBinary"},
|
||||
{0x00190144, nullptr, "SendPostDataBinaryTimeout"},
|
||||
{0x001A0082, nullptr, "SendPostDataRaw"},
|
||||
{0x001B0102, nullptr, "SendPOSTDataRawTimeout"},
|
||||
{0x001C0080, nullptr, "SetPostDataEncoding"},
|
||||
{0x001D0040, nullptr, "NotifyFinishSendPostData"},
|
||||
{0x001E00C4, nullptr, "GetResponseHeader"},
|
||||
{0x001F0144, nullptr, "GetResponseHeaderTimeout"},
|
||||
{0x00200082, nullptr, "GetResponseData"},
|
||||
{0x00210102, nullptr, "GetResponseDataTimeout"},
|
||||
{0x00220040, nullptr, "GetResponseStatusCode"},
|
||||
{0x002300C0, nullptr, "GetResponseStatusCodeTimeout"},
|
||||
{0x00240082, nullptr, "AddTrustedRootCA"},
|
||||
{0x00250080, nullptr, "AddDefaultCert"},
|
||||
{0x00260080, nullptr, "SelectRootCertChain"},
|
||||
{0x002700C4, nullptr, "SetClientCert"},
|
||||
{0x002B0080, nullptr, "SetSSLOpt"},
|
||||
{0x002C0080, nullptr, "SetSSLClearOpt"},
|
||||
{0x002D0000, nullptr, "CreateRootCertChain"},
|
||||
{0x002E0040, nullptr, "DestroyRootCertChain"},
|
||||
{0x002F0082, nullptr, "RootCertChainAddCert"},
|
||||
{0x00300080, nullptr, "RootCertChainAddDefaultCert"},
|
||||
{0x00350186, nullptr, "SetDefaultProxy"},
|
||||
{0x00360000, nullptr, "ClearDNSCache"},
|
||||
{0x00370080, nullptr, "SetKeepAlive"},
|
||||
{0x003800C0, nullptr, "SetPostDataTypeSize"},
|
||||
{0x00390000, nullptr, "Finalize"},
|
||||
{0x00010044, nullptr, "Initialize"},
|
||||
{0x00020082, nullptr, "CreateContext"},
|
||||
{0x00030040, nullptr, "CloseContext"},
|
||||
{0x00040040, nullptr, "CancelConnection"},
|
||||
{0x00050040, nullptr, "GetRequestState"},
|
||||
{0x00060040, nullptr, "GetDownloadSizeState"},
|
||||
{0x00070040, nullptr, "GetRequestError"},
|
||||
{0x00080042, nullptr, "InitializeConnectionSession"},
|
||||
{0x00090040, nullptr, "BeginRequest"},
|
||||
{0x000A0040, nullptr, "BeginRequestAsync"},
|
||||
{0x000B0082, nullptr, "ReceiveData"},
|
||||
{0x000C0102, nullptr, "ReceiveDataTimeout"},
|
||||
{0x000D0146, nullptr, "SetProxy"},
|
||||
{0x000E0040, nullptr, "SetProxyDefault"},
|
||||
{0x000F00C4, nullptr, "SetBasicAuthorization"},
|
||||
{0x00100080, nullptr, "SetSocketBufferSize"},
|
||||
{0x001100C4, nullptr, "AddRequestHeader"},
|
||||
{0x001200C4, nullptr, "AddPostDataAscii"},
|
||||
{0x001300C4, nullptr, "AddPostDataBinary"},
|
||||
{0x00140082, nullptr, "AddPostDataRaw"},
|
||||
{0x00150080, nullptr, "SetPostDataType"},
|
||||
{0x001600C4, nullptr, "SendPostDataAscii"},
|
||||
{0x00170144, nullptr, "SendPostDataAsciiTimeout"},
|
||||
{0x001800C4, nullptr, "SendPostDataBinary"},
|
||||
{0x00190144, nullptr, "SendPostDataBinaryTimeout"},
|
||||
{0x001A0082, nullptr, "SendPostDataRaw"},
|
||||
{0x001B0102, nullptr, "SendPOSTDataRawTimeout"},
|
||||
{0x001C0080, nullptr, "SetPostDataEncoding"},
|
||||
{0x001D0040, nullptr, "NotifyFinishSendPostData"},
|
||||
{0x001E00C4, nullptr, "GetResponseHeader"},
|
||||
{0x001F0144, nullptr, "GetResponseHeaderTimeout"},
|
||||
{0x00200082, nullptr, "GetResponseData"},
|
||||
{0x00210102, nullptr, "GetResponseDataTimeout"},
|
||||
{0x00220040, nullptr, "GetResponseStatusCode"},
|
||||
{0x002300C0, nullptr, "GetResponseStatusCodeTimeout"},
|
||||
{0x00240082, nullptr, "AddTrustedRootCA"},
|
||||
{0x00250080, nullptr, "AddDefaultCert"},
|
||||
{0x00260080, nullptr, "SelectRootCertChain"},
|
||||
{0x002700C4, nullptr, "SetClientCert"},
|
||||
{0x002B0080, nullptr, "SetSSLOpt"},
|
||||
{0x002C0080, nullptr, "SetSSLClearOpt"},
|
||||
{0x002D0000, nullptr, "CreateRootCertChain"},
|
||||
{0x002E0040, nullptr, "DestroyRootCertChain"},
|
||||
{0x002F0082, nullptr, "RootCertChainAddCert"},
|
||||
{0x00300080, nullptr, "RootCertChainAddDefaultCert"},
|
||||
{0x00350186, nullptr, "SetDefaultProxy"},
|
||||
{0x00360000, nullptr, "ClearDNSCache"},
|
||||
{0x00370080, nullptr, "SetKeepAlive"},
|
||||
{0x003800C0, nullptr, "SetPostDataTypeSize"},
|
||||
{0x00390000, nullptr, "Finalize"},
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -5,11 +5,11 @@
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/kernel/shared_memory.h"
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/ir/ir.h"
|
||||
#include "core/hle/service/ir/ir_rst.h"
|
||||
#include "core/hle/service/ir/ir_u.h"
|
||||
#include "core/hle/service/ir/ir_user.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service {
|
||||
namespace IR {
|
||||
@ -32,14 +32,14 @@ void InitializeIrNopShared(Interface* self) {
|
||||
u32* cmd_buff = Kernel::GetCommandBuffer();
|
||||
|
||||
u32 transfer_buff_size = cmd_buff[1];
|
||||
u32 recv_buff_size = cmd_buff[2];
|
||||
u32 unk1 = cmd_buff[3];
|
||||
u32 send_buff_size = cmd_buff[4];
|
||||
u32 unk2 = cmd_buff[5];
|
||||
u8 baud_rate = cmd_buff[6] & 0xFF;
|
||||
Handle handle = cmd_buff[8];
|
||||
u32 recv_buff_size = cmd_buff[2];
|
||||
u32 unk1 = cmd_buff[3];
|
||||
u32 send_buff_size = cmd_buff[4];
|
||||
u32 unk2 = cmd_buff[5];
|
||||
u8 baud_rate = cmd_buff[6] & 0xFF;
|
||||
Handle handle = cmd_buff[8];
|
||||
|
||||
if(Kernel::g_handle_table.IsValid(handle)) {
|
||||
if (Kernel::g_handle_table.IsValid(handle)) {
|
||||
transfer_shared_memory = Kernel::g_handle_table.Get<Kernel::SharedMemory>(handle);
|
||||
transfer_shared_memory->name = "IR:TransferSharedMemory";
|
||||
}
|
||||
@ -47,7 +47,7 @@ void InitializeIrNopShared(Interface* self) {
|
||||
cmd_buff[1] = RESULT_SUCCESS.raw;
|
||||
|
||||
LOG_WARNING(Service_IR, "(STUBBED) called, transfer_buff_size=%d, recv_buff_size=%d, "
|
||||
"unk1=%d, send_buff_size=%d, unk2=%d, baud_rate=%u, handle=0x%08X",
|
||||
"unk1=%d, send_buff_size=%d, unk2=%d, baud_rate=%u, handle=0x%08X",
|
||||
transfer_buff_size, recv_buff_size, unk1, send_buff_size, unk2, baud_rate, handle);
|
||||
}
|
||||
|
||||
@ -94,13 +94,13 @@ void Init() {
|
||||
AddService(new IR_User_Interface);
|
||||
|
||||
using Kernel::MemoryPermission;
|
||||
shared_memory = SharedMemory::Create(nullptr, 0x1000,
|
||||
Kernel::MemoryPermission::ReadWrite, Kernel::MemoryPermission::ReadWrite,
|
||||
0, Kernel::MemoryRegion::BASE, "IR:SharedMemory");
|
||||
shared_memory = SharedMemory::Create(nullptr, 0x1000, Kernel::MemoryPermission::ReadWrite,
|
||||
Kernel::MemoryPermission::ReadWrite, 0,
|
||||
Kernel::MemoryRegion::BASE, "IR:SharedMemory");
|
||||
transfer_shared_memory = nullptr;
|
||||
|
||||
// Create event handle(s)
|
||||
handle_event = Event::Create(ResetType::OneShot, "IR:HandleEvent");
|
||||
handle_event = Event::Create(ResetType::OneShot, "IR:HandleEvent");
|
||||
conn_status_event = Event::Create(ResetType::OneShot, "IR:ConnectionStatusEvent");
|
||||
}
|
||||
|
||||
|
@ -9,10 +9,10 @@ namespace Service {
|
||||
namespace IR {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00010000, GetHandles, "GetHandles"},
|
||||
{0x00020080, nullptr, "Initialize"},
|
||||
{0x00030000, nullptr, "Shutdown"},
|
||||
{0x00090000, nullptr, "WriteToTwoFields"},
|
||||
{0x00010000, GetHandles, "GetHandles"},
|
||||
{0x00020080, nullptr, "Initialize"},
|
||||
{0x00030000, nullptr, "Shutdown"},
|
||||
{0x00090000, nullptr, "WriteToTwoFields"},
|
||||
};
|
||||
|
||||
IR_RST_Interface::IR_RST_Interface() {
|
||||
|
@ -8,24 +8,15 @@ namespace Service {
|
||||
namespace IR {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00010000, nullptr, "Initialize"},
|
||||
{0x00020000, nullptr, "Shutdown"},
|
||||
{0x00030042, nullptr, "StartSendTransfer"},
|
||||
{0x00040000, nullptr, "WaitSendTransfer"},
|
||||
{0x000500C2, nullptr, "StartRecvTransfer"},
|
||||
{0x00060000, nullptr, "WaitRecvTransfer"},
|
||||
{0x00070080, nullptr, "GetRecvTransferCount"},
|
||||
{0x00080000, nullptr, "GetSendState"},
|
||||
{0x00090040, nullptr, "SetBitRate"},
|
||||
{0x000A0000, nullptr, "GetBitRate"},
|
||||
{0x000B0040, nullptr, "SetIRLEDState"},
|
||||
{0x000C0000, nullptr, "GetIRLEDRecvState"},
|
||||
{0x000D0000, nullptr, "GetSendFinishedEvent"},
|
||||
{0x000E0000, nullptr, "GetRecvFinishedEvent"},
|
||||
{0x000F0000, nullptr, "GetTransferState"},
|
||||
{0x00100000, nullptr, "GetErrorStatus"},
|
||||
{0x00110040, nullptr, "SetSleepModeActive"},
|
||||
{0x00120040, nullptr, "SetSleepModeState"},
|
||||
{0x00010000, nullptr, "Initialize"}, {0x00020000, nullptr, "Shutdown"},
|
||||
{0x00030042, nullptr, "StartSendTransfer"}, {0x00040000, nullptr, "WaitSendTransfer"},
|
||||
{0x000500C2, nullptr, "StartRecvTransfer"}, {0x00060000, nullptr, "WaitRecvTransfer"},
|
||||
{0x00070080, nullptr, "GetRecvTransferCount"}, {0x00080000, nullptr, "GetSendState"},
|
||||
{0x00090040, nullptr, "SetBitRate"}, {0x000A0000, nullptr, "GetBitRate"},
|
||||
{0x000B0040, nullptr, "SetIRLEDState"}, {0x000C0000, nullptr, "GetIRLEDRecvState"},
|
||||
{0x000D0000, nullptr, "GetSendFinishedEvent"}, {0x000E0000, nullptr, "GetRecvFinishedEvent"},
|
||||
{0x000F0000, nullptr, "GetTransferState"}, {0x00100000, nullptr, "GetErrorStatus"},
|
||||
{0x00110040, nullptr, "SetSleepModeActive"}, {0x00120040, nullptr, "SetSleepModeState"},
|
||||
};
|
||||
|
||||
IR_U_Interface::IR_U_Interface() {
|
||||
|
@ -9,32 +9,32 @@ namespace Service {
|
||||
namespace IR {
|
||||
|
||||
const Interface::FunctionInfo FunctionTable[] = {
|
||||
{0x00010182, nullptr, "InitializeIrNop"},
|
||||
{0x00020000, FinalizeIrNop, "FinalizeIrNop"},
|
||||
{0x00030000, nullptr, "ClearReceiveBuffer"},
|
||||
{0x00040000, nullptr, "ClearSendBuffer"},
|
||||
{0x000500C0, nullptr, "WaitConnection"},
|
||||
{0x00060040, RequireConnection, "RequireConnection"},
|
||||
{0x000702C0, nullptr, "AutoConnection"},
|
||||
{0x00080000, nullptr, "AnyConnection"},
|
||||
{0x00090000, Disconnect, "Disconnect"},
|
||||
{0x000A0000, nullptr, "GetReceiveEvent"},
|
||||
{0x000B0000, nullptr, "GetSendEvent"},
|
||||
{0x00010182, nullptr, "InitializeIrNop"},
|
||||
{0x00020000, FinalizeIrNop, "FinalizeIrNop"},
|
||||
{0x00030000, nullptr, "ClearReceiveBuffer"},
|
||||
{0x00040000, nullptr, "ClearSendBuffer"},
|
||||
{0x000500C0, nullptr, "WaitConnection"},
|
||||
{0x00060040, RequireConnection, "RequireConnection"},
|
||||
{0x000702C0, nullptr, "AutoConnection"},
|
||||
{0x00080000, nullptr, "AnyConnection"},
|
||||
{0x00090000, Disconnect, "Disconnect"},
|
||||
{0x000A0000, nullptr, "GetReceiveEvent"},
|
||||
{0x000B0000, nullptr, "GetSendEvent"},
|
||||
{0x000C0000, GetConnectionStatusEvent, "GetConnectionStatusEvent"},
|
||||
{0x000D0042, nullptr, "SendIrNop"},
|
||||
{0x000E0042, nullptr, "SendIrNopLarge"},
|
||||
{0x000F0040, nullptr, "ReceiveIrnop"},
|
||||
{0x00100042, nullptr, "ReceiveIrnopLarge"},
|
||||
{0x00110040, nullptr, "GetLatestReceiveErrorResult"},
|
||||
{0x00120040, nullptr, "GetLatestSendErrorResult"},
|
||||
{0x00130000, nullptr, "GetConnectionStatus"},
|
||||
{0x00140000, nullptr, "GetTryingToConnectStatus"},
|
||||
{0x00150000, nullptr, "GetReceiveSizeFreeAndUsed"},
|
||||
{0x00160000, nullptr, "GetSendSizeFreeAndUsed"},
|
||||
{0x00170000, nullptr, "GetConnectionRole"},
|
||||
{0x00180182, InitializeIrNopShared, "InitializeIrNopShared"},
|
||||
{0x00190040, nullptr, "ReleaseReceivedData"},
|
||||
{0x001A0040, nullptr, "SetOwnMachineId"},
|
||||
{0x000D0042, nullptr, "SendIrNop"},
|
||||
{0x000E0042, nullptr, "SendIrNopLarge"},
|
||||
{0x000F0040, nullptr, "ReceiveIrnop"},
|
||||
{0x00100042, nullptr, "ReceiveIrnopLarge"},
|
||||
{0x00110040, nullptr, "GetLatestReceiveErrorResult"},
|
||||
{0x00120040, nullptr, "GetLatestSendErrorResult"},
|
||||
{0x00130000, nullptr, "GetConnectionStatus"},
|
||||
{0x00140000, nullptr, "GetTryingToConnectStatus"},
|
||||
{0x00150000, nullptr, "GetReceiveSizeFreeAndUsed"},
|
||||
{0x00160000, nullptr, "GetSendSizeFreeAndUsed"},
|
||||
{0x00170000, nullptr, "GetConnectionRole"},
|
||||
{0x00180182, InitializeIrNopShared, "InitializeIrNopShared"},
|
||||
{0x00190040, nullptr, "ReleaseReceivedData"},
|
||||
{0x001A0040, nullptr, "SetOwnMachineId"},
|
||||
};
|
||||
|
||||
IR_User_Interface::IR_User_Interface() {
|
||||
|
@ -14,38 +14,29 @@
|
||||
namespace LDR_RO {
|
||||
|
||||
static const ResultCode ERROR_BUFFER_TOO_SMALL = // 0xE0E12C1F
|
||||
ResultCode(static_cast<ErrorDescription>(31), ErrorModule::RO, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
|
||||
ResultCode(static_cast<ErrorDescription>(31), ErrorModule::RO, ErrorSummary::InvalidArgument,
|
||||
ErrorLevel::Usage);
|
||||
|
||||
static ResultCode CROFormatError(u32 description) {
|
||||
return ResultCode(static_cast<ErrorDescription>(description), ErrorModule::RO, ErrorSummary::WrongArgument, ErrorLevel::Permanent);
|
||||
return ResultCode(static_cast<ErrorDescription>(description), ErrorModule::RO,
|
||||
ErrorSummary::WrongArgument, ErrorLevel::Permanent);
|
||||
}
|
||||
|
||||
const std::array<int, 17> CROHelper::ENTRY_SIZE {{
|
||||
1, // code
|
||||
1, // data
|
||||
1, // module name
|
||||
sizeof(SegmentEntry),
|
||||
sizeof(ExportNamedSymbolEntry),
|
||||
sizeof(ExportIndexedSymbolEntry),
|
||||
1, // export strings
|
||||
sizeof(ExportTreeEntry),
|
||||
sizeof(ImportModuleEntry),
|
||||
sizeof(ExternalRelocationEntry),
|
||||
sizeof(ImportNamedSymbolEntry),
|
||||
sizeof(ImportIndexedSymbolEntry),
|
||||
sizeof(ImportAnonymousSymbolEntry),
|
||||
1, // import strings
|
||||
sizeof(StaticAnonymousSymbolEntry),
|
||||
sizeof(InternalRelocationEntry),
|
||||
sizeof(StaticRelocationEntry)
|
||||
}};
|
||||
const std::array<int, 17> CROHelper::ENTRY_SIZE{
|
||||
{1, // code
|
||||
1, // data
|
||||
1, // module name
|
||||
sizeof(SegmentEntry), sizeof(ExportNamedSymbolEntry), sizeof(ExportIndexedSymbolEntry),
|
||||
1, // export strings
|
||||
sizeof(ExportTreeEntry), sizeof(ImportModuleEntry), sizeof(ExternalRelocationEntry),
|
||||
sizeof(ImportNamedSymbolEntry), sizeof(ImportIndexedSymbolEntry),
|
||||
sizeof(ImportAnonymousSymbolEntry),
|
||||
1, // import strings
|
||||
sizeof(StaticAnonymousSymbolEntry), sizeof(InternalRelocationEntry),
|
||||
sizeof(StaticRelocationEntry)}};
|
||||
|
||||
const std::array<CROHelper::HeaderField, 4> CROHelper::FIX_BARRIERS {{
|
||||
Fix0Barrier,
|
||||
Fix1Barrier,
|
||||
Fix2Barrier,
|
||||
Fix3Barrier
|
||||
}};
|
||||
const std::array<CROHelper::HeaderField, 4> CROHelper::FIX_BARRIERS{
|
||||
{Fix0Barrier, Fix1Barrier, Fix2Barrier, Fix3Barrier}};
|
||||
|
||||
VAddr CROHelper::SegmentTagToAddress(SegmentTag segment_tag) const {
|
||||
u32 segment_num = GetField(SegmentNum);
|
||||
@ -63,7 +54,7 @@ VAddr CROHelper::SegmentTagToAddress(SegmentTag segment_tag) const {
|
||||
}
|
||||
|
||||
ResultCode CROHelper::ApplyRelocation(VAddr target_address, RelocationType relocation_type,
|
||||
u32 addend, u32 symbol_address, u32 target_future_address) {
|
||||
u32 addend, u32 symbol_address, u32 target_future_address) {
|
||||
|
||||
switch (relocation_type) {
|
||||
case RelocationType::Nothing:
|
||||
@ -124,7 +115,8 @@ ResultCode CROHelper::ApplyRelocationBatch(VAddr batch, u32 symbol_address, bool
|
||||
return CROFormatError(0x12);
|
||||
}
|
||||
|
||||
ResultCode result = ApplyRelocation(relocation_target, relocation.type, relocation.addend, symbol_address, relocation_target);
|
||||
ResultCode result = ApplyRelocation(relocation_target, relocation.type, relocation.addend,
|
||||
symbol_address, relocation_target);
|
||||
if (result.IsError()) {
|
||||
LOG_ERROR(Service_LDR, "Error applying relocation %08X", result.raw);
|
||||
return result;
|
||||
@ -167,7 +159,7 @@ VAddr CROHelper::FindExportNamedSymbol(const std::string& name) const {
|
||||
|
||||
if (test_byte >= len) {
|
||||
next.raw = entry.left.raw;
|
||||
} else if((name[test_byte] >> test_bit_in_byte) & 1) {
|
||||
} else if ((name[test_byte] >> test_bit_in_byte) & 1) {
|
||||
next.raw = entry.right.raw;
|
||||
} else {
|
||||
next.raw = entry.left.raw;
|
||||
@ -212,26 +204,13 @@ ResultCode CROHelper::RebaseHeader(u32 cro_size) {
|
||||
return error;
|
||||
|
||||
// verifies that all offsets are in the correct order
|
||||
constexpr std::array<HeaderField, 18> OFFSET_ORDER = {{
|
||||
CodeOffset,
|
||||
ModuleNameOffset,
|
||||
SegmentTableOffset,
|
||||
ExportNamedSymbolTableOffset,
|
||||
ExportTreeTableOffset,
|
||||
ExportIndexedSymbolTableOffset,
|
||||
ExportStringsOffset,
|
||||
ImportModuleTableOffset,
|
||||
ExternalRelocationTableOffset,
|
||||
ImportNamedSymbolTableOffset,
|
||||
ImportIndexedSymbolTableOffset,
|
||||
ImportAnonymousSymbolTableOffset,
|
||||
ImportStringsOffset,
|
||||
StaticAnonymousSymbolTableOffset,
|
||||
InternalRelocationTableOffset,
|
||||
StaticRelocationTableOffset,
|
||||
DataOffset,
|
||||
FileSize
|
||||
}};
|
||||
constexpr std::array<HeaderField, 18> OFFSET_ORDER = {
|
||||
{CodeOffset, ModuleNameOffset, SegmentTableOffset, ExportNamedSymbolTableOffset,
|
||||
ExportTreeTableOffset, ExportIndexedSymbolTableOffset, ExportStringsOffset,
|
||||
ImportModuleTableOffset, ExternalRelocationTableOffset, ImportNamedSymbolTableOffset,
|
||||
ImportIndexedSymbolTableOffset, ImportAnonymousSymbolTableOffset, ImportStringsOffset,
|
||||
StaticAnonymousSymbolTableOffset, InternalRelocationTableOffset,
|
||||
StaticRelocationTableOffset, DataOffset, FileSize}};
|
||||
|
||||
u32 prev_offset = GetField(OFFSET_ORDER[0]);
|
||||
u32 cur_offset;
|
||||
@ -266,9 +245,9 @@ ResultCode CROHelper::RebaseHeader(u32 cro_size) {
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultVal<VAddr> CROHelper::RebaseSegmentTable(u32 cro_size,
|
||||
VAddr data_segment_address, u32 data_segment_size,
|
||||
VAddr bss_segment_address, u32 bss_segment_size) {
|
||||
ResultVal<VAddr> CROHelper::RebaseSegmentTable(u32 cro_size, VAddr data_segment_address,
|
||||
u32 data_segment_size, VAddr bss_segment_address,
|
||||
u32 bss_segment_size) {
|
||||
|
||||
u32 prev_data_segment = 0;
|
||||
u32 segment_num = GetField(SegmentNum);
|
||||
@ -309,8 +288,8 @@ ResultCode CROHelper::RebaseExportNamedSymbolTable() {
|
||||
|
||||
if (entry.name_offset != 0) {
|
||||
entry.name_offset += module_address;
|
||||
if (entry.name_offset < export_strings_offset
|
||||
|| entry.name_offset >= export_strings_end) {
|
||||
if (entry.name_offset < export_strings_offset ||
|
||||
entry.name_offset >= export_strings_end) {
|
||||
return CROFormatError(0x11);
|
||||
}
|
||||
}
|
||||
@ -337,9 +316,13 @@ ResultCode CROHelper::RebaseImportModuleTable() {
|
||||
VAddr import_strings_offset = GetField(ImportStringsOffset);
|
||||
VAddr import_strings_end = import_strings_offset + GetField(ImportStringsSize);
|
||||
VAddr import_indexed_symbol_table_offset = GetField(ImportIndexedSymbolTableOffset);
|
||||
VAddr index_import_table_end = import_indexed_symbol_table_offset + GetField(ImportIndexedSymbolNum) * sizeof(ImportIndexedSymbolEntry);
|
||||
VAddr index_import_table_end =
|
||||
import_indexed_symbol_table_offset +
|
||||
GetField(ImportIndexedSymbolNum) * sizeof(ImportIndexedSymbolEntry);
|
||||
VAddr import_anonymous_symbol_table_offset = GetField(ImportAnonymousSymbolTableOffset);
|
||||
VAddr offset_import_table_end = import_anonymous_symbol_table_offset + GetField(ImportAnonymousSymbolNum) * sizeof(ImportAnonymousSymbolEntry);
|
||||
VAddr offset_import_table_end =
|
||||
import_anonymous_symbol_table_offset +
|
||||
GetField(ImportAnonymousSymbolNum) * sizeof(ImportAnonymousSymbolEntry);
|
||||
|
||||
u32 module_num = GetField(ImportModuleNum);
|
||||
for (u32 i = 0; i < module_num; ++i) {
|
||||
@ -348,24 +331,24 @@ ResultCode CROHelper::RebaseImportModuleTable() {
|
||||
|
||||
if (entry.name_offset != 0) {
|
||||
entry.name_offset += module_address;
|
||||
if (entry.name_offset < import_strings_offset
|
||||
|| entry.name_offset >= import_strings_end) {
|
||||
if (entry.name_offset < import_strings_offset ||
|
||||
entry.name_offset >= import_strings_end) {
|
||||
return CROFormatError(0x18);
|
||||
}
|
||||
}
|
||||
|
||||
if (entry.import_indexed_symbol_table_offset != 0) {
|
||||
entry.import_indexed_symbol_table_offset += module_address;
|
||||
if (entry.import_indexed_symbol_table_offset < import_indexed_symbol_table_offset
|
||||
|| entry.import_indexed_symbol_table_offset > index_import_table_end) {
|
||||
if (entry.import_indexed_symbol_table_offset < import_indexed_symbol_table_offset ||
|
||||
entry.import_indexed_symbol_table_offset > index_import_table_end) {
|
||||
return CROFormatError(0x18);
|
||||
}
|
||||
}
|
||||
|
||||
if (entry.import_anonymous_symbol_table_offset != 0) {
|
||||
entry.import_anonymous_symbol_table_offset += module_address;
|
||||
if (entry.import_anonymous_symbol_table_offset < import_anonymous_symbol_table_offset
|
||||
|| entry.import_anonymous_symbol_table_offset > offset_import_table_end) {
|
||||
if (entry.import_anonymous_symbol_table_offset < import_anonymous_symbol_table_offset ||
|
||||
entry.import_anonymous_symbol_table_offset > offset_import_table_end) {
|
||||
return CROFormatError(0x18);
|
||||
}
|
||||
}
|
||||
@ -379,25 +362,27 @@ ResultCode CROHelper::RebaseImportNamedSymbolTable() {
|
||||
VAddr import_strings_offset = GetField(ImportStringsOffset);
|
||||
VAddr import_strings_end = import_strings_offset + GetField(ImportStringsSize);
|
||||
VAddr external_relocation_table_offset = GetField(ExternalRelocationTableOffset);
|
||||
VAddr external_relocation_table_end = external_relocation_table_offset + GetField(ExternalRelocationNum) * sizeof(ExternalRelocationEntry);
|
||||
VAddr external_relocation_table_end =
|
||||
external_relocation_table_offset +
|
||||
GetField(ExternalRelocationNum) * sizeof(ExternalRelocationEntry);
|
||||
|
||||
u32 num = GetField(ImportNamedSymbolNum);
|
||||
for (u32 i = 0; i < num ; ++i) {
|
||||
for (u32 i = 0; i < num; ++i) {
|
||||
ImportNamedSymbolEntry entry;
|
||||
GetEntry(i, entry);
|
||||
|
||||
if (entry.name_offset != 0) {
|
||||
entry.name_offset += module_address;
|
||||
if (entry.name_offset < import_strings_offset
|
||||
|| entry.name_offset >= import_strings_end) {
|
||||
if (entry.name_offset < import_strings_offset ||
|
||||
entry.name_offset >= import_strings_end) {
|
||||
return CROFormatError(0x1B);
|
||||
}
|
||||
}
|
||||
|
||||
if (entry.relocation_batch_offset != 0) {
|
||||
entry.relocation_batch_offset += module_address;
|
||||
if (entry.relocation_batch_offset < external_relocation_table_offset
|
||||
|| entry.relocation_batch_offset > external_relocation_table_end) {
|
||||
if (entry.relocation_batch_offset < external_relocation_table_offset ||
|
||||
entry.relocation_batch_offset > external_relocation_table_end) {
|
||||
return CROFormatError(0x1B);
|
||||
}
|
||||
}
|
||||
@ -409,17 +394,19 @@ ResultCode CROHelper::RebaseImportNamedSymbolTable() {
|
||||
|
||||
ResultCode CROHelper::RebaseImportIndexedSymbolTable() {
|
||||
VAddr external_relocation_table_offset = GetField(ExternalRelocationTableOffset);
|
||||
VAddr external_relocation_table_end = external_relocation_table_offset + GetField(ExternalRelocationNum) * sizeof(ExternalRelocationEntry);
|
||||
VAddr external_relocation_table_end =
|
||||
external_relocation_table_offset +
|
||||
GetField(ExternalRelocationNum) * sizeof(ExternalRelocationEntry);
|
||||
|
||||
u32 num = GetField(ImportIndexedSymbolNum);
|
||||
for (u32 i = 0; i < num ; ++i) {
|
||||
for (u32 i = 0; i < num; ++i) {
|
||||
ImportIndexedSymbolEntry entry;
|
||||
GetEntry(i, entry);
|
||||
|
||||
if (entry.relocation_batch_offset != 0) {
|
||||
entry.relocation_batch_offset += module_address;
|
||||
if (entry.relocation_batch_offset < external_relocation_table_offset
|
||||
|| entry.relocation_batch_offset > external_relocation_table_end) {
|
||||
if (entry.relocation_batch_offset < external_relocation_table_offset ||
|
||||
entry.relocation_batch_offset > external_relocation_table_end) {
|
||||
return CROFormatError(0x14);
|
||||
}
|
||||
}
|
||||
@ -431,17 +418,19 @@ ResultCode CROHelper::RebaseImportIndexedSymbolTable() {
|
||||
|
||||
ResultCode CROHelper::RebaseImportAnonymousSymbolTable() {
|
||||
VAddr external_relocation_table_offset = GetField(ExternalRelocationTableOffset);
|
||||
VAddr external_relocation_table_end = external_relocation_table_offset + GetField(ExternalRelocationNum) * sizeof(ExternalRelocationEntry);
|
||||
VAddr external_relocation_table_end =
|
||||
external_relocation_table_offset +
|
||||
GetField(ExternalRelocationNum) * sizeof(ExternalRelocationEntry);
|
||||
|
||||
u32 num = GetField(ImportAnonymousSymbolNum);
|
||||
for (u32 i = 0; i < num ; ++i) {
|
||||
for (u32 i = 0; i < num; ++i) {
|
||||
ImportAnonymousSymbolEntry entry;
|
||||
GetEntry(i, entry);
|
||||
|
||||
if (entry.relocation_batch_offset != 0) {
|
||||
entry.relocation_batch_offset += module_address;
|
||||
if (entry.relocation_batch_offset < external_relocation_table_offset
|
||||
|| entry.relocation_batch_offset > external_relocation_table_end) {
|
||||
if (entry.relocation_batch_offset < external_relocation_table_offset ||
|
||||
entry.relocation_batch_offset > external_relocation_table_end) {
|
||||
return CROFormatError(0x17);
|
||||
}
|
||||
}
|
||||
@ -475,7 +464,8 @@ ResultCode CROHelper::ResetExternalRelocations() {
|
||||
return CROFormatError(0x12);
|
||||
}
|
||||
|
||||
ResultCode result = ApplyRelocation(relocation_target, relocation.type, relocation.addend, unresolved_symbol, relocation_target);
|
||||
ResultCode result = ApplyRelocation(relocation_target, relocation.type, relocation.addend,
|
||||
unresolved_symbol, relocation_target);
|
||||
if (result.IsError()) {
|
||||
LOG_ERROR(Service_LDR, "Error applying relocation %08X", result.raw);
|
||||
return result;
|
||||
@ -528,23 +518,27 @@ ResultCode CROHelper::ClearExternalRelocations() {
|
||||
|
||||
ResultCode CROHelper::ApplyStaticAnonymousSymbolToCRS(VAddr crs_address) {
|
||||
VAddr static_relocation_table_offset = GetField(StaticRelocationTableOffset);
|
||||
VAddr static_relocation_table_end = static_relocation_table_offset + GetField(StaticRelocationNum) * sizeof(StaticRelocationEntry);
|
||||
VAddr static_relocation_table_end =
|
||||
static_relocation_table_offset +
|
||||
GetField(StaticRelocationNum) * sizeof(StaticRelocationEntry);
|
||||
|
||||
CROHelper crs(crs_address);
|
||||
u32 offset_export_num = GetField(StaticAnonymousSymbolNum);
|
||||
LOG_INFO(Service_LDR, "CRO \"%s\" exports %d static anonymous symbols", ModuleName().data(), offset_export_num);
|
||||
LOG_INFO(Service_LDR, "CRO \"%s\" exports %d static anonymous symbols", ModuleName().data(),
|
||||
offset_export_num);
|
||||
for (u32 i = 0; i < offset_export_num; ++i) {
|
||||
StaticAnonymousSymbolEntry entry;
|
||||
GetEntry(i, entry);
|
||||
u32 batch_address = entry.relocation_batch_offset + module_address;
|
||||
|
||||
if (batch_address < static_relocation_table_offset
|
||||
|| batch_address > static_relocation_table_end) {
|
||||
if (batch_address < static_relocation_table_offset ||
|
||||
batch_address > static_relocation_table_end) {
|
||||
return CROFormatError(0x16);
|
||||
}
|
||||
|
||||
u32 symbol_address = SegmentTagToAddress(entry.symbol_position);
|
||||
LOG_TRACE(Service_LDR, "CRO \"%s\" exports 0x%08X to the static module", ModuleName().data(), symbol_address);
|
||||
LOG_TRACE(Service_LDR, "CRO \"%s\" exports 0x%08X to the static module",
|
||||
ModuleName().data(), symbol_address);
|
||||
ResultCode result = crs.ApplyRelocationBatch(batch_address, symbol_address);
|
||||
if (result.IsError()) {
|
||||
LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw);
|
||||
@ -571,7 +565,8 @@ ResultCode CROHelper::ApplyInternalRelocations(u32 old_data_segment_address) {
|
||||
|
||||
if (target_segment.type == SegmentType::Data) {
|
||||
// If the relocation is to the .data segment, we need to relocate it in the old buffer
|
||||
target_address = old_data_segment_address + relocation.target_position.offset_into_segment;
|
||||
target_address =
|
||||
old_data_segment_address + relocation.target_position.offset_into_segment;
|
||||
} else {
|
||||
target_address = target_addressB;
|
||||
}
|
||||
@ -582,8 +577,10 @@ ResultCode CROHelper::ApplyInternalRelocations(u32 old_data_segment_address) {
|
||||
|
||||
SegmentEntry symbol_segment;
|
||||
GetEntry(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, symbol_segment.offset, target_addressB);
|
||||
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,
|
||||
symbol_segment.offset, target_addressB);
|
||||
if (result.IsError()) {
|
||||
LOG_ERROR(Service_LDR, "Error applying relocation %08X", result.raw);
|
||||
return result;
|
||||
@ -734,25 +731,29 @@ ResultCode CROHelper::ApplyImportNamedSymbol(VAddr crs_address) {
|
||||
Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry));
|
||||
|
||||
if (!relocation_entry.is_batch_resolved) {
|
||||
ResultCode result = ForEachAutoLinkCRO(crs_address, [&](CROHelper source) -> ResultVal<bool> {
|
||||
std::string symbol_name = Memory::ReadCString(entry.name_offset, import_strings_size);
|
||||
u32 symbol_address = source.FindExportNamedSymbol(symbol_name);
|
||||
ResultCode result =
|
||||
ForEachAutoLinkCRO(crs_address, [&](CROHelper source) -> ResultVal<bool> {
|
||||
std::string symbol_name =
|
||||
Memory::ReadCString(entry.name_offset, import_strings_size);
|
||||
u32 symbol_address = source.FindExportNamedSymbol(symbol_name);
|
||||
|
||||
if (symbol_address != 0) {
|
||||
LOG_TRACE(Service_LDR, "CRO \"%s\" imports \"%s\" from \"%s\"",
|
||||
ModuleName().data(), symbol_name.data(), source.ModuleName().data());
|
||||
if (symbol_address != 0) {
|
||||
LOG_TRACE(Service_LDR, "CRO \"%s\" imports \"%s\" from \"%s\"",
|
||||
ModuleName().data(), symbol_name.data(),
|
||||
source.ModuleName().data());
|
||||
|
||||
ResultCode result = ApplyRelocationBatch(relocation_addr, symbol_address);
|
||||
if (result.IsError()) {
|
||||
LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw);
|
||||
return result;
|
||||
ResultCode result = ApplyRelocationBatch(relocation_addr, symbol_address);
|
||||
if (result.IsError()) {
|
||||
LOG_ERROR(Service_LDR, "Error applying relocation batch %08X",
|
||||
result.raw);
|
||||
return result;
|
||||
}
|
||||
|
||||
return MakeResult<bool>(false);
|
||||
}
|
||||
|
||||
return MakeResult<bool>(false);
|
||||
}
|
||||
|
||||
return MakeResult<bool>(true);
|
||||
});
|
||||
return MakeResult<bool>(true);
|
||||
});
|
||||
if (result.IsError()) {
|
||||
return result;
|
||||
}
|
||||
@ -777,7 +778,6 @@ ResultCode CROHelper::ResetImportNamedSymbol() {
|
||||
LOG_ERROR(Service_LDR, "Error reseting relocation batch %08X", result.raw);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
@ -831,40 +831,47 @@ ResultCode CROHelper::ApplyModuleImport(VAddr crs_address) {
|
||||
GetEntry(i, entry);
|
||||
std::string want_cro_name = Memory::ReadCString(entry.name_offset, import_strings_size);
|
||||
|
||||
ResultCode result = ForEachAutoLinkCRO(crs_address, [&](CROHelper source) -> ResultVal<bool> {
|
||||
if (want_cro_name == source.ModuleName()) {
|
||||
LOG_INFO(Service_LDR, "CRO \"%s\" imports %d indexed symbols from \"%s\"",
|
||||
ModuleName().data(), entry.import_indexed_symbol_num, source.ModuleName().data());
|
||||
for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) {
|
||||
ImportIndexedSymbolEntry im;
|
||||
entry.GetImportIndexedSymbolEntry(j, im);
|
||||
ExportIndexedSymbolEntry ex;
|
||||
source.GetEntry(im.index, ex);
|
||||
u32 symbol_address = source.SegmentTagToAddress(ex.symbol_position);
|
||||
LOG_TRACE(Service_LDR, " Imports 0x%08X", symbol_address);
|
||||
ResultCode result = ApplyRelocationBatch(im.relocation_batch_offset, symbol_address);
|
||||
if (result.IsError()) {
|
||||
LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw);
|
||||
return result;
|
||||
ResultCode result =
|
||||
ForEachAutoLinkCRO(crs_address, [&](CROHelper source) -> ResultVal<bool> {
|
||||
if (want_cro_name == source.ModuleName()) {
|
||||
LOG_INFO(Service_LDR, "CRO \"%s\" imports %d indexed symbols from \"%s\"",
|
||||
ModuleName().data(), entry.import_indexed_symbol_num,
|
||||
source.ModuleName().data());
|
||||
for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) {
|
||||
ImportIndexedSymbolEntry im;
|
||||
entry.GetImportIndexedSymbolEntry(j, im);
|
||||
ExportIndexedSymbolEntry ex;
|
||||
source.GetEntry(im.index, ex);
|
||||
u32 symbol_address = source.SegmentTagToAddress(ex.symbol_position);
|
||||
LOG_TRACE(Service_LDR, " Imports 0x%08X", symbol_address);
|
||||
ResultCode result =
|
||||
ApplyRelocationBatch(im.relocation_batch_offset, symbol_address);
|
||||
if (result.IsError()) {
|
||||
LOG_ERROR(Service_LDR, "Error applying relocation batch %08X",
|
||||
result.raw);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG_INFO(Service_LDR, "CRO \"%s\" imports %d anonymous symbols from \"%s\"",
|
||||
ModuleName().data(), entry.import_anonymous_symbol_num, source.ModuleName().data());
|
||||
for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) {
|
||||
ImportAnonymousSymbolEntry im;
|
||||
entry.GetImportAnonymousSymbolEntry(j, im);
|
||||
u32 symbol_address = source.SegmentTagToAddress(im.symbol_position);
|
||||
LOG_TRACE(Service_LDR, " Imports 0x%08X", symbol_address);
|
||||
ResultCode result = ApplyRelocationBatch(im.relocation_batch_offset, symbol_address);
|
||||
if (result.IsError()) {
|
||||
LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw);
|
||||
return result;
|
||||
LOG_INFO(Service_LDR, "CRO \"%s\" imports %d anonymous symbols from \"%s\"",
|
||||
ModuleName().data(), entry.import_anonymous_symbol_num,
|
||||
source.ModuleName().data());
|
||||
for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) {
|
||||
ImportAnonymousSymbolEntry im;
|
||||
entry.GetImportAnonymousSymbolEntry(j, im);
|
||||
u32 symbol_address = source.SegmentTagToAddress(im.symbol_position);
|
||||
LOG_TRACE(Service_LDR, " Imports 0x%08X", symbol_address);
|
||||
ResultCode result =
|
||||
ApplyRelocationBatch(im.relocation_batch_offset, symbol_address);
|
||||
if (result.IsError()) {
|
||||
LOG_ERROR(Service_LDR, "Error applying relocation batch %08X",
|
||||
result.raw);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return MakeResult<bool>(false);
|
||||
}
|
||||
return MakeResult<bool>(false);
|
||||
}
|
||||
return MakeResult<bool>(true);
|
||||
});
|
||||
return MakeResult<bool>(true);
|
||||
});
|
||||
if (result.IsError()) {
|
||||
return result;
|
||||
}
|
||||
@ -873,8 +880,8 @@ ResultCode CROHelper::ApplyModuleImport(VAddr crs_address) {
|
||||
}
|
||||
|
||||
ResultCode CROHelper::ApplyExportNamedSymbol(CROHelper target) {
|
||||
LOG_DEBUG(Service_LDR, "CRO \"%s\" exports named symbols to \"%s\"",
|
||||
ModuleName().data(), target.ModuleName().data());
|
||||
LOG_DEBUG(Service_LDR, "CRO \"%s\" exports named symbols to \"%s\"", ModuleName().data(),
|
||||
target.ModuleName().data());
|
||||
u32 target_import_strings_size = target.GetField(ImportStringsSize);
|
||||
u32 target_symbol_import_num = target.GetField(ImportNamedSymbolNum);
|
||||
for (u32 i = 0; i < target_symbol_import_num; ++i) {
|
||||
@ -885,7 +892,8 @@ ResultCode CROHelper::ApplyExportNamedSymbol(CROHelper target) {
|
||||
Memory::ReadBlock(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);
|
||||
std::string symbol_name =
|
||||
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 \"%s\"", symbol_name.data());
|
||||
@ -901,8 +909,8 @@ ResultCode CROHelper::ApplyExportNamedSymbol(CROHelper target) {
|
||||
}
|
||||
|
||||
ResultCode CROHelper::ResetExportNamedSymbol(CROHelper target) {
|
||||
LOG_DEBUG(Service_LDR, "CRO \"%s\" unexports named symbols to \"%s\"",
|
||||
ModuleName().data(), target.ModuleName().data());
|
||||
LOG_DEBUG(Service_LDR, "CRO \"%s\" unexports named symbols to \"%s\"", ModuleName().data(),
|
||||
target.ModuleName().data());
|
||||
u32 unresolved_symbol = target.GetOnUnresolvedAddress();
|
||||
u32 target_import_strings_size = target.GetField(ImportStringsSize);
|
||||
u32 target_symbol_import_num = target.GetField(ImportNamedSymbolNum);
|
||||
@ -914,11 +922,13 @@ ResultCode CROHelper::ResetExportNamedSymbol(CROHelper target) {
|
||||
Memory::ReadBlock(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);
|
||||
std::string symbol_name =
|
||||
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 \"%s\"", symbol_name.data());
|
||||
ResultCode result = target.ApplyRelocationBatch(relocation_addr, unresolved_symbol, true);
|
||||
ResultCode result =
|
||||
target.ApplyRelocationBatch(relocation_addr, unresolved_symbol, true);
|
||||
if (result.IsError()) {
|
||||
LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw);
|
||||
return result;
|
||||
@ -940,8 +950,8 @@ ResultCode CROHelper::ApplyModuleExport(CROHelper target) {
|
||||
if (Memory::ReadCString(entry.name_offset, target_import_string_size) != module_name)
|
||||
continue;
|
||||
|
||||
LOG_INFO(Service_LDR, "CRO \"%s\" exports %d indexed symbols to \"%s\"",
|
||||
module_name.data(), entry.import_indexed_symbol_num, target.ModuleName().data());
|
||||
LOG_INFO(Service_LDR, "CRO \"%s\" exports %d indexed symbols to \"%s\"", module_name.data(),
|
||||
entry.import_indexed_symbol_num, target.ModuleName().data());
|
||||
for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) {
|
||||
ImportIndexedSymbolEntry im;
|
||||
entry.GetImportIndexedSymbolEntry(j, im);
|
||||
@ -949,7 +959,8 @@ ResultCode CROHelper::ApplyModuleExport(CROHelper target) {
|
||||
GetEntry(im.index, ex);
|
||||
u32 symbol_address = SegmentTagToAddress(ex.symbol_position);
|
||||
LOG_TRACE(Service_LDR, " exports symbol 0x%08X", symbol_address);
|
||||
ResultCode result = target.ApplyRelocationBatch(im.relocation_batch_offset, symbol_address);
|
||||
ResultCode result =
|
||||
target.ApplyRelocationBatch(im.relocation_batch_offset, symbol_address);
|
||||
if (result.IsError()) {
|
||||
LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw);
|
||||
return result;
|
||||
@ -957,13 +968,14 @@ ResultCode CROHelper::ApplyModuleExport(CROHelper target) {
|
||||
}
|
||||
|
||||
LOG_INFO(Service_LDR, "CRO \"%s\" exports %d anonymous symbols to \"%s\"",
|
||||
module_name.data(), entry.import_anonymous_symbol_num, target.ModuleName().data());
|
||||
module_name.data(), entry.import_anonymous_symbol_num, target.ModuleName().data());
|
||||
for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) {
|
||||
ImportAnonymousSymbolEntry im;
|
||||
entry.GetImportAnonymousSymbolEntry(j, im);
|
||||
u32 symbol_address = SegmentTagToAddress(im.symbol_position);
|
||||
LOG_TRACE(Service_LDR, " exports symbol 0x%08X", symbol_address);
|
||||
ResultCode result = target.ApplyRelocationBatch(im.relocation_batch_offset, symbol_address);
|
||||
ResultCode result =
|
||||
target.ApplyRelocationBatch(im.relocation_batch_offset, symbol_address);
|
||||
if (result.IsError()) {
|
||||
LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw);
|
||||
return result;
|
||||
@ -987,12 +999,13 @@ ResultCode CROHelper::ResetModuleExport(CROHelper target) {
|
||||
if (Memory::ReadCString(entry.name_offset, target_import_string_size) != module_name)
|
||||
continue;
|
||||
|
||||
LOG_DEBUG(Service_LDR, "CRO \"%s\" unexports indexed symbols to \"%s\"",
|
||||
module_name.data(), target.ModuleName().data());
|
||||
LOG_DEBUG(Service_LDR, "CRO \"%s\" unexports indexed symbols to \"%s\"", module_name.data(),
|
||||
target.ModuleName().data());
|
||||
for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) {
|
||||
ImportIndexedSymbolEntry im;
|
||||
entry.GetImportIndexedSymbolEntry(j, im);
|
||||
ResultCode result = target.ApplyRelocationBatch(im.relocation_batch_offset, unresolved_symbol, true);
|
||||
ResultCode result =
|
||||
target.ApplyRelocationBatch(im.relocation_batch_offset, unresolved_symbol, true);
|
||||
if (result.IsError()) {
|
||||
LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw);
|
||||
return result;
|
||||
@ -1000,11 +1013,12 @@ ResultCode CROHelper::ResetModuleExport(CROHelper target) {
|
||||
}
|
||||
|
||||
LOG_DEBUG(Service_LDR, "CRO \"%s\" unexports anonymous symbols to \"%s\"",
|
||||
module_name.data(), target.ModuleName().data());
|
||||
module_name.data(), target.ModuleName().data());
|
||||
for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) {
|
||||
ImportAnonymousSymbolEntry im;
|
||||
entry.GetImportAnonymousSymbolEntry(j, im);
|
||||
ResultCode result = target.ApplyRelocationBatch(im.relocation_batch_offset, unresolved_symbol, true);
|
||||
ResultCode result =
|
||||
target.ApplyRelocationBatch(im.relocation_batch_offset, unresolved_symbol, true);
|
||||
if (result.IsError()) {
|
||||
LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw);
|
||||
return result;
|
||||
@ -1025,25 +1039,27 @@ ResultCode CROHelper::ApplyExitRelocations(VAddr crs_address) {
|
||||
ExternalRelocationEntry relocation_entry;
|
||||
Memory::ReadBlock(relocation_addr, &relocation_entry, sizeof(ExternalRelocationEntry));
|
||||
|
||||
if (Memory::ReadCString(entry.name_offset, import_strings_size) == "__aeabi_atexit"){
|
||||
ResultCode result = ForEachAutoLinkCRO(crs_address, [&](CROHelper source) -> ResultVal<bool> {
|
||||
u32 symbol_address = source.FindExportNamedSymbol("nnroAeabiAtexit_");
|
||||
if (Memory::ReadCString(entry.name_offset, import_strings_size) == "__aeabi_atexit") {
|
||||
ResultCode result =
|
||||
ForEachAutoLinkCRO(crs_address, [&](CROHelper source) -> ResultVal<bool> {
|
||||
u32 symbol_address = source.FindExportNamedSymbol("nnroAeabiAtexit_");
|
||||
|
||||
if (symbol_address != 0) {
|
||||
LOG_DEBUG(Service_LDR, "CRO \"%s\" import exit function from \"%s\"",
|
||||
ModuleName().data(), source.ModuleName().data());
|
||||
if (symbol_address != 0) {
|
||||
LOG_DEBUG(Service_LDR, "CRO \"%s\" import exit function from \"%s\"",
|
||||
ModuleName().data(), source.ModuleName().data());
|
||||
|
||||
ResultCode result = ApplyRelocationBatch(relocation_addr, symbol_address);
|
||||
if (result.IsError()) {
|
||||
LOG_ERROR(Service_LDR, "Error applying relocation batch %08X", result.raw);
|
||||
return result;
|
||||
ResultCode result = ApplyRelocationBatch(relocation_addr, symbol_address);
|
||||
if (result.IsError()) {
|
||||
LOG_ERROR(Service_LDR, "Error applying relocation batch %08X",
|
||||
result.raw);
|
||||
return result;
|
||||
}
|
||||
|
||||
return MakeResult<bool>(false);
|
||||
}
|
||||
|
||||
return MakeResult<bool>(false);
|
||||
}
|
||||
|
||||
return MakeResult<bool>(true);
|
||||
});
|
||||
return MakeResult<bool>(true);
|
||||
});
|
||||
if (result.IsError()) {
|
||||
LOG_ERROR(Service_LDR, "Error applying exit relocation %08X", result.raw);
|
||||
return result;
|
||||
@ -1070,9 +1086,9 @@ static ResultCode VerifyStringTableLength(VAddr address, u32 size) {
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultCode CROHelper::Rebase(VAddr crs_address, u32 cro_size,
|
||||
VAddr data_segment_addresss, u32 data_segment_size,
|
||||
VAddr bss_segment_address, u32 bss_segment_size, bool is_crs) {
|
||||
ResultCode CROHelper::Rebase(VAddr crs_address, u32 cro_size, VAddr data_segment_addresss,
|
||||
u32 data_segment_size, VAddr bss_segment_address, u32 bss_segment_size,
|
||||
bool is_crs) {
|
||||
|
||||
ResultCode result = RebaseHeader(cro_size);
|
||||
if (result.IsError()) {
|
||||
@ -1088,9 +1104,8 @@ ResultCode CROHelper::Rebase(VAddr crs_address, u32 cro_size,
|
||||
|
||||
u32 prev_data_segment_address = 0;
|
||||
if (!is_crs) {
|
||||
auto result_val = RebaseSegmentTable(cro_size,
|
||||
data_segment_addresss, data_segment_size,
|
||||
bss_segment_address, bss_segment_size);
|
||||
auto result_val = RebaseSegmentTable(cro_size, data_segment_addresss, data_segment_size,
|
||||
bss_segment_address, bss_segment_size);
|
||||
if (result_val.Failed()) {
|
||||
LOG_ERROR(Service_LDR, "Error rebasing segment table %08X", result_val.Code().raw);
|
||||
return result_val.Code();
|
||||
@ -1374,7 +1389,8 @@ void CROHelper::Unregister(VAddr crs_address) {
|
||||
CROHelper next_head(crs.NextModule()), previous_head(crs.PreviousModule());
|
||||
CROHelper next(NextModule()), previous(PreviousModule());
|
||||
|
||||
if (module_address == next_head.module_address || module_address == previous_head.module_address) {
|
||||
if (module_address == next_head.module_address ||
|
||||
module_address == previous_head.module_address) {
|
||||
// removing head
|
||||
if (next.module_address) {
|
||||
// the next is new head
|
||||
@ -1400,7 +1416,8 @@ void CROHelper::Unregister(VAddr crs_address) {
|
||||
// let head's previous point to the new tail
|
||||
if (next_head.module_address && next_head.PreviousModule() == module_address) {
|
||||
next_head.SetPreviousModule(previous.module_address);
|
||||
} else if (previous_head.module_address && previous_head.PreviousModule() == module_address) {
|
||||
} else if (previous_head.module_address &&
|
||||
previous_head.PreviousModule() == module_address) {
|
||||
previous_head.SetPreviousModule(previous.module_address);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
@ -1419,9 +1436,9 @@ u32 CROHelper::GetFixEnd(u32 fix_level) const {
|
||||
u32 entry_size_i = 2;
|
||||
int field = ModuleNameOffset;
|
||||
while (true) {
|
||||
end = std::max<u32>(end,
|
||||
GetField(static_cast<HeaderField>(field)) +
|
||||
GetField(static_cast<HeaderField>(field + 1)) * ENTRY_SIZE[entry_size_i]);
|
||||
end = std::max<u32>(end, GetField(static_cast<HeaderField>(field)) +
|
||||
GetField(static_cast<HeaderField>(field + 1)) *
|
||||
ENTRY_SIZE[entry_size_i]);
|
||||
|
||||
++entry_size_i;
|
||||
field += 2;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user