citra-emu
/
citra-canary
Archived
1
0
Fork 0

Merge pull request #3462 from wwylele/am-new-framework

Service/AM: convert to ServiceFramework
This commit is contained in:
Weiyi Wang 2018-03-03 18:29:47 +02:00 committed by GitHub
commit 001ad9da3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 845 additions and 912 deletions

View File

@ -117,10 +117,7 @@ public:
// TODO : ensure that translate params are added after all regular params // TODO : ensure that translate params are added after all regular params
template <typename... H> template <typename... H>
void PushCopyHandles(H... handles); [[deprecated]] void PushCopyHandles(H... handles);
template <typename... H>
void PushMoveHandles(H... handles);
template <typename... O> template <typename... O>
void PushCopyObjects(Kernel::SharedPtr<O>... pointers); void PushCopyObjects(Kernel::SharedPtr<O>... pointers);
@ -131,11 +128,15 @@ public:
[[deprecated]] void PushStaticBuffer(VAddr buffer_vaddr, size_t size, u8 buffer_id); [[deprecated]] void PushStaticBuffer(VAddr buffer_vaddr, size_t size, u8 buffer_id);
void PushStaticBuffer(const std::vector<u8>& buffer, u8 buffer_id); void PushStaticBuffer(const std::vector<u8>& buffer, u8 buffer_id);
[[deprecated]] void PushMappedBuffer(VAddr buffer_vaddr, size_t size,
MappedBufferPermissions perms);
/// Pushes an HLE MappedBuffer interface back to unmapped the buffer. /// Pushes an HLE MappedBuffer interface back to unmapped the buffer.
void PushMappedBuffer(const Kernel::MappedBuffer& mapped_buffer); void PushMappedBuffer(const Kernel::MappedBuffer& mapped_buffer);
private:
template <typename... H>
void PushCopyHLEHandles(H... handles);
template <typename... H>
void PushMoveHLEHandles(H... handles);
}; };
/// Push /// /// Push ///
@ -186,24 +187,29 @@ void RequestBuilder::Push(const First& first_value, const Other&... other_values
template <typename... H> template <typename... H>
inline void RequestBuilder::PushCopyHandles(H... handles) { inline void RequestBuilder::PushCopyHandles(H... handles) {
Push(CopyHandleDesc(sizeof...(H))); PushCopyHLEHandles(handles...);
Push(static_cast<Kernel::Handle>(handles)...);
} }
template <typename... H> template <typename... H>
inline void RequestBuilder::PushMoveHandles(H... handles) { inline void RequestBuilder::PushCopyHLEHandles(H... handles) {
Push(CopyHandleDesc(sizeof...(H)));
Push(static_cast<u32>(handles)...);
}
template <typename... H>
inline void RequestBuilder::PushMoveHLEHandles(H... handles) {
Push(MoveHandleDesc(sizeof...(H))); Push(MoveHandleDesc(sizeof...(H)));
Push(static_cast<Kernel::Handle>(handles)...); Push(static_cast<u32>(handles)...);
} }
template <typename... O> template <typename... O>
inline void RequestBuilder::PushCopyObjects(Kernel::SharedPtr<O>... pointers) { inline void RequestBuilder::PushCopyObjects(Kernel::SharedPtr<O>... pointers) {
PushCopyHandles(context->AddOutgoingHandle(std::move(pointers))...); PushCopyHLEHandles(context->AddOutgoingHandle(std::move(pointers))...);
} }
template <typename... O> template <typename... O>
inline void RequestBuilder::PushMoveObjects(Kernel::SharedPtr<O>... pointers) { inline void RequestBuilder::PushMoveObjects(Kernel::SharedPtr<O>... pointers) {
PushMoveHandles(context->AddOutgoingHandle(std::move(pointers))...); PushMoveHLEHandles(context->AddOutgoingHandle(std::move(pointers))...);
} }
inline void RequestBuilder::PushStaticBuffer(VAddr buffer_vaddr, size_t size, u8 buffer_id) { inline void RequestBuilder::PushStaticBuffer(VAddr buffer_vaddr, size_t size, u8 buffer_id) {
@ -221,12 +227,6 @@ inline void RequestBuilder::PushStaticBuffer(const std::vector<u8>& buffer, u8 b
context->AddStaticBuffer(buffer_id, buffer); context->AddStaticBuffer(buffer_id, buffer);
} }
inline void RequestBuilder::PushMappedBuffer(VAddr buffer_vaddr, size_t size,
MappedBufferPermissions perms) {
Push(MappedBufferDesc(size, perms));
Push(buffer_vaddr);
}
inline void RequestBuilder::PushMappedBuffer(const Kernel::MappedBuffer& mapped_buffer) { inline void RequestBuilder::PushMappedBuffer(const Kernel::MappedBuffer& mapped_buffer) {
Push(mapped_buffer.GenerateDescriptor()); Push(mapped_buffer.GenerateDescriptor());
Push(mapped_buffer.GetId()); Push(mapped_buffer.GetId());
@ -284,24 +284,6 @@ public:
return static_cast<T>(Pop<std::underlying_type_t<T>>()); return static_cast<T>(Pop<std::underlying_type_t<T>>());
} }
/// Equivalent to calling `PopHandles<1>()[0]`.
Kernel::Handle PopHandle();
/**
* Pops a descriptor containing `N` handles. The handles are returned as an array. The
* descriptor must contain exactly `N` handles, it is not permitted to, for example, call
* PopHandles<1>() twice to read a multi-handle descriptor with 2 handles, or to make a single
* PopHandles<2>() call to read 2 single-handle descriptors.
*/
template <unsigned int N>
std::array<Kernel::Handle, N> PopHandles();
/// Convenience wrapper around PopHandles() which assigns the handles to the passed references.
template <typename... H>
void PopHandles(H&... handles) {
std::tie(handles...) = PopHandles<sizeof...(H)>();
}
/// Equivalent to calling `PopGenericObjects<1>()[0]`. /// Equivalent to calling `PopGenericObjects<1>()[0]`.
Kernel::SharedPtr<Kernel::Object> PopGenericObject(); Kernel::SharedPtr<Kernel::Object> PopGenericObject();
@ -311,8 +293,10 @@ public:
/** /**
* Pop a descriptor containing `N` handles and resolves them to Kernel::Object pointers. If a * Pop a descriptor containing `N` handles and resolves them to Kernel::Object pointers. If a
* handle is invalid, null is returned for that object instead. The same caveats from * handle is invalid, null is returned for that object instead. The descriptor must contain
* PopHandles() apply regarding `N` matching the number of handles in the descriptor. * exactly `N` handles, it is not permitted to, for example, call PopGenericObjects<1>() twice
* to read a multi-handle descriptor with 2 handles, or to make a single PopGenericObjects<2>()
* call to read 2 single-handle descriptors.
*/ */
template <unsigned int N> template <unsigned int N>
std::array<Kernel::SharedPtr<Kernel::Object>, N> PopGenericObjects(); std::array<Kernel::SharedPtr<Kernel::Object>, N> PopGenericObjects();
@ -355,17 +339,6 @@ public:
*/ */
const std::vector<u8>& PopStaticBuffer(); const std::vector<u8>& PopStaticBuffer();
/**
* @brief Pops the mapped buffer vaddr
* @return The virtual address of the buffer
* @param[out] data_size If non-null, the pointed value will be set to the size of the data
* given by the source process
* @param[out] buffer_perms If non-null, the pointed value will be set to the permissions of the
* buffer
*/
[[deprecated]] VAddr PopMappedBuffer(size_t* data_size,
MappedBufferPermissions* buffer_perms = nullptr);
/// Pops a mapped buffer descriptor with its vaddr and resolves it to an HLE interface /// Pops a mapped buffer descriptor with its vaddr and resolves it to an HLE interface
Kernel::MappedBuffer& PopMappedBuffer(); Kernel::MappedBuffer& PopMappedBuffer();
@ -382,6 +355,10 @@ public:
*/ */
template <typename T> template <typename T>
T PopRaw(); T PopRaw();
private:
template <unsigned int N>
std::array<u32, N> PopHLEHandles();
}; };
/// Pop /// /// Pop ///
@ -443,32 +420,23 @@ void RequestParser::Pop(First& first_value, Other&... other_values) {
Pop(other_values...); Pop(other_values...);
} }
inline Kernel::Handle RequestParser::PopHandle() {
const u32 handle_descriptor = Pop<u32>();
DEBUG_ASSERT_MSG(IsHandleDescriptor(handle_descriptor),
"Tried to pop handle(s) but the descriptor is not a handle descriptor");
DEBUG_ASSERT_MSG(HandleNumberFromDesc(handle_descriptor) == 1,
"Descriptor indicates that there isn't exactly one handle");
return Pop<Kernel::Handle>();
}
template <unsigned int N> template <unsigned int N>
std::array<Kernel::Handle, N> RequestParser::PopHandles() { std::array<u32, N> RequestParser::PopHLEHandles() {
u32 handle_descriptor = Pop<u32>(); u32 handle_descriptor = Pop<u32>();
ASSERT_MSG(IsHandleDescriptor(handle_descriptor), ASSERT_MSG(IsHandleDescriptor(handle_descriptor),
"Tried to pop handle(s) but the descriptor is not a handle descriptor"); "Tried to pop handle(s) but the descriptor is not a handle descriptor");
ASSERT_MSG(N == HandleNumberFromDesc(handle_descriptor), ASSERT_MSG(N == HandleNumberFromDesc(handle_descriptor),
"Number of handles doesn't match the descriptor"); "Number of handles doesn't match the descriptor");
std::array<Kernel::Handle, N> handles{}; std::array<u32, N> handles{};
for (Kernel::Handle& handle : handles) { for (u32& handle : handles) {
handle = Pop<Kernel::Handle>(); handle = Pop<u32>();
} }
return handles; return handles;
} }
inline Kernel::SharedPtr<Kernel::Object> RequestParser::PopGenericObject() { inline Kernel::SharedPtr<Kernel::Object> RequestParser::PopGenericObject() {
Kernel::Handle handle = PopHandle(); auto[handle] = PopHLEHandles<1>();
return context->GetIncomingHandle(handle); return context->GetIncomingHandle(handle);
} }
@ -479,7 +447,7 @@ Kernel::SharedPtr<T> RequestParser::PopObject() {
template <unsigned int N> template <unsigned int N>
inline std::array<Kernel::SharedPtr<Kernel::Object>, N> RequestParser::PopGenericObjects() { inline std::array<Kernel::SharedPtr<Kernel::Object>, N> RequestParser::PopGenericObjects() {
std::array<Kernel::Handle, N> handles = PopHandles<N>(); std::array<u32, N> handles = PopHLEHandles<N>();
std::array<Kernel::SharedPtr<Kernel::Object>, N> pointers; std::array<Kernel::SharedPtr<Kernel::Object>, N> pointers;
for (int i = 0; i < N; ++i) { for (int i = 0; i < N; ++i) {
pointers[i] = context->GetIncomingHandle(handles[i]); pointers[i] = context->GetIncomingHandle(handles[i]);
@ -524,17 +492,6 @@ inline const std::vector<u8>& RequestParser::PopStaticBuffer() {
return context->GetStaticBuffer(buffer_info.buffer_id); return context->GetStaticBuffer(buffer_info.buffer_id);
} }
inline VAddr RequestParser::PopMappedBuffer(size_t* data_size,
MappedBufferPermissions* buffer_perms) {
const u32 sbuffer_descriptor = Pop<u32>();
MappedBufferDescInfo bufferInfo{sbuffer_descriptor};
if (data_size != nullptr)
*data_size = bufferInfo.size;
if (buffer_perms != nullptr)
*buffer_perms = bufferInfo.perms;
return Pop<VAddr>();
}
inline Kernel::MappedBuffer& RequestParser::PopMappedBuffer() { inline Kernel::MappedBuffer& RequestParser::PopMappedBuffer() {
u32 mapped_buffer_descriptor = Pop<u32>(); u32 mapped_buffer_descriptor = Pop<u32>();
ASSERT_MSG(GetDescriptorType(mapped_buffer_descriptor) == MappedBuffer, ASSERT_MSG(GetDescriptorType(mapped_buffer_descriptor) == MappedBuffer,

View File

@ -3,7 +3,6 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <algorithm> #include <algorithm>
#include <array>
#include <cinttypes> #include <cinttypes>
#include <cstddef> #include <cstddef>
#include <cstring> #include <cstring>
@ -27,7 +26,6 @@
#include "core/hle/service/am/am_sys.h" #include "core/hle/service/am/am_sys.h"
#include "core/hle/service/am/am_u.h" #include "core/hle/service/am/am_u.h"
#include "core/hle/service/fs/archive.h" #include "core/hle/service/fs/archive.h"
#include "core/hle/service/service.h"
#include "core/loader/loader.h" #include "core/loader/loader.h"
#include "core/loader/smdh.h" #include "core/loader/smdh.h"
@ -41,12 +39,6 @@ constexpr u8 VARIATION_SYSTEM = 0x02;
constexpr u32 TID_HIGH_UPDATE = 0x0004000E; constexpr u32 TID_HIGH_UPDATE = 0x0004000E;
constexpr u32 TID_HIGH_DLC = 0x0004008C; constexpr u32 TID_HIGH_DLC = 0x0004008C;
// CIA installation static context variables
static bool cia_installing = false;
static bool lists_initialized = false;
static std::array<std::vector<u64_le>, 3> am_title_list;
struct TitleInfo { struct TitleInfo {
u64_le tid; u64_le tid;
u64_le size; u64_le size;
@ -454,7 +446,7 @@ std::string GetMediaTitlePath(Service::FS::MediaType media_type) {
return ""; return "";
} }
void ScanForTitles(Service::FS::MediaType media_type) { void Module::ScanForTitles(Service::FS::MediaType media_type) {
am_title_list[static_cast<u32>(media_type)].clear(); am_title_list[static_cast<u32>(media_type)].clear();
std::string title_path = GetMediaTitlePath(media_type); std::string title_path = GetMediaTitlePath(media_type);
@ -473,31 +465,33 @@ void ScanForTitles(Service::FS::MediaType media_type) {
} }
} }
void ScanForAllTitles() { void Module::ScanForAllTitles() {
ScanForTitles(Service::FS::MediaType::NAND); ScanForTitles(Service::FS::MediaType::NAND);
ScanForTitles(Service::FS::MediaType::SDMC); ScanForTitles(Service::FS::MediaType::SDMC);
} }
void GetNumPrograms(Service::Interface* self) { Module::Interface::Interface(std::shared_ptr<Module> am, const char* name, u32 max_session)
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1, 1, 0); // 0x00010040 : ServiceFramework(name, max_session), am(std::move(am)) {}
Module::Interface::~Interface() = default;
void Module::Interface::GetNumPrograms(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(ctx, 0x0001, 1, 0); // 0x00010040
u32 media_type = rp.Pop<u8>(); u32 media_type = rp.Pop<u8>();
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.Push<u32>(am_title_list[media_type].size()); rb.Push<u32>(am->am_title_list[media_type].size());
} }
void FindDLCContentInfos(Service::Interface* self) { void Module::Interface::FindDLCContentInfos(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1002, 4, 4); // 0x10020104 IPC::RequestParser rp(ctx, 0x1002, 4, 4); // 0x10020104
auto media_type = static_cast<Service::FS::MediaType>(rp.Pop<u8>()); auto media_type = static_cast<Service::FS::MediaType>(rp.Pop<u8>());
u64 title_id = rp.Pop<u64>(); u64 title_id = rp.Pop<u64>();
u32 content_count = rp.Pop<u32>(); u32 content_count = rp.Pop<u32>();
auto& content_requested_in = rp.PopMappedBuffer();
size_t input_buffer_size, output_buffer_size; auto& content_info_out = rp.PopMappedBuffer();
IPC::MappedBufferPermissions input_buffer_perms, output_buffer_perms;
VAddr content_requested_in = rp.PopMappedBuffer(&input_buffer_size, &input_buffer_perms);
VAddr content_info_out = rp.PopMappedBuffer(&output_buffer_size, &output_buffer_perms);
// Validate that only DLC TIDs are passed in // Validate that only DLC TIDs are passed in
u32 tid_high = static_cast<u32>(title_id >> 32); u32 tid_high = static_cast<u32>(title_id >> 32);
@ -505,19 +499,20 @@ void FindDLCContentInfos(Service::Interface* self) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 4); IPC::RequestBuilder rb = rp.MakeBuilder(1, 4);
rb.Push(ResultCode(ErrCodes::InvalidTIDInList, ErrorModule::AM, rb.Push(ResultCode(ErrCodes::InvalidTIDInList, ErrorModule::AM,
ErrorSummary::InvalidArgument, ErrorLevel::Usage)); ErrorSummary::InvalidArgument, ErrorLevel::Usage));
rb.PushMappedBuffer(content_requested_in, input_buffer_size, input_buffer_perms); rb.PushMappedBuffer(content_requested_in);
rb.PushMappedBuffer(content_info_out, output_buffer_size, output_buffer_perms); rb.PushMappedBuffer(content_info_out);
return; return;
} }
std::vector<u16_le> content_requested(content_count); std::vector<u16_le> content_requested(content_count);
Memory::ReadBlock(content_requested_in, content_requested.data(), content_count * sizeof(u16)); content_requested_in.Read(content_requested.data(), 0, content_count * sizeof(u16));
std::string tmd_path = GetTitleMetadataPath(media_type, title_id); std::string tmd_path = GetTitleMetadataPath(media_type, title_id);
u32 content_read = 0; u32 content_read = 0;
FileSys::TitleMetadata tmd; FileSys::TitleMetadata tmd;
if (tmd.Load(tmd_path) == Loader::ResultStatus::Success) { if (tmd.Load(tmd_path) == Loader::ResultStatus::Success) {
std::size_t write_offset = 0;
// Get info for each content index requested // Get info for each content index requested
for (size_t i = 0; i < content_count; i++) { for (size_t i = 0; i < content_count; i++) {
std::shared_ptr<FileUtil::IOFile> romfs_file; std::shared_ptr<FileUtil::IOFile> romfs_file;
@ -534,29 +529,26 @@ void FindDLCContentInfos(Service::Interface* self) {
content_info.size = tmd.GetContentSizeByIndex(content_requested[i]); content_info.size = tmd.GetContentSizeByIndex(content_requested[i]);
content_info.romfs_size = romfs_size; content_info.romfs_size = romfs_size;
Memory::WriteBlock(content_info_out, &content_info, sizeof(ContentInfo)); content_info_out.Write(&content_info, write_offset, sizeof(ContentInfo));
content_info_out += sizeof(ContentInfo); write_offset += sizeof(ContentInfo);
content_read++; content_read++;
} }
} }
IPC::RequestBuilder rb = rp.MakeBuilder(1, 4); IPC::RequestBuilder rb = rp.MakeBuilder(1, 4);
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.PushMappedBuffer(content_requested_in, input_buffer_size, input_buffer_perms); rb.PushMappedBuffer(content_requested_in);
rb.PushMappedBuffer(content_info_out, output_buffer_size, output_buffer_perms); rb.PushMappedBuffer(content_info_out);
} }
void ListDLCContentInfos(Service::Interface* self) { void Module::Interface::ListDLCContentInfos(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1003, 5, 2); // 0x10030142 IPC::RequestParser rp(ctx, 0x1003, 5, 2); // 0x10030142
u32 content_count = rp.Pop<u32>(); u32 content_count = rp.Pop<u32>();
auto media_type = static_cast<Service::FS::MediaType>(rp.Pop<u8>()); auto media_type = static_cast<Service::FS::MediaType>(rp.Pop<u8>());
u64 title_id = rp.Pop<u64>(); u64 title_id = rp.Pop<u64>();
u32 start_index = rp.Pop<u32>(); u32 start_index = rp.Pop<u32>();
auto& content_info_out = rp.PopMappedBuffer();
size_t output_buffer_size;
IPC::MappedBufferPermissions output_buffer_perms;
VAddr content_info_out = rp.PopMappedBuffer(&output_buffer_size, &output_buffer_perms);
// Validate that only DLC TIDs are passed in // Validate that only DLC TIDs are passed in
u32 tid_high = static_cast<u32>(title_id >> 32); u32 tid_high = static_cast<u32>(title_id >> 32);
@ -565,7 +557,7 @@ void ListDLCContentInfos(Service::Interface* self) {
rb.Push(ResultCode(ErrCodes::InvalidTIDInList, ErrorModule::AM, rb.Push(ResultCode(ErrCodes::InvalidTIDInList, ErrorModule::AM,
ErrorSummary::InvalidArgument, ErrorLevel::Usage)); ErrorSummary::InvalidArgument, ErrorLevel::Usage));
rb.Push<u32>(0); rb.Push<u32>(0);
rb.PushMappedBuffer(content_info_out, output_buffer_size, output_buffer_perms); rb.PushMappedBuffer(content_info_out);
return; return;
} }
@ -575,6 +567,7 @@ void ListDLCContentInfos(Service::Interface* self) {
FileSys::TitleMetadata tmd; FileSys::TitleMetadata tmd;
if (tmd.Load(tmd_path) == Loader::ResultStatus::Success) { if (tmd.Load(tmd_path) == Loader::ResultStatus::Success) {
copied = std::min(content_count, static_cast<u32>(tmd.GetContentCount())); copied = std::min(content_count, static_cast<u32>(tmd.GetContentCount()));
std::size_t write_offset = 0;
for (u32 i = start_index; i < copied; i++) { for (u32 i = start_index; i < copied; i++) {
std::shared_ptr<FileUtil::IOFile> romfs_file; std::shared_ptr<FileUtil::IOFile> romfs_file;
u64 romfs_offset = 0; u64 romfs_offset = 0;
@ -590,58 +583,61 @@ void ListDLCContentInfos(Service::Interface* self) {
content_info.size = tmd.GetContentSizeByIndex(i); content_info.size = tmd.GetContentSizeByIndex(i);
content_info.romfs_size = romfs_size; content_info.romfs_size = romfs_size;
Memory::WriteBlock(content_info_out, &content_info, sizeof(ContentInfo)); content_info_out.Write(&content_info, write_offset, sizeof(ContentInfo));
content_info_out += sizeof(ContentInfo); write_offset += sizeof(ContentInfo);
} }
} }
IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.Push(copied); rb.Push(copied);
rb.PushMappedBuffer(content_info_out, output_buffer_size, output_buffer_perms); rb.PushMappedBuffer(content_info_out);
} }
void DeleteContents(Service::Interface* self) { void Module::Interface::DeleteContents(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1004, 4, 2); // 0x10040102 IPC::RequestParser rp(ctx, 0x1004, 4, 2); // 0x10040102
u8 media_type = rp.Pop<u8>(); u8 media_type = rp.Pop<u8>();
u64 title_id = rp.Pop<u64>(); u64 title_id = rp.Pop<u64>();
u32 content_count = rp.Pop<u32>(); u32 content_count = rp.Pop<u32>();
VAddr content_ids_in = rp.PopMappedBuffer(nullptr); auto& content_ids_in = rp.PopMappedBuffer();
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, title_id=0x%016" PRIx64 rb.PushMappedBuffer(content_ids_in);
", content_count=%u, content_ids_in=0x%08x", LOG_WARNING(Service_AM, "(STUBBED) media_type=%u, title_id=0x%016" PRIx64 ", content_count=%u",
media_type, title_id, content_count, content_ids_in); media_type, title_id, content_count);
} }
void GetProgramList(Service::Interface* self) { void Module::Interface::GetProgramList(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 2, 2, 2); // 0x00020082 IPC::RequestParser rp(ctx, 0x0002, 2, 2); // 0x00020082
u32 count = rp.Pop<u32>(); u32 count = rp.Pop<u32>();
u8 media_type = rp.Pop<u8>(); u8 media_type = rp.Pop<u8>();
VAddr title_ids_output_pointer = rp.PopMappedBuffer(nullptr); auto& title_ids_output = rp.PopMappedBuffer();
if (!Memory::IsValidVirtualAddress(title_ids_output_pointer) || media_type > 2) { if (media_type > 2) {
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
rb.Push<u32>(-1); // TODO(shinyquagsire23): Find the right error code rb.Push<u32>(-1); // TODO(shinyquagsire23): Find the right error code
rb.Push<u32>(0); rb.Push<u32>(0);
rb.PushMappedBuffer(title_ids_output);
return; return;
} }
u32 media_count = static_cast<u32>(am_title_list[media_type].size()); u32 media_count = static_cast<u32>(am->am_title_list[media_type].size());
u32 copied = std::min(media_count, count); u32 copied = std::min(media_count, count);
Memory::WriteBlock(title_ids_output_pointer, am_title_list[media_type].data(), title_ids_output.Write(am->am_title_list[media_type].data(), 0, copied * sizeof(u64));
copied * sizeof(u64));
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.Push(copied); rb.Push(copied);
rb.PushMappedBuffer(title_ids_output);
} }
ResultCode GetTitleInfoFromList(const std::vector<u64>& title_id_list, ResultCode GetTitleInfoFromList(const std::vector<u64>& title_id_list,
Service::FS::MediaType media_type, VAddr title_info_out) { Service::FS::MediaType media_type,
Kernel::MappedBuffer& title_info_out) {
std::size_t write_offset = 0;
for (u32 i = 0; i < title_id_list.size(); i++) { for (u32 i = 0; i < title_id_list.size(); i++) {
std::string tmd_path = GetTitleMetadataPath(media_type, title_id_list[i]); std::string tmd_path = GetTitleMetadataPath(media_type, title_id_list[i]);
@ -659,37 +655,34 @@ ResultCode GetTitleInfoFromList(const std::vector<u64>& title_id_list,
return ResultCode(ErrorDescription::NotFound, ErrorModule::AM, return ResultCode(ErrorDescription::NotFound, ErrorModule::AM,
ErrorSummary::InvalidState, ErrorLevel::Permanent); ErrorSummary::InvalidState, ErrorLevel::Permanent);
} }
Memory::WriteBlock(title_info_out, &title_info, sizeof(TitleInfo)); title_info_out.Write(&title_info, write_offset, sizeof(TitleInfo));
title_info_out += sizeof(TitleInfo); write_offset += sizeof(TitleInfo);
} }
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }
void GetProgramInfos(Service::Interface* self) { void Module::Interface::GetProgramInfos(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 3, 2, 4); // 0x00030084 IPC::RequestParser rp(ctx, 0x0003, 2, 4); // 0x00030084
auto media_type = static_cast<Service::FS::MediaType>(rp.Pop<u8>()); auto media_type = static_cast<Service::FS::MediaType>(rp.Pop<u8>());
u32 title_count = rp.Pop<u32>(); u32 title_count = rp.Pop<u32>();
auto& title_id_list_buffer = rp.PopMappedBuffer();
size_t title_id_list_size, title_info_size; auto& title_info_out = rp.PopMappedBuffer();
IPC::MappedBufferPermissions title_id_list_perms, title_info_perms;
VAddr title_id_list_pointer = rp.PopMappedBuffer(&title_id_list_size, &title_id_list_perms);
VAddr title_info_out = rp.PopMappedBuffer(&title_info_size, &title_info_perms);
std::vector<u64> title_id_list(title_count); std::vector<u64> title_id_list(title_count);
Memory::ReadBlock(title_id_list_pointer, title_id_list.data(), title_count * sizeof(u64)); title_id_list_buffer.Read(title_id_list.data(), 0, title_count * sizeof(u64));
ResultCode result = GetTitleInfoFromList(title_id_list, media_type, title_info_out); ResultCode result = GetTitleInfoFromList(title_id_list, media_type, title_info_out);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 4); IPC::RequestBuilder rb = rp.MakeBuilder(1, 4);
rb.Push(result); rb.Push(result);
rb.PushMappedBuffer(title_id_list_pointer, title_id_list_size, title_id_list_perms); rb.PushMappedBuffer(title_id_list_buffer);
rb.PushMappedBuffer(title_info_out, title_info_size, title_info_perms); rb.PushMappedBuffer(title_info_out);
} }
void DeleteUserProgram(Service::Interface* self) { void Module::Interface::DeleteUserProgram(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x000400, 3, 0); IPC::RequestParser rp(ctx, 0x0004, 3, 0);
auto media_type = rp.PopEnum<FS::MediaType>(); auto media_type = rp.PopEnum<FS::MediaType>();
u32 low = rp.Pop<u32>(); u32 low = rp.Pop<u32>();
u32 high = rp.Pop<u32>(); u32 high = rp.Pop<u32>();
@ -712,25 +705,22 @@ void DeleteUserProgram(Service::Interface* self) {
return; return;
} }
bool success = FileUtil::DeleteDirRecursively(path); bool success = FileUtil::DeleteDirRecursively(path);
ScanForAllTitles(); am->ScanForAllTitles();
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
if (!success) if (!success)
LOG_ERROR(Service_AM, "FileUtil::DeleteDirRecursively unexpectedly failed"); LOG_ERROR(Service_AM, "FileUtil::DeleteDirRecursively unexpectedly failed");
} }
void GetDLCTitleInfos(Service::Interface* self) { void Module::Interface::GetDLCTitleInfos(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1005, 2, 4); // 0x10050084 IPC::RequestParser rp(ctx, 0x1005, 2, 4); // 0x10050084
auto media_type = static_cast<Service::FS::MediaType>(rp.Pop<u8>()); auto media_type = static_cast<Service::FS::MediaType>(rp.Pop<u8>());
u32 title_count = rp.Pop<u32>(); u32 title_count = rp.Pop<u32>();
auto& title_id_list_buffer = rp.PopMappedBuffer();
size_t title_id_list_size, title_info_size; auto& title_info_out = rp.PopMappedBuffer();
IPC::MappedBufferPermissions title_id_list_perms, title_info_perms;
VAddr title_id_list_pointer = rp.PopMappedBuffer(&title_id_list_size, &title_id_list_perms);
VAddr title_info_out = rp.PopMappedBuffer(&title_info_size, &title_info_perms);
std::vector<u64> title_id_list(title_count); std::vector<u64> title_id_list(title_count);
Memory::ReadBlock(title_id_list_pointer, title_id_list.data(), title_count * sizeof(u64)); title_id_list_buffer.Read(title_id_list.data(), 0, title_count * sizeof(u64));
ResultCode result = RESULT_SUCCESS; ResultCode result = RESULT_SUCCESS;
@ -750,23 +740,20 @@ void GetDLCTitleInfos(Service::Interface* self) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 4); IPC::RequestBuilder rb = rp.MakeBuilder(1, 4);
rb.Push(result); rb.Push(result);
rb.PushMappedBuffer(title_id_list_pointer, title_id_list_size, title_id_list_perms); rb.PushMappedBuffer(title_id_list_buffer);
rb.PushMappedBuffer(title_info_out, title_info_size, title_info_perms); rb.PushMappedBuffer(title_info_out);
} }
void GetPatchTitleInfos(Service::Interface* self) { void Module::Interface::GetPatchTitleInfos(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x100D, 2, 4); // 0x100D0084 IPC::RequestParser rp(ctx, 0x100D, 2, 4); // 0x100D0084
auto media_type = static_cast<Service::FS::MediaType>(rp.Pop<u8>()); auto media_type = static_cast<Service::FS::MediaType>(rp.Pop<u8>());
u32 title_count = rp.Pop<u32>(); u32 title_count = rp.Pop<u32>();
auto& title_id_list_buffer = rp.PopMappedBuffer();
size_t title_id_list_size, title_info_size; auto& title_info_out = rp.PopMappedBuffer();
IPC::MappedBufferPermissions title_id_list_perms, title_info_perms;
VAddr title_id_list_pointer = rp.PopMappedBuffer(&title_id_list_size, &title_id_list_perms);
VAddr title_info_out = rp.PopMappedBuffer(&title_info_size, &title_info_perms);
std::vector<u64> title_id_list(title_count); std::vector<u64> title_id_list(title_count);
Memory::ReadBlock(title_id_list_pointer, title_id_list.data(), title_count * sizeof(u64)); title_id_list_buffer.Read(title_id_list.data(), 0, title_count * sizeof(u64));
ResultCode result = RESULT_SUCCESS; ResultCode result = RESULT_SUCCESS;
@ -786,39 +773,40 @@ void GetPatchTitleInfos(Service::Interface* self) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 4); IPC::RequestBuilder rb = rp.MakeBuilder(1, 4);
rb.Push(result); rb.Push(result);
rb.PushMappedBuffer(title_id_list_pointer, title_id_list_size, title_id_list_perms); rb.PushMappedBuffer(title_id_list_buffer);
rb.PushMappedBuffer(title_info_out, title_info_size, title_info_perms); rb.PushMappedBuffer(title_info_out);
} }
void ListDataTitleTicketInfos(Service::Interface* self) { void Module::Interface::ListDataTitleTicketInfos(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1007, 4, 4); // 0x10070102 IPC::RequestParser rp(ctx, 0x1007, 4, 2); // 0x10070102
u32 ticket_count = rp.Pop<u32>(); u32 ticket_count = rp.Pop<u32>();
u64 title_id = rp.Pop<u64>(); u64 title_id = rp.Pop<u64>();
u32 start_index = rp.Pop<u32>(); u32 start_index = rp.Pop<u32>();
VAddr ticket_info_out = rp.PopMappedBuffer(nullptr); auto& ticket_info_out = rp.PopMappedBuffer();
VAddr ticket_info_write = ticket_info_out;
std::size_t write_offset = 0;
for (u32 i = 0; i < ticket_count; i++) { for (u32 i = 0; i < ticket_count; i++) {
TicketInfo ticket_info = {}; TicketInfo ticket_info = {};
ticket_info.title_id = title_id; ticket_info.title_id = title_id;
ticket_info.version = 0; // TODO ticket_info.version = 0; // TODO
ticket_info.size = 0; // TODO ticket_info.size = 0; // TODO
Memory::WriteBlock(ticket_info_write, &ticket_info, sizeof(TicketInfo)); ticket_info_out.Write(&ticket_info, write_offset, sizeof(TicketInfo));
ticket_info_write += sizeof(TicketInfo); write_offset += sizeof(TicketInfo);
} }
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.Push(ticket_count); rb.Push(ticket_count);
rb.PushMappedBuffer(ticket_info_out);
LOG_WARNING(Service_AM, "(STUBBED) ticket_count=0x%08X, title_id=0x%016" PRIx64 LOG_WARNING(Service_AM,
", start_index=0x%08X, ticket_info_out=0x%08X", "(STUBBED) ticket_count=0x%08X, title_id=0x%016" PRIx64 ", start_index=0x%08X",
ticket_count, title_id, start_index, ticket_info_out); ticket_count, title_id, start_index);
} }
void GetDLCContentInfoCount(Service::Interface* self) { void Module::Interface::GetDLCContentInfoCount(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x1001, 3, 0); // 0x100100C0 IPC::RequestParser rp(ctx, 0x1001, 3, 0); // 0x100100C0
auto media_type = static_cast<Service::FS::MediaType>(rp.Pop<u8>()); auto media_type = static_cast<Service::FS::MediaType>(rp.Pop<u8>());
u64 title_id = rp.Pop<u64>(); u64 title_id = rp.Pop<u64>();
@ -847,8 +835,8 @@ void GetDLCContentInfoCount(Service::Interface* self) {
} }
} }
void DeleteTicket(Service::Interface* self) { void Module::Interface::DeleteTicket(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 7, 2, 0); // 0x00070080 IPC::RequestParser rp(ctx, 0x0007, 2, 0); // 0x00070080
u64 title_id = rp.Pop<u64>(); u64 title_id = rp.Pop<u64>();
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
@ -856,8 +844,8 @@ void DeleteTicket(Service::Interface* self) {
LOG_WARNING(Service_AM, "(STUBBED) called title_id=0x%016" PRIx64 "", title_id); LOG_WARNING(Service_AM, "(STUBBED) called title_id=0x%016" PRIx64 "", title_id);
} }
void GetNumTickets(Service::Interface* self) { void Module::Interface::GetNumTickets(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 8, 0, 0); // 0x00080000 IPC::RequestParser rp(ctx, 0x0008, 0, 0); // 0x00080000
u32 ticket_count = 0; u32 ticket_count = 0;
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
@ -866,22 +854,22 @@ void GetNumTickets(Service::Interface* self) {
LOG_WARNING(Service_AM, "(STUBBED) called ticket_count=0x%08x", ticket_count); LOG_WARNING(Service_AM, "(STUBBED) called ticket_count=0x%08x", ticket_count);
} }
void GetTicketList(Service::Interface* self) { void Module::Interface::GetTicketList(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 9, 2, 2); // 0x00090082 IPC::RequestParser rp(ctx, 0x0009, 2, 2); // 0x00090082
u32 ticket_list_count = rp.Pop<u32>(); u32 ticket_list_count = rp.Pop<u32>();
u32 ticket_index = rp.Pop<u32>(); u32 ticket_index = rp.Pop<u32>();
VAddr ticket_tids_out = rp.PopMappedBuffer(nullptr); auto& ticket_tids_out = rp.PopMappedBuffer();
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.Push(ticket_list_count); rb.Push(ticket_list_count);
LOG_WARNING(Service_AM, rb.PushMappedBuffer(ticket_tids_out);
"(STUBBED) ticket_list_count=0x%08x, ticket_index=0x%08x, ticket_tids_out=0x%08x", LOG_WARNING(Service_AM, "(STUBBED) ticket_list_count=0x%08x, ticket_index=0x%08x",
ticket_list_count, ticket_index, ticket_tids_out); ticket_list_count, ticket_index);
} }
void QueryAvailableTitleDatabase(Service::Interface* self) { void Module::Interface::QueryAvailableTitleDatabase(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x19, 1, 0); // 0x190040 IPC::RequestParser rp(ctx, 0x0019, 1, 0); // 0x190040
u8 media_type = rp.Pop<u8>(); u8 media_type = rp.Pop<u8>();
IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0);
@ -891,8 +879,8 @@ void QueryAvailableTitleDatabase(Service::Interface* self) {
LOG_WARNING(Service_AM, "(STUBBED) media_type=%u", media_type); LOG_WARNING(Service_AM, "(STUBBED) media_type=%u", media_type);
} }
void CheckContentRights(Service::Interface* self) { void Module::Interface::CheckContentRights(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x25, 3, 0); // 0x2500C0 IPC::RequestParser rp(ctx, 0x0025, 3, 0); // 0x2500C0
u64 tid = rp.Pop<u64>(); u64 tid = rp.Pop<u64>();
u16 content_index = rp.Pop<u16>(); u16 content_index = rp.Pop<u16>();
@ -907,8 +895,8 @@ void CheckContentRights(Service::Interface* self) {
LOG_WARNING(Service_AM, "(STUBBED) tid=%016" PRIx64 ", content_index=%u", tid, content_index); LOG_WARNING(Service_AM, "(STUBBED) tid=%016" PRIx64 ", content_index=%u", tid, content_index);
} }
void CheckContentRightsIgnorePlatform(Service::Interface* self) { void Module::Interface::CheckContentRightsIgnorePlatform(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x2D, 3, 0); // 0x2D00C0 IPC::RequestParser rp(ctx, 0x002D, 3, 0); // 0x2D00C0
u64 tid = rp.Pop<u64>(); u64 tid = rp.Pop<u64>();
u16 content_index = rp.Pop<u16>(); u16 content_index = rp.Pop<u16>();
@ -923,11 +911,11 @@ void CheckContentRightsIgnorePlatform(Service::Interface* self) {
LOG_WARNING(Service_AM, "(STUBBED) tid=%016" PRIx64 ", content_index=%u", tid, content_index); LOG_WARNING(Service_AM, "(STUBBED) tid=%016" PRIx64 ", content_index=%u", tid, content_index);
} }
void BeginImportProgram(Service::Interface* self) { void Module::Interface::BeginImportProgram(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0402, 1, 0); // 0x04020040 IPC::RequestParser rp(ctx, 0x0402, 1, 0); // 0x04020040
auto media_type = static_cast<Service::FS::MediaType>(rp.Pop<u8>()); auto media_type = static_cast<Service::FS::MediaType>(rp.Pop<u8>());
if (cia_installing) { if (am->cia_installing) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(ResultCode(ErrCodes::CIACurrentlyInstalling, ErrorModule::AM, rb.Push(ResultCode(ErrCodes::CIACurrentlyInstalling, ErrorModule::AM,
ErrorSummary::InvalidState, ErrorLevel::Permanent)); ErrorSummary::InvalidState, ErrorLevel::Permanent));
@ -940,33 +928,32 @@ void BeginImportProgram(Service::Interface* self) {
auto file = auto file =
std::make_shared<Service::FS::File>(std::make_unique<CIAFile>(media_type), cia_path); std::make_shared<Service::FS::File>(std::make_unique<CIAFile>(media_type), cia_path);
cia_installing = true; am->cia_installing = true;
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
rb.Push(RESULT_SUCCESS); // No error rb.Push(RESULT_SUCCESS); // No error
rb.PushCopyHandles(Kernel::g_handle_table.Create(file->Connect()).Unwrap()); rb.PushCopyObjects(file->Connect());
LOG_WARNING(Service_AM, "(STUBBED) media_type=%u", static_cast<u32>(media_type)); LOG_WARNING(Service_AM, "(STUBBED) media_type=%u", static_cast<u32>(media_type));
} }
void EndImportProgram(Service::Interface* self) { void Module::Interface::EndImportProgram(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0405, 0, 2); // 0x04050002 IPC::RequestParser rp(ctx, 0x0405, 0, 2); // 0x04050002
auto cia_handle = rp.PopHandle(); auto cia = rp.PopObject<Kernel::ClientSession>();
Kernel::g_handle_table.Close(cia_handle); am->ScanForAllTitles();
ScanForAllTitles();
cia_installing = false; am->cia_installing = false;
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
} }
ResultVal<std::shared_ptr<Service::FS::File>> GetFileFromHandle(Kernel::Handle handle) { ResultVal<std::shared_ptr<Service::FS::File>> GetFileFromSession(
// Step up the chain from Handle->ClientSession->ServerSession and then Kernel::SharedPtr<Kernel::ClientSession> file_session) {
// Step up the chain from ClientSession->ServerSession and then
// cast to File. For AM on 3DS, invalid handles actually hang the system. // cast to File. For AM on 3DS, invalid handles actually hang the system.
auto file_session = Kernel::g_handle_table.Get<Kernel::ClientSession>(handle);
if (file_session == nullptr || file_session->parent == nullptr) { if (file_session->parent == nullptr) {
LOG_WARNING(Service_AM, "Invalid file handle!"); LOG_WARNING(Service_AM, "Invalid file handle!");
return Kernel::ERR_INVALID_HANDLE; return Kernel::ERR_INVALID_HANDLE;
} }
@ -994,12 +981,12 @@ ResultVal<std::shared_ptr<Service::FS::File>> GetFileFromHandle(Kernel::Handle h
return Kernel::ERR_NOT_IMPLEMENTED; return Kernel::ERR_NOT_IMPLEMENTED;
} }
void GetProgramInfoFromCia(Service::Interface* self) { void Module::Interface::GetProgramInfoFromCia(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0408, 1, 2); // 0x04080042 IPC::RequestParser rp(ctx, 0x0408, 1, 2); // 0x04080042
auto media_type = static_cast<Service::FS::MediaType>(rp.Pop<u8>()); auto media_type = static_cast<Service::FS::MediaType>(rp.Pop<u8>());
auto cia = rp.PopObject<Kernel::ClientSession>();
// Get a File from our Handle auto file_res = GetFileFromSession(cia);
auto file_res = GetFileFromHandle(rp.PopHandle());
if (!file_res.Succeeded()) { if (!file_res.Succeeded()) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(file_res.Code()); rb.Push(file_res.Code());
@ -1032,65 +1019,61 @@ void GetProgramInfoFromCia(Service::Interface* self) {
rb.PushRaw<TitleInfo>(title_info); rb.PushRaw<TitleInfo>(title_info);
} }
void GetSystemMenuDataFromCia(Service::Interface* self) { void Module::Interface::GetSystemMenuDataFromCia(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0409, 0, 4); // 0x04090004 IPC::RequestParser rp(ctx, 0x0409, 0, 4); // 0x04090004
auto cia = rp.PopObject<Kernel::ClientSession>();
auto& output_buffer = rp.PopMappedBuffer();
// Get a File from our Handle auto file_res = GetFileFromSession(cia);
auto file_res = GetFileFromHandle(rp.PopHandle());
if (!file_res.Succeeded()) { if (!file_res.Succeeded()) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
rb.Push(file_res.Code()); rb.Push(file_res.Code());
rb.PushMappedBuffer(output_buffer);
return; return;
} }
size_t output_buffer_size; std::size_t output_buffer_size = std::min(output_buffer.GetSize(), sizeof(Loader::SMDH));
IPC::MappedBufferPermissions output_buffer_perms;
VAddr output_buffer = rp.PopMappedBuffer(&output_buffer_size, &output_buffer_perms);
output_buffer_size = std::min(output_buffer_size, sizeof(Loader::SMDH));
auto file = file_res.Unwrap(); auto file = file_res.Unwrap();
FileSys::CIAContainer container; FileSys::CIAContainer container;
if (container.Load(*file->backend) != Loader::ResultStatus::Success) { if (container.Load(*file->backend) != Loader::ResultStatus::Success) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
rb.Push(ResultCode(ErrCodes::InvalidCIAHeader, ErrorModule::AM, rb.Push(ResultCode(ErrCodes::InvalidCIAHeader, ErrorModule::AM,
ErrorSummary::InvalidArgument, ErrorLevel::Permanent)); ErrorSummary::InvalidArgument, ErrorLevel::Permanent));
rb.PushMappedBuffer(output_buffer);
return; return;
} }
std::vector<u8> temp(output_buffer_size); std::vector<u8> temp(output_buffer_size);
// Read from the Meta offset + 0x400 for the 0x36C0-large SMDH // Read from the Meta offset + 0x400 for the 0x36C0-large SMDH
auto read_result = auto read_result = file->backend->Read(
file->backend->Read(container.GetMetadataOffset() + FileSys::CIA_METADATA_SIZE, container.GetMetadataOffset() + FileSys::CIA_METADATA_SIZE, temp.size(), temp.data());
output_buffer_size, temp.data()); if (read_result.Failed() || *read_result != temp.size()) {
if (read_result.Failed() || *read_result != output_buffer_size) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(ResultCode(ErrCodes::InvalidCIAHeader, ErrorModule::AM, rb.Push(ResultCode(ErrCodes::InvalidCIAHeader, ErrorModule::AM,
ErrorSummary::InvalidArgument, ErrorLevel::Permanent)); ErrorSummary::InvalidArgument, ErrorLevel::Permanent));
rb.PushMappedBuffer(output_buffer);
return; return;
} }
Memory::WriteBlock(output_buffer, temp.data(), output_buffer_size); output_buffer.Write(temp.data(), 0, temp.size());
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
rb.PushMappedBuffer(output_buffer, output_buffer_size, output_buffer_perms);
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.PushMappedBuffer(output_buffer);
} }
void GetDependencyListFromCia(Service::Interface* self) { void Module::Interface::GetDependencyListFromCia(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x040A, 0, 2); // 0x040A0002 IPC::RequestParser rp(ctx, 0x040A, 0, 2); // 0x040A0002
auto cia = rp.PopObject<Kernel::ClientSession>();
// Get a File from our Handle auto file_res = GetFileFromSession(cia);
auto file_res = GetFileFromHandle(rp.PopHandle());
if (!file_res.Succeeded()) { if (!file_res.Succeeded()) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(file_res.Code()); rb.Push(file_res.Code());
return; return;
} }
size_t output_buffer_size;
VAddr output_buffer = rp.PeekStaticBuffer(0, &output_buffer_size);
output_buffer_size = std::min(output_buffer_size, FileSys::CIA_DEPENDENCY_SIZE);
auto file = file_res.Unwrap(); auto file = file_res.Unwrap();
FileSys::CIAContainer container; FileSys::CIAContainer container;
if (container.Load(*file->backend) != Loader::ResultStatus::Success) { if (container.Load(*file->backend) != Loader::ResultStatus::Success) {
@ -1100,18 +1083,19 @@ void GetDependencyListFromCia(Service::Interface* self) {
return; return;
} }
Memory::WriteBlock(output_buffer, container.GetDependencies().data(), output_buffer_size); std::vector<u8> buffer(FileSys::CIA_DEPENDENCY_SIZE);
std::memcpy(buffer.data(), container.GetDependencies().data(), buffer.size());
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.PushStaticBuffer(output_buffer, output_buffer_size, 0); rb.PushStaticBuffer(buffer, 0);
} }
void GetTransferSizeFromCia(Service::Interface* self) { void Module::Interface::GetTransferSizeFromCia(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x040B, 0, 2); // 0x040B0002 IPC::RequestParser rp(ctx, 0x040B, 0, 2); // 0x040B0002
auto cia = rp.PopObject<Kernel::ClientSession>();
// Get a File from our Handle auto file_res = GetFileFromSession(cia);
auto file_res = GetFileFromHandle(rp.PopHandle());
if (!file_res.Succeeded()) { if (!file_res.Succeeded()) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(file_res.Code()); rb.Push(file_res.Code());
@ -1132,11 +1116,11 @@ void GetTransferSizeFromCia(Service::Interface* self) {
rb.Push(container.GetMetadataOffset()); rb.Push(container.GetMetadataOffset());
} }
void GetCoreVersionFromCia(Service::Interface* self) { void Module::Interface::GetCoreVersionFromCia(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x040C, 0, 2); // 0x040C0002 IPC::RequestParser rp(ctx, 0x040C, 0, 2); // 0x040C0002
auto cia = rp.PopObject<Kernel::ClientSession>();
// Get a File from our Handle auto file_res = GetFileFromSession(cia);
auto file_res = GetFileFromHandle(rp.PopHandle());
if (!file_res.Succeeded()) { if (!file_res.Succeeded()) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(file_res.Code()); rb.Push(file_res.Code());
@ -1157,12 +1141,12 @@ void GetCoreVersionFromCia(Service::Interface* self) {
rb.Push(container.GetCoreVersion()); rb.Push(container.GetCoreVersion());
} }
void GetRequiredSizeFromCia(Service::Interface* self) { void Module::Interface::GetRequiredSizeFromCia(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x040D, 1, 2); // 0x040D0042 IPC::RequestParser rp(ctx, 0x040D, 1, 2); // 0x040D0042
auto media_type = static_cast<Service::FS::MediaType>(rp.Pop<u8>()); auto media_type = static_cast<Service::FS::MediaType>(rp.Pop<u8>());
auto cia = rp.PopObject<Kernel::ClientSession>();
// Get a File from our Handle auto file_res = GetFileFromSession(cia);
auto file_res = GetFileFromHandle(rp.PopHandle());
if (!file_res.Succeeded()) { if (!file_res.Succeeded()) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(file_res.Code()); rb.Push(file_res.Code());
@ -1186,8 +1170,8 @@ void GetRequiredSizeFromCia(Service::Interface* self) {
rb.Push(container.GetTitleMetadata().GetContentSizeByIndex(FileSys::TMDContentIndex::Main)); rb.Push(container.GetTitleMetadata().GetContentSizeByIndex(FileSys::TMDContentIndex::Main));
} }
void DeleteProgram(Service::Interface* self) { void Module::Interface::DeleteProgram(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0410, 3, 0); IPC::RequestParser rp(ctx, 0x0410, 3, 0);
auto media_type = rp.PopEnum<FS::MediaType>(); auto media_type = rp.PopEnum<FS::MediaType>();
u32 low = rp.Pop<u32>(); u32 low = rp.Pop<u32>();
u32 high = rp.Pop<u32>(); u32 high = rp.Pop<u32>();
@ -1202,17 +1186,17 @@ void DeleteProgram(Service::Interface* self) {
return; return;
} }
bool success = FileUtil::DeleteDirRecursively(path); bool success = FileUtil::DeleteDirRecursively(path);
ScanForAllTitles(); am->ScanForAllTitles();
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
if (!success) if (!success)
LOG_ERROR(Service_AM, "FileUtil::DeleteDirRecursively unexpectedly failed"); LOG_ERROR(Service_AM, "FileUtil::DeleteDirRecursively unexpectedly failed");
} }
void GetMetaSizeFromCia(Service::Interface* self) { void Module::Interface::GetMetaSizeFromCia(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0413, 0, 2); // 0x04130002 IPC::RequestParser rp(ctx, 0x0413, 0, 2); // 0x04130002
auto cia = rp.PopObject<Kernel::ClientSession>();
// Get a File from our Handle auto file_res = GetFileFromSession(cia);
auto file_res = GetFileFromHandle(rp.PopHandle());
if (!file_res.Succeeded()) { if (!file_res.Succeeded()) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
rb.Push(file_res.Code()); rb.Push(file_res.Code());
@ -1234,31 +1218,30 @@ void GetMetaSizeFromCia(Service::Interface* self) {
rb.Push(container.GetMetadataSize()); rb.Push(container.GetMetadataSize());
} }
void GetMetaDataFromCia(Service::Interface* self) { void Module::Interface::GetMetaDataFromCia(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x0414, 0, 2); // 0x04140044 IPC::RequestParser rp(ctx, 0x0414, 1, 4); // 0x04140044
u32 output_size = rp.Pop<u32>(); u32 output_size = rp.Pop<u32>();
auto cia = rp.PopObject<Kernel::ClientSession>();
auto& output_buffer = rp.PopMappedBuffer();
// Get a File from our Handle auto file_res = GetFileFromSession(cia);
auto file_res = GetFileFromHandle(rp.PopHandle());
if (!file_res.Succeeded()) { if (!file_res.Succeeded()) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
rb.Push(file_res.Code()); rb.Push(file_res.Code());
rb.PushMappedBuffer(output_buffer);
return; return;
} }
size_t output_buffer_size;
VAddr output_buffer = rp.PeekStaticBuffer(0, &output_buffer_size);
// Don't write beyond the actual static buffer size. // Don't write beyond the actual static buffer size.
output_size = std::min(static_cast<u32>(output_buffer_size), output_size); output_size = std::min(static_cast<u32>(output_buffer.GetSize()), output_size);
auto file = file_res.Unwrap(); auto file = file_res.Unwrap();
FileSys::CIAContainer container; FileSys::CIAContainer container;
if (container.Load(*file->backend) != Loader::ResultStatus::Success) { if (container.Load(*file->backend) != Loader::ResultStatus::Success) {
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
rb.Push(ResultCode(ErrCodes::InvalidCIAHeader, ErrorModule::AM, rb.Push(ResultCode(ErrCodes::InvalidCIAHeader, ErrorModule::AM,
ErrorSummary::InvalidArgument, ErrorLevel::Permanent)); ErrorSummary::InvalidArgument, ErrorLevel::Permanent));
rb.PushMappedBuffer(output_buffer);
return; return;
} }
@ -1272,23 +1255,24 @@ void GetMetaDataFromCia(Service::Interface* self) {
return; return;
} }
Memory::WriteBlock(output_buffer, temp.data(), output_size); output_buffer.Write(temp.data(), 0, output_size);
IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2);
rb.Push(RESULT_SUCCESS); rb.Push(RESULT_SUCCESS);
rb.PushStaticBuffer(output_buffer, output_buffer_size, 0); rb.PushMappedBuffer(output_buffer);
} }
void Init() { Module::Module() {
AddService(new AM_APP_Interface);
AddService(new AM_NET_Interface);
AddService(new AM_SYS_Interface);
AddService(new AM_U_Interface);
ScanForAllTitles(); ScanForAllTitles();
} }
void Shutdown() { Module::~Module() = default;
cia_installing = false;
void InstallInterfaces(SM::ServiceManager& service_manager) {
auto am = std::make_shared<Module>();
std::make_shared<AM_APP>(am)->InstallAsService(service_manager);
std::make_shared<AM_NET>(am)->InstallAsService(service_manager);
std::make_shared<AM_SYS>(am)->InstallAsService(service_manager);
std::make_shared<AM_U>(am)->InstallAsService(service_manager);
} }
} // namespace AM } // namespace AM

