// Copyright 2018 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #include #include #include "common/logging/log.h" #include "common/scope_exit.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" #include "core/hle/service/lm/lm.h" #include "core/hle/service/lm/manager.h" #include "core/hle/service/service.h" #include "core/memory.h" namespace Service::LM { class ILogger final : public ServiceFramework { public: explicit ILogger(Manager& manager_, Core::Memory::Memory& memory_) : ServiceFramework("ILogger"), manager{manager_}, memory{memory_} { static const FunctionInfo functions[] = { {0, &ILogger::Log, "Log"}, {1, &ILogger::SetDestination, "SetDestination"}, }; RegisterHandlers(functions); } private: void Log(Kernel::HLERequestContext& ctx) { // This function only succeeds - Get that out of the way IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); // Read MessageHeader, despite not doing anything with it right now MessageHeader header{}; VAddr addr{ctx.BufferDescriptorX()[0].Address()}; const VAddr end_addr{addr + ctx.BufferDescriptorX()[0].size}; memory.ReadBlock(addr, &header, sizeof(MessageHeader)); addr += sizeof(MessageHeader); FieldMap fields; while (addr < end_addr) { const auto field = static_cast(memory.Read8(addr++)); const auto length = memory.Read8(addr++); if (static_cast(memory.Read8(addr)) == Field::Skip) { ++addr; } SCOPE_EXIT({ addr += length; }); if (field == Field::Skip) { continue; } std::vector data(length); memory.ReadBlock(addr, data.data(), length); fields.emplace(field, std::move(data)); } manager.Log({header, std::move(fields)}); } void SetDestination(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto destination = rp.PopEnum(); LOG_DEBUG(Service_LM, "called, destination={:08X}", static_cast(destination)); manager.SetDestination(destination); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } Manager& manager; Core::Memory::Memory& memory; }; class LM final : public ServiceFramework { public: explicit LM(Manager& manager_, Core::Memory::Memory& memory_) : ServiceFramework{"lm"}, manager{manager_}, memory{memory_} { // clang-format off static const FunctionInfo functions[] = { {0, &LM::OpenLogger, "OpenLogger"}, }; // clang-format on RegisterHandlers(functions); } private: void OpenLogger(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_LM, "called"); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface(manager, memory); } Manager& manager; Core::Memory::Memory& memory; }; void InstallInterfaces(Core::System& system) { std::make_shared(system.GetLogManager(), system.Memory()) ->InstallAsService(system.ServiceManager()); } } // namespace Service::LM