void GSP_GPU::RegisterInterruptRelayQueue(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x13, 1, 2); u32 flags = rp.Pop<u32>(); auto interrupt_event = rp.PopObject<Kernel::Event>(); // TODO(mailwl): return right error code instead assert ASSERT_MSG((interrupt_event != nullptr), "handle is not valid!"); interrupt_event->SetName("GSP_GSP_GPU::interrupt_event"); SessionData* session_data = GetSessionData(ctx.Session()); session_data->interrupt_event = std::move(interrupt_event); session_data->registered = true; IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); if (first_initialization) { // This specific code is required for a successful initialization, rather than 0 first_initialization = false; rb.Push(RESULT_FIRST_INITIALIZATION); } else { rb.Push(RESULT_SUCCESS); } rb.Push(session_data->thread_id); rb.PushCopyObjects(shared_memory); LOG_DEBUG(Service_GSP, "called, flags=0x{:08X}", flags); }
void HTTP_C::InitializeConnectionSession(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x8, 1, 2); const Context::Handle context_handle = rp.Pop<u32>(); u32 pid = rp.PopPID(); auto* session_data = GetSessionData(ctx.Session()); ASSERT(session_data); if (session_data->initialized) { LOG_ERROR(Service_HTTP, "Tried to initialize an already initialized session"); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(ERROR_STATE_ERROR); return; } // TODO(Subv): Check that the input PID matches the PID that created the context. auto itr = contexts.find(context_handle); if (itr == contexts.end()) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(ResultCode(ErrCodes::ContextNotFound, ErrorModule::HTTP, ErrorSummary::InvalidState, ErrorLevel::Permanent)); return; } session_data->initialized = true; session_data->session_id = ++session_counter; // Bind the context to the current session. session_data->current_http_context = context_handle; IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(RESULT_SUCCESS); LOG_DEBUG(Service_HTTP, "called, context_id={} pid={}", context_handle, pid); }
void GSP_GPU::ReadHWRegs(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x4, 2, 0); u32 reg_addr = rp.Pop<u32>(); u32 input_size = rp.Pop<u32>(); static constexpr u32 MaxReadSize = 0x80; u32 size = std::min(input_size, MaxReadSize); if ((reg_addr % 4) != 0 || reg_addr >= 0x420000) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(ERR_REGS_OUTOFRANGE_OR_MISALIGNED); LOG_ERROR(Service_GSP, "Invalid address 0x{:08x}", reg_addr); return; } // size should be word-aligned if ((size % 4) != 0) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(ERR_REGS_MISALIGNED); LOG_ERROR(Service_GSP, "Invalid size 0x{:08x}", size); return; } std::vector<u8> buffer(size); for (u32 offset = 0; offset < size; ++offset) { HW::Read<u8>(buffer[offset], REGS_BEGIN + reg_addr + offset); } IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); rb.Push(RESULT_SUCCESS); rb.PushStaticBuffer(std::move(buffer), 0); }
void HTTP_C::Initialize(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x1, 1, 4); const u32 shmem_size = rp.Pop<u32>(); u32 pid = rp.PopPID(); shared_memory = rp.PopObject<Kernel::SharedMemory>(); if (shared_memory) { shared_memory->name = "HTTP_C:shared_memory"; } LOG_WARNING(Service_HTTP, "(STUBBED) called, shared memory size: {} pid: {}", shmem_size, pid); auto* session_data = GetSessionData(ctx.Session()); ASSERT(session_data); if (session_data->initialized) { LOG_ERROR(Service_HTTP, "Tried to initialize an already initialized session"); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(ERROR_STATE_ERROR); return; } session_data->initialized = true; IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); // This returns 0xd8a0a046 if no network connection is available. // Just assume we are always connected. rb.Push(RESULT_SUCCESS); }
void Module::Interface::GetShellState(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x6, 0, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(RESULT_SUCCESS); rb.Push(ptm->shell_open); }
void HTTP_C::CloseClientCertContext(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x34, 1, 0); ClientCertContext::Handle cert_handle = rp.Pop<u32>(); auto* session_data = GetSessionData(ctx.Session()); ASSERT(session_data); if (client_certs.find(cert_handle) == client_certs.end()) { LOG_ERROR(Service_HTTP, "Command called with a unkown client cert handle {}", cert_handle); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); // This just return success without doing anything rb.Push(RESULT_SUCCESS); return; } if (client_certs[cert_handle].session_id != session_data->session_id) { LOG_ERROR(Service_HTTP, "called from another main session"); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); // This just return success without doing anything rb.Push(RESULT_SUCCESS); return; } client_certs.erase(cert_handle); session_data->num_client_certs--; IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(RESULT_SUCCESS); LOG_DEBUG(Service_HTTP, "called, cert_handle={}", cert_handle); }
void File::Write(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x0803, 4, 2); u64 offset = rp.Pop<u64>(); u32 length = rp.Pop<u32>(); u32 flush = rp.Pop<u32>(); auto& buffer = rp.PopMappedBuffer(); LOG_TRACE(Service_FS, "Write {}: offset=0x{:x} length={}, flush=0x{:x}", GetName(), offset, length, flush); IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); const FileSessionSlot* file = GetSessionData(ctx.Session()); // Subfiles can not be written to if (file->subfile) { rb.Push(FileSys::ERROR_UNSUPPORTED_OPEN_FLAGS); rb.Push<u32>(0); rb.PushMappedBuffer(buffer); return; } std::vector<u8> data(length); buffer.Read(data.data(), 0, data.size()); ResultVal<std::size_t> written = backend->Write(offset, data.size(), flush != 0, data.data()); if (written.Failed()) { rb.Push(written.Code()); rb.Push<u32>(0); } else { rb.Push(RESULT_SUCCESS); rb.Push<u32>(static_cast<u32>(*written)); } rb.PushMappedBuffer(buffer); }
void Module::Interface::GetSoftwareClosedFlag(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x80F, 0, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(RESULT_SUCCESS); rb.Push(false); LOG_WARNING(Service_PTM, "(STUBBED) called"); }
void Module::Interface::GetBatteryLevel(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x7, 0, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(RESULT_SUCCESS); rb.Push(static_cast<u32>(ChargeLevels::CompletelyFull)); // Set to a completely full battery LOG_WARNING(Service_PTM, "(STUBBED) called"); }
void Module::Interface::GetBatteryChargeState(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x8, 0, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(RESULT_SUCCESS); rb.Push(ptm->battery_is_charging); LOG_WARNING(Service_PTM, "(STUBBED) called"); }
void Module::Interface::GetPedometerState(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x9, 0, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(RESULT_SUCCESS); rb.Push(ptm->pedometer_is_counting); LOG_WARNING(Service_PTM, "(STUBBED) called"); }
void CheckNew3DS(IPC::RequestBuilder& rb) { const bool is_new_3ds = Settings::values.is_new_3ds; if (is_new_3ds) { LOG_CRITICAL(Service_PTM, "The option 'is_new_3ds' is enabled as part of the 'System' " "settings. Citra does not fully support New 3DS emulation yet!"); } rb.Push(RESULT_SUCCESS); rb.Push(is_new_3ds); LOG_WARNING(Service_PTM, "(STUBBED) called isNew3DS = 0x{:08x}", static_cast<u32>(is_new_3ds)); }
void FS_USER::OpenFileDirectly(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x803, 8, 4); rp.Skip(1, false); // Transaction auto archive_id = rp.PopEnum<FS::ArchiveIdCode>(); auto archivename_type = rp.PopEnum<FileSys::LowPathType>(); u32 archivename_size = rp.Pop<u32>(); auto filename_type = rp.PopEnum<FileSys::LowPathType>(); u32 filename_size = rp.Pop<u32>(); FileSys::Mode mode{rp.Pop<u32>()}; u32 attributes = rp.Pop<u32>(); // TODO(Link Mauve): do something with those attributes. std::vector<u8> archivename = rp.PopStaticBuffer(); std::vector<u8> filename = rp.PopStaticBuffer(); ASSERT(archivename.size() == archivename_size); ASSERT(filename.size() == filename_size); FileSys::Path archive_path(archivename_type, archivename); FileSys::Path file_path(filename_type, filename); LOG_DEBUG(Service_FS, "archive_id=0x{:08X} archive_path={} file_path={}, mode={} attributes={}", static_cast<u32>(archive_id), archive_path.DebugStr(), file_path.DebugStr(), mode.hex, attributes); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); ResultVal<ArchiveHandle> archive_handle = archives.OpenArchive(archive_id, archive_path); if (archive_handle.Failed()) { LOG_ERROR(Service_FS, "Failed to get a handle for archive archive_id=0x{:08X} archive_path={}", static_cast<u32>(archive_id), archive_path.DebugStr()); rb.Push(archive_handle.Code()); rb.PushMoveObjects<Kernel::Object>(nullptr); return; } SCOPE_EXIT({ archives.CloseArchive(*archive_handle); });
void File::Flush(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x0809, 0, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); const FileSessionSlot* file = GetSessionData(ctx.Session()); // Subfiles can not be flushed. if (file->subfile) { rb.Push(FileSys::ERROR_UNSUPPORTED_OPEN_FLAGS); return; } backend->Flush(); rb.Push(RESULT_SUCCESS); }
void Module::Interface::StopCommunication(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x04, 0, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(RESULT_SUCCESS); LOG_WARNING(Service_NFC, "(STUBBED) called"); }
/** * IR::GetHandles service function * Outputs: * 1 : Result of function, 0 on success, otherwise error code * 2 : Translate header, used by the ARM11-kernel * 3 : Shared memory handle * 4 : Event handle */ static void GetHandles(Interface* self) { IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x01, 0, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 3); rb.Push(RESULT_SUCCESS); rb.PushMoveHandles(Kernel::g_handle_table.Create(Service::IR::shared_memory).Unwrap(), Kernel::g_handle_table.Create(Service::IR::update_event).Unwrap()); }
void Module::Interface::UnscrambleLocalFriendCode(Kernel::HLERequestContext& ctx) { const std::size_t scrambled_friend_code_size = 12; const std::size_t friend_code_size = 8; IPC::RequestParser rp(ctx, 0x1C, 1, 2); const u32 friend_code_count = rp.Pop<u32>(); std::vector<u8> scrambled_friend_codes = rp.PopStaticBuffer(); ASSERT_MSG(scrambled_friend_codes.size() == (friend_code_count * scrambled_friend_code_size), "Wrong input buffer size"); std::vector<u8> unscrambled_friend_codes(friend_code_count * friend_code_size, 0); // TODO(B3N30): Unscramble the codes and compare them against the friend list // Only write 0 if the code isn't in friend list, otherwise write the // unscrambled one // // Code for unscrambling (should be compared to HW): // std::array<u16, 6> scambled_friend_code; // Memory::ReadBlock(scrambled_friend_codes+(current*scrambled_friend_code_size), // scambled_friend_code.data(), scrambled_friend_code_size); std::array<u16, 4> // unscrambled_friend_code; unscrambled_friend_code[0] = scambled_friend_code[0] ^ // scambled_friend_code[5]; unscrambled_friend_code[1] = scambled_friend_code[1] ^ // scambled_friend_code[5]; unscrambled_friend_code[2] = scambled_friend_code[2] ^ // scambled_friend_code[5]; unscrambled_friend_code[3] = scambled_friend_code[3] ^ // scambled_friend_code[5]; LOG_WARNING(Service_FRD, "(STUBBED) called"); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); rb.Push(RESULT_SUCCESS); rb.PushStaticBuffer(unscrambled_friend_codes, 0); }
void FS_USER::OpenFile(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x0802, 7, 2); rp.Skip(1, false); // Transaction. ArchiveHandle archive_handle = rp.Pop<u64>(); auto filename_type = rp.PopEnum<FileSys::LowPathType>(); u32 filename_size = rp.Pop<u32>(); FileSys::Mode mode{rp.Pop<u32>()}; u32 attributes = rp.Pop<u32>(); // TODO(Link Mauve): do something with those attributes. std::vector<u8> filename = rp.PopStaticBuffer(); ASSERT(filename.size() == filename_size); FileSys::Path file_path(filename_type, filename); LOG_DEBUG(Service_FS, "path={}, mode={} attrs={}", file_path.DebugStr(), mode.hex, attributes); ResultVal<std::shared_ptr<File>> file_res = archives.OpenFileFromArchive(archive_handle, file_path, mode); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); rb.Push(file_res.Code()); if (file_res.Succeeded()) { std::shared_ptr<File> file = *file_res; rb.PushMoveObjects(file->Connect()); } else { rb.PushMoveObjects<Kernel::Object>(nullptr); LOG_ERROR(Service_FS, "failed to get a handle for file {}", file_path.DebugStr()); } }
void Module::Interface::GetTagState(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x0D, 0, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(RESULT_SUCCESS); rb.PushEnum(nfc->nfc_tag_state); LOG_DEBUG(Service_NFC, "(STUBBED) called"); }
void Module::Interface::GetTagOutOfRangeEvent(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x0C, 0, 0); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); rb.Push(RESULT_SUCCESS); rb.PushCopyObjects(nfc->tag_out_of_range_event); LOG_WARNING(Service_NFC, "(STUBBED) called"); }
void File::GetPriority(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x080B, 0, 0); const FileSessionSlot* file = GetSessionData(ctx.Session()); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(RESULT_SUCCESS); rb.Push(file->priority); }
static void SetDitheringWeightParams(Interface* self) { IPC::RequestParser rp(Kernel::GetCommandBuffer(), 0x24, 8, 0); // 0x240200 rp.PopRaw(dithering_weight_params); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(RESULT_SUCCESS); LOG_DEBUG(Service_Y2R, "called"); }
void Module::Interface::CommunicationGetStatus(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x0F, 0, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(RESULT_SUCCESS); rb.PushEnum(nfc->nfc_status); LOG_DEBUG(Service_NFC, "(STUBBED) called"); }
void GSP_GPU::SetBufferSwap(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x5, 8, 0); u32 screen_id = rp.Pop<u32>(); auto fb_info = rp.PopRaw<FrameBufferInfo>(); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(GSP::SetBufferSwap(screen_id, fb_info)); }
void Module::Interface::GetMyFriendKey(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x5, 0, 0); IPC::RequestBuilder rb = rp.MakeBuilder(5, 0); rb.Push(RESULT_SUCCESS); rb.PushRaw(frd->my_friend_key); LOG_WARNING(Service_FRD, "(STUBBED) called"); }
void File::OpenSubFile(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x0801, 4, 0); s64 offset = rp.PopRaw<s64>(); s64 size = rp.PopRaw<s64>(); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); const FileSessionSlot* original_file = GetSessionData(ctx.Session()); if (original_file->subfile) { // OpenSubFile can not be called on a file which is already as subfile rb.Push(FileSys::ERROR_UNSUPPORTED_OPEN_FLAGS); return; } if (offset < 0 || size < 0) { rb.Push(FileSys::ERR_WRITE_BEYOND_END); return; } std::size_t end = offset + size; // TODO(Subv): Check for overflow and return ERR_WRITE_BEYOND_END if (end > original_file->size) { rb.Push(FileSys::ERR_WRITE_BEYOND_END); return; } using Kernel::ClientSession; using Kernel::ServerSession; using Kernel::SharedPtr; auto sessions = system.Kernel().CreateSessionPair(GetName()); auto server = std::get<SharedPtr<ServerSession>>(sessions); ClientConnected(server); FileSessionSlot* slot = GetSessionData(server); slot->priority = original_file->priority; slot->offset = offset; slot->size = size; slot->subfile = true; rb.Push(RESULT_SUCCESS); rb.PushMoveObjects(std::get<SharedPtr<ClientSession>>(sessions)); }
void Module::Interface::GetTotalStepCount(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0xC, 0, 0); IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); rb.Push(RESULT_SUCCESS); rb.Push<u32>(0); LOG_WARNING(Service_PTM, "(STUBBED) called"); }
void File::GetSize(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x0804, 0, 0); const FileSessionSlot* file = GetSessionData(ctx.Session()); IPC::RequestBuilder rb = rp.MakeBuilder(3, 0); rb.Push(RESULT_SUCCESS); rb.Push<u64>(file->size); }
void File::SetSize(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x0805, 2, 0); u64 size = rp.Pop<u64>(); FileSessionSlot* file = GetSessionData(ctx.Session()); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); // SetSize can not be called on subfiles. if (file->subfile) { rb.Push(FileSys::ERROR_UNSUPPORTED_OPEN_FLAGS); return; } file->size = size; backend->SetSize(size); rb.Push(RESULT_SUCCESS); }
void File::SetPriority(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x080A, 1, 0); FileSessionSlot* file = GetSessionData(ctx.Session()); file->priority = rp.Pop<u32>(); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(RESULT_SUCCESS); }