Merge master

This commit is contained in:
PabloMK7 2023-07-31 11:07:21 +02:00
commit 307e20d43d
44 changed files with 1360 additions and 374 deletions

View File

@ -5,20 +5,24 @@
#include "common/common_types.h" #include "common/common_types.h"
namespace AudioCore {
struct ADTSData { struct ADTSData {
u8 header_length; u8 header_length = 0;
bool MPEG2; bool mpeg2 = false;
u8 profile; u8 profile = 0;
u8 channels; u8 channels = 0;
u8 channel_idx; u8 channel_idx = 0;
u8 framecount; u8 framecount = 0;
u8 samplerate_idx; u8 samplerate_idx = 0;
u32 length; u32 length = 0;
u32 samplerate; u32 samplerate = 0;
}; };
ADTSData ParseADTS(const char* buffer); ADTSData ParseADTS(const u8* buffer);
// last two bytes of MF AAC decoder user data // last two bytes of MF AAC decoder user data
// see https://docs.microsoft.com/en-us/windows/desktop/medfound/aac-decoder#example-media-types // see https://docs.microsoft.com/en-us/windows/desktop/medfound/aac-decoder#example-media-types
u16 MFGetAACTag(const ADTSData& input); u16 MFGetAACTag(const ADTSData& input);
} // namespace AudioCore

View File

@ -3,44 +3,59 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <array> #include <array>
#include "adts.h" #include "adts.h"
#include "common/bit_field.h"
namespace AudioCore {
constexpr std::array<u32, 16> freq_table = {96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, constexpr std::array<u32, 16> freq_table = {96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
16000, 12000, 11025, 8000, 7350, 0, 0, 0}; 16000, 12000, 11025, 8000, 7350, 0, 0, 0};
constexpr std::array<u8, 8> channel_table = {0, 1, 2, 3, 4, 5, 6, 8}; constexpr std::array<u8, 8> channel_table = {0, 1, 2, 3, 4, 5, 6, 8};
ADTSData ParseADTS(const char* buffer) { struct ADTSHeader {
u32 tmp = 0; union {
ADTSData out; std::array<u8, 7> raw{};
BitFieldBE<52, 12, u64> sync_word;
BitFieldBE<51, 1, u64> mpeg2;
BitFieldBE<49, 2, u64> layer;
BitFieldBE<48, 1, u64> protection_absent;
BitFieldBE<46, 2, u64> profile;
BitFieldBE<42, 4, u64> samplerate_idx;
BitFieldBE<41, 1, u64> private_bit;
BitFieldBE<38, 3, u64> channel_idx;
BitFieldBE<37, 1, u64> originality;
BitFieldBE<36, 1, u64> home;
BitFieldBE<35, 1, u64> copyright_id;
BitFieldBE<34, 1, u64> copyright_id_start;
BitFieldBE<21, 13, u64> frame_length;
BitFieldBE<10, 11, u64> buffer_fullness;
BitFieldBE<8, 2, u64> frame_count;
};
};
ADTSData ParseADTS(const u8* buffer) {
ADTSHeader header;
memcpy(header.raw.data(), buffer, sizeof(header.raw));
// sync word 0xfff // sync word 0xfff
tmp = (buffer[0] << 8) | (buffer[1] & 0xf0); if (header.sync_word != 0xfff) {
if ((tmp & 0xffff) != 0xfff0) { return {};
out.length = 0;
return out;
} }
ADTSData out{};
// bit 16 = no CRC // bit 16 = no CRC
out.header_length = (buffer[1] & 0x1) ? 7 : 9; out.header_length = header.protection_absent ? 7 : 9;
out.MPEG2 = (buffer[1] >> 3) & 0x1; out.mpeg2 = static_cast<bool>(header.mpeg2);
// bit 17 to 18 // bit 17 to 18
out.profile = (buffer[2] >> 6) + 1; out.profile = static_cast<u8>(header.profile) + 1;
// bit 19 to 22 // bit 19 to 22
tmp = (buffer[2] >> 2) & 0xf; out.samplerate_idx = static_cast<u8>(header.samplerate_idx);
out.samplerate_idx = tmp; out.samplerate = header.samplerate_idx > 15 ? 0 : freq_table[header.samplerate_idx];
out.samplerate = (tmp > 15) ? 0 : freq_table[tmp];
// bit 24 to 26 // bit 24 to 26
tmp = ((buffer[2] & 0x1) << 2) | ((buffer[3] >> 6) & 0x3); out.channel_idx = static_cast<u8>(header.channel_idx);
out.channel_idx = tmp; out.channels = (header.channel_idx > 7) ? 0 : channel_table[header.channel_idx];
out.channels = (tmp > 7) ? 0 : channel_table[tmp];
// bit 55 to 56 // bit 55 to 56
out.framecount = (buffer[6] & 0x3) + 1; out.framecount = static_cast<u8>(header.frame_count + 1);
// bit 31 to 43 // bit 31 to 43
tmp = (buffer[3] & 0x3) << 11; out.length = static_cast<u32>(header.frame_length);
tmp |= (buffer[4] << 3) & 0x7f8;
tmp |= (buffer[5] >> 5) & 0x7;
out.length = tmp;
return out; return out;
} }
@ -61,3 +76,4 @@ u16 MFGetAACTag(const ADTSData& input) {
return tag; return tag;
} }
} // namespace AudioCore

View File