View File

@ -4,12 +4,15 @@
#pragma once #pragma once
#include <array>
#include <functional> #include <functional>
#include <string> #include <string>
#include <vector>
#include "common/common_types.h" #include "common/common_types.h"
#include "core/file_sys/cia_container.h" #include "core/file_sys/cia_container.h"
#include "core/file_sys/file_backend.h" #include "core/file_sys/file_backend.h"
#include "core/hle/result.h" #include "core/hle/result.h"
#include "core/hle/service/service.h"
namespace Service { namespace Service {
namespace FS { namespace FS {
@ -18,9 +21,6 @@ enum class MediaType : u32;
} }
namespace Service { namespace Service {
class Interface;
namespace AM { namespace AM {
namespace ErrCodes { namespace ErrCodes {
@ -138,18 +138,18 @@ std::string GetTitlePath(Service::FS::MediaType media_type, u64 tid);
*/ */
std::string GetMediaTitlePath(Service::FS::MediaType media_type); std::string GetMediaTitlePath(Service::FS::MediaType media_type);
/** class Module final {
* Scans the for titles in a storage medium for listing. public:
* @param media_type the storage medium to scan Module();
*/ ~Module();
void ScanForTitles(Service::FS::MediaType media_type);
/** class Interface : public ServiceFramework<Interface> {
* Scans all storage mediums for titles for listing. public:
*/ Interface(std::shared_ptr<Module> am, const char* name, u32 max_session);
void ScanForAllTitles(); ~Interface();
/** protected:
/**
* AM::GetNumPrograms service function * AM::GetNumPrograms service function
* Gets the number of installed titles in the requested media type * Gets the number of installed titles in the requested media type
* Inputs: * Inputs:
@ -159,9 +159,9 @@ void ScanForAllTitles();
* 1 : Result, 0 on success, otherwise error code * 1 : Result, 0 on success, otherwise error code
* 2 : The number of titles in the requested media type * 2 : The number of titles in the requested media type
*/ */
void GetNumPrograms(Service::Interface* self); void GetNumPrograms(Kernel::HLERequestContext& ctx);
/** /**
* AM::FindDLCContentInfos service function * AM::FindDLCContentInfos service function
* Explicitly checks that TID high value is 0004008C or an error is returned. * Explicitly checks that TID high value is 0004008C or an error is returned.
* Inputs: * Inputs:
@ -173,9 +173,9 @@ void GetNumPrograms(Service::Interface* self);
* Outputs: * Outputs:
* 1 : Result, 0 on success, otherwise error code * 1 : Result, 0 on success, otherwise error code
*/ */
void FindDLCContentInfos(Service::Interface* self); void FindDLCContentInfos(Kernel::HLERequestContext& ctx);
/** /**
* AM::ListDLCContentInfos service function * AM::ListDLCContentInfos service function
* Explicitly checks that TID high value is 0004008C or an error is returned. * Explicitly checks that TID high value is 0004008C or an error is returned.
* Inputs: * Inputs:
@ -188,9 +188,9 @@ void FindDLCContentInfos(Service::Interface* self);
* 1 : Result, 0 on success, otherwise error code * 1 : Result, 0 on success, otherwise error code
* 2 : Number of content infos returned * 2 : Number of content infos returned
*/ */
void ListDLCContentInfos(Service::Interface* self); void ListDLCContentInfos(Kernel::HLERequestContext& ctx);
/** /**
* AM::DeleteContents service function * AM::DeleteContents service function
* Inputs: * Inputs:
* 1 : MediaType * 1 : MediaType
@ -200,11 +200,12 @@ void ListDLCContentInfos(Service::Interface* self);
* Outputs: * Outputs:
* 1 : Result, 0 on success, otherwise error code * 1 : Result, 0 on success, otherwise error code
*/ */
void DeleteContents(Service::Interface* self); void DeleteContents(Kernel::HLERequestContext& ctx);
/** /**
* AM::GetProgramList service function * AM::GetProgramList service function
* Loads information about the desired number of titles from the desired media type into an array * Loads information about the desired number of titles from the desired media type into an
* array
* Inputs: * Inputs:
* 1 : Title count * 1 : Title count
* 2 : Media type to load the titles from * 2 : Media type to load the titles from
@ -213,9 +214,9 @@ void DeleteContents(Service::Interface* self);
* 1 : Result, 0 on success, otherwise error code * 1 : Result, 0 on success, otherwise error code
* 2 : The number of titles loaded from the requested media type * 2 : The number of titles loaded from the requested media type
*/ */
void GetProgramList(Service::Interface* self); void GetProgramList(Kernel::HLERequestContext& ctx);
/** /**
* AM::GetProgramInfos service function * AM::GetProgramInfos service function
* Inputs: * Inputs:
* 1 : u8 Mediatype * 1 : u8 Mediatype
@ -225,9 +226,9 @@ void GetProgramList(Service::Interface* self);
* Outputs: * Outputs:
* 1 : Result, 0 on success, otherwise error code * 1 : Result, 0 on success, otherwise error code
*/ */
void GetProgramInfos(Service::Interface* self); void GetProgramInfos(Kernel::HLERequestContext& ctx);
/** /**
* AM::DeleteUserProgram service function * AM::DeleteUserProgram service function
* Deletes a user program * Deletes a user program
* Inputs: * Inputs:
@ -236,9 +237,9 @@ void GetProgramInfos(Service::Interface* self);
* Outputs: * Outputs:
* 1 : Result, 0 on success, otherwise error code * 1 : Result, 0 on success, otherwise error code
*/ */
void DeleteUserProgram(Service::Interface* self); void DeleteUserProgram(Kernel::HLERequestContext& ctx);
/** /**
* AM::GetDLCTitleInfos service function * AM::GetDLCTitleInfos service function
* Wrapper for AM::GetProgramInfos, explicitly checks that TID high value is 0004008C. * Wrapper for AM::GetProgramInfos, explicitly checks that TID high value is 0004008C.
* Inputs: * Inputs:
@ -249,9 +250,9 @@ void DeleteUserProgram(Service::Interface* self);
* Outputs: * Outputs:
* 1 : Result, 0 on success, otherwise error code * 1 : Result, 0 on success, otherwise error code
*/ */
void GetDLCTitleInfos(Service::Interface* self); void GetDLCTitleInfos(Kernel::HLERequestContext& ctx);
/** /**
* AM::GetPatchTitleInfos service function * AM::GetPatchTitleInfos service function
* Wrapper for AM::GetProgramInfos, explicitly checks that TID high value is 0004000E. * Wrapper for AM::GetProgramInfos, explicitly checks that TID high value is 0004000E.
* Inputs: * Inputs:
@ -264,9 +265,9 @@ void GetDLCTitleInfos(Service::Interface* self);
* 2 : TitleIDList input pointer * 2 : TitleIDList input pointer
* 4 : TitleList output pointer * 4 : TitleList output pointer
*/ */
void GetPatchTitleInfos(Service::Interface* self); void GetPatchTitleInfos(Kernel::HLERequestContext& ctx);
/** /**
* AM::ListDataTitleTicketInfos service function * AM::ListDataTitleTicketInfos service function
* Inputs: * Inputs:
* 1 : Ticket count * 1 : Ticket count
@ -278,9 +279,9 @@ void GetPatchTitleInfos(Service::Interface* self);
* 1 : Result, 0 on success, otherwise error code * 1 : Result, 0 on success, otherwise error code
* 2 : Number of ticket infos returned * 2 : Number of ticket infos returned
*/ */
void ListDataTitleTicketInfos(Service::Interface* self); void ListDataTitleTicketInfos(Kernel::HLERequestContext& ctx);
/** /**
* AM::GetDLCContentInfoCount service function * AM::GetDLCContentInfoCount service function
* Explicitly checks that TID high value is 0004008C or an error is returned. * Explicitly checks that TID high value is 0004008C or an error is returned.
* Inputs: * Inputs:
@ -291,26 +292,26 @@ void ListDataTitleTicketInfos(Service::Interface* self);
* 1 : Result, 0 on success, otherwise error code * 1 : Result, 0 on success, otherwise error code
* 2 : Number of content infos plus one * 2 : Number of content infos plus one
*/ */
void GetDLCContentInfoCount(Service::Interface* self); void GetDLCContentInfoCount(Kernel::HLERequestContext& ctx);
/** /**
* AM::DeleteTicket service function * AM::DeleteTicket service function
* Inputs: * Inputs:
* 1-2 : u64, Title ID * 1-2 : u64, Title ID
* Outputs: * Outputs:
* 1 : Result, 0 on success, otherwise error code * 1 : Result, 0 on success, otherwise error code
*/ */
void DeleteTicket(Service::Interface* self); void DeleteTicket(Kernel::HLERequestContext& ctx);
/** /**
* AM::GetNumTickets service function * AM::GetNumTickets service function
* Outputs: * Outputs:
* 1 : Result, 0 on success, otherwise error code * 1 : Result, 0 on success, otherwise error code
* 2 : Number of tickets * 2 : Number of tickets
*/ */
void GetNumTickets(Service::Interface* self); void GetNumTickets(Kernel::HLERequestContext& ctx);
/** /**
* AM::GetTicketList service function * AM::GetTicketList service function
* Inputs: * Inputs:
* 1 : Number of TicketList * 1 : Number of TicketList
@ -320,9 +321,9 @@ void GetNumTickets(Service::Interface* self);
* 1 : Result, 0 on success, otherwise error code * 1 : Result, 0 on success, otherwise error code
* 2 : Total TicketList * 2 : Total TicketList
*/ */
void GetTicketList(Service::Interface* self); void GetTicketList(Kernel::HLERequestContext& ctx);
/** /**
* AM::QueryAvailableTitleDatabase service function * AM::QueryAvailableTitleDatabase service function
* Inputs: * Inputs:
* 1 : Media Type * 1 : Media Type
@ -330,9 +331,9 @@ void GetTicketList(Service::Interface* self);
* 1 : Result, 0 on success, otherwise error code * 1 : Result, 0 on success, otherwise error code
* 2 : Boolean, database availability * 2 : Boolean, database availability
*/ */
void QueryAvailableTitleDatabase(Service::Interface* self); void QueryAvailableTitleDatabase(Kernel::HLERequestContext& ctx);
/** /**
* AM::CheckContentRights service function * AM::CheckContentRights service function
* Inputs: * Inputs:
* 1-2 : Title ID * 1-2 : Title ID
@ -341,9 +342,9 @@ void QueryAvailableTitleDatabase(Service::Interface* self);
* 1 : Result, 0 on success, otherwise error code * 1 : Result, 0 on success, otherwise error code
* 2 : Boolean, whether we have rights to this content * 2 : Boolean, whether we have rights to this content
*/ */
void CheckContentRights(Service::Interface* self); void CheckContentRights(Kernel::HLERequestContext& ctx);
/** /**
* AM::CheckContentRightsIgnorePlatform service function * AM::CheckContentRightsIgnorePlatform service function
* Inputs: * Inputs:
* 1-2 : Title ID * 1-2 : Title ID
@ -352,9 +353,9 @@ void CheckContentRights(Service::Interface* self);
* 1 : Result, 0 on success, otherwise error code * 1 : Result, 0 on success, otherwise error code
* 2 : Boolean, whether we have rights to this content * 2 : Boolean, whether we have rights to this content
*/ */
void CheckContentRightsIgnorePlatform(Service::Interface* self); void CheckContentRightsIgnorePlatform(Kernel::HLERequestContext& ctx);
/** /**
* AM::BeginImportProgram service function * AM::BeginImportProgram service function
* Begin importing from a CTR Installable Archive * Begin importing from a CTR Installable Archive
* Inputs: * Inputs:
@ -364,9 +365,9 @@ void CheckContentRightsIgnorePlatform(Service::Interface* self);
* 1 : Result, 0 on success, otherwise error code * 1 : Result, 0 on success, otherwise error code
* 2-3 : CIAFile handle for application to write to * 2-3 : CIAFile handle for application to write to
*/ */
void BeginImportProgram(Service::Interface* self); void BeginImportProgram(Kernel::HLERequestContext& ctx);
/** /**
* AM::EndImportProgram service function * AM::EndImportProgram service function
* Finish importing from a CTR Installable Archive * Finish importing from a CTR Installable Archive
* Inputs: * Inputs:
@ -375,9 +376,9 @@ void BeginImportProgram(Service::Interface* self);
* Outputs: * Outputs:
* 1 : Result, 0 on success, otherwise error code * 1 : Result, 0 on success, otherwise error code
*/ */
void EndImportProgram(Service::Interface* self); void EndImportProgram(Kernel::HLERequestContext& ctx);
/** /**
* AM::GetProgramInfoFromCia service function * AM::GetProgramInfoFromCia service function
* Get TitleInfo from a CIA file handle * Get TitleInfo from a CIA file handle
* Inputs: * Inputs:
@ -388,9 +389,9 @@ void EndImportProgram(Service::Interface* self);
* 1 : Result, 0 on success, otherwise error code * 1 : Result, 0 on success, otherwise error code
* 2-8: TitleInfo structure * 2-8: TitleInfo structure
*/ */
void GetProgramInfoFromCia(Service::Interface* self); void GetProgramInfoFromCia(Kernel::HLERequestContext& ctx);
/** /**
* AM::GetSystemMenuDataFromCia service function * AM::GetSystemMenuDataFromCia service function
* Loads a CIA file's SMDH data into a specified buffer * Loads a CIA file's SMDH data into a specified buffer
* Inputs: * Inputs:
@ -400,9 +401,9 @@ void GetProgramInfoFromCia(Service::Interface* self);
* Outputs: * Outputs:
* 1 : Result, 0 on success, otherwise error code * 1 : Result, 0 on success, otherwise error code
*/ */
void GetSystemMenuDataFromCia(Service::Interface* self); void GetSystemMenuDataFromCia(Kernel::HLERequestContext& ctx);
/** /**
* AM::GetDependencyListFromCia service function * AM::GetDependencyListFromCia service function
* Loads a CIA's dependency list into a specified buffer * Loads a CIA's dependency list into a specified buffer
* Inputs: * Inputs:
@ -412,9 +413,9 @@ void GetSystemMenuDataFromCia(Service::Interface* self);
* Outputs: * Outputs:
* 1 : Result, 0 on success, otherwise error code * 1 : Result, 0 on success, otherwise error code
*/ */
void GetDependencyListFromCia(Service::Interface* self); void GetDependencyListFromCia(Kernel::HLERequestContext& ctx);
/** /**
* AM::GetTransferSizeFromCia service function * AM::GetTransferSizeFromCia service function
* Returns the total expected transfer size up to the CIA meta offset from a CIA * Returns the total expected transfer size up to the CIA meta offset from a CIA
* Inputs: * Inputs:
@ -424,9 +425,9 @@ void GetDependencyListFromCia(Service::Interface* self);
* 1 : Result, 0 on success, otherwise error code * 1 : Result, 0 on success, otherwise error code
* 2-3 : Transfer size * 2-3 : Transfer size
*/ */
void GetTransferSizeFromCia(Service::Interface* self); void GetTransferSizeFromCia(Kernel::HLERequestContext& ctx);
/** /**
* AM::GetCoreVersionFromCia service function * AM::GetCoreVersionFromCia service function
* Returns the core version from a CIA * Returns the core version from a CIA
* Inputs: * Inputs:
@ -436,9 +437,9 @@ void GetTransferSizeFromCia(Service::Interface* self);
* 1 : Result, 0 on success, otherwise error code * 1 : Result, 0 on success, otherwise error code
* 2 : Core version * 2 : Core version
*/ */
void GetCoreVersionFromCia(Service::Interface* self); void GetCoreVersionFromCia(Kernel::HLERequestContext& ctx);
/** /**
* AM::GetRequiredSizeFromCia service function * AM::GetRequiredSizeFromCia service function
* Returns the required amount of free space required to install a given CIA file * Returns the required amount of free space required to install a given CIA file
* Inputs: * Inputs:
@ -449,9 +450,9 @@ void GetCoreVersionFromCia(Service::Interface* self);
* 1 : Result, 0 on success, otherwise error code * 1 : Result, 0 on success, otherwise error code
* 2-3 : Required free space for CIA * 2-3 : Required free space for CIA
*/ */
void GetRequiredSizeFromCia(Service::Interface* self); void GetRequiredSizeFromCia(Kernel::HLERequestContext& ctx);
/** /**
* AM::DeleteProgram service function * AM::DeleteProgram service function
* Deletes a program * Deletes a program
* Inputs: * Inputs:
@ -461,9 +462,9 @@ void GetRequiredSizeFromCia(Service::Interface* self);
* Outputs: * Outputs:
* 1 : Result, 0 on success, otherwise error code * 1 : Result, 0 on success, otherwise error code
*/ */
void DeleteProgram(Service::Interface* self); void DeleteProgram(Kernel::HLERequestContext& ctx);
/** /**
* AM::GetMetaSizeFromCia service function * AM::GetMetaSizeFromCia service function
* Returns the size of a given CIA's meta section * Returns the size of a given CIA's meta section
* Inputs: * Inputs:
@ -473,9 +474,9 @@ void DeleteProgram(Service::Interface* self);
* 1 : Result, 0 on success, otherwise error code * 1 : Result, 0 on success, otherwise error code
* 2 : Meta section size * 2 : Meta section size
*/ */
void GetMetaSizeFromCia(Service::Interface* self); void GetMetaSizeFromCia(Kernel::HLERequestContext& ctx);
/** /**
* AM::GetMetaDataFromCia service function * AM::GetMetaDataFromCia service function
* Loads meta section data from a CIA file into a given buffer * Loads meta section data from a CIA file into a given buffer
* Inputs: * Inputs:
@ -485,13 +486,29 @@ void GetMetaSizeFromCia(Service::Interface* self);
* Outputs: * Outputs:
* 1 : Result, 0 on success, otherwise error code * 1 : Result, 0 on success, otherwise error code
*/ */
void GetMetaDataFromCia(Service::Interface* self); void GetMetaDataFromCia(Kernel::HLERequestContext& ctx);
/// Initialize AM service private:
void Init(); std::shared_ptr<Module> am;
};
/// Shutdown AM service private:
void Shutdown(); /**
* Scans the for titles in a storage medium for listing.
* @param media_type the storage medium to scan
*/
void ScanForTitles(Service::FS::MediaType media_type);
/**
* Scans all storage mediums for titles for listing.
*/
void ScanForAllTitles();
bool cia_installing = false;
std::array<std::vector<u64_le>, 3> am_title_list;
};
void InstallInterfaces(SM::ServiceManager& service_manager);
} // namespace AM } // namespace AM
} // namespace Service } // namespace Service

View File

@ -2,30 +2,28 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/am_app.h" #include "core/hle/service/am/am_app.h"
namespace Service { namespace Service {
namespace AM { namespace AM {
const Interface::FunctionInfo FunctionTable[] = { AM_APP::AM_APP(std::shared_ptr<Module> am) : Module::Interface(std::move(am), "am:app", 5) {
{0x100100C0, GetDLCContentInfoCount, "GetDLCContentInfoCount"}, static const FunctionInfo functions[] = {
{0x10020104, FindDLCContentInfos, "FindDLCContentInfos"}, {0x100100C0, &AM_APP::GetDLCContentInfoCount, "GetDLCContentInfoCount"},
{0x10030142, ListDLCContentInfos, "ListDLCContentInfos"}, {0x10020104, &AM_APP::FindDLCContentInfos, "FindDLCContentInfos"},
{0x10040102, DeleteContents, "DeleteContents"}, {0x10030142, &AM_APP::ListDLCContentInfos, "ListDLCContentInfos"},
{0x10050084, GetDLCTitleInfos, "GetDLCTitleInfos"}, {0x10040102, &AM_APP::DeleteContents, "DeleteContents"},
{0x10050084, &AM_APP::GetDLCTitleInfos, "GetDLCTitleInfos"},
{0x10060080, nullptr, "GetNumDataTitleTickets"}, {0x10060080, nullptr, "GetNumDataTitleTickets"},
{0x10070102, ListDataTitleTicketInfos, "ListDataTitleTicketInfos"}, {0x10070102, &AM_APP::ListDataTitleTicketInfos, "ListDataTitleTicketInfos"},
{0x100801C2, nullptr, "GetItemRights"}, {0x100801C2, nullptr, "GetItemRights"},
{0x100900C0, nullptr, "IsDataTitleInUse"}, {0x100900C0, nullptr, "IsDataTitleInUse"},
{0x100A0000, nullptr, "IsExternalTitleDatabaseInitialized"}, {0x100A0000, nullptr, "IsExternalTitleDatabaseInitialized"},
{0x100B00C0, nullptr, "GetNumExistingContentInfos"}, {0x100B00C0, nullptr, "GetNumExistingContentInfos"},
{0x100C0142, nullptr, "ListExistingContentInfos"}, {0x100C0142, nullptr, "ListExistingContentInfos"},
{0x100D0084, GetPatchTitleInfos, "GetPatchTitleInfos"}, {0x100D0084, &AM_APP::GetPatchTitleInfos, "GetPatchTitleInfos"},
}; };
RegisterHandlers(functions);
AM_APP_Interface::AM_APP_Interface() {
Register(FunctionTable);
} }
} // namespace AM } // namespace AM

View File

@ -4,18 +4,14 @@
#pragma once #pragma once
#include "core/hle/service/service.h" #include "core/hle/service/am/am.h"
namespace Service { namespace Service {
namespace AM { namespace AM {
class AM_APP_Interface : public Service::Interface { class AM_APP final : public Module::Interface {
public: public:
AM_APP_Interface(); explicit AM_APP(std::shared_ptr<Module> am);
std::string GetPortName() const override {
return "am:app";
}
}; };
} // namespace AM } // namespace AM

View File

@ -2,22 +2,22 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/am_net.h" #include "core/hle/service/am/am_net.h"
namespace Service { namespace Service {
namespace AM { namespace AM {
const Interface::FunctionInfo FunctionTable[] = { AM_NET::AM_NET(std::shared_ptr<Module> am) : Module::Interface(std::move(am), "am:net", 5) {
{0x00010040, GetNumPrograms, "GetNumPrograms"}, static const FunctionInfo functions[] = {
{0x00020082, GetProgramList, "GetProgramList"}, {0x00010040, &AM_NET::GetNumPrograms, "GetNumPrograms"},
{0x00030084, GetProgramInfos, "GetProgramInfos"}, {0x00020082, &AM_NET::GetProgramList, "GetProgramList"},
{0x000400C0, DeleteUserProgram, "DeleteUserProgram"}, {0x00030084, &AM_NET::GetProgramInfos, "GetProgramInfos"},
{0x000400C0, &AM_NET::DeleteUserProgram, "DeleteUserProgram"},
{0x000500C0, nullptr, "GetProductCode"}, {0x000500C0, nullptr, "GetProductCode"},
{0x000600C0, nullptr, "GetStorageId"}, {0x000600C0, nullptr, "GetStorageId"},
{0x00070080, DeleteTicket, "DeleteTicket"}, {0x00070080, &AM_NET::DeleteTicket, "DeleteTicket"},
{0x00080000, GetNumTickets, "GetNumTickets"}, {0x00080000, &AM_NET::GetNumTickets, "GetNumTickets"},
{0x00090082, GetTicketList, "GetTicketList"}, {0x00090082, &AM_NET::GetTicketList, "GetTicketList"},
{0x000A0000, nullptr, "GetDeviceID"}, {0x000A0000, nullptr, "GetDeviceID"},
{0x000B0040, nullptr, "GetNumImportTitleContexts"}, {0x000B0040, nullptr, "GetNumImportTitleContexts"},
{0x000C0082, nullptr, "GetImportTitleContextList"}, {0x000C0082, nullptr, "GetImportTitleContextList"},
@ -55,25 +55,25 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x002C0084, nullptr, "GetProgramInfosIgnorePlatform"}, {0x002C0084, nullptr, "GetProgramInfosIgnorePlatform"},
{0x002D00C0, nullptr, "CheckContentRightsIgnorePlatform"}, {0x002D00C0, nullptr, "CheckContentRightsIgnorePlatform"},
{0x04010080, nullptr, "UpdateFirmwareTo"}, {0x04010080, nullptr, "UpdateFirmwareTo"},
{0x04020040, BeginImportProgram, "BeginImportProgram"}, {0x04020040, &AM_NET::BeginImportProgram, "BeginImportProgram"},
{0x04030000, nullptr, "BeginImportProgramTemporarily"}, {0x04030000, nullptr, "BeginImportProgramTemporarily"},
{0x04040002, nullptr, "CancelImportProgram"}, {0x04040002, nullptr, "CancelImportProgram"},
{0x04050002, EndImportProgram, "EndImportProgram"}, {0x04050002, &AM_NET::EndImportProgram, "EndImportProgram"},
{0x04060002, nullptr, "EndImportProgramWithoutCommit"}, {0x04060002, nullptr, "EndImportProgramWithoutCommit"},
{0x040700C2, nullptr, "CommitImportPrograms"}, {0x040700C2, nullptr, "CommitImportPrograms"},
{0x04080042, GetProgramInfoFromCia, "GetProgramInfoFromCia"}, {0x04080042, &AM_NET::GetProgramInfoFromCia, "GetProgramInfoFromCia"},
{0x04090004, GetSystemMenuDataFromCia, "GetSystemMenuDataFromCia"}, {0x04090004, &AM_NET::GetSystemMenuDataFromCia, "GetSystemMenuDataFromCia"},
{0x040A0002, GetDependencyListFromCia, "GetDependencyListFromCia"}, {0x040A0002, &AM_NET::GetDependencyListFromCia, "GetDependencyListFromCia"},
{0x040B0002, GetTransferSizeFromCia, "GetTransferSizeFromCia"}, {0x040B0002, &AM_NET::GetTransferSizeFromCia, "GetTransferSizeFromCia"},
{0x040C0002, GetCoreVersionFromCia, "GetCoreVersionFromCia"}, {0x040C0002, &AM_NET::GetCoreVersionFromCia, "GetCoreVersionFromCia"},
{0x040D0042, GetRequiredSizeFromCia, "GetRequiredSizeFromCia"}, {0x040D0042, &AM_NET::GetRequiredSizeFromCia, "GetRequiredSizeFromCia"},
{0x040E00C2, nullptr, "CommitImportProgramsAndUpdateFirmwareAuto"}, {0x040E00C2, nullptr, "CommitImportProgramsAndUpdateFirmwareAuto"},
{0x040F0000, nullptr, "UpdateFirmwareAuto"}, {0x040F0000, nullptr, "UpdateFirmwareAuto"},
{0x041000C0, DeleteProgram, "DeleteProgram"}, {0x041000C0, &AM_NET::DeleteProgram, "DeleteProgram"},
{0x04110044, nullptr, "GetTwlProgramListForReboot"}, {0x04110044, nullptr, "GetTwlProgramListForReboot"},
{0x04120000, nullptr, "GetSystemUpdaterMutex"}, {0x04120000, nullptr, "GetSystemUpdaterMutex"},
{0x04130002, GetMetaSizeFromCia, "GetMetaSizeFromCia"}, {0x04130002, &AM_NET::GetMetaSizeFromCia, "GetMetaSizeFromCia"},
{0x04140044, GetMetaDataFromCia, "GetMetaDataFromCia"}, {0x04140044, &AM_NET::GetMetaDataFromCia, "GetMetaDataFromCia"},
{0x04150080, nullptr, "CheckDemoLaunchRights"}, {0x04150080, nullptr, "CheckDemoLaunchRights"},
{0x041600C0, nullptr, "GetInternalTitleLocationInfo"}, {0x041600C0, nullptr, "GetInternalTitleLocationInfo"},
{0x041700C0, nullptr, "PerpetuateAgbSaveData"}, {0x041700C0, nullptr, "PerpetuateAgbSaveData"},
@ -119,10 +119,8 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x08260042, nullptr, "UpdateImportContentContexts"}, {0x08260042, nullptr, "UpdateImportContentContexts"},
{0x08270000, nullptr, "DeleteAllDemoLaunchInfos"}, {0x08270000, nullptr, "DeleteAllDemoLaunchInfos"},
{0x082800C0, nullptr, "BeginImportTitleForOverWrite"}, {0x082800C0, nullptr, "BeginImportTitleForOverWrite"},
}; };
RegisterHandlers(functions);
AM_NET_Interface::AM_NET_Interface() {
Register(FunctionTable);
} }
} // namespace AM } // namespace AM

View File

@ -4,18 +4,14 @@
#pragma once #pragma once
#include "core/hle/service/service.h" #include "core/hle/service/am/am.h"
namespace Service { namespace Service {
namespace AM { namespace AM {
class AM_NET_Interface : public Service::Interface { class AM_NET final : public Module::Interface {
public: public:
AM_NET_Interface(); explicit AM_NET(std::shared_ptr<Module> am);
std::string GetPortName() const override {
return "am:net";
}
}; };
} // namespace AM } // namespace AM

View File

@ -2,22 +2,22 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/am_sys.h" #include "core/hle/service/am/am_sys.h"
namespace Service { namespace Service {
namespace AM { namespace AM {
const Interface::FunctionInfo FunctionTable[] = { AM_SYS::AM_SYS(std::shared_ptr<Module> am) : Module::Interface(std::move(am), "am:sys", 5) {
{0x00010040, GetNumPrograms, "GetNumPrograms"}, static const FunctionInfo functions[] = {
{0x00020082, GetProgramList, "GetProgramList"}, {0x00010040, &AM_SYS::GetNumPrograms, "GetNumPrograms"},
{0x00030084, GetProgramInfos, "GetProgramInfos"}, {0x00020082, &AM_SYS::GetProgramList, "GetProgramList"},
{0x000400C0, DeleteUserProgram, "DeleteUserProgram"}, {0x00030084, &AM_SYS::GetProgramInfos, "GetProgramInfos"},
{0x000400C0, &AM_SYS::DeleteUserProgram, "DeleteUserProgram"},
{0x000500C0, nullptr, "GetProductCode"}, {0x000500C0, nullptr, "GetProductCode"},
{0x000600C0, nullptr, "GetStorageId"}, {0x000600C0, nullptr, "GetStorageId"},
{0x00070080, DeleteTicket, "DeleteTicket"}, {0x00070080, &AM_SYS::DeleteTicket, "DeleteTicket"},
{0x00080000, GetNumTickets, "GetNumTickets"}, {0x00080000, &AM_SYS::GetNumTickets, "GetNumTickets"},
{0x00090082, GetTicketList, "GetTicketList"}, {0x00090082, &AM_SYS::GetTicketList, "GetTicketList"},
{0x000A0000, nullptr, "GetDeviceID"}, {0x000A0000, nullptr, "GetDeviceID"},
{0x000B0040, nullptr, "GetNumImportTitleContexts"}, {0x000B0040, nullptr, "GetNumImportTitleContexts"},
{0x000C0082, nullptr, "GetImportTitleContextList"}, {0x000C0082, nullptr, "GetImportTitleContextList"},
@ -33,7 +33,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00160000, nullptr, "DeleteAllTemporaryPrograms"}, {0x00160000, nullptr, "DeleteAllTemporaryPrograms"},
{0x00170044, nullptr, "ImportTwlBackupLegacy"}, {0x00170044, nullptr, "ImportTwlBackupLegacy"},
{0x00180080, nullptr, "InitializeTitleDatabase"}, {0x00180080, nullptr, "InitializeTitleDatabase"},
{0x00190040, QueryAvailableTitleDatabase, "QueryAvailableTitleDatabase"}, {0x00190040, &AM_SYS::QueryAvailableTitleDatabase, "QueryAvailableTitleDatabase"},
{0x001A00C0, nullptr, "CalcTwlBackupSize"}, {0x001A00C0, nullptr, "CalcTwlBackupSize"},
{0x001B0144, nullptr, "ExportTwlBackup"}, {0x001B0144, nullptr, "ExportTwlBackup"},
{0x001C0084, nullptr, "ImportTwlBackup"}, {0x001C0084, nullptr, "ImportTwlBackup"},
@ -45,7 +45,7 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x00220080, nullptr, "DeleteAllImportContextsFiltered"}, {0x00220080, nullptr, "DeleteAllImportContextsFiltered"},
{0x00230080, nullptr, "GetNumImportTitleContextsFiltered"}, {0x00230080, nullptr, "GetNumImportTitleContextsFiltered"},
{0x002400C2, nullptr, "GetImportTitleContextListFiltered"}, {0x002400C2, nullptr, "GetImportTitleContextListFiltered"},
{0x002500C0, CheckContentRights, "CheckContentRights"}, {0x002500C0, &AM_SYS::CheckContentRights, "CheckContentRights"},
{0x00260044, nullptr, "GetTicketLimitInfos"}, {0x00260044, nullptr, "GetTicketLimitInfos"},
{0x00270044, nullptr, "GetDemoLaunchInfos"}, {0x00270044, nullptr, "GetDemoLaunchInfos"},
{0x00280108, nullptr, "ReadTwlBackupInfoEx"}, {0x00280108, nullptr, "ReadTwlBackupInfoEx"},
@ -53,24 +53,22 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x002A00C0, nullptr, "GetNumExistingContentInfosSystem"}, {0x002A00C0, nullptr, "GetNumExistingContentInfosSystem"},
{0x002B0142, nullptr, "ListExistingContentInfosSystem"}, {0x002B0142, nullptr, "ListExistingContentInfosSystem"},
{0x002C0084, nullptr, "GetProgramInfosIgnorePlatform"}, {0x002C0084, nullptr, "GetProgramInfosIgnorePlatform"},
{0x002D00C0, CheckContentRightsIgnorePlatform, "CheckContentRightsIgnorePlatform"}, {0x002D00C0, &AM_SYS::CheckContentRightsIgnorePlatform, "CheckContentRightsIgnorePlatform"},
{0x100100C0, GetDLCContentInfoCount, "GetDLCContentInfoCount"}, {0x100100C0, &AM_SYS::GetDLCContentInfoCount, "GetDLCContentInfoCount"},
{0x10020104, FindDLCContentInfos, "FindDLCContentInfos"}, {0x10020104, &AM_SYS::FindDLCContentInfos, "FindDLCContentInfos"},
{0x10030142, ListDLCContentInfos, "ListDLCContentInfos"}, {0x10030142, &AM_SYS::ListDLCContentInfos, "ListDLCContentInfos"},
{0x10040102, DeleteContents, "DeleteContents"}, {0x10040102, &AM_SYS::DeleteContents, "DeleteContents"},
{0x10050084, GetDLCTitleInfos, "GetDLCTitleInfos"}, {0x10050084, &AM_SYS::GetDLCTitleInfos, "GetDLCTitleInfos"},
{0x10060080, nullptr, "GetNumDataTitleTickets"}, {0x10060080, nullptr, "GetNumDataTitleTickets"},
{0x10070102, ListDataTitleTicketInfos, "ListDataTitleTicketInfos"}, {0x10070102, &AM_SYS::ListDataTitleTicketInfos, "ListDataTitleTicketInfos"},
{0x100801C2, nullptr, "GetItemRights"}, {0x100801C2, nullptr, "GetItemRights"},
{0x100900C0, nullptr, "IsDataTitleInUse"}, {0x100900C0, nullptr, "IsDataTitleInUse"},
{0x100A0000, nullptr, "IsExternalTitleDatabaseInitialized"}, {0x100A0000, nullptr, "IsExternalTitleDatabaseInitialized"},
{0x100B00C0, nullptr, "GetNumExistingContentInfos"}, {0x100B00C0, nullptr, "GetNumExistingContentInfos"},
{0x100C0142, nullptr, "ListExistingContentInfos"}, {0x100C0142, nullptr, "ListExistingContentInfos"},
{0x100D0084, GetPatchTitleInfos, "GetPatchTitleInfos"}, {0x100D0084, &AM_SYS::GetPatchTitleInfos, "GetPatchTitleInfos"},
}; };
RegisterHandlers(functions);
AM_SYS_Interface::AM_SYS_Interface() {
Register(FunctionTable);
} }
} // namespace AM } // namespace AM

View File

@ -4,18 +4,14 @@
#pragma once #pragma once
#include "core/hle/service/service.h" #include "core/hle/service/am/am.h"
namespace Service { namespace Service {
namespace AM { namespace AM {
class AM_SYS_Interface : public Service::Interface { class AM_SYS final : public Module::Interface {
public: public:
AM_SYS_Interface(); explicit AM_SYS(std::shared_ptr<Module> am);
std::string GetPortName() const override {
return "am:sys";
}
}; };
} // namespace AM } // namespace AM

View File

@ -2,22 +2,22 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/am_u.h" #include "core/hle/service/am/am_u.h"
namespace Service { namespace Service {
namespace AM { namespace AM {
const Interface::FunctionInfo FunctionTable[] = { AM_U::AM_U(std::shared_ptr<Module> am) : Module::Interface(std::move(am), "am:u", 5) {
{0x00010040, GetNumPrograms, "GetNumPrograms"}, static const FunctionInfo functions[] = {
{0x00020082, GetProgramList, "GetProgramList"}, {0x00010040, &AM_U::GetNumPrograms, "GetNumPrograms"},
{0x00030084, GetProgramInfos, "GetProgramInfos"}, {0x00020082, &AM_U::GetProgramList, "GetProgramList"},
{0x000400C0, DeleteUserProgram, "DeleteUserProgram"}, {0x00030084, &AM_U::GetProgramInfos, "GetProgramInfos"},
{0x000400C0, &AM_U::DeleteUserProgram, "DeleteUserProgram"},
{0x000500C0, nullptr, "GetProductCode"}, {0x000500C0, nullptr, "GetProductCode"},
{0x000600C0, nullptr, "GetStorageId"}, {0x000600C0, nullptr, "GetStorageId"},
{0x00070080, DeleteTicket, "DeleteTicket"}, {0x00070080, &AM_U::DeleteTicket, "DeleteTicket"},
{0x00080000, GetNumTickets, "GetNumTickets"}, {0x00080000, &AM_U::GetNumTickets, "GetNumTickets"},
{0x00090082, GetTicketList, "GetTicketList"}, {0x00090082, &AM_U::GetTicketList, "GetTicketList"},
{0x000A0000, nullptr, "GetDeviceID"}, {0x000A0000, nullptr, "GetDeviceID"},
{0x000B0040, nullptr, "GetNumImportTitleContexts"}, {0x000B0040, nullptr, "GetNumImportTitleContexts"},
{0x000C0082, nullptr, "GetImportTitleContextList"}, {0x000C0082, nullptr, "GetImportTitleContextList"},
@ -55,34 +55,32 @@ const Interface::FunctionInfo FunctionTable[] = {
{0x002C0084, nullptr, "GetProgramInfosIgnorePlatform"}, {0x002C0084, nullptr, "GetProgramInfosIgnorePlatform"},
{0x002D00C0, nullptr, "CheckContentRightsIgnorePlatform"}, {0x002D00C0, nullptr, "CheckContentRightsIgnorePlatform"},
{0x04010080, nullptr, "UpdateFirmwareTo"}, {0x04010080, nullptr, "UpdateFirmwareTo"},
{0x04020040, BeginImportProgram, "BeginImportProgram"}, {0x04020040, &AM_U::BeginImportProgram, "BeginImportProgram"},
{0x04030000, nullptr, "BeginImportProgramTemporarily"}, {0x04030000, nullptr, "BeginImportProgramTemporarily"},
{0x04040002, nullptr, "CancelImportProgram"}, {0x04040002, nullptr, "CancelImportProgram"},
{0x04050002, EndImportProgram, "EndImportProgram"}, {0x04050002, &AM_U::EndImportProgram, "EndImportProgram"},
{0x04060002, nullptr, "EndImportProgramWithoutCommit"}, {0x04060002, nullptr, "EndImportProgramWithoutCommit"},
{0x040700C2, nullptr, "CommitImportPrograms"}, {0x040700C2, nullptr, "CommitImportPrograms"},
{0x04080042, GetProgramInfoFromCia, "GetProgramInfoFromCia"}, {0x04080042, &AM_U::GetProgramInfoFromCia, "GetProgramInfoFromCia"},
{0x04090004, GetSystemMenuDataFromCia, "GetSystemMenuDataFromCia"}, {0x04090004, &AM_U::GetSystemMenuDataFromCia, "GetSystemMenuDataFromCia"},
{0x040A0002, GetDependencyListFromCia, "GetDependencyListFromCia"}, {0x040A0002, &AM_U::GetDependencyListFromCia, "GetDependencyListFromCia"},
{0x040B0002, GetTransferSizeFromCia, "GetTransferSizeFromCia"}, {0x040B0002, &AM_U::GetTransferSizeFromCia, "GetTransferSizeFromCia"},
{0x040C0002, GetCoreVersionFromCia, "GetCoreVersionFromCia"}, {0x040C0002, &AM_U::GetCoreVersionFromCia, "GetCoreVersionFromCia"},
{0x040D0042, GetRequiredSizeFromCia, "GetRequiredSizeFromCia"}, {0x040D0042, &AM_U::GetRequiredSizeFromCia, "GetRequiredSizeFromCia"},
{0x040E00C2, nullptr, "CommitImportProgramsAndUpdateFirmwareAuto"}, {0x040E00C2, nullptr, "CommitImportProgramsAndUpdateFirmwareAuto"},
{0x040F0000, nullptr, "UpdateFirmwareAuto"}, {0x040F0000, nullptr, "UpdateFirmwareAuto"},
{0x041000C0, DeleteProgram, "DeleteProgram"}, {0x041000C0, &AM_U::DeleteProgram, "DeleteProgram"},
{0x04110044, nullptr, "GetTwlProgramListForReboot"}, {0x04110044, nullptr, "GetTwlProgramListForReboot"},
{0x04120000, nullptr, "GetSystemUpdaterMutex"}, {0x04120000, nullptr, "GetSystemUpdaterMutex"},
{0x04130002, GetMetaSizeFromCia, "GetMetaSizeFromCia"}, {0x04130002, &AM_U::GetMetaSizeFromCia, "GetMetaSizeFromCia"},
{0x04140044, GetMetaDataFromCia, "GetMetaDataFromCia"}, {0x04140044, &AM_U::GetMetaDataFromCia, "GetMetaDataFromCia"},
{0x04150080, nullptr, "CheckDemoLaunchRights"}, {0x04150080, nullptr, "CheckDemoLaunchRights"},
{0x041600C0, nullptr, "GetInternalTitleLocationInfo"}, {0x041600C0, nullptr, "GetInternalTitleLocationInfo"},
{0x041700C0, nullptr, "PerpetuateAgbSaveData"}, {0x041700C0, nullptr, "PerpetuateAgbSaveData"},
{0x04180040, nullptr, "BeginImportProgramForOverWrite"}, {0x04180040, nullptr, "BeginImportProgramForOverWrite"},
{0x04190000, nullptr, "BeginImportSystemProgram"}, {0x04190000, nullptr, "BeginImportSystemProgram"},
}; };
RegisterHandlers(functions);
AM_U_Interface::AM_U_Interface() {
Register(FunctionTable);
} }
} // namespace AM } // namespace AM

View File

@ -4,18 +4,14 @@
#pragma once #pragma once
#include "core/hle/service/service.h" #include "core/hle/service/am/am.h"
namespace Service { namespace Service {
namespace AM { namespace AM {
class AM_U_Interface : public Service::Interface { class AM_U final : public Module::Interface {
public: public:
AM_U_Interface(); explicit AM_U(std::shared_ptr<Module> am);
std::string GetPortName() const override {
return "am:u";
}
}; };
} // namespace AM } // namespace AM

View File

@ -100,7 +100,7 @@ void FS_USER::OpenFileDirectly(Kernel::HLERequestContext& ctx) {
"Failed to get a handle for archive archive_id=0x%08X archive_path=%s", "Failed to get a handle for archive archive_id=0x%08X archive_path=%s",
static_cast<u32>(archive_id), archive_path.DebugStr().c_str()); static_cast<u32>(archive_id), archive_path.DebugStr().c_str());
rb.Push(archive_handle.Code()); rb.Push(archive_handle.Code());
rb.PushMoveHandles(0); rb.PushMoveObjects<Kernel::Object>(nullptr);
return; return;
} }
SCOPE_EXIT({ Service::FS::CloseArchive(*archive_handle); }); SCOPE_EXIT({ Service::FS::CloseArchive(*archive_handle); });

View File

@ -237,7 +237,7 @@ void Init() {
FS::InstallInterfaces(*SM::g_service_manager); FS::InstallInterfaces(*SM::g_service_manager);
FS::ArchiveInit(); FS::ArchiveInit();
ACT::Init(); ACT::Init();
AM::Init(); AM::InstallInterfaces(*SM::g_service_manager);
APT::InstallInterfaces(*SM::g_service_manager); APT::InstallInterfaces(*SM::g_service_manager);
BOSS::Init(); BOSS::Init();
CAM::InstallInterfaces(*SM::g_service_manager); CAM::InstallInterfaces(*SM::g_service_manager);
@ -280,7 +280,6 @@ void Shutdown() {
CFG::Shutdown(); CFG::Shutdown();
CECD::Shutdown(); CECD::Shutdown();
BOSS::Shutdown(); BOSS::Shutdown();
AM::Shutdown();
FS::ArchiveShutdown(); FS::ArchiveShutdown();
SM::g_service_manager = nullptr; SM::g_service_manager = nullptr;