@ -24,7 +24,7 @@ private:
std::optional<BinaryMessage> Decode(const BinaryMessage& request); std::optional<BinaryMessage> Decode(const BinaryMessage& request);
void Clear(); void Clear();
bool InitializeDecoder(ADTSData& adts_header); bool InitializeDecoder(AudioCore::ADTSData& adts_header);
static OSStatus DataFunc(AudioConverterRef in_audio_converter, u32* io_number_data_packets, static OSStatus DataFunc(AudioConverterRef in_audio_converter, u32* io_number_data_packets,
AudioBufferList* io_data, AudioBufferList* io_data,
@ -33,7 +33,7 @@ private:
Memory::MemorySystem& memory; Memory::MemorySystem& memory;
ADTSData adts_config; AudioCore::ADTSData adts_config;
AudioStreamBasicDescription output_format = {}; AudioStreamBasicDescription output_format = {};
AudioConverterRef converter = nullptr; AudioConverterRef converter = nullptr;
@ -101,7 +101,7 @@ std::optional<BinaryMessage> AudioToolboxDecoder::Impl::ProcessRequest(
} }
} }
bool AudioToolboxDecoder::Impl::InitializeDecoder(ADTSData& adts_header) { bool AudioToolboxDecoder::Impl::InitializeDecoder(AudioCore::ADTSData& adts_header) {
if (converter) { if (converter) {
if (adts_config.channels == adts_header.channels && if (adts_config.channels == adts_header.channels &&
adts_config.samplerate == adts_header.samplerate) { adts_config.samplerate == adts_header.samplerate) {
@ -183,8 +183,9 @@ std::optional<BinaryMessage> AudioToolboxDecoder::Impl::Decode(const BinaryMessa
return {}; return {};
} }
auto data = memory.GetFCRAMPointer(request.decode_aac_request.src_addr - Memory::FCRAM_PADDR); const auto data =
auto adts_header = ParseADTS(reinterpret_cast<const char*>(data)); memory.GetFCRAMPointer(request.decode_aac_request.src_addr - Memory::FCRAM_PADDR);
auto adts_header = AudioCore::ParseADTS(data);
curr_data = data + adts_header.header_length; curr_data = data + adts_header.header_length;
curr_data_len = request.decode_aac_request.size - adts_header.header_length; curr_data_len = request.decode_aac_request.size - adts_header.header_length;

View File

@ -27,7 +27,7 @@ public:
~Impl(); ~Impl();
std::optional<BinaryMessage> ProcessRequest(const BinaryMessage& request); std::optional<BinaryMessage> ProcessRequest(const BinaryMessage& request);
bool SetMediaType(const ADTSData& adts_data); bool SetMediaType(const AudioCore::ADTSData& adts_data);
private: private:
std::optional<BinaryMessage> Initalize(const BinaryMessage& request); std::optional<BinaryMessage> Initalize(const BinaryMessage& request);
@ -36,8 +36,8 @@ private:
Memory::MemorySystem& memory; Memory::MemorySystem& memory;
std::unique_ptr<AMediaCodec, AMediaCodecRelease> decoder; std::unique_ptr<AMediaCodec, AMediaCodecRelease> decoder;
// default: 2 channles, 48000 samplerate // default: 2 channles, 48000 samplerate
ADTSData mADTSData{ AudioCore::ADTSData mADTSData{
/*header_length*/ 7, /*MPEG2*/ false, /*profile*/ 2, /*header_length*/ 7, /*mpeg2*/ false, /*profile*/ 2,
/*channels*/ 2, /*channel_idx*/ 2, /*framecount*/ 0, /*channels*/ 2, /*channel_idx*/ 2, /*framecount*/ 0,
/*samplerate_idx*/ 3, /*length*/ 0, /*samplerate*/ 48000}; /*samplerate_idx*/ 3, /*length*/ 0, /*samplerate*/ 48000};
}; };
@ -54,7 +54,7 @@ std::optional<BinaryMessage> MediaNDKDecoder::Impl::Initalize(const BinaryMessag
return response; return response;
} }
bool MediaNDKDecoder::Impl::SetMediaType(const ADTSData& adts_data) { bool MediaNDKDecoder::Impl::SetMediaType(const AudioCore::ADTSData& adts_data) {
const char* mime = "audio/mp4a-latm"; const char* mime = "audio/mp4a-latm";
if (decoder && mADTSData.profile == adts_data.profile && if (decoder && mADTSData.profile == adts_data.profile &&
mADTSData.channel_idx == adts_data.channel_idx && mADTSData.channel_idx == adts_data.channel_idx &&
@ -141,8 +141,9 @@ std::optional<BinaryMessage> MediaNDKDecoder::Impl::Decode(const BinaryMessage&
return response; return response;
} }
u8* data = memory.GetFCRAMPointer(request.decode_aac_request.src_addr - Memory::FCRAM_PADDR); const u8* data =
ADTSData adts_data = ParseADTS(reinterpret_cast<const char*>(data)); memory.GetFCRAMPointer(request.decode_aac_request.src_addr - Memory::FCRAM_PADDR);
ADTSData adts_data = AudioCore::ParseADTS(data);
SetMediaType(adts_data); SetMediaType(adts_data);
response.decode_aac_response.sample_rate = GetSampleRateEnum(adts_data.samplerate); response.decode_aac_response.sample_rate = GetSampleRateEnum(adts_data.samplerate);
response.decode_aac_response.num_channels = adts_data.channels; response.decode_aac_response.num_channels = adts_data.channels;

View File

@ -23,7 +23,8 @@ private:
std::optional<BinaryMessage> Decode(const BinaryMessage& request); std::optional<BinaryMessage> Decode(const BinaryMessage& request);
MFOutputState DecodingLoop(ADTSData adts_header, std::array<std::vector<u8>, 2>& out_streams); MFOutputState DecodingLoop(AudioCore::ADTSData adts_header,
std::array<std::vector<u8>, 2>& out_streams);
bool transform_initialized = false; bool transform_initialized = false;
bool format_selected = false; bool format_selected = false;
@ -139,7 +140,7 @@ std::optional<BinaryMessage> WMFDecoder::Impl::Initalize(const BinaryMessage& re
return response; return response;
} }
MFOutputState WMFDecoder::Impl::DecodingLoop(ADTSData adts_header, MFOutputState WMFDecoder::Impl::DecodingLoop(AudioCore::ADTSData adts_header,
std::array<std::vector<u8>, 2>& out_streams) { std::array<std::vector<u8>, 2>& out_streams) {
std::optional<std::vector<f32>> output_buffer; std::optional<std::vector<f32>> output_buffer;
@ -210,14 +211,14 @@ std::optional<BinaryMessage> WMFDecoder::Impl::Decode(const BinaryMessage& reque
request.decode_aac_request.src_addr); request.decode_aac_request.src_addr);
return std::nullopt; return std::nullopt;
} }
u8* data = memory.GetFCRAMPointer(request.decode_aac_request.src_addr - Memory::FCRAM_PADDR); const u8* data =
memory.GetFCRAMPointer(request.decode_aac_request.src_addr - Memory::FCRAM_PADDR);
std::array<std::vector<u8>, 2> out_streams; std::array<std::vector<u8>, 2> out_streams;
unique_mfptr<IMFSample> sample; unique_mfptr<IMFSample> sample;
MFInputState input_status = MFInputState::OK; MFInputState input_status = MFInputState::OK;
MFOutputState output_status = MFOutputState::OK; MFOutputState output_status = MFOutputState::OK;
std::optional<ADTSMeta> adts_meta = std::optional<ADTSMeta> adts_meta = DetectMediaType(data, request.decode_aac_request.size);
DetectMediaType((char*)data, request.decode_aac_request.size);
if (!adts_meta) { if (!adts_meta) {
LOG_ERROR(Audio_DSP, "Unable to deduce decoding parameters from ADTS stream"); LOG_ERROR(Audio_DSP, "Unable to deduce decoding parameters from ADTS stream");

View File

@ -110,8 +110,9 @@ unique_mfptr<IMFSample> CreateSample(const void* data, DWORD len, DWORD alignmen
return sample; return sample;
} }
bool SelectInputMediaType(IMFTransform* transform, int in_stream_id, const ADTSData& adts, bool SelectInputMediaType(IMFTransform* transform, int in_stream_id,
const UINT8* user_data, UINT32 user_data_len, GUID audio_format) { const AudioCore::ADTSData& adts, const UINT8* user_data,
UINT32 user_data_len, GUID audio_format) {
HRESULT hr = S_OK; HRESULT hr = S_OK;
unique_mfptr<IMFMediaType> t; unique_mfptr<IMFMediaType> t;
@ -190,12 +191,12 @@ bool SelectOutputMediaType(IMFTransform* transform, int out_stream_id, GUID audi
return false; return false;
} }
std::optional<ADTSMeta> DetectMediaType(char* buffer, std::size_t len) { std::optional<ADTSMeta> DetectMediaType(const u8* buffer, std::size_t len) {
if (len < 7) { if (len < 7) {
return std::nullopt; return std::nullopt;
} }
ADTSData tmp; AudioCore::ADTSData tmp;
ADTSMeta result; ADTSMeta result;
// see https://docs.microsoft.com/en-us/windows/desktop/api/mmreg/ns-mmreg-heaacwaveinfo_tag // see https://docs.microsoft.com/en-us/windows/desktop/api/mmreg/ns-mmreg-heaacwaveinfo_tag
// for the meaning of the byte array below // for the meaning of the byte array below
@ -207,7 +208,7 @@ std::optional<ADTSMeta> DetectMediaType(char* buffer, std::size_t len) {
UINT8 aac_tmp[] = {0x01, 0x00, 0xfe, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x00, 0x00}; UINT8 aac_tmp[] = {0x01, 0x00, 0xfe, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x00, 0x00};
uint16_t tag = 0; uint16_t tag = 0;
tmp = ParseADTS(buffer); tmp = AudioCore::ParseADTS(buffer);
if (tmp.length == 0) { if (tmp.length == 0) {
return std::nullopt; return std::nullopt;
} }
@ -215,7 +216,7 @@ std::optional<ADTSMeta> DetectMediaType(char* buffer, std::size_t len) {
tag = MFGetAACTag(tmp); tag = MFGetAACTag(tmp);
aac_tmp[12] |= (tag & 0xff00) >> 8; aac_tmp[12] |= (tag & 0xff00) >> 8;
aac_tmp[13] |= (tag & 0x00ff); aac_tmp[13] |= (tag & 0x00ff);
std::memcpy(&(result.ADTSHeader), &tmp, sizeof(ADTSData)); std::memcpy(&(result.ADTSHeader), &tmp, sizeof(AudioCore::ADTSData));
std::memcpy(&(result.AACTag), aac_tmp, 14); std::memcpy(&(result.AACTag), aac_tmp, 14);
return result; return result;
} }

View File

@ -99,7 +99,7 @@ void ReportError(std::string msg, HRESULT hr);
// data type for transferring ADTS metadata between functions // data type for transferring ADTS metadata between functions
struct ADTSMeta { struct ADTSMeta {
ADTSData ADTSHeader; AudioCore::ADTSData ADTSHeader;
u8 AACTag[14]; u8 AACTag[14];
}; };
@ -110,10 +110,10 @@ bool InitMFDLL();
unique_mfptr<IMFTransform> MFDecoderInit(GUID audio_format = MFAudioFormat_AAC); unique_mfptr<IMFTransform> MFDecoderInit(GUID audio_format = MFAudioFormat_AAC);
unique_mfptr<IMFSample> CreateSample(const void* data, DWORD len, DWORD alignment = 1, unique_mfptr<IMFSample> CreateSample(const void* data, DWORD len, DWORD alignment = 1,
LONGLONG duration = 0); LONGLONG duration = 0);
bool SelectInputMediaType(IMFTransform* transform, int in_stream_id, const ADTSData& adts, bool SelectInputMediaType(IMFTransform* transform, int in_stream_id,
const UINT8* user_data, UINT32 user_data_len, const AudioCore::ADTSData& adts, const UINT8* user_data,
GUID audio_format = MFAudioFormat_AAC); UINT32 user_data_len, GUID audio_format = MFAudioFormat_AAC);
std::optional<ADTSMeta> DetectMediaType(char* buffer, std::size_t len); std::optional<ADTSMeta> DetectMediaType(const u8* buffer, std::size_t len);
bool SelectOutputMediaType(IMFTransform* transform, int out_stream_id, bool SelectOutputMediaType(IMFTransform* transform, int out_stream_id,
GUID audio_format = MFAudioFormat_PCM); GUID audio_format = MFAudioFormat_PCM);
void MFFlush(IMFTransform* transform); void MFFlush(IMFTransform* transform);

View File

@ -29,7 +29,7 @@ Config::~Config() {
const std::array<int, Settings::NativeButton::NumButtons> Config::default_buttons = { const std::array<int, Settings::NativeButton::NumButtons> Config::default_buttons = {
Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, Qt::Key_T, Qt::Key_G, Qt::Key_A, Qt::Key_S, Qt::Key_Z, Qt::Key_X, Qt::Key_T, Qt::Key_G,
Qt::Key_F, Qt::Key_H, Qt::Key_Q, Qt::Key_W, Qt::Key_M, Qt::Key_N, Qt::Key_F, Qt::Key_H, Qt::Key_Q, Qt::Key_W, Qt::Key_M, Qt::Key_N,
Qt::Key_O, Qt::Key_P, Qt::Key_1, Qt::Key_2, Qt::Key_B, Qt::Key_O, Qt::Key_P, Qt::Key_1, Qt::Key_2, Qt::Key_B, Qt::Key_V,
}; };
const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> Config::default_analogs{{ const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> Config::default_analogs{{

View File

@ -162,7 +162,7 @@ ConfigureInput::ConfigureInput(QWidget* parent)
ui->buttonDpadUp, ui->buttonDpadDown, ui->buttonDpadLeft, ui->buttonDpadRight, ui->buttonDpadUp, ui->buttonDpadDown, ui->buttonDpadLeft, ui->buttonDpadRight,
ui->buttonL, ui->buttonR, ui->buttonStart, ui->buttonSelect, ui->buttonL, ui->buttonR, ui->buttonStart, ui->buttonSelect,
ui->buttonDebug, ui->buttonGpio14, ui->buttonZL, ui->buttonZR, ui->buttonDebug, ui->buttonGpio14, ui->buttonZL, ui->buttonZR,
ui->buttonHome, ui->buttonHome, ui->buttonPower,
}; };
analog_map_buttons = {{ analog_map_buttons = {{

View File

@ -305,6 +305,24 @@
</layout> </layout>
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
<layout class="QVBoxLayout" name="verticalLayout_34">
<item>
<widget class="QLabel" name="label_37">
<property name="text">
<string>Power:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="buttonPower">
<property name="text">
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<layout class="QVBoxLayout" name="verticalLayout_28"> <layout class="QVBoxLayout" name="verticalLayout_28">
<item> <item>
<widget class="QLabel" name="label_36"> <widget class="QLabel" name="label_36">
@ -340,7 +358,7 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="2" column="0"> <item row="3" column="0">
<layout class="QVBoxLayout" name="verticalLayout_32"> <layout class="QVBoxLayout" name="verticalLayout_32">
<item> <item>
<widget class="QLabel" name="label_40"> <widget class="QLabel" name="label_40">

View File

@ -100,13 +100,14 @@ enum Values {
ZR, ZR,
Home, Home,
Power,
NumButtons, NumButtons,
}; };
constexpr int BUTTON_HID_BEGIN = A; constexpr int BUTTON_HID_BEGIN = A;
constexpr int BUTTON_IR_BEGIN = ZL; constexpr int BUTTON_IR_BEGIN = ZL;
constexpr int BUTTON_NS_BEGIN = Home; constexpr int BUTTON_NS_BEGIN = Power;
constexpr int BUTTON_HID_END = BUTTON_IR_BEGIN; constexpr int BUTTON_HID_END = BUTTON_IR_BEGIN;
constexpr int BUTTON_IR_END = BUTTON_NS_BEGIN; constexpr int BUTTON_IR_END = BUTTON_NS_BEGIN;
@ -134,6 +135,7 @@ static const std::array<const char*, NumButtons> mapping = {{
"button_zl", "button_zl",
"button_zr", "button_zr",
"button_home", "button_home",
"button_power",
}}; }};
} // namespace NativeButton } // namespace NativeButton

View File

@ -259,14 +259,13 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
return ResultStatus::ErrorGetLoader; return ResultStatus::ErrorGetLoader;
} }
std::pair<std::optional<u32>, Loader::ResultStatus> system_mode =
app_loader->LoadKernelSystemMode();
if (system_mode.second != Loader::ResultStatus::Success) { auto memory_mode = app_loader->LoadKernelMemoryMode();
if (memory_mode.second != Loader::ResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to determine system mode (Error {})!", LOG_CRITICAL(Core, "Failed to determine system mode (Error {})!",
static_cast<int>(system_mode.second)); static_cast<int>(memory_mode.second));
switch (system_mode.second) { switch (memory_mode.second) {
case Loader::ResultStatus::ErrorEncrypted: case Loader::ResultStatus::ErrorEncrypted:
return ResultStatus::ErrorLoader_ErrorEncrypted; return ResultStatus::ErrorLoader_ErrorEncrypted;
case Loader::ResultStatus::ErrorInvalidFormat: case Loader::ResultStatus::ErrorInvalidFormat:
@ -278,15 +277,15 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
} }
} }
ASSERT(system_mode.first); ASSERT(memory_mode.first);
auto n3ds_mode = app_loader->LoadKernelN3dsMode(); auto n3ds_hw_caps = app_loader->LoadNew3dsHwCapabilities();
ASSERT(n3ds_mode.first); ASSERT(n3ds_hw_caps.first);
u32 num_cores = 2; u32 num_cores = 2;
if (Settings::values.is_new_3ds) { if (Settings::values.is_new_3ds) {
num_cores = 4; num_cores = 4;
} }
ResultStatus init_result{ ResultStatus init_result{
Init(emu_window, secondary_window, *system_mode.first, *n3ds_mode.first, num_cores)}; Init(emu_window, secondary_window, *memory_mode.first, *n3ds_hw_caps.first, num_cores)};
if (init_result != ResultStatus::Success) { if (init_result != ResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!", LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
static_cast<u32>(init_result)); static_cast<u32>(init_result));
@ -363,8 +362,9 @@ void System::Reschedule() {
} }
System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, System::ResultStatus System::Init(Frontend::EmuWindow& emu_window,
Frontend::EmuWindow* secondary_window, u32 system_mode, Frontend::EmuWindow* secondary_window,
u8 n3ds_mode, u32 num_cores) { Kernel::MemoryMode memory_mode,
const Kernel::New3dsHwCapabilities& n3ds_hw_caps, u32 num_cores) {
LOG_DEBUG(HW_Memory, "initialized OK"); LOG_DEBUG(HW_Memory, "initialized OK");
memory = std::make_unique<Memory::MemorySystem>(); memory = std::make_unique<Memory::MemorySystem>();
@ -372,7 +372,7 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window,
timing = std::make_unique<Timing>(num_cores, Settings::values.cpu_clock_percentage.GetValue()); timing = std::make_unique<Timing>(num_cores, Settings::values.cpu_clock_percentage.GetValue());
kernel = std::make_unique<Kernel::KernelSystem>( kernel = std::make_unique<Kernel::KernelSystem>(
*memory, *timing, [this] { PrepareReschedule(); }, system_mode, num_cores, n3ds_mode); *memory, *timing, [this] { PrepareReschedule(); }, memory_mode, num_cores, n3ds_hw_caps);
exclusive_monitor = MakeExclusiveMonitor(*memory, num_cores); exclusive_monitor = MakeExclusiveMonitor(*memory, num_cores);
cpu_cores.reserve(num_cores); cpu_cores.reserve(num_cores);
@ -673,10 +673,10 @@ void System::serialize(Archive& ar, const unsigned int file_version) {
Shutdown(true); Shutdown(true);
// Re-initialize everything like it was before // Re-initialize everything like it was before
auto system_mode = this->app_loader->LoadKernelSystemMode(); auto memory_mode = this->app_loader->LoadKernelMemoryMode();
auto n3ds_mode = this->app_loader->LoadKernelN3dsMode(); auto n3ds_hw_caps = this->app_loader->LoadNew3dsHwCapabilities();
[[maybe_unused]] const System::ResultStatus result = Init( [[maybe_unused]] const System::ResultStatus result = Init(
*m_emu_window, m_secondary_window, *system_mode.first, *n3ds_mode.first, num_cores); *m_emu_window, m_secondary_window, *memory_mode.first, *n3ds_hw_caps.first, num_cores);
} }
// flush on save, don't flush on load // flush on save, don't flush on load

View File

@ -342,8 +342,10 @@ private:
* @return ResultStatus code, indicating if the operation succeeded. * @return ResultStatus code, indicating if the operation succeeded.
*/ */
[[nodiscard]] ResultStatus Init(Frontend::EmuWindow& emu_window, [[nodiscard]] ResultStatus Init(Frontend::EmuWindow& emu_window,
Frontend::EmuWindow* secondary_window, u32 system_mode, Frontend::EmuWindow* secondary_window,
u8 n3ds_mode, u32 num_cores); Kernel::MemoryMode memory_mode,
const Kernel::New3dsHwCapabilities& n3ds_hw_caps,
u32 num_cores);
/// Reschedule the core emulation /// Reschedule the core emulation
void Reschedule(); void Reschedule();

View File

@ -165,7 +165,11 @@ struct ExHeader_StorageInfo {
struct ExHeader_ARM11_SystemLocalCaps { struct ExHeader_ARM11_SystemLocalCaps {
u64_le program_id; u64_le program_id;
u32_le core_version; u32_le core_version;
u8 reserved_flag; union {
u8 n3ds_cpu_flags;
BitField<0, 1, u8> enable_l2_cache;
BitField<1, 1, u8> enable_804MHz_cpu;
};
u8 n3ds_mode; u8 n3ds_mode;
union { union {
u8 flags0; u8 flags0;

View File

@ -181,6 +181,12 @@ std::array<u8, 16> TitleMetadata::GetContentCTRByIndex(std::size_t index) const
return ctr; return ctr;
} }
bool TitleMetadata::HasEncryptedContent() const {
return std::any_of(tmd_chunks.begin(), tmd_chunks.end(), [](auto& chunk) {
return (static_cast<u16>(chunk.type) & FileSys::TMDContentTypeFlag::Encrypted) != 0;
});
}
void TitleMetadata::SetTitleID(u64 title_id) { void TitleMetadata::SetTitleID(u64 title_id) {
tmd_body.title_id = title_id; tmd_body.title_id = title_id;
} }

View File

@ -98,6 +98,7 @@ public:
u16 GetContentTypeByIndex(std::size_t index) const; u16 GetContentTypeByIndex(std::size_t index) const;
u64 GetContentSizeByIndex(std::size_t index) const; u64 GetContentSizeByIndex(std::size_t index) const;
std::array<u8, 16> GetContentCTRByIndex(std::size_t index) const; std::array<u8, 16> GetContentCTRByIndex(std::size_t index) const;
bool HasEncryptedContent() const;
void SetTitleID(u64 title_id); void SetTitleID(u64 title_id);
void SetTitleType(u32 type); void SetTitleType(u32 type);

View File

@ -23,13 +23,15 @@ namespace Kernel {
/// Initialize the kernel /// Initialize the kernel
KernelSystem::KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing, KernelSystem::KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing,
std::function<void()> prepare_reschedule_callback, u32 system_mode, std::function<void()> prepare_reschedule_callback,
u32 num_cores, u8 n3ds_mode) MemoryMode memory_mode, u32 num_cores,
const New3dsHwCapabilities& n3ds_hw_caps)
: memory(memory), timing(timing), : memory(memory), timing(timing),
prepare_reschedule_callback(std::move(prepare_reschedule_callback)) { prepare_reschedule_callback(std::move(prepare_reschedule_callback)), memory_mode(memory_mode),
n3ds_hw_caps(n3ds_hw_caps) {
std::generate(memory_regions.begin(), memory_regions.end(), std::generate(memory_regions.begin(), memory_regions.end(),
[] { return std::make_shared<MemoryRegionInfo>(); }); [] { return std::make_shared<MemoryRegionInfo>(); });
MemoryInit(system_mode, n3ds_mode); MemoryInit(memory_mode, n3ds_hw_caps.memory_mode);
resource_limits = std::make_unique<ResourceLimitList>(*this); resource_limits = std::make_unique<ResourceLimitList>(*this);
for (u32 core_id = 0; core_id < num_cores; ++core_id) { for (u32 core_id = 0; core_id < num_cores; ++core_id) {
@ -176,6 +178,8 @@ void KernelSystem::serialize(Archive& ar, const unsigned int file_version) {
ar& shared_page_handler; ar& shared_page_handler;
ar& stored_processes; ar& stored_processes;
ar& next_thread_id; ar& next_thread_id;
ar& memory_mode;
ar& n3ds_hw_caps;
// Deliberately don't include debugger info to allow debugging through loads // Deliberately don't include debugger info to allow debugging through loads
if (Archive::is_loading::value) { if (Archive::is_loading::value) {

View File

@ -97,11 +97,44 @@ union CoreVersion {
BitField<24, 8, u32> major; BitField<24, 8, u32> major;
}; };
/// Common memory memory modes.
enum class MemoryMode : u8 {
Prod = 0, ///< 64MB app memory
Dev1 = 2, ///< 96MB app memory
Dev2 = 3, ///< 80MB app memory
Dev3 = 4, ///< 72MB app memory
Dev4 = 5, ///< 32MB app memory
};
/// New 3DS memory modes.
enum class New3dsMemoryMode : u8 {
Legacy = 0, ///< Use Old 3DS system mode.
NewProd = 1, ///< 124MB app memory
NewDev1 = 2, ///< 178MB app memory
NewDev2 = 3, ///< 124MB app memory
};
/// Structure containing N3DS hardware capability flags.
struct New3dsHwCapabilities {
bool enable_l2_cache; ///< Whether extra L2 cache should be enabled.
bool enable_804MHz_cpu; ///< Whether the CPU should run at 804MHz.
New3dsMemoryMode memory_mode; ///< The New 3DS memory mode.
private:
template <class Archive>
void serialize(Archive& ar, const unsigned int) {
ar& enable_l2_cache;
ar& enable_804MHz_cpu;
ar& memory_mode;
}
friend class boost::serialization::access;
};
class KernelSystem { class KernelSystem {
public: public:
explicit KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing, explicit KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing,
std::function<void()> prepare_reschedule_callback, u32 system_mode, std::function<void()> prepare_reschedule_callback, MemoryMode memory_mode,
u32 num_cores, u8 n3ds_mode); u32 num_cores, const New3dsHwCapabilities& n3ds_hw_caps);
~KernelSystem(); ~KernelSystem();
using PortPair = std::pair<std::shared_ptr<ServerPort>, std::shared_ptr<ClientPort>>; using PortPair = std::pair<std::shared_ptr<ServerPort>, std::shared_ptr<ClientPort>>;
@ -279,6 +312,14 @@ public:
void ResetThreadIDs(); void ResetThreadIDs();
MemoryMode GetMemoryMode() const {
return memory_mode;
}
const New3dsHwCapabilities& GetNew3dsHwCapabilities() const {
return n3ds_hw_caps;
}
/// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort /// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort
std::unordered_map<std::string, std::shared_ptr<ClientPort>> named_ports; std::unordered_map<std::string, std::shared_ptr<ClientPort>> named_ports;
@ -289,7 +330,7 @@ public:
Core::Timing& timing; Core::Timing& timing;
private: private:
void MemoryInit(u32 mem_type, u8 n3ds_mode); void MemoryInit(MemoryMode memory_mode, New3dsMemoryMode n3ds_mode);
std::function<void()> prepare_reschedule_callback; std::function<void()> prepare_reschedule_callback;
@ -324,6 +365,9 @@ private:
u32 next_thread_id; u32 next_thread_id;
MemoryMode memory_mode;
New3dsHwCapabilities n3ds_hw_caps;
friend class boost::serialization::access; friend class boost::serialization::access;
template <class Archive> template <class Archive>
void serialize(Archive& ar, const unsigned int file_version); void serialize(Archive& ar, const unsigned int file_version);

View File

@ -37,29 +37,20 @@ static const u32 memory_region_sizes[8][3] = {
{0x0B200000, 0x02E00000, 0x02000000}, // 7 {0x0B200000, 0x02E00000, 0x02000000}, // 7
}; };
namespace MemoryMode { void KernelSystem::MemoryInit(MemoryMode memory_mode, New3dsMemoryMode n3ds_mode) {
enum N3DSMode : u8 {
Mode6 = 1,
Mode7 = 2,
Mode6_2 = 3,
};
}
void KernelSystem::MemoryInit(u32 mem_type, u8 n3ds_mode) {
ASSERT(mem_type != 1);
const bool is_new_3ds = Settings::values.is_new_3ds.GetValue(); const bool is_new_3ds = Settings::values.is_new_3ds.GetValue();
u32 reported_mem_type = mem_type; u32 mem_type_index = static_cast<u32>(memory_mode);
u32 reported_mem_type = static_cast<u32>(memory_mode);
if (is_new_3ds) { if (is_new_3ds) {
if (n3ds_mode == MemoryMode::Mode6 || n3ds_mode == MemoryMode::Mode6_2) { if (n3ds_mode == New3dsMemoryMode::NewProd || n3ds_mode == New3dsMemoryMode::NewDev2) {
mem_type = 6; mem_type_index = 6;
reported_mem_type = 6; reported_mem_type = 6;
} else if (n3ds_mode == MemoryMode::Mode7) { } else if (n3ds_mode == New3dsMemoryMode::NewDev1) {
mem_type = 7; mem_type_index = 7;
reported_mem_type = 7; reported_mem_type = 7;
} else { } else {
// On the N3ds, all O3ds configurations (<=5) are forced to 6 instead. // On the N3ds, all O3ds configurations (<=5) are forced to 6 instead.
mem_type = 6; mem_type_index = 6;
} }
} }
@ -67,7 +58,7 @@ void KernelSystem::MemoryInit(u32 mem_type, u8 n3ds_mode) {
// the sizes specified in the memory_region_sizes table. // the sizes specified in the memory_region_sizes table.
VAddr base = 0; VAddr base = 0;
for (int i = 0; i < 3; ++i) { for (int i = 0; i < 3; ++i) {
memory_regions[i]->Reset(base, memory_region_sizes[mem_type][i]); memory_regions[i]->Reset(base, memory_region_sizes[mem_type_index][i]);
base += memory_regions[i]->size; base += memory_regions[i]->size;
} }

View File

@ -96,22 +96,38 @@ ResultVal<std::size_t> CIAFile::Read(u64 offset, std::size_t length, u8* buffer)
} }
ResultCode CIAFile::WriteTicket() { ResultCode CIAFile::WriteTicket() {
container.LoadTicket(data, container.GetTicketOffset()); auto load_result = container.LoadTicket(data, container.GetTicketOffset());
if (load_result != Loader::ResultStatus::Success) {
LOG_ERROR(Service_AM, "Could not read ticket from CIA.");
// TODO: Correct result code.
return {ErrCodes::InvalidCIAHeader, ErrorModule::AM, ErrorSummary::InvalidArgument,
ErrorLevel::Permanent};
}
// TODO: Write out .tik files to nand?
install_state = CIAInstallState::TicketLoaded; install_state = CIAInstallState::TicketLoaded;
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
ResultCode CIAFile::WriteTitleMetadata() { ResultCode CIAFile::WriteTitleMetadata() {
container.LoadTitleMetadata(data, container.GetTitleMetadataOffset()); auto load_result = container.LoadTitleMetadata(data, container.GetTitleMetadataOffset());
if (load_result != Loader::ResultStatus::Success) {
LOG_ERROR(Service_AM, "Could not read title metadata from CIA.");
// TODO: Correct result code.
return {ErrCodes::InvalidCIAHeader, ErrorModule::AM, ErrorSummary::InvalidArgument,
ErrorLevel::Permanent};
}
FileSys::TitleMetadata tmd = container.GetTitleMetadata(); FileSys::TitleMetadata tmd = container.GetTitleMetadata();
tmd.Print(); tmd.Print();
// If a TMD already exists for this app (ie 00000000.tmd), the incoming TMD // If a TMD already exists for this app (ie 00000000.tmd), the incoming TMD
// will be the same plus one, (ie 00000001.tmd), both will be kept until // will be the same plus one, (ie 00000001.tmd), both will be kept until
// the install is finalized and old contents can be discarded. // the install is finalized and old contents can be discarded.
if (FileUtil::Exists(GetTitleMetadataPath(media_type, tmd.GetTitleID()))) if (FileUtil::Exists(GetTitleMetadataPath(media_type, tmd.GetTitleID()))) {
is_update = true; is_update = true;
}
std::string tmd_path = GetTitleMetadataPath(media_type, tmd.GetTitleID(), is_update); std::string tmd_path = GetTitleMetadataPath(media_type, tmd.GetTitleID(), is_update);
@ -121,19 +137,34 @@ ResultCode CIAFile::WriteTitleMetadata() {
FileUtil::CreateFullPath(tmd_folder); FileUtil::CreateFullPath(tmd_folder);
// Save TMD so that we can start getting new .app paths // Save TMD so that we can start getting new .app paths
if (tmd.Save(tmd_path) != Loader::ResultStatus::Success) if (tmd.Save(tmd_path) != Loader::ResultStatus::Success) {
return FileSys::ERROR_INSUFFICIENT_SPACE; LOG_ERROR(Service_AM, "Failed to install title metadata file from CIA.");
// TODO: Correct result code.
return FileSys::ERROR_FILE_NOT_FOUND;
}
// Create any other .app folders which may not exist yet // Create any other .app folders which may not exist yet
std::string app_folder; std::string app_folder;
Common::SplitPath(GetTitleContentPath(media_type, tmd.GetTitleID(), auto main_content_path = GetTitleContentPath(media_type, tmd.GetTitleID(),
FileSys::TMDContentIndex::Main, is_update), FileSys::TMDContentIndex::Main, is_update);
&app_folder, nullptr, nullptr); Common::SplitPath(main_content_path, &app_folder, nullptr, nullptr);
FileUtil::CreateFullPath(app_folder); FileUtil::CreateFullPath(app_folder);
auto content_count = container.GetTitleMetadata().GetContentCount(); auto content_count = container.GetTitleMetadata().GetContentCount();
content_written.resize(content_count); content_written.resize(content_count);
content_files.clear();
for (std::size_t i = 0; i < content_count; i++) {
auto path = GetTitleContentPath(media_type, tmd.GetTitleID(), i, is_update);
auto& file = content_files.emplace_back(path, "wb");
if (!file.IsOpen()) {
LOG_ERROR(Service_AM, "Could not open output file '{}' for content {}.", path, i);
// TODO: Correct error code.
return FileSys::ERROR_FILE_NOT_FOUND;
}
}
if (container.GetTitleMetadata().HasEncryptedContent()) {
if (auto title_key = container.GetTicket().GetTitleKey()) { if (auto title_key = container.GetTicket().GetTitleKey()) {
decryption_state->content.resize(content_count); decryption_state->content.resize(content_count);
for (std::size_t i = 0; i < content_count; ++i) { for (std::size_t i = 0; i < content_count; ++i) {
@ -142,7 +173,13 @@ ResultCode CIAFile::WriteTitleMetadata() {
ctr.data()); ctr.data());
} }
} else { } else {
LOG_ERROR(Service_AM, "Can't get title key from ticket"); LOG_ERROR(Service_AM, "Could not read title key from ticket for encrypted CIA.");
// TODO: Correct error code.
return FileSys::ERROR_FILE_NOT_FOUND;
}
} else {
LOG_INFO(Service_AM,
"Title has no encrypted content, skipping initializing decryption state.");
} }
install_state = CIAInstallState::TMDLoaded; install_state = CIAInstallState::TMDLoaded;
@ -155,7 +192,7 @@ ResultVal<std::size_t> CIAFile::WriteContentData(u64 offset, std::size_t length,
// has been written since we might get a written buffer which contains multiple .app // has been written since we might get a written buffer which contains multiple .app
// contents or only part of a larger .app's contents. // contents or only part of a larger .app's contents.
const u64 offset_max = offset + length; const u64 offset_max = offset + length;
for (std::size_t i = 0; i < container.GetTitleMetadata().GetContentCount(); i++) { for (std::size_t i = 0; i < content_written.size(); i++) {
if (content_written[i] < container.GetContentSize(i)) { if (content_written[i] < container.GetContentSize(i)) {
// The size, minimum unwritten offset, and maximum unwritten offset of this content // The size, minimum unwritten offset, and maximum unwritten offset of this content
const u64 size = container.GetContentSize(i); const u64 size = container.GetContentSize(i);
@ -174,22 +211,12 @@ ResultVal<std::size_t> CIAFile::WriteContentData(u64 offset, std::size_t length,
// Since the incoming TMD has already been written, we can use GetTitleContentPath // Since the incoming TMD has already been written, we can use GetTitleContentPath
// to get the content paths to write to. // to get the content paths to write to.
FileSys::TitleMetadata tmd = container.GetTitleMetadata(); FileSys::TitleMetadata tmd = container.GetTitleMetadata();
FileUtil::IOFile file(GetTitleContentPath(media_type, tmd.GetTitleID(), i, is_update), auto& file = content_files[i];
content_written[i] ? "ab" : "wb");
if (!file.IsOpen()) {
return FileSys::ERROR_INSUFFICIENT_SPACE;
}
std::vector<u8> temp(buffer + (range_min - offset), std::vector<u8> temp(buffer + (range_min - offset),
buffer + (range_min - offset) + available_to_write); buffer + (range_min - offset) + available_to_write);
if ((tmd.GetContentTypeByIndex(i) & FileSys::TMDContentTypeFlag::Encrypted) != 0) { if ((tmd.GetContentTypeByIndex(i) & FileSys::TMDContentTypeFlag::Encrypted) != 0) {
if (decryption_state->content.size() <= i) {
// TODO: There is probably no correct error to return here. What error should be
// returned?
return FileSys::ERROR_INSUFFICIENT_SPACE;
}
decryption_state->content[i].ProcessData(temp.data(), temp.data(), temp.size()); decryption_state->content[i].ProcessData(temp.data(), temp.data(), temp.size());
} }
@ -234,8 +261,9 @@ ResultVal<std::size_t> CIAFile::Write(u64 offset, std::size_t length, bool flush
} }
// If we don't have a header yet, we can't pull offsets of other sections // If we don't have a header yet, we can't pull offsets of other sections
if (install_state == CIAInstallState::InstallStarted) if (install_state == CIAInstallState::InstallStarted) {
return length; return length;
}
// If we have been given data before (or including) .app content, pull it into // If we have been given data before (or including) .app content, pull it into
// our buffer, but only pull *up to* the content offset, no further. // our buffer, but only pull *up to* the content offset, no further.
@ -251,28 +279,30 @@ ResultVal<std::size_t> CIAFile::Write(u64 offset, std::size_t length, bool flush
std::memcpy(data.data() + copy_offset, buffer + buf_offset, buf_copy_size); std::memcpy(data.data() + copy_offset, buffer + buf_offset, buf_copy_size);
} }
// TODO(shinyquagsire23): Write out .tik files to nand?
// The end of our TMD is at the beginning of Content data, so ensure we have that much // The end of our TMD is at the beginning of Content data, so ensure we have that much
// buffered before trying to parse. // buffered before trying to parse.
if (written >= container.GetContentOffset() && install_state != CIAInstallState::TMDLoaded) { if (written >= container.GetContentOffset() && install_state != CIAInstallState::TMDLoaded) {
auto result = WriteTicket(); auto result = WriteTicket();
if (result.IsError()) if (result.IsError()) {
return result;
result = WriteTitleMetadata();
if (result.IsError())
return result; return result;
} }
result = WriteTitleMetadata();
if (result.IsError()) {
return result;
}
}
// Content data sizes can only be retrieved from TMD data // Content data sizes can only be retrieved from TMD data
if (install_state != CIAInstallState::TMDLoaded) if (install_state != CIAInstallState::TMDLoaded) {
return length; return length;
}
// From this point forward, data will no longer be buffered in data // From this point forward, data will no longer be buffered in data
auto result = WriteContentData(offset, length, buffer); auto result = WriteContentData(offset, length, buffer);
if (result.Failed()) if (result.Failed()) {
return result; return result;
}
return length; return length;
} }
@ -286,11 +316,13 @@ bool CIAFile::SetSize(u64 size) const {
} }
bool CIAFile::Close() const { bool CIAFile::Close() const {
bool complete = true; bool complete =
for (std::size_t i = 0; i < container.GetTitleMetadata().GetContentCount(); i++) { install_state >= CIAInstallState::TMDLoaded &&
if (content_written[i] < container.GetContentSize(static_cast<u16>(i))) content_written.size() == container.GetTitleMetadata().GetContentCount() &&
complete = false; std::all_of(content_written.begin(), content_written.end(),
} [this, i = 0](auto& bytes_written) mutable {
return bytes_written >= container.GetContentSize(static_cast<u16>(i++));
});
// Install aborted // Install aborted
if (!complete) { if (!complete) {
@ -314,16 +346,17 @@ bool CIAFile::Close() const {
// For each content ID in the old TMD, check if there is a matching ID in the new // For each content ID in the old TMD, check if there is a matching ID in the new
// TMD. If a CIA contains (and wrote to) an identical ID, it should be kept while // TMD. If a CIA contains (and wrote to) an identical ID, it should be kept while
// IDs which only existed for the old TMD should be deleted. // IDs which only existed for the old TMD should be deleted.
for (u16 old_index = 0; old_index < old_tmd.GetContentCount(); old_index++) { for (std::size_t old_index = 0; old_index < old_tmd.GetContentCount(); old_index++) {
bool abort = false; bool abort = false;
for (u16 new_index = 0; new_index < new_tmd.GetContentCount(); new_index++) { for (std::size_t new_index = 0; new_index < new_tmd.GetContentCount(); new_index++) {
if (old_tmd.GetContentIDByIndex(old_index) == if (old_tmd.GetContentIDByIndex(old_index) ==
new_tmd.GetContentIDByIndex(new_index)) { new_tmd.GetContentIDByIndex(new_index)) {
abort = true; abort = true;
} }
} }
if (abort) if (abort) {
break; break;
}
// If the file to delete is the current launched rom, signal the system to delete // If the file to delete is the current launched rom, signal the system to delete
// the current rom instead of deleting it now, once all the handles to the file // the current rom instead of deleting it now, once all the handles to the file
@ -331,9 +364,10 @@ bool CIAFile::Close() const {
std::string to_delete = std::string to_delete =
GetTitleContentPath(media_type, old_tmd.GetTitleID(), old_index); GetTitleContentPath(media_type, old_tmd.GetTitleID(), old_index);
if (!(Core::System::GetInstance().IsPoweredOn() && if (!(Core::System::GetInstance().IsPoweredOn() &&
Core::System::GetInstance().SetSelfDelete(to_delete))) Core::System::GetInstance().SetSelfDelete(to_delete))) {
FileUtil::Delete(to_delete); FileUtil::Delete(to_delete);
} }
}
FileUtil::Delete(old_tmd_path); FileUtil::Delete(old_tmd_path);
} }
@ -357,29 +391,29 @@ InstallStatus InstallCIA(const std::string& path,
Service::AM::GetTitleMediaType(container.GetTitleMetadata().GetTitleID())); Service::AM::GetTitleMediaType(container.GetTitleMetadata().GetTitleID()));
bool title_key_available = container.GetTicket().GetTitleKey().has_value(); bool title_key_available = container.GetTicket().GetTitleKey().has_value();
if (!title_key_available && container.GetTitleMetadata().HasEncryptedContent()) {
for (std::size_t i = 0; i < container.GetTitleMetadata().GetContentCount(); i++) { LOG_ERROR(Service_AM, "File {} is encrypted and no title key is available! Aborting...",
if ((container.GetTitleMetadata().GetContentTypeByIndex(static_cast<u16>(i)) & path);
FileSys::TMDContentTypeFlag::Encrypted) &&
!title_key_available) {
LOG_ERROR(Service_AM, "File {} is encrypted! Aborting...", path);
return InstallStatus::ErrorEncrypted; return InstallStatus::ErrorEncrypted;
} }
}
FileUtil::IOFile file(path, "rb"); FileUtil::IOFile file(path, "rb");
if (!file.IsOpen()) if (!file.IsOpen()) {
LOG_ERROR(Service_AM, "Could not open CIA file '{}'.", path);
return InstallStatus::ErrorFailedToOpenFile; return InstallStatus::ErrorFailedToOpenFile;
}
std::array<u8, 0x10000> buffer; std::array<u8, 0x10000> buffer;
auto file_size = file.GetSize();
std::size_t total_bytes_read = 0; std::size_t total_bytes_read = 0;
while (total_bytes_read != file.GetSize()) { while (total_bytes_read != file_size) {
std::size_t bytes_read = file.ReadBytes(buffer.data(), buffer.size()); std::size_t bytes_read = file.ReadBytes(buffer.data(), buffer.size());
auto result = installFile.Write(static_cast<u64>(total_bytes_read), bytes_read, true, auto result = installFile.Write(static_cast<u64>(total_bytes_read), bytes_read, true,
static_cast<u8*>(buffer.data())); static_cast<u8*>(buffer.data()));
if (update_callback) if (update_callback) {
update_callback(total_bytes_read, file.GetSize()); update_callback(total_bytes_read, file_size);
}
if (result.Failed()) { if (result.Failed()) {
LOG_ERROR(Service_AM, "CIA file installation aborted with error code {:08x}", LOG_ERROR(Service_AM, "CIA file installation aborted with error code {:08x}",
result.Code().raw); result.Code().raw);
@ -521,6 +555,11 @@ InstallStatus InstallFromNus(u64 title_id, int version) {
#endif #endif
} }
u64 GetTitleUpdateId(u64 title_id) {
// Real services seem to just discard and replace the whole high word.
return (title_id & 0xFFFFFFFF) | (static_cast<u64>(TID_HIGH_UPDATE) << 32);
}
Service::FS::MediaType GetTitleMediaType(u64 titleId) { Service::FS::MediaType GetTitleMediaType(u64 titleId) {
u16 platform = static_cast<u16>(titleId >> 48); u16 platform = static_cast<u16>(titleId >> 48);
u16 category = static_cast<u16>((titleId >> 32) & 0xFFFF); u16 category = static_cast<u16>((titleId >> 32) & 0xFFFF);

View File

@ -26,6 +26,10 @@ namespace Core {
class System; class System;
} }
namespace FileUtil {
class IOFile;
}
namespace Service::FS { namespace Service::FS {
enum class MediaType : u32; enum class MediaType : u32;
} }
@ -96,6 +100,7 @@ private:
FileSys::CIAContainer container; FileSys::CIAContainer container;
std::vector<u8> data; std::vector<u8> data;
std::vector<u64> content_written; std::vector<u64> content_written;
std::vector<FileUtil::IOFile> content_files;
Service::FS::MediaType media_type; Service::FS::MediaType media_type;
class DecryptionState; class DecryptionState;
@ -118,6 +123,13 @@ InstallStatus InstallCIA(const std::string& path,
*/ */
InstallStatus InstallFromNus(u64 title_id, int version = -1); InstallStatus InstallFromNus(u64 title_id, int version = -1);
/**
* Get the update title ID for a title
* @param titleId the title ID
* @returns The update title ID
*/
u64 GetTitleUpdateId(u64 title_id);
/** /**
* Get the mediatype for an installed title * Get the mediatype for an installed title
* @param titleId the installed title ID * @param titleId the installed title ID

View File

@ -19,7 +19,7 @@ SERVICE_CONSTRUCT_IMPL(Service::APT::AppletManager)
namespace Service::APT { namespace Service::APT {
/// The interval at which the home button update callback will be called, 16.6ms /// The interval at which the home button update callback will be called, 16.6ms
static constexpr u64 home_button_update_interval_us = 16666; static constexpr u64 button_update_interval_us = 16666;
struct AppletTitleData { struct AppletTitleData {
// There are two possible applet ids for each applet. // There are two possible applet ids for each applet.
@ -232,7 +232,7 @@ void AppletManager::CancelAndSendParameter(const MessageParameter& parameter) {
parameter.sender_id); parameter.sender_id);
if (parameter.buffer.size() >= sizeof(CaptureBufferInfo)) { if (parameter.buffer.size() >= sizeof(CaptureBufferInfo)) {
SendCaptureBufferInfo(parameter.buffer); SetCaptureInfo(parameter.buffer);
CaptureFrameBuffers(); CaptureFrameBuffers();
} }
@ -407,11 +407,56 @@ ResultCode AppletManager::Enable(AppletAttributes attributes) {
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
ResultCode AppletManager::Finalize(AppletId app_id) {
auto slot = GetAppletSlotFromId(app_id);
if (slot == AppletSlot::Error) {
return {ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound,
ErrorLevel::Status};
}
auto slot_data = GetAppletSlot(slot);
slot_data->Reset();
auto inactive = active_slot == AppletSlot::Error;
if (!inactive) {
auto active_slot_data = GetAppletSlot(active_slot);
inactive = active_slot_data->applet_id == AppletId::None ||
active_slot_data->attributes.applet_pos.Value() == AppletPos::Invalid;
}
if (inactive) {
active_slot = GetAppletSlotFromPos(AppletPos::System);
}
return RESULT_SUCCESS;
}
u32 AppletManager::CountRegisteredApplet() {
return static_cast<u32>(std::count_if(applet_slots.begin(), applet_slots.end(),
[](auto& slot_data) { return slot_data.registered; }));
}
bool AppletManager::IsRegistered(AppletId app_id) { bool AppletManager::IsRegistered(AppletId app_id) {
auto slot = GetAppletSlotFromId(app_id); auto slot = GetAppletSlotFromId(app_id);
return slot != AppletSlot::Error && GetAppletSlot(slot)->registered; return slot != AppletSlot::Error && GetAppletSlot(slot)->registered;
} }
ResultVal<AppletAttributes> AppletManager::GetAttribute(AppletId app_id) {
auto slot = GetAppletSlotFromId(app_id);
if (slot == AppletSlot::Error) {
return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound,
ErrorLevel::Status);
}
auto slot_data = GetAppletSlot(slot);
if (!slot_data->registered) {
return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotFound,
ErrorLevel::Status);
}
return slot_data->attributes;
}
ResultVal<Notification> AppletManager::InquireNotification(AppletId app_id) { ResultVal<Notification> AppletManager::InquireNotification(AppletId app_id) {
auto slot = GetAppletSlotFromId(app_id); auto slot = GetAppletSlotFromId(app_id);
if (slot != AppletSlot::Error) { if (slot != AppletSlot::Error) {
@ -441,6 +486,15 @@ ResultCode AppletManager::SendNotification(Notification notification) {
ErrorLevel::Status}; ErrorLevel::Status};
} }
void AppletManager::SendNotificationToAll(Notification notification) {
for (auto& slot_data : applet_slots) {
if (slot_data.registered) {
slot_data.notification = notification;
slot_data.notification_event->Signal();
}
}
}
ResultCode AppletManager::PrepareToStartLibraryApplet(AppletId applet_id) { ResultCode AppletManager::PrepareToStartLibraryApplet(AppletId applet_id) {
// The real APT service returns an error if there's a pending APT parameter when this function // The real APT service returns an error if there's a pending APT parameter when this function
// is called. // is called.
@ -457,6 +511,8 @@ ResultCode AppletManager::PrepareToStartLibraryApplet(AppletId applet_id) {
last_library_launcher_slot = active_slot; last_library_launcher_slot = active_slot;
last_prepared_library_applet = applet_id; last_prepared_library_applet = applet_id;
capture_buffer_info.reset();
auto cfg = Service::CFG::GetModule(system); auto cfg = Service::CFG::GetModule(system);
auto process = auto process =
NS::LaunchTitle(FS::MediaType::NAND, GetTitleIdForApplet(applet_id, cfg->GetRegionValue())); NS::LaunchTitle(FS::MediaType::NAND, GetTitleIdForApplet(applet_id, cfg->GetRegionValue()));
@ -594,6 +650,71 @@ ResultCode AppletManager::CancelLibraryApplet(bool app_exiting) {
}); });
} }
ResultCode AppletManager::SendDspSleep(AppletId from_applet_id,
std::shared_ptr<Kernel::Object> object) {
auto lib_slot = GetAppletSlotFromPos(AppletPos::Library);
auto lib_app_id =
lib_slot != AppletSlot::Error ? GetAppletSlot(lib_slot)->applet_id : AppletId::None;
if (from_applet_id == lib_app_id) {
SendParameter({
.sender_id = from_applet_id,
.destination_id = AppletId::Application,
.signal = SignalType::DspSleep,
.object = std::move(object),
});
}
auto sys_lib_slot = GetAppletSlotFromPos(AppletPos::SysLibrary);
auto sys_lib_app_id =
sys_lib_slot != AppletSlot::Error ? GetAppletSlot(sys_lib_slot)->applet_id : AppletId::None;
if (from_applet_id == sys_lib_app_id) {
auto sys_slot = GetAppletSlotFromPos(AppletPos::System);
auto sys_app_id =
sys_slot != AppletSlot::Error ? GetAppletSlot(sys_slot)->applet_id : AppletId::None;
SendParameter({
.sender_id = from_applet_id,
.destination_id = sys_app_id,
.signal = SignalType::DspSleep,
.object = std::move(object),
});
}
return RESULT_SUCCESS;
}
ResultCode AppletManager::SendDspWakeUp(AppletId from_applet_id,
std::shared_ptr<Kernel::Object> object) {
auto lib_slot = GetAppletSlotFromPos(AppletPos::Library);
auto lib_app_id =
lib_slot != AppletSlot::Error ? GetAppletSlot(lib_slot)->applet_id : AppletId::None;
if (from_applet_id == lib_app_id) {
SendParameter({
.sender_id = from_applet_id,
.destination_id = AppletId::Application,
.signal = SignalType::DspSleep,
.object = std::move(object),
});
} else {
auto sys_lib_slot = GetAppletSlotFromPos(AppletPos::SysLibrary);
auto sys_lib_app_id = sys_lib_slot != AppletSlot::Error
? GetAppletSlot(sys_lib_slot)->applet_id
: AppletId::None;
if (from_applet_id == sys_lib_app_id) {
auto sys_slot = GetAppletSlotFromPos(AppletPos::System);
auto sys_app_id =
sys_slot != AppletSlot::Error ? GetAppletSlot(sys_slot)->applet_id : AppletId::None;
SendParameter({
.sender_id = from_applet_id,
.destination_id = sys_app_id,
.signal = SignalType::DspSleep,
.object = std::move(object),
});
}
}
return RESULT_SUCCESS;
}
ResultCode AppletManager::PrepareToStartSystemApplet(AppletId applet_id) { ResultCode AppletManager::PrepareToStartSystemApplet(AppletId applet_id) {
// The real APT service returns an error if there's a pending APT parameter when this function // The real APT service returns an error if there's a pending APT parameter when this function
// is called. // is called.
@ -730,6 +851,9 @@ ResultCode AppletManager::PrepareToJumpToHomeMenu() {
} }
last_jump_to_home_slot = active_slot; last_jump_to_home_slot = active_slot;
capture_buffer_info.reset();
if (last_jump_to_home_slot == AppletSlot::Application) { if (last_jump_to_home_slot == AppletSlot::Application) {
EnsureHomeMenuLoaded(); EnsureHomeMenuLoaded();
} }
@ -963,10 +1087,7 @@ ResultVal<AppletManager::AppletInfo> AppletManager::GetAppletInfo(AppletId app_i
ErrorLevel::Status); ErrorLevel::Status);
} }
// TODO: Basic heuristic to guess media type, needs proper implementation. auto media_type = Service::AM::GetTitleMediaType(slot_data->title_id);
auto media_type = ((slot_data->title_id >> 32) & 0xFFFFFFFF) == 0x00040000
? Service::FS::MediaType::SDMC
: Service::FS::MediaType::NAND;
return AppletInfo{ return AppletInfo{
.title_id = slot_data->title_id, .title_id = slot_data->title_id,
.media_type = media_type, .media_type = media_type,
@ -976,6 +1097,61 @@ ResultVal<AppletManager::AppletInfo> AppletManager::GetAppletInfo(AppletId app_i
}; };
} }
ResultVal<Service::FS::MediaType> AppletManager::Unknown54(u32 in_param) {
auto slot_data = GetAppletSlot(AppletSlot::Application);
if (slot_data->applet_id == AppletId::None) {
return ResultCode{ErrCodes::AppNotRunning, ErrorModule::Applet, ErrorSummary::InvalidState,
ErrorLevel::Permanent};
}
if (in_param >= 0x80) {
// TODO: Add error description name when the parameter is known.
return ResultCode{10, ErrorModule::Applet, ErrorSummary::InvalidArgument,
ErrorLevel::Usage};
}
// TODO: Figure out what this logic is actually for.
auto check_target =
in_param >= 0x40 ? Service::FS::MediaType::GameCard : Service::FS::MediaType::SDMC;
auto check_update = in_param == 0x01 || in_param == 0x42;
auto app_media_type = Service::AM::GetTitleMediaType(slot_data->title_id);
auto app_update_media_type =
Service::AM::GetTitleMediaType(Service::AM::GetTitleUpdateId(slot_data->title_id));
if (app_media_type == check_target || (check_update && app_update_media_type == check_target)) {
return Service::FS::MediaType::SDMC;
} else {
return Service::FS::MediaType::NAND;
}
}
TargetPlatform AppletManager::GetTargetPlatform() {
if (Settings::values.is_new_3ds.GetValue() && !new_3ds_mode_blocked) {
return TargetPlatform::New3ds;
} else {
return TargetPlatform::Old3ds;
}
}
ApplicationRunningMode AppletManager::GetApplicationRunningMode() {
auto slot_data = GetAppletSlot(AppletSlot::Application);
if (slot_data->applet_id == AppletId::None) {
return ApplicationRunningMode::NoApplication;
}
// APT checks whether the system is a New 3DS and the 804MHz CPU speed is enabled to determine
// the result.
auto new_3ds_mode = GetTargetPlatform() == TargetPlatform::New3ds &&
system.Kernel().GetNew3dsHwCapabilities().enable_804MHz_cpu;
if (slot_data->registered) {
return new_3ds_mode ? ApplicationRunningMode::New3dsRegistered
: ApplicationRunningMode::Old3dsRegistered;
} else {
return new_3ds_mode ? ApplicationRunningMode::New3dsUnregistered
: ApplicationRunningMode::Old3dsUnregistered;
}
}
ResultCode AppletManager::PrepareToDoApplicationJump(u64 title_id, FS::MediaType media_type, ResultCode AppletManager::PrepareToDoApplicationJump(u64 title_id, FS::MediaType media_type,
ApplicationJumpFlags flags) { ApplicationJumpFlags flags) {
// A running application can not launch another application directly because the applet state // A running application can not launch another application directly because the applet state
@ -988,11 +1164,8 @@ ResultCode AppletManager::PrepareToDoApplicationJump(u64 title_id, FS::MediaType
// Save the title data to send it to the Home Menu when DoApplicationJump is called. // Save the title data to send it to the Home Menu when DoApplicationJump is called.
auto application_slot_data = GetAppletSlot(AppletSlot::Application); auto application_slot_data = GetAppletSlot(AppletSlot::Application);
app_jump_parameters.current_title_id = application_slot_data->title_id; app_jump_parameters.current_title_id = application_slot_data->title_id;
// TODO: Basic heuristic to guess media type, needs proper implementation.
app_jump_parameters.current_media_type = app_jump_parameters.current_media_type =
((application_slot_data->title_id >> 32) & 0xFFFFFFFF) == 0x00040000 Service::AM::GetTitleMediaType(application_slot_data->title_id);
? Service::FS::MediaType::SDMC
: Service::FS::MediaType::NAND;
if (flags == ApplicationJumpFlags::UseCurrentParameters) { if (flags == ApplicationJumpFlags::UseCurrentParameters) {
app_jump_parameters.next_title_id = app_jump_parameters.current_title_id; app_jump_parameters.next_title_id = app_jump_parameters.current_title_id;
app_jump_parameters.next_media_type = app_jump_parameters.current_media_type; app_jump_parameters.next_media_type = app_jump_parameters.current_media_type;
@ -1055,19 +1228,8 @@ ResultCode AppletManager::DoApplicationJump(const DeliverArg& arg) {
return RESULT_SUCCESS; return RESULT_SUCCESS;
*/ */
auto new_path = Service::AM::GetTitleContentPath(app_jump_parameters.next_media_type, NS::RebootToTitle(system, app_jump_parameters.next_media_type,
app_jump_parameters.next_title_id); app_jump_parameters.next_title_id);
if (new_path.empty() || !FileUtil::Exists(new_path)) {
// TODO: This can happen if the requested title is not installed. Need a way to find
// non-installed titles in the game list.
LOG_CRITICAL(
Service_APT,
"Failed to find title during application jump: {} Resetting current title instead.",
new_path);
new_path.clear();
}
system.RequestReset(new_path);
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
} }
@ -1093,6 +1255,8 @@ ResultCode AppletManager::PrepareToStartApplication(u64 title_id, FS::MediaType
app_start_parameters->next_title_id = title_id; app_start_parameters->next_title_id = title_id;
app_start_parameters->next_media_type = media_type; app_start_parameters->next_media_type = media_type;
capture_buffer_info.reset();
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
@ -1126,13 +1290,14 @@ ResultCode AppletManager::StartApplication(const std::vector<u8>& parameter,
app_start_parameters.reset(); app_start_parameters.reset();
if (!paused) { if (!paused) {
return WakeupApplication(); return WakeupApplication(nullptr, {});
} }
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
ResultCode AppletManager::WakeupApplication() { ResultCode AppletManager::WakeupApplication(std::shared_ptr<Kernel::Object> object,
const std::vector<u8>& buffer) {
// Send a Wakeup signal via the apt parameter to the application once it registers itself. // Send a Wakeup signal via the apt parameter to the application once it registers itself.
// The real APT service does this by spin waiting on another thread until the application is // The real APT service does this by spin waiting on another thread until the application is
// registered. // registered.
@ -1140,6 +1305,8 @@ ResultCode AppletManager::WakeupApplication() {
.sender_id = AppletId::HomeMenu, .sender_id = AppletId::HomeMenu,
.destination_id = AppletId::Application, .destination_id = AppletId::Application,
.signal = SignalType::Wakeup, .signal = SignalType::Wakeup,
.object = std::move(object),
.buffer = buffer,
}); });
return RESULT_SUCCESS; return RESULT_SUCCESS;
@ -1199,48 +1366,74 @@ void AppletManager::EnsureHomeMenuLoaded() {
} }
} }
static void CaptureFrameBuffer(Core::System& system, u32 capture_offset, VAddr src, u32 height, static u32 GetDisplayBufferModePixelSize(DisplayBufferMode mode) {
u32 format) { switch (mode) {
static constexpr auto screen_capture_base_vaddr = static_cast<VAddr>(0x1F500000); // NOTE: APT does in fact use pixel size 3 for R8G8B8A8 captures.
static constexpr auto screen_width = 240; case DisplayBufferMode::R8G8B8A8:
static constexpr auto screen_width_pow2 = 256; case DisplayBufferMode::R8G8B8:
const auto bpp = format < 2 ? 3 : 2; return 3;
case DisplayBufferMode::R5G6B5:
case DisplayBufferMode::R5G5B5A1:
case DisplayBufferMode::R4G4B4A4:
return 2;
case DisplayBufferMode::Unimportable:
return 0;
default:
UNREACHABLE_MSG("Unknown display buffer mode {}", mode);
return 0;
}
}
Memory::RasterizerFlushVirtualRegion(src, screen_width * height * bpp, static void CaptureFrameBuffer(Core::System& system, u32 capture_offset, VAddr src, u32 height,
DisplayBufferMode mode) {
const auto bpp = GetDisplayBufferModePixelSize(mode);
if (bpp == 0) {
return;
}
Memory::RasterizerFlushVirtualRegion(src, GSP::FRAMEBUFFER_WIDTH * height * bpp,
Memory::FlushMode::Flush); Memory::FlushMode::Flush);
auto dst_vaddr = screen_capture_base_vaddr + capture_offset; // Address in VRAM that APT copies framebuffer captures to.
constexpr VAddr screen_capture_base_vaddr = Memory::VRAM_VADDR + 0x500000;
const auto dst_vaddr = screen_capture_base_vaddr + capture_offset;
auto dst_ptr = system.Memory().GetPointer(dst_vaddr); auto dst_ptr = system.Memory().GetPointer(dst_vaddr);
if (!dst_ptr) {
LOG_ERROR(Service_APT,
"Could not retrieve framebuffer capture destination buffer, skipping screen.");
return;
}
const auto src_ptr = system.Memory().GetPointer(src); const auto src_ptr = system.Memory().GetPointer(src);
if (!src_ptr) {
LOG_ERROR(Service_APT,
"Could not retrieve framebuffer capture source buffer, skipping screen.");
return;
}
for (u32 y = 0; y < height; y++) { for (u32 y = 0; y < height; y++) {
for (u32 x = 0; x < screen_width; x++) { for (u32 x = 0; x < GSP::FRAMEBUFFER_WIDTH; x++) {
auto dst_offset = const auto dst_offset = VideoCore::GetMortonOffset(x, y, bpp) +
VideoCore::GetMortonOffset(x, y, bpp) + (y & ~7) * screen_width_pow2 * bpp; (y & ~7) * GSP::FRAMEBUFFER_WIDTH_POW2 * bpp;
auto src_offset = bpp * (screen_width * y + x); const auto src_offset = bpp * (GSP::FRAMEBUFFER_WIDTH * y + x);
std::memcpy(dst_ptr + dst_offset, src_ptr + src_offset, bpp); std::memcpy(dst_ptr + dst_offset, src_ptr + src_offset, bpp);
} }
} }
Memory::RasterizerFlushVirtualRegion(dst_vaddr, screen_width_pow2 * height * bpp, Memory::RasterizerFlushVirtualRegion(dst_vaddr, GSP::FRAMEBUFFER_WIDTH_POW2 * height * bpp,
Memory::FlushMode::Invalidate); Memory::FlushMode::Invalidate);
} }
void AppletManager::CaptureFrameBuffers() { void AppletManager::CaptureFrameBuffers() {
auto gsp = CaptureFrameBuffer(system, capture_info->bottom_screen_left_offset,
Core::System::GetInstance().ServiceManager().GetService<Service::GSP::GSP_GPU>("gsp::Gpu"); GSP::FRAMEBUFFER_SAVE_AREA_BOTTOM, GSP::BOTTOM_FRAMEBUFFER_HEIGHT,
auto active_thread_id = gsp->GetActiveThreadId();
auto top_screen = gsp->GetFrameBufferInfo(active_thread_id, 0);
auto bottom_screen = gsp->GetFrameBufferInfo(active_thread_id, 1);
auto top_fb = top_screen->framebuffer_info[top_screen->index];
auto bottom_fb = bottom_screen->framebuffer_info[bottom_screen->index];
CaptureFrameBuffer(system, capture_info->bottom_screen_left_offset, bottom_fb.address_left, 320,
capture_info->bottom_screen_format); capture_info->bottom_screen_format);
CaptureFrameBuffer(system, capture_info->top_screen_left_offset, top_fb.address_left, 400, CaptureFrameBuffer(system, capture_info->top_screen_left_offset,
GSP::FRAMEBUFFER_SAVE_AREA_TOP_LEFT, GSP::TOP_FRAMEBUFFER_HEIGHT,
capture_info->top_screen_format); capture_info->top_screen_format);
if (capture_info->is_3d) { if (capture_info->is_3d) {
CaptureFrameBuffer(system, capture_info->top_screen_right_offset, top_fb.address_right, 400, CaptureFrameBuffer(system, capture_info->top_screen_right_offset,
GSP::FRAMEBUFFER_SAVE_AREA_TOP_RIGHT, GSP::TOP_FRAMEBUFFER_HEIGHT,
capture_info->top_screen_format); capture_info->top_screen_format);
} }
} }
@ -1248,27 +1441,38 @@ void AppletManager::CaptureFrameBuffers() {
void AppletManager::LoadInputDevices() { void AppletManager::LoadInputDevices() {
home_button = Input::CreateDevice<Input::ButtonDevice>( home_button = Input::CreateDevice<Input::ButtonDevice>(
Settings::values.current_input_profile.buttons[Settings::NativeButton::Home]); Settings::values.current_input_profile.buttons[Settings::NativeButton::Home]);
power_button = Input::CreateDevice<Input::ButtonDevice>(
Settings::values.current_input_profile.buttons[Settings::NativeButton::Power]);
} }
void AppletManager::HomeButtonUpdateEvent(std::uintptr_t user_data, s64 cycles_late) { void AppletManager::ButtonUpdateEvent(std::uintptr_t user_data, s64 cycles_late) {
if (is_device_reload_pending.exchange(false)) { if (is_device_reload_pending.exchange(false)) {
LoadInputDevices(); LoadInputDevices();
} }
const bool state = home_button->GetStatus();
// NOTE: We technically do support loading and jumping to home menu even if it isn't // NOTE: We technically do support loading and jumping to home menu even if it isn't
// initially registered. However since the home menu suspend is not bug-free, we don't // initially registered. However since the home menu suspend is not bug-free, we don't
// want normal users who didn't launch the home menu accidentally pressing the home // want normal users who didn't launch the home menu accidentally pressing the home
// button binding and freezing their game, so for now, gate it to only environments // button binding and freezing their game, so for now, gate it to only environments
// where the home menu was already loaded by the user (last condition). // where the home menu was already loaded by the user (last condition).
if (state && !last_home_button_state && GetAppletSlot(AppletSlot::HomeMenu)->registered) {
if (GetAppletSlot(AppletSlot::HomeMenu)->registered) {
const bool home_state = home_button->GetStatus();
if (home_state && !last_home_button_state) {
SendNotification(Notification::HomeButtonSingle); SendNotification(Notification::HomeButtonSingle);
} }
last_home_button_state = state; last_home_button_state = home_state;
const bool power_state = power_button->GetStatus();
if (power_state && !last_power_button_state) {
SendNotificationToAll(Notification::PowerButtonClick);
}
last_power_button_state = power_state;
}
// Reschedule recurrent event // Reschedule recurrent event
Core::System::GetInstance().CoreTiming().ScheduleEvent( system.CoreTiming().ScheduleEvent(usToCycles(button_update_interval_us) - cycles_late,
usToCycles(home_button_update_interval_us) - cycles_late, home_button_update_event); button_update_event);
} }
AppletManager::AppletManager(Core::System& system) : system(system) { AppletManager::AppletManager(Core::System& system) : system(system) {
@ -1286,12 +1490,11 @@ AppletManager::AppletManager(Core::System& system) : system(system) {
system.Kernel().CreateEvent(Kernel::ResetType::OneShot, "APT:Parameter"); system.Kernel().CreateEvent(Kernel::ResetType::OneShot, "APT:Parameter");
} }
HLE::Applets::Init(); HLE::Applets::Init();
home_button_update_event = Core::System::GetInstance().CoreTiming().RegisterEvent( button_update_event = system.CoreTiming().RegisterEvent(
"Home Button Update Event", [this](std::uintptr_t user_data, s64 cycles_late) { "APT Button Update Event", [this](std::uintptr_t user_data, s64 cycles_late) {
HomeButtonUpdateEvent(user_data, cycles_late); ButtonUpdateEvent(user_data, cycles_late);
}); });
Core::System::GetInstance().CoreTiming().ScheduleEvent( system.CoreTiming().ScheduleEvent(usToCycles(button_update_interval_us), button_update_event);
usToCycles(home_button_update_interval_us), home_button_update_event);
} }
AppletManager::~AppletManager() { AppletManager::~AppletManager() {

View File

@ -99,6 +99,21 @@ enum class AppletId : u32 {
Memolib2 = 0x409, Memolib2 = 0x409,
}; };
/// Application Old/New 3DS target platforms
enum class TargetPlatform : u8 {
Old3ds = 0,
New3ds = 1,
};
/// Application Old/New 3DS running modes
enum class ApplicationRunningMode : u8 {
NoApplication = 0,
Old3dsRegistered = 1,
New3dsRegistered = 2,
Old3dsUnregistered = 3,
New3dsUnregistered = 4,
};
/// Holds information about the parameters used in Send/Glance/ReceiveParameter /// Holds information about the parameters used in Send/Glance/ReceiveParameter
struct MessageParameter { struct MessageParameter {
AppletId sender_id = AppletId::None; AppletId sender_id = AppletId::None;
@ -195,6 +210,15 @@ private:
friend class boost::serialization::access; friend class boost::serialization::access;
}; };
enum class DisplayBufferMode : u32_le {
R8G8B8A8 = 0,
R8G8B8 = 1,
R5G6B5 = 2,
R5G5B5A1 = 3,
R4G4B4A4 = 4,
Unimportable = 0xFFFFFFFF,
};
/// Used by the application to pass information about the current framebuffer to applets. /// Used by the application to pass information about the current framebuffer to applets.
struct CaptureBufferInfo { struct CaptureBufferInfo {
u32_le size; u32_le size;
@ -202,10 +226,10 @@ struct CaptureBufferInfo {
INSERT_PADDING_BYTES(0x3); // Padding for alignment INSERT_PADDING_BYTES(0x3); // Padding for alignment
u32_le top_screen_left_offset; u32_le top_screen_left_offset;
u32_le top_screen_right_offset; u32_le top_screen_right_offset;
u32_le top_screen_format; DisplayBufferMode top_screen_format;
u32_le bottom_screen_left_offset; u32_le bottom_screen_left_offset;
u32_le bottom_screen_right_offset; u32_le bottom_screen_right_offset;
u32_le bottom_screen_format; DisplayBufferMode bottom_screen_format;
private: private:
template <class Archive> template <class Archive>
@ -256,10 +280,14 @@ public:
ResultVal<InitializeResult> Initialize(AppletId app_id, AppletAttributes attributes); ResultVal<InitializeResult> Initialize(AppletId app_id, AppletAttributes attributes);
ResultCode Enable(AppletAttributes attributes); ResultCode Enable(AppletAttributes attributes);
ResultCode Finalize(AppletId app_id);
u32 CountRegisteredApplet();
bool IsRegistered(AppletId app_id); bool IsRegistered(AppletId app_id);
ResultVal<AppletAttributes> GetAttribute(AppletId app_id);
ResultVal<Notification> InquireNotification(AppletId app_id); ResultVal<Notification> InquireNotification(AppletId app_id);
ResultCode SendNotification(Notification notification); ResultCode SendNotification(Notification notification);
void SendNotificationToAll(Notification notification);
ResultCode PrepareToStartLibraryApplet(AppletId applet_id); ResultCode PrepareToStartLibraryApplet(AppletId applet_id);
ResultCode PreloadLibraryApplet(AppletId applet_id); ResultCode PreloadLibraryApplet(AppletId applet_id);
@ -271,6 +299,9 @@ public:
const std::vector<u8>& buffer); const std::vector<u8>& buffer);
ResultCode CancelLibraryApplet(bool app_exiting); ResultCode CancelLibraryApplet(bool app_exiting);
ResultCode SendDspSleep(AppletId from_applet_id, std::shared_ptr<Kernel::Object> object);
ResultCode SendDspWakeUp(AppletId from_applet_id, std::shared_ptr<Kernel::Object> object);
ResultCode PrepareToStartSystemApplet(AppletId applet_id); ResultCode PrepareToStartSystemApplet(AppletId applet_id);
ResultCode StartSystemApplet(AppletId applet_id, std::shared_ptr<Kernel::Object> object, ResultCode StartSystemApplet(AppletId applet_id, std::shared_ptr<Kernel::Object> object,
const std::vector<u8>& buffer); const std::vector<u8>& buffer);
@ -294,8 +325,10 @@ public:
ApplicationJumpFlags flags); ApplicationJumpFlags flags);
ResultCode DoApplicationJump(const DeliverArg& arg); ResultCode DoApplicationJump(const DeliverArg& arg);
boost::optional<DeliverArg> ReceiveDeliverArg() const { boost::optional<DeliverArg> ReceiveDeliverArg() {
return deliver_arg; auto arg = deliver_arg;
deliver_arg = boost::none;
return arg;
} }
void SetDeliverArg(boost::optional<DeliverArg> arg) { void SetDeliverArg(boost::optional<DeliverArg> arg) {
deliver_arg = std::move(arg); deliver_arg = std::move(arg);
@ -309,22 +342,34 @@ public:
} }
return buffer; return buffer;
} }
std::vector<u8> ReceiveCaptureBufferInfo() { void SetCaptureInfo(std::vector<u8> buffer) {
std::vector<u8> buffer = GetCaptureInfo();
capture_info.reset();
return buffer;
}
void SendCaptureBufferInfo(std::vector<u8> buffer) {
ASSERT_MSG(buffer.size() >= sizeof(CaptureBufferInfo), "CaptureBufferInfo is too small."); ASSERT_MSG(buffer.size() >= sizeof(CaptureBufferInfo), "CaptureBufferInfo is too small.");
capture_info.emplace(); capture_info.emplace();
std::memcpy(&capture_info.get(), buffer.data(), sizeof(CaptureBufferInfo)); std::memcpy(&capture_info.get(), buffer.data(), sizeof(CaptureBufferInfo));
} }
std::vector<u8> ReceiveCaptureBufferInfo() {
std::vector<u8> buffer;
if (capture_buffer_info) {
buffer.resize(sizeof(CaptureBufferInfo));
std::memcpy(buffer.data(), &capture_buffer_info.get(), sizeof(CaptureBufferInfo));
capture_buffer_info.reset();
}
return buffer;
}
void SendCaptureBufferInfo(std::vector<u8> buffer) {
ASSERT_MSG(buffer.size() >= sizeof(CaptureBufferInfo), "CaptureBufferInfo is too small.");
capture_buffer_info.emplace();
std::memcpy(&capture_buffer_info.get(), buffer.data(), sizeof(CaptureBufferInfo));
}
ResultCode PrepareToStartApplication(u64 title_id, FS::MediaType media_type); ResultCode PrepareToStartApplication(u64 title_id, FS::MediaType media_type);
ResultCode StartApplication(const std::vector<u8>& parameter, const std::vector<u8>& hmac, ResultCode StartApplication(const std::vector<u8>& parameter, const std::vector<u8>& hmac,
bool paused); bool paused);
ResultCode WakeupApplication(); ResultCode WakeupApplication(std::shared_ptr<Kernel::Object> object,
const std::vector<u8>& buffer);
ResultCode CancelApplication(); ResultCode CancelApplication();
struct AppletManInfo { struct AppletManInfo {
@ -349,6 +394,10 @@ public:
return app_jump_parameters; return app_jump_parameters;
} }
ResultVal<Service::FS::MediaType> Unknown54(u32 in_param);
TargetPlatform GetTargetPlatform();
ApplicationRunningMode GetApplicationRunningMode();
private: private:
/// APT lock retrieved via GetLockHandle. /// APT lock retrieved via GetLockHandle.
std::shared_ptr<Kernel::Mutex> lock; std::shared_ptr<Kernel::Mutex> lock;
@ -366,6 +415,7 @@ private:
boost::optional<DeliverArg> deliver_arg{}; boost::optional<DeliverArg> deliver_arg{};
boost::optional<CaptureBufferInfo> capture_info; boost::optional<CaptureBufferInfo> capture_info;
boost::optional<CaptureBufferInfo> capture_buffer_info;
static constexpr std::size_t NumAppletSlot = 4; static constexpr std::size_t NumAppletSlot = 4;
@ -427,10 +477,16 @@ private:
bool application_cancelled = false; bool application_cancelled = false;
AppletSlot application_close_target = AppletSlot::Error; AppletSlot application_close_target = AppletSlot::Error;
Core::TimingEventType* home_button_update_event; // This flag is used to determine if an app that supports New 3DS capabilities should use them.
// It also affects the results of APT:GetTargetPlatform and APT:GetApplicationRunningMode.
bool new_3ds_mode_blocked = false;
Core::TimingEventType* button_update_event;
std::atomic<bool> is_device_reload_pending{true}; std::atomic<bool> is_device_reload_pending{true};
std::unique_ptr<Input::ButtonDevice> home_button; std::unique_ptr<Input::ButtonDevice> home_button;
std::unique_ptr<Input::ButtonDevice> power_button;
bool last_home_button_state = false; bool last_home_button_state = false;
bool last_power_button_state = false;
Core::System& system; Core::System& system;
@ -455,7 +511,7 @@ private:
void CaptureFrameBuffers(); void CaptureFrameBuffers();
void LoadInputDevices(); void LoadInputDevices();
void HomeButtonUpdateEvent(std::uintptr_t user_data, s64 cycles_late); void ButtonUpdateEvent(std::uintptr_t user_data, s64 cycles_late);
template <class Archive> template <class Archive>
void serialize(Archive& ar, const unsigned int file_version) { void serialize(Archive& ar, const unsigned int file_version) {
@ -465,6 +521,8 @@ private:
ar& delayed_parameter; ar& delayed_parameter;
ar& app_start_parameters; ar& app_start_parameters;
ar& deliver_arg; ar& deliver_arg;
ar& capture_info;
ar& capture_buffer_info;
ar& active_slot; ar& active_slot;
ar& last_library_launcher_slot; ar& last_library_launcher_slot;
ar& last_prepared_library_applet; ar& last_prepared_library_applet;
@ -474,6 +532,7 @@ private:
ar& ordered_to_close_application; ar& ordered_to_close_application;
ar& application_cancelled; ar& application_cancelled;
ar& application_close_target; ar& application_close_target;
ar& new_3ds_mode_blocked;
ar& lock; ar& lock;
ar& capture_info; ar& capture_info;
} }

View File

@ -16,16 +16,19 @@
#include "core/hle/kernel/mutex.h" #include "core/hle/kernel/mutex.h"
#include "core/hle/kernel/shared_memory.h" #include "core/hle/kernel/shared_memory.h"
#include "core/hle/romfs.h" #include "core/hle/romfs.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/apt/applet_manager.h" #include "core/hle/service/apt/applet_manager.h"
#include "core/hle/service/apt/apt.h" #include "core/hle/service/apt/apt.h"
#include "core/hle/service/apt/apt_a.h" #include "core/hle/service/apt/apt_a.h"
#include "core/hle/service/apt/apt_s.h" #include "core/hle/service/apt/apt_s.h"
#include "core/hle/service/apt/apt_u.h" #include "core/hle/service/apt/apt_u.h"
#include "core/hle/service/apt/bcfnt/bcfnt.h" #include "core/hle/service/apt/bcfnt/bcfnt.h"
#include "core/hle/service/apt/ns.h"
#include "core/hle/service/apt/ns_c.h" #include "core/hle/service/apt/ns_c.h"
#include "core/hle/service/apt/ns_s.h" #include "core/hle/service/apt/ns_s.h"
#include "core/hle/service/cfg/cfg.h" #include "core/hle/service/cfg/cfg.h"
#include "core/hle/service/fs/archive.h" #include "core/hle/service/fs/archive.h"
#include "core/hle/service/fs/fs_user.h"
#include "core/hle/service/ptm/ptm.h" #include "core/hle/service/ptm/ptm.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
#include "core/hw/aes/ccm.h" #include "core/hw/aes/ccm.h"
@ -41,7 +44,6 @@ void Module::serialize(Archive& ar, const unsigned int file_version) {
ar& shared_font_loaded; ar& shared_font_loaded;
ar& shared_font_relocated; ar& shared_font_relocated;
ar& cpu_percent; ar& cpu_percent;
ar& unknown_ns_state_field;
ar& screen_capture_post_permission; ar& screen_capture_post_permission;
ar& applet_manager; ar& applet_manager;
if (file_version > 0) { if (file_version > 0) {
@ -90,14 +92,19 @@ void Module::NSInterface::RebootSystem(Kernel::HLERequestContext& ctx) {
const auto title_id = rp.Pop<u64>(); const auto title_id = rp.Pop<u64>();
const auto media_type = static_cast<FS::MediaType>(rp.Pop<u8>()); const auto media_type = static_cast<FS::MediaType>(rp.Pop<u8>());
rp.Skip(1, false); // Skip padding rp.Skip(1, false); // Skip padding
// TODO: Utilize requested memory type.
const auto mem_type = rp.Pop<u8>(); const auto mem_type = rp.Pop<u8>();
LOG_WARNING(Service_APT, LOG_WARNING(Service_APT,
"called launch_title={}, title_id={:016X}, media_type={:02X}, mem_type={:02X}", "called launch_title={}, title_id={:016X}, media_type={:02X}, mem_type={:02X}",
launch_title, title_id, media_type, mem_type); launch_title, title_id, media_type, mem_type);
// TODO: Implement loading a specific title. // TODO: Handle mem type.
if (launch_title) {
NS::RebootToTitle(apt->system, media_type, title_id);
} else {
apt->system.RequestReset(); apt->system.RequestReset();
}
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
@ -371,6 +378,16 @@ void Module::APTInterface::Enable(Kernel::HLERequestContext& ctx) {
rb.Push(apt->applet_manager->Enable(attributes)); rb.Push(apt->applet_manager->Enable(attributes));
} }
void Module::APTInterface::Finalize(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
const auto applet_id = rp.PopEnum<AppletId>();
LOG_DEBUG(Service_APT, "called applet_id={:08X}", applet_id);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(apt->applet_manager->Finalize(applet_id));
}
void Module::APTInterface::GetAppletManInfo(Kernel::HLERequestContext& ctx) { void Module::APTInterface::GetAppletManInfo(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx); IPC::RequestParser rp(ctx);
auto applet_pos = rp.PopEnum<AppletPos>(); auto applet_pos = rp.PopEnum<AppletPos>();
@ -391,6 +408,16 @@ void Module::APTInterface::GetAppletManInfo(Kernel::HLERequestContext& ctx) {
} }
} }
void Module::APTInterface::CountRegisteredApplet(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
LOG_DEBUG(Service_APT, "called");
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
rb.Push(RESULT_SUCCESS);
rb.Push(apt->applet_manager->CountRegisteredApplet());
}
void Module::APTInterface::IsRegistered(Kernel::HLERequestContext& ctx) { void Module::APTInterface::IsRegistered(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx); IPC::RequestParser rp(ctx);
const auto app_id = rp.PopEnum<AppletId>(); const auto app_id = rp.PopEnum<AppletId>();
@ -402,6 +429,23 @@ void Module::APTInterface::IsRegistered(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_APT, "called app_id={:#010X}", app_id); LOG_DEBUG(Service_APT, "called app_id={:#010X}", app_id);
} }
void Module::APTInterface::GetAttribute(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
const auto app_id = rp.PopEnum<AppletId>();
LOG_DEBUG(Service_APT, "called app_id={:#010X}", app_id);
auto applet_attr = apt->applet_manager->GetAttribute(app_id);
if (applet_attr.Failed()) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(applet_attr.Code());
} else {
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
rb.Push(RESULT_SUCCESS);
rb.Push(applet_attr.Unwrap().raw);
}
}
void Module::APTInterface::InquireNotification(Kernel::HLERequestContext& ctx) { void Module::APTInterface::InquireNotification(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx); IPC::RequestParser rp(ctx);
const auto app_id = rp.PopEnum<AppletId>(); const auto app_id = rp.PopEnum<AppletId>();
@ -557,6 +601,21 @@ void Module::APTInterface::GetProgramIdOnApplicationJump(Kernel::HLERequestConte
rb.Push(static_cast<u8>(parameters.next_media_type)); rb.Push(static_cast<u8>(parameters.next_media_type));
} }
void Module::APTInterface::SendDeliverArg(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
const auto param_size = rp.Pop<u32>();
const auto hmac_size = rp.Pop<u32>();
const auto param = rp.PopStaticBuffer();
const auto hmac = rp.PopStaticBuffer();
LOG_DEBUG(Service_APT, "called param_size={:08X}, hmac_size={:08X}", param_size, hmac_size);
apt->applet_manager->SetDeliverArg(DeliverArg{param, hmac});
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(RESULT_SUCCESS);
}
void Module::APTInterface::ReceiveDeliverArg(Kernel::HLERequestContext& ctx) { void Module::APTInterface::ReceiveDeliverArg(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx); IPC::RequestParser rp(ctx);
const auto param_size = rp.Pop<u32>(); const auto param_size = rp.Pop<u32>();
@ -611,7 +670,7 @@ void Module::APTInterface::WakeupApplication(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_APT, "called"); LOG_DEBUG(Service_APT, "called");
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(apt->applet_manager->WakeupApplication()); rb.Push(apt->applet_manager->WakeupApplication(nullptr, {}));
} }
void Module::APTInterface::CancelApplication(Kernel::HLERequestContext& ctx) { void Module::APTInterface::CancelApplication(Kernel::HLERequestContext& ctx) {
@ -856,6 +915,28 @@ void Module::APTInterface::OrderToCloseSystemApplet(Kernel::HLERequestContext& c
rb.Push(apt->applet_manager->OrderToCloseSystemApplet()); rb.Push(apt->applet_manager->OrderToCloseSystemApplet());
} }
void Module::APTInterface::SendDspSleep(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
const auto from_app_id = rp.PopEnum<AppletId>();
const auto object = rp.PopGenericObject();
LOG_DEBUG(Service_APT, "called, from_app_id={:08X}", from_app_id);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(apt->applet_manager->SendDspSleep(from_app_id, object));
}
void Module::APTInterface::SendDspWakeUp(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
const auto from_app_id = rp.PopEnum<AppletId>();
const auto object = rp.PopGenericObject();
LOG_DEBUG(Service_APT, "called, from_app_id={:08X}", from_app_id);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(apt->applet_manager->SendDspWakeUp(from_app_id, object));
}
void Module::APTInterface::PrepareToJumpToHomeMenu(Kernel::HLERequestContext& ctx) { void Module::APTInterface::PrepareToJumpToHomeMenu(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx); IPC::RequestParser rp(ctx);
@ -972,29 +1053,124 @@ void Module::APTInterface::GetCaptureInfo(Kernel::HLERequestContext& ctx) {
rb.PushStaticBuffer(std::move(screen_capture_buffer), 0); rb.PushStaticBuffer(std::move(screen_capture_buffer), 0);
} }
void Module::APTInterface::SetScreenCapPostPermission(Kernel::HLERequestContext& ctx) { void Module::APTInterface::Unknown54(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx); IPC::RequestParser rp(ctx);
auto in_param = rp.Pop<u32>();
LOG_DEBUG(Service_APT, "called, screen_capture_post_permission={}", LOG_DEBUG(Service_APT, "called, in_param={}", in_param);
apt->screen_capture_post_permission);
apt->screen_capture_post_permission = static_cast<ScreencapPostPermission>(rp.Pop<u32>() & 0xF); auto media_type = apt->applet_manager->Unknown54(in_param);
if (media_type.Failed()) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(media_type.Code());
} else {
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
rb.Push(RESULT_SUCCESS);
rb.PushEnum(media_type.Unwrap());
}
}
void Module::APTInterface::SetScreenCapturePostPermission(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
auto permission = rp.Pop<u32>();
LOG_DEBUG(Service_APT, "called, permission={}", permission);
apt->screen_capture_post_permission = static_cast<ScreencapPostPermission>(permission & 0xF);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(RESULT_SUCCESS); // No error rb.Push(RESULT_SUCCESS); // No error
} }
void Module::APTInterface::GetScreenCapPostPermission(Kernel::HLERequestContext& ctx) { void Module::APTInterface::GetScreenCapturePostPermission(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx); IPC::RequestParser rp(ctx);
LOG_DEBUG(Service_APT, "(STUBBED) called, screen_capture_post_permission={}", LOG_DEBUG(Service_APT, "called");
apt->screen_capture_post_permission);
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
rb.Push(RESULT_SUCCESS); // No error rb.Push(RESULT_SUCCESS); // No error
rb.Push(static_cast<u32>(apt->screen_capture_post_permission)); rb.Push(static_cast<u32>(apt->screen_capture_post_permission));
} }
void Module::APTInterface::WakeupApplication2(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
const auto buffer_size = rp.Pop<u32>();
const auto object = rp.PopGenericObject();
const auto buffer = rp.PopStaticBuffer();
LOG_DEBUG(Service_APT, "called buffer_size={:#010X}", buffer_size);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(apt->applet_manager->WakeupApplication(object, buffer));
}
void Module::APTInterface::GetProgramId(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
const auto process_id = rp.PopPID();
LOG_DEBUG(Service_APT, "called process_id={}", process_id);
IPC::RequestBuilder rb = rp.MakeBuilder(3, 0);
rb.Push(RESULT_SUCCESS);
auto fs_user =
Core::System::GetInstance().ServiceManager().GetService<Service::FS::FS_USER>("fs:USER");
ASSERT_MSG(fs_user != nullptr, "fs:USER service is missing.");
auto program_info_result = fs_user->GetProgramLaunchInfo(process_id);
if (program_info_result.Failed()) {
// On failure, APT still returns a success result with a program ID of 0.
rb.Push<u64>(0);
} else {
rb.Push(program_info_result.Unwrap().program_id);
}
}
void Module::APTInterface::GetProgramInfo(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
const auto title_id = rp.Pop<u64>();
const auto media_type = static_cast<FS::MediaType>(rp.Pop<u8>());
rp.Skip(1, false); // Skip padding
LOG_WARNING(Service_APT, "called title_id={:016X}, media_type={:02X}", title_id, media_type);
std::string path = Service::AM::GetTitleContentPath(media_type, title_id);
auto loader = Loader::GetLoader(path);
if (!loader) {
LOG_WARNING(Service_APT, "Could not find .app for title 0x{:016x}", title_id);
// TODO: Proper error code
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(RESULT_UNKNOWN);
return;
}
auto memory_mode = loader->LoadKernelMemoryMode();
if (memory_mode.second != Loader::ResultStatus::Success || !memory_mode.first) {
LOG_ERROR(Service_APT, "Could not load memory mode for title 0x{:016x}", title_id);
// TODO: Proper error code
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(RESULT_UNKNOWN);
return;
}
auto core_version = loader->LoadCoreVersion();
if (core_version.second != Loader::ResultStatus::Success || !core_version.first) {
LOG_ERROR(Service_APT, "Could not load core version for title 0x{:016x}", title_id);
// TODO: Proper error code
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(RESULT_UNKNOWN);
return;
}
IPC::RequestBuilder rb = rp.MakeBuilder(3, 0);
rb.Push(RESULT_SUCCESS);
rb.Push(static_cast<u8>(memory_mode.first.value()));
rb.Push(core_version.first.value());
}
void Module::APTInterface::GetAppletInfo(Kernel::HLERequestContext& ctx) { void Module::APTInterface::GetAppletInfo(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx); IPC::RequestParser rp(ctx);
const auto app_id = rp.PopEnum<AppletId>(); const auto app_id = rp.PopEnum<AppletId>();
@ -1154,37 +1330,83 @@ void Module::APTInterface::Unwrap(Kernel::HLERequestContext& ctx) {
rb.PushMappedBuffer(output); rb.PushMappedBuffer(output);
} }
void Module::APTInterface::CheckNew3DSApp(Kernel::HLERequestContext& ctx) { void Module::APTInterface::Reboot(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
const auto title_id = rp.Pop<u64>();
const auto media_type = static_cast<FS::MediaType>(rp.Pop<u8>());
rp.Skip(1, false); // Skip padding
const auto mem_type = rp.Pop<u8>();
const auto firm_tid_low = rp.Pop<u32>();
LOG_WARNING(Service_APT,
"called title_id={:016X}, media_type={:02X}, mem_type={:02X}, firm_tid_low={:08X}",
title_id, media_type, mem_type, firm_tid_low);
// TODO: Handle mem type and FIRM TID low.
NS::RebootToTitle(apt->system, media_type, title_id);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(RESULT_SUCCESS);
}
void Module::APTInterface::HardwareResetAsync(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx); IPC::RequestParser rp(ctx);
LOG_WARNING(Service_APT, "(STUBBED) called"); LOG_WARNING(Service_APT, "called");
apt->system.RequestReset();
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(RESULT_SUCCESS);
}
void Module::APTInterface::GetTargetPlatform(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
LOG_DEBUG(Service_APT, "called");
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
if (apt->unknown_ns_state_field) {
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.Push<u32>(0); rb.PushEnum(apt->applet_manager->GetTargetPlatform());
} else {
PTM::CheckNew3DS(rb);
}
} }
void Module::APTInterface::CheckNew3DS(Kernel::HLERequestContext& ctx) { void Module::APTInterface::CheckNew3DS(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx); IPC::RequestParser rp(ctx);
LOG_DEBUG(Service_APT, "called");
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
LOG_WARNING(Service_APT, "(STUBBED) called");
PTM::CheckNew3DS(rb); PTM::CheckNew3DS(rb);
} }
void Module::APTInterface::Unknown0x0103(Kernel::HLERequestContext& ctx) { void Module::APTInterface::GetApplicationRunningMode(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx); IPC::RequestParser rp(ctx);
LOG_DEBUG(Service_APT, "called");
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
LOG_WARNING(Service_APT, "(STUBBED) called");
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.Push<u8>(Settings::values.is_new_3ds ? 2 : 1); rb.PushEnum(apt->applet_manager->GetApplicationRunningMode());
}
void Module::APTInterface::IsStandardMemoryLayout(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx);
LOG_DEBUG(Service_APT, "called");
bool is_standard;
if (Settings::values.is_new_3ds) {
// Memory layout is standard if it is not NewDev1 (178MB)
is_standard = apt->system.Kernel().GetNew3dsHwCapabilities().memory_mode !=
Kernel::New3dsMemoryMode::NewDev1;
} else {
// Memory layout is standard if it is Prod (64MB)
is_standard = apt->system.Kernel().GetMemoryMode() == Kernel::MemoryMode::Prod;
}
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
rb.Push(RESULT_SUCCESS);
rb.Push(is_standard);
} }
void Module::APTInterface::IsTitleAllowed(Kernel::HLERequestContext& ctx) { void Module::APTInterface::IsTitleAllowed(Kernel::HLERequestContext& ctx) {

View File

@ -214,6 +214,15 @@ public:
*/ */
void Enable(Kernel::HLERequestContext& ctx); void Enable(Kernel::HLERequestContext& ctx);
/**
* APT::Finalize service function
* Inputs:
* 1 : Applet ID
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
void Finalize(Kernel::HLERequestContext& ctx);
/** /**
* APT::GetAppletManInfo service function. * APT::GetAppletManInfo service function.
* Inputs: * Inputs:
@ -241,6 +250,15 @@ public:
*/ */
void GetAppletInfo(Kernel::HLERequestContext& ctx); void GetAppletInfo(Kernel::HLERequestContext& ctx);
/**
* APT::CountRegisteredApplet service function
* Outputs:
* 0 : Return header
* 1 : Result of function, 0 on success, otherwise error code
* 2 : Number of registered applets
*/
void CountRegisteredApplet(Kernel::HLERequestContext& ctx);
/** /**
* APT::IsRegistered service function. This returns whether the specified AppID is * 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 * registered with NS yet. An AppID is "registered" once the process associated with the
@ -257,6 +275,17 @@ public:
*/ */
void IsRegistered(Kernel::HLERequestContext& ctx); void IsRegistered(Kernel::HLERequestContext& ctx);
/**
* APT::GetAttribute service function
* Inputs:
* 1 : AppID
* Outputs:
* 0 : Return header
* 1 : Result of function, 0 on success, otherwise error code
* 2 : Applet Attributes
*/
void GetAttribute(Kernel::HLERequestContext& ctx);
void InquireNotification(Kernel::HLERequestContext& ctx); void InquireNotification(Kernel::HLERequestContext& ctx);
/** /**
@ -596,6 +625,21 @@ public:
*/ */
void GetProgramIdOnApplicationJump(Kernel::HLERequestContext& ctx); void GetProgramIdOnApplicationJump(Kernel::HLERequestContext& ctx);
/**
* APT::SendDeliverArg service function
* Inputs:
* 0 : Command header [0x00340084]
* 1 : Parameter Size (capped to 0x300)
* 2 : HMAC Size (capped to 0x20)
* 3 : (Parameter Size << 14) | 2
* 4 : Input buffer for Parameter
* 5 : (HMAC Size << 14) | 0x802
* 6 : Input buffer for HMAC
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
void SendDeliverArg(Kernel::HLERequestContext& ctx);
/** /**
* APT::ReceiveDeliverArg service function * APT::ReceiveDeliverArg service function
* Inputs: * Inputs:
@ -687,6 +731,30 @@ public:
*/ */
void OrderToCloseSystemApplet(Kernel::HLERequestContext& ctx); void OrderToCloseSystemApplet(Kernel::HLERequestContext& ctx);
/**
* APT::SendDspSleep service function
* Inputs:
* 1 : Source App ID
* 2 : Handle translation header (0x0)
* 3 : Handle parameter
* Outputs:
* 0 : Header code
* 1 : Result code
*/
void SendDspSleep(Kernel::HLERequestContext& ctx);
/**
* APT::SendDspWakeUp service function
* Inputs:
* 1 : Source App ID
* 2 : Handle translation header (0x0)
* 3 : Handle parameter
* Outputs:
* 0 : Header code
* 1 : Result code
*/
void SendDspWakeUp(Kernel::HLERequestContext& ctx);
/** /**
* APT::PrepareToJumpToHomeMenu service function * APT::PrepareToJumpToHomeMenu service function
* Inputs: * Inputs:
@ -818,27 +886,97 @@ public:
void GetStartupArgument(Kernel::HLERequestContext& ctx); void GetStartupArgument(Kernel::HLERequestContext& ctx);
/** /**
* APT::SetScreenCapPostPermission service function * APT::Unknown54 service function
* Inputs:
* 0 : Header Code[0x00540040]
* 1 : Unknown
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
* 2 : Media Type
*/
void Unknown54(Kernel::HLERequestContext& ctx);
/**
* APT::SetScreenCapturePostPermission service function
* Inputs: * Inputs:
* 0 : Header Code[0x00550040] * 0 : Header Code[0x00550040]
* 1 : u8 The screenshot posting permission * 1 : u8 The screenshot posting permission
* Outputs: * Outputs:
* 1 : Result of function, 0 on success, otherwise error code * 1 : Result of function, 0 on success, otherwise error code
*/ */
void SetScreenCapPostPermission(Kernel::HLERequestContext& ctx); void SetScreenCapturePostPermission(Kernel::HLERequestContext& ctx);
/** /**
* APT::GetScreenCapPostPermission service function * APT::GetScreenCapturePostPermission service function
* Inputs: * Inputs:
* 0 : Header Code[0x00560000] * 0 : Header Code[0x00560000]
* Outputs: * Outputs:
* 1 : Result of function, 0 on success, otherwise error code * 1 : Result of function, 0 on success, otherwise error code
* 2 : u8 The screenshot posting permission * 2 : u8 The screenshot posting permission
*/ */
void GetScreenCapPostPermission(Kernel::HLERequestContext& ctx); void GetScreenCapturePostPermission(Kernel::HLERequestContext& ctx);
/** /**
* APT::CheckNew3DSApp service function * APT::WakeupApplication2 service function.
* Inputs:
* 1 : Buffer parameter size, (max is 0x1000)
* 2 : Handle translation header (0x0)
* 3 : Handle parameter
* 4 : (Buffer parameter size << 14) | 2
* 5 : Buffer parameter pointer
* Outputs:
* 0 : Return Header
* 1 : Result of function, 0 on success, otherwise error code
*/
void WakeupApplication2(Kernel::HLERequestContext& ctx);
/**
* APT::GetProgramId service function.
* Inputs:
* 1 : Process ID translation header (0x20)
* 2 : Process ID (filled in by kernel)
* Outputs:
* 0 : Return Header
* 1 : Result of function, 0 on success, otherwise error code
* 2-3 : u64 Program ID
*/
void GetProgramId(Kernel::HLERequestContext& ctx);
/**
* APT::GetProgramInfo service function.
* Inputs:
* 1-2 : Title ID
* 3 : Media Type
* 4 : Padding
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
* 2 : Required app memory mode
* 3 : Required app FIRM title ID low
*/
void GetProgramInfo(Kernel::HLERequestContext& ctx);
/**
* APT::Reboot service function.
* Inputs:
* 1-2 : Title ID
* 3 : Media Type
* 4 : Padding
* 5 : Launch memory type
* 6 : FIRM title ID low 32-bits
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
void Reboot(Kernel::HLERequestContext& ctx);
/**
* APT::HardwareResetAsync service function.
* Outputs:
* 1 : Result of function, 0 on success, otherwise error code
*/
void HardwareResetAsync(Kernel::HLERequestContext& ctx);
/**
* APT::GetTargetPlatform service function
* Outputs: * Outputs:
* 1: Result code, 0 on success, otherwise error code * 1: Result code, 0 on success, otherwise error code
* 2: u8 output: 0 = Old3DS, 1 = New3DS. * 2: u8 output: 0 = Old3DS, 1 = New3DS.
@ -849,7 +987,7 @@ public:
* Normally this NS state field is zero, however this state field is set to 1 * Normally this NS state field is zero, however this state field is set to 1
* when APT:PrepareToStartApplication is used with flags bit8 is set. * when APT:PrepareToStartApplication is used with flags bit8 is set.
*/ */
void CheckNew3DSApp(Kernel::HLERequestContext& ctx); void GetTargetPlatform(Kernel::HLERequestContext& ctx);
/** /**
* Wrapper for PTMSYSM:CheckNew3DS * Wrapper for PTMSYSM:CheckNew3DS
@ -861,12 +999,20 @@ public:
void CheckNew3DS(Kernel::HLERequestContext& ctx); void CheckNew3DS(Kernel::HLERequestContext& ctx);
/** /**
* APT::Unknown0x0103 service function. Determines whether Smash 4 allows C-Stick * APT::GetApplicationRunningMode service function
* Outputs: * Outputs:
* 1: Result code, 0 on success otherwise error code * 1: Result code, 0 on success otherwise error code
* 2: u8 output: 2 = New3DS+valid/initialized (in Smash 4), 1 = Old3DS or invalid * 2: u8 output: 0 = No application, 1/3 = Old 3DS, 2/4 = New 3DS
*/ */
void Unknown0x0103(Kernel::HLERequestContext& ctx); void GetApplicationRunningMode(Kernel::HLERequestContext& ctx);
/**
* APT::IsStandardMemoryLayout service function
* Outputs:
* 1: Result code, 0 on success otherwise error code
* 2: bool output: Whether the system is in its standard memory layout.
*/
void IsStandardMemoryLayout(Kernel::HLERequestContext& ctx);
/** /**
* APT::IsTitleAllowed service function * APT::IsTitleAllowed service function
@ -906,9 +1052,6 @@ private:
u32 cpu_percent = 0; ///< CPU time available to the running application u32 cpu_percent = 0; ///< CPU time available to the running application
// APT::CheckNew3DSApp will check this unknown_ns_state_field to determine processing mode
u8 unknown_ns_state_field = 0;
std::array<u8, SysMenuArgSize> sys_menu_arg_buffer; std::array<u8, SysMenuArgSize> sys_menu_arg_buffer;
ScreencapPostPermission screen_capture_post_permission = ScreencapPostPermission screen_capture_post_permission =

View File

@ -14,13 +14,13 @@ APT_A::APT_A(std::shared_ptr<Module> apt)
{0x0001, &APT_A::GetLockHandle, "GetLockHandle"}, {0x0001, &APT_A::GetLockHandle, "GetLockHandle"},
{0x0002, &APT_A::Initialize, "Initialize"}, {0x0002, &APT_A::Initialize, "Initialize"},
{0x0003, &APT_A::Enable, "Enable"}, {0x0003, &APT_A::Enable, "Enable"},
{0x0004, nullptr, "Finalize"}, {0x0004, &APT_A::Finalize, "Finalize"},
{0x0005, &APT_A::GetAppletManInfo, "GetAppletManInfo"}, {0x0005, &APT_A::GetAppletManInfo, "GetAppletManInfo"},
{0x0006, &APT_A::GetAppletInfo, "GetAppletInfo"}, {0x0006, &APT_A::GetAppletInfo, "GetAppletInfo"},
{0x0007, nullptr, "GetLastSignaledAppletId"}, {0x0007, nullptr, "GetLastSignaledAppletId"},
{0x0008, nullptr, "CountRegisteredApplet"}, {0x0008, &APT_A::CountRegisteredApplet, "CountRegisteredApplet"},
{0x0009, &APT_A::IsRegistered, "IsRegistered"}, {0x0009, &APT_A::IsRegistered, "IsRegistered"},
{0x000A, nullptr, "GetAttribute"}, {0x000A, &APT_A::GetAttribute, "GetAttribute"},
{0x000B, &APT_A::InquireNotification, "InquireNotification"}, {0x000B, &APT_A::InquireNotification, "InquireNotification"},
{0x000C, &APT_A::SendParameter, "SendParameter"}, {0x000C, &APT_A::SendParameter, "SendParameter"},
{0x000D, &APT_A::ReceiveParameter, "ReceiveParameter"}, {0x000D, &APT_A::ReceiveParameter, "ReceiveParameter"},
@ -39,7 +39,7 @@ APT_A::APT_A(std::shared_ptr<Module> apt)
{0x001A, &APT_A::PrepareToStartNewestHomeMenu, "PrepareToStartNewestHomeMenu"}, {0x001A, &APT_A::PrepareToStartNewestHomeMenu, "PrepareToStartNewestHomeMenu"},
{0x001B, &APT_A::StartApplication, "StartApplication"}, {0x001B, &APT_A::StartApplication, "StartApplication"},
{0x001C, &APT_A::WakeupApplication, "WakeupApplication"}, {0x001C, &APT_A::WakeupApplication, "WakeupApplication"},
{0x001D, nullptr, "CancelApplication"}, {0x001D, &APT_A::CancelApplication, "CancelApplication"},
{0x001E, &APT_A::StartLibraryApplet, "StartLibraryApplet"}, {0x001E, &APT_A::StartLibraryApplet, "StartLibraryApplet"},
{0x001F, &APT_A::StartSystemApplet, "StartSystemApplet"}, {0x001F, &APT_A::StartSystemApplet, "StartSystemApplet"},
{0x0020, nullptr, "StartNewestHomeMenu"}, {0x0020, nullptr, "StartNewestHomeMenu"},
@ -62,7 +62,7 @@ APT_A::APT_A(std::shared_ptr<Module> apt)
{0x0031, &APT_A::PrepareToDoApplicationJump, "PrepareToDoApplicationJump"}, {0x0031, &APT_A::PrepareToDoApplicationJump, "PrepareToDoApplicationJump"},
{0x0032, &APT_A::DoApplicationJump, "DoApplicationJump"}, {0x0032, &APT_A::DoApplicationJump, "DoApplicationJump"},
{0x0033, &APT_A::GetProgramIdOnApplicationJump, "GetProgramIdOnApplicationJump"}, {0x0033, &APT_A::GetProgramIdOnApplicationJump, "GetProgramIdOnApplicationJump"},
{0x0034, nullptr, "SendDeliverArg"}, {0x0034, &APT_A::SendDeliverArg, "SendDeliverArg"},
{0x0035, &APT_A::ReceiveDeliverArg, "ReceiveDeliverArg"}, {0x0035, &APT_A::ReceiveDeliverArg, "ReceiveDeliverArg"},
{0x0036, &APT_A::LoadSysMenuArg, "LoadSysMenuArg"}, {0x0036, &APT_A::LoadSysMenuArg, "LoadSysMenuArg"},
{0x0037, &APT_A::StoreSysMenuArg, "StoreSysMenuArg"}, {0x0037, &APT_A::StoreSysMenuArg, "StoreSysMenuArg"},
@ -70,8 +70,8 @@ APT_A::APT_A(std::shared_ptr<Module> apt)
{0x0039, nullptr, "PrepareToStartResidentApplet"}, {0x0039, nullptr, "PrepareToStartResidentApplet"},
{0x003A, nullptr, "StartResidentApplet"}, {0x003A, nullptr, "StartResidentApplet"},
{0x003B, &APT_A::CancelLibraryApplet, "CancelLibraryApplet"}, {0x003B, &APT_A::CancelLibraryApplet, "CancelLibraryApplet"},
{0x003C, nullptr, "SendDspSleep"}, {0x003C, &APT_A::SendDspSleep, "SendDspSleep"},
{0x003D, nullptr, "SendDspWakeUp"}, {0x003D, &APT_A::SendDspWakeUp, "SendDspWakeUp"},
{0x003E, nullptr, "ReplySleepQuery"}, {0x003E, nullptr, "ReplySleepQuery"},
{0x003F, nullptr, "ReplySleepNotificationComplete"}, {0x003F, nullptr, "ReplySleepNotificationComplete"},
{0x0040, &APT_A::SendCaptureBufferInfo, "SendCaptureBufferInfo"}, {0x0040, &APT_A::SendCaptureBufferInfo, "SendCaptureBufferInfo"},
@ -82,26 +82,27 @@ APT_A::APT_A(std::shared_ptr<Module> apt)
{0x0045, &APT_A::GetWirelessRebootInfo, "GetWirelessRebootInfo"}, {0x0045, &APT_A::GetWirelessRebootInfo, "GetWirelessRebootInfo"},
{0x0046, &APT_A::Wrap, "Wrap"}, {0x0046, &APT_A::Wrap, "Wrap"},
{0x0047, &APT_A::Unwrap, "Unwrap"}, {0x0047, &APT_A::Unwrap, "Unwrap"},
{0x0048, nullptr, "GetProgramInfo"}, {0x0048, &APT_A::GetProgramInfo, "GetProgramInfo"},
{0x0049, nullptr, "Reboot"}, {0x0049, &APT_A::Reboot, "Reboot"},
{0x004A, &APT_A::GetCaptureInfo, "GetCaptureInfo"}, {0x004A, &APT_A::GetCaptureInfo, "GetCaptureInfo"},
{0x004B, &APT_A::AppletUtility, "AppletUtility"}, {0x004B, &APT_A::AppletUtility, "AppletUtility"},
{0x004C, nullptr, "SetFatalErrDispMode"}, {0x004C, nullptr, "SetFatalErrDispMode"},
{0x004D, nullptr, "GetAppletProgramInfo"}, {0x004D, nullptr, "GetAppletProgramInfo"},
{0x004E, nullptr, "HardwareResetAsync"}, {0x004E, &APT_A::HardwareResetAsync, "HardwareResetAsync"},
{0x004F, &APT_A::SetAppCpuTimeLimit, "SetAppCpuTimeLimit"}, {0x004F, &APT_A::SetAppCpuTimeLimit, "SetAppCpuTimeLimit"},
{0x0050, &APT_A::GetAppCpuTimeLimit, "GetAppCpuTimeLimit"}, {0x0050, &APT_A::GetAppCpuTimeLimit, "GetAppCpuTimeLimit"},
{0x0051, &APT_A::GetStartupArgument, "GetStartupArgument"}, {0x0051, &APT_A::GetStartupArgument, "GetStartupArgument"},
{0x0052, nullptr, "Wrap1"}, {0x0052, nullptr, "Wrap1"},
{0x0053, nullptr, "Unwrap1"}, {0x0053, nullptr, "Unwrap1"},
{0x0055, &APT_A::SetScreenCapPostPermission, "SetScreenCapPostPermission"}, {0x0054, &APT_A::Unknown54, "Unknown54"},
{0x0056, &APT_A::GetScreenCapPostPermission, "GetScreenCapPostPermission"}, {0x0055, &APT_A::SetScreenCapturePostPermission, "SetScreenCapturePostPermission"},
{0x0057, nullptr, "WakeupApplication2"}, {0x0056, &APT_A::GetScreenCapturePostPermission, "GetScreenCapturePostPermission"},
{0x0058, nullptr, "GetProgramID"}, {0x0057, &APT_A::WakeupApplication2, "WakeupApplication2"},
{0x0101, &APT_A::CheckNew3DSApp, "CheckNew3DSApp"}, {0x0058, &APT_A::GetProgramId, "GetProgramId"},
{0x0101, &APT_A::GetTargetPlatform, "GetTargetPlatform"},
{0x0102, &APT_A::CheckNew3DS, "CheckNew3DS"}, {0x0102, &APT_A::CheckNew3DS, "CheckNew3DS"},
{0x0103, &APT_A::Unknown0x0103, "Unknown0x0103"}, {0x0103, &APT_A::GetApplicationRunningMode, "GetApplicationRunningMode"},
{0x0104, nullptr, "IsStandardMemoryLayout"}, {0x0104, &APT_A::IsStandardMemoryLayout, "IsStandardMemoryLayout"},
{0x0105, &APT_A::IsTitleAllowed, "IsTitleAllowed"}, {0x0105, &APT_A::IsTitleAllowed, "IsTitleAllowed"},
// clang-format on // clang-format on
}; };

View File

@ -14,13 +14,13 @@ APT_S::APT_S(std::shared_ptr<Module> apt)
{0x0001, &APT_S::GetLockHandle, "GetLockHandle"}, {0x0001, &APT_S::GetLockHandle, "GetLockHandle"},
{0x0002, &APT_S::Initialize, "Initialize"}, {0x0002, &APT_S::Initialize, "Initialize"},
{0x0003, &APT_S::Enable, "Enable"}, {0x0003, &APT_S::Enable, "Enable"},
{0x0004, nullptr, "Finalize"}, {0x0004, &APT_S::Finalize, "Finalize"},
{0x0005, &APT_S::GetAppletManInfo, "GetAppletManInfo"}, {0x0005, &APT_S::GetAppletManInfo, "GetAppletManInfo"},
{0x0006, &APT_S::GetAppletInfo, "GetAppletInfo"}, {0x0006, &APT_S::GetAppletInfo, "GetAppletInfo"},
{0x0007, nullptr, "GetLastSignaledAppletId"}, {0x0007, nullptr, "GetLastSignaledAppletId"},
{0x0008, nullptr, "CountRegisteredApplet"}, {0x0008, &APT_S::CountRegisteredApplet, "CountRegisteredApplet"},
{0x0009, &APT_S::IsRegistered, "IsRegistered"}, {0x0009, &APT_S::IsRegistered, "IsRegistered"},
{0x000A, nullptr, "GetAttribute"}, {0x000A, &APT_S::GetAttribute, "GetAttribute"},
{0x000B, &APT_S::InquireNotification, "InquireNotification"}, {0x000B, &APT_S::InquireNotification, "InquireNotification"},
{0x000C, &APT_S::SendParameter, "SendParameter"}, {0x000C, &APT_S::SendParameter, "SendParameter"},
{0x000D, &APT_S::ReceiveParameter, "ReceiveParameter"}, {0x000D, &APT_S::ReceiveParameter, "ReceiveParameter"},
@ -39,7 +39,7 @@ APT_S::APT_S(std::shared_ptr<Module> apt)
{0x001A, &APT_S::PrepareToStartNewestHomeMenu, "PrepareToStartNewestHomeMenu"}, {0x001A, &APT_S::PrepareToStartNewestHomeMenu, "PrepareToStartNewestHomeMenu"},
{0x001B, &APT_S::StartApplication, "StartApplication"}, {0x001B, &APT_S::StartApplication, "StartApplication"},
{0x001C, &APT_S::WakeupApplication, "WakeupApplication"}, {0x001C, &APT_S::WakeupApplication, "WakeupApplication"},
{0x001D, nullptr, "CancelApplication"}, {0x001D, &APT_S::CancelApplication, "CancelApplication"},
{0x001E, &APT_S::StartLibraryApplet, "StartLibraryApplet"}, {0x001E, &APT_S::StartLibraryApplet, "StartLibraryApplet"},
{0x001F, &APT_S::StartSystemApplet, "StartSystemApplet"}, {0x001F, &APT_S::StartSystemApplet, "StartSystemApplet"},
{0x0020, nullptr, "StartNewestHomeMenu"}, {0x0020, nullptr, "StartNewestHomeMenu"},
@ -62,7 +62,7 @@ APT_S::APT_S(std::shared_ptr<Module> apt)
{0x0031, &APT_S::PrepareToDoApplicationJump, "PrepareToDoApplicationJump"}, {0x0031, &APT_S::PrepareToDoApplicationJump, "PrepareToDoApplicationJump"},
{0x0032, &APT_S::DoApplicationJump, "DoApplicationJump"}, {0x0032, &APT_S::DoApplicationJump, "DoApplicationJump"},
{0x0033, &APT_S::GetProgramIdOnApplicationJump, "GetProgramIdOnApplicationJump"}, {0x0033, &APT_S::GetProgramIdOnApplicationJump, "GetProgramIdOnApplicationJump"},
{0x0034, nullptr, "SendDeliverArg"}, {0x0034, &APT_S::SendDeliverArg, "SendDeliverArg"},
{0x0035, &APT_S::ReceiveDeliverArg, "ReceiveDeliverArg"}, {0x0035, &APT_S::ReceiveDeliverArg, "ReceiveDeliverArg"},
{0x0036, &APT_S::LoadSysMenuArg, "LoadSysMenuArg"}, {0x0036, &APT_S::LoadSysMenuArg, "LoadSysMenuArg"},
{0x0037, &APT_S::StoreSysMenuArg, "StoreSysMenuArg"}, {0x0037, &APT_S::StoreSysMenuArg, "StoreSysMenuArg"},
@ -70,8 +70,8 @@ APT_S::APT_S(std::shared_ptr<Module> apt)
{0x0039, nullptr, "PrepareToStartResidentApplet"}, {0x0039, nullptr, "PrepareToStartResidentApplet"},
{0x003A, nullptr, "StartResidentApplet"}, {0x003A, nullptr, "StartResidentApplet"},
{0x003B, &APT_S::CancelLibraryApplet, "CancelLibraryApplet"}, {0x003B, &APT_S::CancelLibraryApplet, "CancelLibraryApplet"},
{0x003C, nullptr, "SendDspSleep"}, {0x003C, &APT_S::SendDspSleep, "SendDspSleep"},
{0x003D, nullptr, "SendDspWakeUp"}, {0x003D, &APT_S::SendDspWakeUp, "SendDspWakeUp"},
{0x003E, nullptr, "ReplySleepQuery"}, {0x003E, nullptr, "ReplySleepQuery"},
{0x003F, nullptr, "ReplySleepNotificationComplete"}, {0x003F, nullptr, "ReplySleepNotificationComplete"},
{0x0040, &APT_S::SendCaptureBufferInfo, "SendCaptureBufferInfo"}, {0x0040, &APT_S::SendCaptureBufferInfo, "SendCaptureBufferInfo"},
@ -82,26 +82,27 @@ APT_S::APT_S(std::shared_ptr<Module> apt)
{0x0045, &APT_S::GetWirelessRebootInfo, "GetWirelessRebootInfo"}, {0x0045, &APT_S::GetWirelessRebootInfo, "GetWirelessRebootInfo"},
{0x0046, &APT_S::Wrap, "Wrap"}, {0x0046, &APT_S::Wrap, "Wrap"},
{0x0047, &APT_S::Unwrap, "Unwrap"}, {0x0047, &APT_S::Unwrap, "Unwrap"},
{0x0048, nullptr, "GetProgramInfo"}, {0x0048, &APT_S::GetProgramInfo, "GetProgramInfo"},
{0x0049, nullptr, "Reboot"}, {0x0049, &APT_S::Reboot, "Reboot"},
{0x004A, &APT_S::GetCaptureInfo, "GetCaptureInfo"}, {0x004A, &APT_S::GetCaptureInfo, "GetCaptureInfo"},
{0x004B, &APT_S::AppletUtility, "AppletUtility"}, {0x004B, &APT_S::AppletUtility, "AppletUtility"},
{0x004C, nullptr, "SetFatalErrDispMode"}, {0x004C, nullptr, "SetFatalErrDispMode"},
{0x004D, nullptr, "GetAppletProgramInfo"}, {0x004D, nullptr, "GetAppletProgramInfo"},
{0x004E, nullptr, "HardwareResetAsync"}, {0x004E, &APT_S::HardwareResetAsync, "HardwareResetAsync"},
{0x004F, &APT_S::SetAppCpuTimeLimit, "SetAppCpuTimeLimit"}, {0x004F, &APT_S::SetAppCpuTimeLimit, "SetAppCpuTimeLimit"},
{0x0050, &APT_S::GetAppCpuTimeLimit, "GetAppCpuTimeLimit"}, {0x0050, &APT_S::GetAppCpuTimeLimit, "GetAppCpuTimeLimit"},
{0x0051, &APT_S::GetStartupArgument, "GetStartupArgument"}, {0x0051, &APT_S::GetStartupArgument, "GetStartupArgument"},
{0x0052, nullptr, "Wrap1"}, {0x0052, nullptr, "Wrap1"},
{0x0053, nullptr, "Unwrap1"}, {0x0053, nullptr, "Unwrap1"},
{0x0055, &APT_S::SetScreenCapPostPermission, "SetScreenCapPostPermission"}, {0x0054, &APT_S::Unknown54, "Unknown54"},
{0x0056, &APT_S::GetScreenCapPostPermission, "GetScreenCapPostPermission"}, {0x0055, &APT_S::SetScreenCapturePostPermission, "SetScreenCapturePostPermission"},
{0x0057, nullptr, "WakeupApplication2"}, {0x0056, &APT_S::GetScreenCapturePostPermission, "GetScreenCapturePostPermission"},
{0x0058, nullptr, "GetProgramID"}, {0x0057, &APT_S::WakeupApplication2, "WakeupApplication2"},
{0x0101, &APT_S::CheckNew3DSApp, "CheckNew3DSApp"}, {0x0058, &APT_S::GetProgramId, "GetProgramId"},
{0x0101, &APT_S::GetTargetPlatform, "GetTargetPlatform"},
{0x0102, &APT_S::CheckNew3DS, "CheckNew3DS"}, {0x0102, &APT_S::CheckNew3DS, "CheckNew3DS"},
{0x0103, &APT_S::Unknown0x0103, "Unknown0x0103"}, {0x0103, &APT_S::GetApplicationRunningMode, "GetApplicationRunningMode"},
{0x0104, nullptr, "IsStandardMemoryLayout"}, {0x0104, &APT_S::IsStandardMemoryLayout, "IsStandardMemoryLayout"},
{0x0105, &APT_S::IsTitleAllowed, "IsTitleAllowed"}, {0x0105, &APT_S::IsTitleAllowed, "IsTitleAllowed"},
// clang-format on // clang-format on
}; };

View File

@ -14,13 +14,13 @@ APT_U::APT_U(std::shared_ptr<Module> apt)
{0x0001, &APT_U::GetLockHandle, "GetLockHandle"}, {0x0001, &APT_U::GetLockHandle, "GetLockHandle"},
{0x0002, &APT_U::Initialize, "Initialize"}, {0x0002, &APT_U::Initialize, "Initialize"},
{0x0003, &APT_U::Enable, "Enable"}, {0x0003, &APT_U::Enable, "Enable"},
{0x0004, nullptr, "Finalize"}, {0x0004, &APT_U::Finalize, "Finalize"},
{0x0005, &APT_U::GetAppletManInfo, "GetAppletManInfo"}, {0x0005, &APT_U::GetAppletManInfo, "GetAppletManInfo"},
{0x0006, &APT_U::GetAppletInfo, "GetAppletInfo"}, {0x0006, &APT_U::GetAppletInfo, "GetAppletInfo"},
{0x0007, nullptr, "GetLastSignaledAppletId"}, {0x0007, nullptr, "GetLastSignaledAppletId"},
{0x0008, nullptr, "CountRegisteredApplet"}, {0x0008, &APT_U::CountRegisteredApplet, "CountRegisteredApplet"},
{0x0009, &APT_U::IsRegistered, "IsRegistered"}, {0x0009, &APT_U::IsRegistered, "IsRegistered"},
{0x000A, nullptr, "GetAttribute"}, {0x000A, &APT_U::GetAttribute, "GetAttribute"},
{0x000B, &APT_U::InquireNotification, "InquireNotification"}, {0x000B, &APT_U::InquireNotification, "InquireNotification"},
{0x000C, &APT_U::SendParameter, "SendParameter"}, {0x000C, &APT_U::SendParameter, "SendParameter"},
{0x000D, &APT_U::ReceiveParameter, "ReceiveParameter"}, {0x000D, &APT_U::ReceiveParameter, "ReceiveParameter"},
@ -39,7 +39,7 @@ APT_U::APT_U(std::shared_ptr<Module> apt)
{0x001A, &APT_U::PrepareToStartNewestHomeMenu, "PrepareToStartNewestHomeMenu"}, {0x001A, &APT_U::PrepareToStartNewestHomeMenu, "PrepareToStartNewestHomeMenu"},
{0x001B, &APT_U::StartApplication, "StartApplication"}, {0x001B, &APT_U::StartApplication, "StartApplication"},
{0x001C, &APT_U::WakeupApplication, "WakeupApplication"}, {0x001C, &APT_U::WakeupApplication, "WakeupApplication"},
{0x001D, nullptr, "CancelApplication"}, {0x001D, &APT_U::CancelApplication, "CancelApplication"},
{0x001E, &APT_U::StartLibraryApplet, "StartLibraryApplet"}, {0x001E, &APT_U::StartLibraryApplet, "StartLibraryApplet"},
{0x001F, &APT_U::StartSystemApplet, "StartSystemApplet"}, {0x001F, &APT_U::StartSystemApplet, "StartSystemApplet"},
{0x0020, nullptr, "StartNewestHomeMenu"}, {0x0020, nullptr, "StartNewestHomeMenu"},
@ -62,7 +62,7 @@ APT_U::APT_U(std::shared_ptr<Module> apt)
{0x0031, &APT_U::PrepareToDoApplicationJump, "PrepareToDoApplicationJump"}, {0x0031, &APT_U::PrepareToDoApplicationJump, "PrepareToDoApplicationJump"},
{0x0032, &APT_U::DoApplicationJump, "DoApplicationJump"}, {0x0032, &APT_U::DoApplicationJump, "DoApplicationJump"},
{0x0033, &APT_U::GetProgramIdOnApplicationJump, "GetProgramIdOnApplicationJump"}, {0x0033, &APT_U::GetProgramIdOnApplicationJump, "GetProgramIdOnApplicationJump"},
{0x0034, nullptr, "SendDeliverArg"}, {0x0034, &APT_U::SendDeliverArg, "SendDeliverArg"},
{0x0035, &APT_U::ReceiveDeliverArg, "ReceiveDeliverArg"}, {0x0035, &APT_U::ReceiveDeliverArg, "ReceiveDeliverArg"},
{0x0036, &APT_U::LoadSysMenuArg, "LoadSysMenuArg"}, {0x0036, &APT_U::LoadSysMenuArg, "LoadSysMenuArg"},
{0x0037, &APT_U::StoreSysMenuArg, "StoreSysMenuArg"}, {0x0037, &APT_U::StoreSysMenuArg, "StoreSysMenuArg"},
@ -70,8 +70,8 @@ APT_U::APT_U(std::shared_ptr<Module> apt)
{0x0039, nullptr, "PrepareToStartResidentApplet"}, {0x0039, nullptr, "PrepareToStartResidentApplet"},
{0x003A, nullptr, "StartResidentApplet"}, {0x003A, nullptr, "StartResidentApplet"},
{0x003B, &APT_U::CancelLibraryApplet, "CancelLibraryApplet"}, {0x003B, &APT_U::CancelLibraryApplet, "CancelLibraryApplet"},
{0x003C, nullptr, "SendDspSleep"}, {0x003C, &APT_U::SendDspSleep, "SendDspSleep"},
{0x003D, nullptr, "SendDspWakeUp"}, {0x003D, &APT_U::SendDspWakeUp, "SendDspWakeUp"},
{0x003E, nullptr, "ReplySleepQuery"}, {0x003E, nullptr, "ReplySleepQuery"},
{0x003F, nullptr, "ReplySleepNotificationComplete"}, {0x003F, nullptr, "ReplySleepNotificationComplete"},
{0x0040, &APT_U::SendCaptureBufferInfo, "SendCaptureBufferInfo"}, {0x0040, &APT_U::SendCaptureBufferInfo, "SendCaptureBufferInfo"},
@ -82,26 +82,27 @@ APT_U::APT_U(std::shared_ptr<Module> apt)
{0x0045, &APT_U::GetWirelessRebootInfo, "GetWirelessRebootInfo"}, {0x0045, &APT_U::GetWirelessRebootInfo, "GetWirelessRebootInfo"},
{0x0046, &APT_U::Wrap, "Wrap"}, {0x0046, &APT_U::Wrap, "Wrap"},
{0x0047, &APT_U::Unwrap, "Unwrap"}, {0x0047, &APT_U::Unwrap, "Unwrap"},
{0x0048, nullptr, "GetProgramInfo"}, {0x0048, &APT_U::GetProgramInfo, "GetProgramInfo"},
{0x0049, nullptr, "Reboot"}, {0x0049, &APT_U::Reboot, "Reboot"},
{0x004A, &APT_U::GetCaptureInfo, "GetCaptureInfo"}, {0x004A, &APT_U::GetCaptureInfo, "GetCaptureInfo"},
{0x004B, &APT_U::AppletUtility, "AppletUtility"}, {0x004B, &APT_U::AppletUtility, "AppletUtility"},
{0x004C, nullptr, "SetFatalErrDispMode"}, {0x004C, nullptr, "SetFatalErrDispMode"},
{0x004D, nullptr, "GetAppletProgramInfo"}, {0x004D, nullptr, "GetAppletProgramInfo"},
{0x004E, nullptr, "HardwareResetAsync"}, {0x004E, &APT_U::HardwareResetAsync, "HardwareResetAsync"},
{0x004F, &APT_U::SetAppCpuTimeLimit, "SetAppCpuTimeLimit"}, {0x004F, &APT_U::SetAppCpuTimeLimit, "SetAppCpuTimeLimit"},
{0x0050, &APT_U::GetAppCpuTimeLimit, "GetAppCpuTimeLimit"}, {0x0050, &APT_U::GetAppCpuTimeLimit, "GetAppCpuTimeLimit"},
{0x0051, &APT_U::GetStartupArgument, "GetStartupArgument"}, {0x0051, &APT_U::GetStartupArgument, "GetStartupArgument"},
{0x0052, nullptr, "Wrap1"}, {0x0052, nullptr, "Wrap1"},
{0x0053, nullptr, "Unwrap1"}, {0x0053, nullptr, "Unwrap1"},
{0x0055, &APT_U::SetScreenCapPostPermission, "SetScreenCapPostPermission"}, {0x0054, &APT_U::Unknown54, "Unknown54"},
{0x0056, &APT_U::GetScreenCapPostPermission, "GetScreenCapPostPermission"}, {0x0055, &APT_U::SetScreenCapturePostPermission, "SetScreenCapturePostPermission"},
{0x0057, nullptr, "WakeupApplication2"}, {0x0056, &APT_U::GetScreenCapturePostPermission, "GetScreenCapturePostPermission"},
{0x0058, nullptr, "GetProgramID"}, {0x0057, &APT_U::WakeupApplication2, "WakeupApplication2"},
{0x0101, &APT_U::CheckNew3DSApp, "CheckNew3DSApp"}, {0x0058, &APT_U::GetProgramId, "GetProgramId"},
{0x0101, &APT_U::GetTargetPlatform, "GetTargetPlatform"},
{0x0102, &APT_U::CheckNew3DS, "CheckNew3DS"}, {0x0102, &APT_U::CheckNew3DS, "CheckNew3DS"},
{0x0103, &APT_U::Unknown0x0103, "Unknown0x0103"}, {0x0103, &APT_U::GetApplicationRunningMode, "GetApplicationRunningMode"},
{0x0104, nullptr, "IsStandardMemoryLayout"}, {0x0104, &APT_U::IsStandardMemoryLayout, "IsStandardMemoryLayout"},
{0x0105, &APT_U::IsTitleAllowed, "IsTitleAllowed"}, {0x0105, &APT_U::IsTitleAllowed, "IsTitleAllowed"},
// clang-format on // clang-format on
}; };

View File

@ -8,5 +8,6 @@ namespace Service::APT::ErrCodes {
enum { enum {
ParameterPresent = 2, ParameterPresent = 2,
InvalidAppletSlot = 4, InvalidAppletSlot = 4,
AppNotRunning = 11,
}; };
} // namespace Service::APT::ErrCodes } // namespace Service::APT::ErrCodes

View File

@ -29,4 +29,17 @@ std::shared_ptr<Kernel::Process> LaunchTitle(FS::MediaType media_type, u64 title
return process; return process;
} }
void RebootToTitle(Core::System& system, FS::MediaType media_type, u64 title_id) {
auto new_path = AM::GetTitleContentPath(media_type, title_id);
if (new_path.empty() || !FileUtil::Exists(new_path)) {
// TODO: This can happen if the requested title is not installed. Need a way to find
// non-installed titles in the game list.
LOG_CRITICAL(Service_APT,
"Failed to find title '{}' to jump to, resetting current title instead.",
new_path);
new_path.clear();
}
system.RequestReset(new_path);
}
} // namespace Service::NS } // namespace Service::NS

View File

@ -18,4 +18,7 @@ namespace Service::NS {
/// Loads and launches the title identified by title_id in the specified media type. /// Loads and launches the title identified by title_id in the specified media type.
std::shared_ptr<Kernel::Process> LaunchTitle(FS::MediaType media_type, u64 title_id); std::shared_ptr<Kernel::Process> LaunchTitle(FS::MediaType media_type, u64 title_id);
/// Reboots the system to the specified title.
void RebootToTitle(Core::System& system, FS::MediaType media_type, u64 title_id);
} // namespace Service::NS } // namespace Service::NS

View File

@ -693,30 +693,23 @@ void FS_USER::GetProductInfo(Kernel::HLERequestContext& ctx) {
void FS_USER::GetProgramLaunchInfo(Kernel::HLERequestContext& ctx) { void FS_USER::GetProgramLaunchInfo(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx); IPC::RequestParser rp(ctx);
const auto process_id = rp.Pop<u32>();
u32 process_id = rp.Pop<u32>();
LOG_DEBUG(Service_FS, "process_id={}", process_id); LOG_DEBUG(Service_FS, "process_id={}", process_id);
auto program_info = program_info_map.find(process_id);
IPC::RequestBuilder rb = rp.MakeBuilder(5, 0); IPC::RequestBuilder rb = rp.MakeBuilder(5, 0);
if (program_info == program_info_map.end()) { auto program_info_result = GetProgramLaunchInfo(process_id);
if (program_info_result.Failed()) {
// Note: In this case, the rest of the parameters are not changed but the command header // Note: In this case, the rest of the parameters are not changed but the command header
// remains the same. // remains the same.
rb.Push(ResultCode(FileSys::ErrCodes::ArchiveNotMounted, ErrorModule::FS, rb.Push(program_info_result.Code());
ErrorSummary::NotFound, ErrorLevel::Status));
rb.Skip(4, false); rb.Skip(4, false);
return; return;
} }
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.Push(program_info->second.program_id); rb.PushRaw(program_info_result.Unwrap());
rb.Push(static_cast<u8>(program_info->second.media_type));
// TODO(Subv): Find out what this value means.
rb.Push<u32>(0);
} }
void FS_USER::ObsoletedCreateExtSaveData(Kernel::HLERequestContext& ctx) { void FS_USER::ObsoletedCreateExtSaveData(Kernel::HLERequestContext& ctx) {

View File

@ -7,6 +7,7 @@
#include <unordered_map> #include <unordered_map>
#include <boost/serialization/base_object.hpp> #include <boost/serialization/base_object.hpp>
#include "common/common_types.h" #include "common/common_types.h"
#include "core/file_sys/errors.h"
#include "core/hle/service/service.h" #include "core/hle/service/service.h"
namespace Core { namespace Core {
@ -17,6 +18,13 @@ namespace Service::FS {
class ArchiveManager; class ArchiveManager;
struct ProgramInfo {
u64 program_id;
MediaType media_type;
INSERT_PADDING_BYTES(4);
};
static_assert(sizeof(ProgramInfo) == 0x10, "ProgramInfo struct has incorrect size");
struct ClientSlot : public Kernel::SessionRequestHandler::SessionDataBase { struct ClientSlot : public Kernel::SessionRequestHandler::SessionDataBase {
// We retrieves program ID for client process on FS::Initialize(WithSDKVersion) // We retrieves program ID for client process on FS::Initialize(WithSDKVersion)
// Real 3DS matches program ID and process ID based on data registered by loader via fs:REG, so // Real 3DS matches program ID and process ID based on data registered by loader via fs:REG, so
@ -55,6 +63,17 @@ public:
bool GetProductInfo(u32 process_id, ProductInfo& out_product_info); bool GetProductInfo(u32 process_id, ProductInfo& out_product_info);
/// Gets the registered program info of a process.
ResultVal<ProgramInfo> GetProgramLaunchInfo(u32 process_id) const {
auto info = program_info_map.find(process_id);
if (info != program_info_map.end()) {
return info->second;
} else {
return ResultCode(FileSys::ErrCodes::ArchiveNotMounted, ErrorModule::FS,
ErrorSummary::NotFound, ErrorLevel::Status);
}
}
private: private:
void Initialize(Kernel::HLERequestContext& ctx); void Initialize(Kernel::HLERequestContext& ctx);
@ -656,11 +675,6 @@ private:
static ResultVal<u16> GetSpecialContentIndexFromTMD(MediaType media_type, u64 title_id, static ResultVal<u16> GetSpecialContentIndexFromTMD(MediaType media_type, u64 title_id,
SpecialContentType type); SpecialContentType type);
struct ProgramInfo {
u64 program_id;
MediaType media_type;
};
std::unordered_map<u32, ProgramInfo> program_info_map; std::unordered_map<u32, ProgramInfo> program_info_map;
std::string current_gamecard_path; std::string current_gamecard_path;

View File

@ -704,18 +704,73 @@ void GSP_GPU::ImportDisplayCaptureInfo(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_GSP, "called"); LOG_WARNING(Service_GSP, "called");
} }
static void CopyFrameBuffer(Core::System& system, VAddr dst, VAddr src, u32 stride, u32 lines) {
auto dst_ptr = system.Memory().GetPointer(dst);
const auto src_ptr = system.Memory().GetPointer(src);
if (!dst_ptr || !src_ptr) {
LOG_WARNING(Service_GSP,
"Could not resolve pointers for framebuffer capture, skipping screen.");
return;
}
Memory::RasterizerFlushVirtualRegion(src, stride * lines, Memory::FlushMode::Flush);
std::memcpy(dst_ptr, src_ptr, stride * lines);
Memory::RasterizerFlushVirtualRegion(dst, stride * lines, Memory::FlushMode::Invalidate);
}
void GSP_GPU::SaveVramSysArea(Kernel::HLERequestContext& ctx) { void GSP_GPU::SaveVramSysArea(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx); IPC::RequestParser rp(ctx);
if (active_thread_id == std::numeric_limits<u32>::max()) {
LOG_WARNING(Service_GSP, "Called without an active thread.");
// TODO: Find the right error code.
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(-1);
return;
}
LOG_INFO(Service_GSP, "called"); LOG_INFO(Service_GSP, "called");
// TODO: This should also DMA framebuffers into VRAM and save LCD register state. // TODO: This should also save LCD register state.
Memory::RasterizerFlushVirtualRegion(Memory::VRAM_VADDR, Memory::VRAM_SIZE, Memory::RasterizerFlushVirtualRegion(Memory::VRAM_VADDR, Memory::VRAM_SIZE,
Memory::FlushMode::Flush); Memory::FlushMode::Flush);
auto vram = system.Memory().GetPointer(Memory::VRAM_VADDR); const auto vram = system.Memory().GetPointer(Memory::VRAM_VADDR);
saved_vram.emplace(std::vector<u8>(Memory::VRAM_SIZE)); saved_vram.emplace(std::vector<u8>(Memory::VRAM_SIZE));
std::memcpy(saved_vram.get().data(), vram, Memory::VRAM_SIZE); std::memcpy(saved_vram.get().data(), vram, Memory::VRAM_SIZE);
const auto top_screen = GetFrameBufferInfo(active_thread_id, 0);
if (top_screen) {
const auto top_fb = top_screen->framebuffer_info[top_screen->index];
if (top_fb.address_left) {
CopyFrameBuffer(system, FRAMEBUFFER_SAVE_AREA_TOP_LEFT, top_fb.address_left,
top_fb.stride, TOP_FRAMEBUFFER_HEIGHT);
} else {
LOG_WARNING(Service_GSP, "No framebuffer bound to top left screen, skipping capture.");
}
if (top_fb.address_right) {
CopyFrameBuffer(system, FRAMEBUFFER_SAVE_AREA_TOP_RIGHT, top_fb.address_right,
top_fb.stride, TOP_FRAMEBUFFER_HEIGHT);
} else {
LOG_WARNING(Service_GSP, "No framebuffer bound to top right screen, skipping capture.");
}
} else {
LOG_WARNING(Service_GSP, "No top screen bound, skipping capture.");
}
const auto bottom_screen = GetFrameBufferInfo(active_thread_id, 1);
if (bottom_screen) {
const auto bottom_fb = bottom_screen->framebuffer_info[bottom_screen->index];
if (bottom_fb.address_left) {
CopyFrameBuffer(system, FRAMEBUFFER_SAVE_AREA_BOTTOM, bottom_fb.address_left,
bottom_fb.stride, BOTTOM_FRAMEBUFFER_HEIGHT);
} else {
LOG_WARNING(Service_GSP, "No framebuffer bound to bottom screen, skipping capture.");
}
} else {
LOG_WARNING(Service_GSP, "No bottom screen bound, skipping capture.");
}
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
} }
@ -819,7 +874,7 @@ SessionData* GSP_GPU::FindRegisteredThreadData(u32 thread_id) {
return nullptr; return nullptr;
} }
GSP_GPU::GSP_GPU(Core::System& system) : ServiceFramework("gsp::Gpu", 2), system(system) { GSP_GPU::GSP_GPU(Core::System& system) : ServiceFramework("gsp::Gpu", 4), system(system) {
static const FunctionInfo functions[] = { static const FunctionInfo functions[] = {
// clang-format off // clang-format off
{0x0001, &GSP_GPU::WriteHWRegs, "WriteHWRegs"}, {0x0001, &GSP_GPU::WriteHWRegs, "WriteHWRegs"},

View File

@ -186,6 +186,17 @@ struct CommandBuffer {
}; };
static_assert(sizeof(CommandBuffer) == 0x200, "CommandBuffer struct has incorrect size"); static_assert(sizeof(CommandBuffer) == 0x200, "CommandBuffer struct has incorrect size");
constexpr u32 FRAMEBUFFER_WIDTH = 240;
constexpr u32 FRAMEBUFFER_WIDTH_POW2 = 256;
constexpr u32 TOP_FRAMEBUFFER_HEIGHT = 400;
constexpr u32 BOTTOM_FRAMEBUFFER_HEIGHT = 320;
constexpr u32 FRAMEBUFFER_HEIGHT_POW2 = 512;
// These are the VRAM addresses that GSP copies framebuffers to in SaveVramSysArea.
constexpr VAddr FRAMEBUFFER_SAVE_AREA_TOP_LEFT = Memory::VRAM_VADDR + 0x273000;
constexpr VAddr FRAMEBUFFER_SAVE_AREA_TOP_RIGHT = Memory::VRAM_VADDR + 0x2B9800;
constexpr VAddr FRAMEBUFFER_SAVE_AREA_BOTTOM = Memory::VRAM_VADDR + 0x4C7800;
class GSP_GPU; class GSP_GPU;
class SessionData : public Kernel::SessionRequestHandler::SessionDataBase { class SessionData : public Kernel::SessionRequestHandler::SessionDataBase {

View File

@ -13,6 +13,7 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "common/file_util.h" #include "common/file_util.h"
#include "core/file_sys/romfs_reader.h" #include "core/file_sys/romfs_reader.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/object.h" #include "core/hle/kernel/object.h"
namespace Kernel { namespace Kernel {
@ -99,23 +100,36 @@ public:
virtual ResultStatus Load(std::shared_ptr<Kernel::Process>& process) = 0; virtual ResultStatus Load(std::shared_ptr<Kernel::Process>& process) = 0;
/** /**
* Loads the system mode that this application needs. * Loads the core version (FIRM title ID low) that this application needs.
* This function defaults to 2 (96MB allocated to the application) if it can't read the * This function defaults to 0x2 (NATIVE_FIRM) if it can't read the
* information. * information.
* @returns A pair with the optional system mode, and the status. * @returns A pair with the optional core version, and the status.
*/ */
virtual std::pair<std::optional<u32>, ResultStatus> LoadKernelSystemMode() { virtual std::pair<std::optional<u32>, ResultStatus> LoadCoreVersion() {
// 96MB allocated to the application. return std::make_pair(0x2, ResultStatus::Success);
return std::make_pair(2, ResultStatus::Success);
} }
/** /**
* Loads the N3ds mode that this application uses. * Loads the memory mode that this application needs.
* It defaults to 0 (O3DS default) if it can't read the information. * This function defaults to Dev1 (96MB allocated to the application) if it can't read the
* @returns A pair with the optional N3ds mode, and the status. * information.
* @returns A pair with the optional memory mode, and the status.
*/ */
virtual std::pair<std::optional<u8>, ResultStatus> LoadKernelN3dsMode() { virtual std::pair<std::optional<Kernel::MemoryMode>, ResultStatus> LoadKernelMemoryMode() {
return std::make_pair(u8(0), ResultStatus::Success); // 96MB allocated to the application.
return std::make_pair(Kernel::MemoryMode::Dev1, ResultStatus::Success);
}
/**
* Loads the N3DS hardware capabilities that this application uses.
* It defaults to all disabled (O3DS) if it can't read the information.
* @returns A pair with the optional N3DS hardware capabilities, and the status.
*/
virtual std::pair<std::optional<Kernel::New3dsHwCapabilities>, ResultStatus>
LoadNew3dsHwCapabilities() {
return std::make_pair(
Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy},
ResultStatus::Success);
} }
/** /**

View File

@ -16,6 +16,7 @@
#include "core/core.h" #include "core/core.h"
#include "core/file_sys/ncch_container.h" #include "core/file_sys/ncch_container.h"
#include "core/file_sys/title_metadata.h" #include "core/file_sys/title_metadata.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/process.h" #include "core/hle/kernel/process.h"
#include "core/hle/kernel/resource_limit.h" #include "core/hle/kernel/resource_limit.h"
#include "core/hle/service/am/am.h" #include "core/hle/service/am/am.h"
@ -47,7 +48,7 @@ FileType AppLoader_NCCH::IdentifyType(FileUtil::IOFile& file) {
return FileType::Error; return FileType::Error;
} }
std::pair<std::optional<u32>, ResultStatus> AppLoader_NCCH::LoadKernelSystemMode() { std::pair<std::optional<u32>, ResultStatus> AppLoader_NCCH::LoadCoreVersion() {
if (!is_loaded) { if (!is_loaded) {
ResultStatus res = base_ncch.Load(); ResultStatus res = base_ncch.Load();
if (res != ResultStatus::Success) { if (res != ResultStatus::Success) {
@ -55,12 +56,12 @@ std::pair<std::optional<u32>, ResultStatus> AppLoader_NCCH::LoadKernelSystemMode
} }
} }
// Set the system mode as the one from the exheader. // Provide the core version from the exheader.
return std::make_pair(overlay_ncch->exheader_header.arm11_system_local_caps.system_mode.Value(), auto& ncch_caps = overlay_ncch->exheader_header.arm11_system_local_caps;
ResultStatus::Success); return std::make_pair(ncch_caps.core_version, ResultStatus::Success);
} }
std::pair<std::optional<u8>, ResultStatus> AppLoader_NCCH::LoadKernelN3dsMode() { std::pair<std::optional<Kernel::MemoryMode>, ResultStatus> AppLoader_NCCH::LoadKernelMemoryMode() {
if (!is_loaded) { if (!is_loaded) {
ResultStatus res = base_ncch.Load(); ResultStatus res = base_ncch.Load();
if (res != ResultStatus::Success) { if (res != ResultStatus::Success) {
@ -68,9 +69,29 @@ std::pair<std::optional<u8>, ResultStatus> AppLoader_NCCH::LoadKernelN3dsMode()
} }
} }
// Set the system mode as the one from the exheader. // Provide the memory mode from the exheader.
return std::make_pair(overlay_ncch->exheader_header.arm11_system_local_caps.n3ds_mode, auto& ncch_caps = overlay_ncch->exheader_header.arm11_system_local_caps;
ResultStatus::Success); auto mode = static_cast<Kernel::MemoryMode>(ncch_caps.system_mode.Value());
return std::make_pair(mode, ResultStatus::Success);
}
std::pair<std::optional<Kernel::New3dsHwCapabilities>, ResultStatus>
AppLoader_NCCH::LoadNew3dsHwCapabilities() {
if (!is_loaded) {
ResultStatus res = base_ncch.Load();
if (res != ResultStatus::Success) {
return std::make_pair(std::nullopt, res);
}
}
// Provide the capabilities from the exheader.
auto& ncch_caps = overlay_ncch->exheader_header.arm11_system_local_caps;
auto caps = Kernel::New3dsHwCapabilities{
ncch_caps.enable_l2_cache != 0,
ncch_caps.enable_804MHz_cpu != 0,
static_cast<Kernel::New3dsMemoryMode>(ncch_caps.n3ds_mode),
};
return std::make_pair(std::move(caps), ResultStatus::Success);
} }
ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr<Kernel::Process>& process) { ResultStatus AppLoader_NCCH::LoadExec(std::shared_ptr<Kernel::Process>& process) {

View File

@ -32,13 +32,16 @@ public:
ResultStatus Load(std::shared_ptr<Kernel::Process>& process) override; ResultStatus Load(std::shared_ptr<Kernel::Process>& process) override;
std::pair<std::optional<u32>, ResultStatus> LoadCoreVersion() override;
/** /**
* Loads the Exheader and returns the system mode for this application. * Loads the Exheader and returns the system mode for this application.
* @returns A pair with the optional system mode, and and the status. * @returns A pair with the optional system mode, and and the status.
*/ */
std::pair<std::optional<u32>, ResultStatus> LoadKernelSystemMode() override; std::pair<std::optional<Kernel::MemoryMode>, ResultStatus> LoadKernelMemoryMode() override;
std::pair<std::optional<u8>, ResultStatus> LoadKernelN3dsMode() override; std::pair<std::optional<Kernel::New3dsHwCapabilities>, ResultStatus> LoadNew3dsHwCapabilities()
override;
ResultStatus IsExecutable(bool& out_executable) override; ResultStatus IsExecutable(bool& out_executable) override;

View File

@ -12,6 +12,7 @@ add_executable(tests
core/memory/vm_manager.cpp core/memory/vm_manager.cpp
precompiled_headers.h precompiled_headers.h
audio_core/hle/hle.cpp audio_core/hle/hle.cpp
audio_core/hle/adts_reader.cpp
audio_core/lle/lle.cpp audio_core/lle/lle.cpp
audio_core/audio_fixures.h audio_core/audio_fixures.h
audio_core/decoder_tests.cpp audio_core/decoder_tests.cpp

View File

@ -0,0 +1,75 @@
// Copyright 2023 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <catch2/catch_test_macros.hpp>
#include "audio_core/hle/adts.h"
namespace {
constexpr std::array<u32, 16> freq_table = {96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
16000, 12000, 11025, 8000, 7350, 0, 0, 0};
constexpr std::array<u8, 8> channel_table = {0, 1, 2, 3, 4, 5, 6, 8};
AudioCore::ADTSData ParseADTS_Old(const unsigned char* buffer) {
u32 tmp = 0;
AudioCore::ADTSData out{};
// sync word 0xfff
tmp = (buffer[0] << 8) | (buffer[1] & 0xf0);
if ((tmp & 0xffff) != 0xfff0) {
out.length = 0;
return out;
}
// bit 16 = no CRC
out.header_length = (buffer[1] & 0x1) ? 7 : 9;
out.mpeg2 = (buffer[1] >> 3) & 0x1;
// bit 17 to 18
out.profile = (buffer[2] >> 6) + 1;
// bit 19 to 22
tmp = (buffer[2] >> 2) & 0xf;
out.samplerate_idx = tmp;
out.samplerate = (tmp > 15) ? 0 : freq_table[tmp];
// bit 24 to 26
tmp = ((buffer[2] & 0x1) << 2) | ((buffer[3] >> 6) & 0x3);
out.channel_idx = tmp;
out.channels = (tmp > 7) ? 0 : channel_table[tmp];
// bit 55 to 56
out.framecount = (buffer[6] & 0x3) + 1;
// bit 31 to 43
tmp = (buffer[3] & 0x3) << 11;
tmp |= (buffer[4] << 3) & 0x7f8;
tmp |= (buffer[5] >> 5) & 0x7;
out.length = tmp;
return out;
}
} // namespace
TEST_CASE("ParseADTS fuzz", "[audio_core][hle]") {
for (u32 i = 0; i < 0x10000; i++) {
std::array<u8, 7> adts_header;
std::string adts_header_string = "ADTS Header: ";
for (auto& it : adts_header) {
it = static_cast<u8>(rand());
adts_header_string.append(fmt::format("{:2X} ", it));
}
INFO(adts_header_string);
AudioCore::ADTSData out_old_impl =
ParseADTS_Old(reinterpret_cast<const unsigned char*>(adts_header.data()));
AudioCore::ADTSData out = AudioCore::ParseADTS(adts_header.data());
REQUIRE(out_old_impl.length == out.length);
REQUIRE(out_old_impl.channels == out.channels);
REQUIRE(out_old_impl.channel_idx == out.channel_idx);
REQUIRE(out_old_impl.framecount == out.framecount);
REQUIRE(out_old_impl.header_length == out.header_length);
REQUIRE(out_old_impl.mpeg2 == out.mpeg2);
REQUIRE(out_old_impl.profile == out.profile);
REQUIRE(out_old_impl.samplerate == out.samplerate);
REQUIRE(out_old_impl.samplerate_idx == out.samplerate_idx);
}
}

View File

@ -18,7 +18,8 @@ TestEnvironment::TestEnvironment(bool mutable_memory_)
timing = std::make_unique<Core::Timing>(1, 100); timing = std::make_unique<Core::Timing>(1, 100);
memory = std::make_unique<Memory::MemorySystem>(); memory = std::make_unique<Memory::MemorySystem>();
kernel = std::make_unique<Kernel::KernelSystem>( kernel = std::make_unique<Kernel::KernelSystem>(
*memory, *timing, [] {}, 0, 1, 0); *memory, *timing, [] {}, Kernel::MemoryMode::Prod, 1,
Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy});
kernel->SetCurrentProcess(kernel->CreateProcess(kernel->CreateCodeSet("", 0))); kernel->SetCurrentProcess(kernel->CreateProcess(kernel->CreateCodeSet("", 0)));
page_table = kernel->GetCurrentProcess()->vm_manager.page_table; page_table = kernel->GetCurrentProcess()->vm_manager.page_table;

View File

@ -25,7 +25,8 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
Core::Timing timing(1, 100); Core::Timing timing(1, 100);
Memory::MemorySystem memory; Memory::MemorySystem memory;
Kernel::KernelSystem kernel( Kernel::KernelSystem kernel(
memory, timing, [] {}, 0, 1, 0); memory, timing, [] {}, Kernel::MemoryMode::Prod, 1,
Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy});
auto [server, client] = kernel.CreateSessionPair(); auto [server, client] = kernel.CreateSessionPair();
HLERequestContext context(kernel, std::move(server), nullptr); HLERequestContext context(kernel, std::move(server), nullptr);
@ -248,7 +249,8 @@ TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
Core::Timing timing(1, 100); Core::Timing timing(1, 100);
Memory::MemorySystem memory; Memory::MemorySystem memory;
Kernel::KernelSystem kernel( Kernel::KernelSystem kernel(
memory, timing, [] {}, 0, 1, 0); memory, timing, [] {}, Kernel::MemoryMode::Prod, 1,
Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy});
auto [server, client] = kernel.CreateSessionPair(); auto [server, client] = kernel.CreateSessionPair();
HLERequestContext context(kernel, std::move(server), nullptr); HLERequestContext context(kernel, std::move(server), nullptr);

View File

@ -11,7 +11,8 @@ TEST_CASE("memory.IsValidVirtualAddress", "[core][memory]") {
Core::Timing timing(1, 100); Core::Timing timing(1, 100);
Memory::MemorySystem memory; Memory::MemorySystem memory;
Kernel::KernelSystem kernel( Kernel::KernelSystem kernel(
memory, timing, [] {}, 0, 1, 0); memory, timing, [] {}, Kernel::MemoryMode::Prod, 1,
Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy});
SECTION("these regions should not be mapped on an empty process") { SECTION("these regions should not be mapped on an empty process") {
auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0)); auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0));
CHECK(memory.IsValidVirtualAddress(*process, Memory::PROCESS_IMAGE_VADDR) == false); CHECK(memory.IsValidVirtualAddress(*process, Memory::PROCESS_IMAGE_VADDR) == false);

View File

@ -17,7 +17,8 @@ TEST_CASE("Memory Basics", "[kernel][memory]") {
Core::Timing timing(1, 100); Core::Timing timing(1, 100);
Memory::MemorySystem memory; Memory::MemorySystem memory;
Kernel::KernelSystem kernel( Kernel::KernelSystem kernel(
memory, timing, [] {}, 0, 1, 0); memory, timing, [] {}, Kernel::MemoryMode::Prod, 1,
Kernel::New3dsHwCapabilities{false, false, Kernel::New3dsMemoryMode::Legacy});
Kernel::Process process(kernel); Kernel::Process process(kernel);
SECTION("mapping memory") { SECTION("mapping memory") {
// Because of the PageTable, Kernel::VMManager is too big to be created on the stack. // Because of the PageTable, Kernel::VMManager is too big to be created on the stack.