summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/lm/lm.cpp
blob: 74ecaef1b7f7acc31d8ada4c8e1d15db4b15b011 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
// Copyright 2018 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

#include <sstream>
#include <string>

#include "common/logging/log.h"
#include "common/scope_exit.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<ILogger> {
public:
    explicit ILogger(Manager& manager_, 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<Field>(Memory::Read8(addr++));
            const auto length = Memory::Read8(addr++);

            if (static_cast<Field>(Memory::Read8(addr)) == Field::Skip) {
                ++addr;
            }

            SCOPE_EXIT({ addr += length; });

            if (field == Field::Skip) {
                continue;
            }

            std::vector<u8> 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<DestinationFlag>();

        LOG_DEBUG(Service_LM, "called, destination={:08X}", static_cast<u32>(destination));

        manager.SetDestination(destination);

        IPC::ResponseBuilder rb{ctx, 2};
        rb.Push(RESULT_SUCCESS);
    }

    Manager& manager;
    Memory::Memory& memory;
};

class LM final : public ServiceFramework<LM> {
public:
    explicit LM(Manager& manager_, 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<ILogger>(manager, memory);
    }

    Manager& manager;
    Memory::Memory& memory;
};

void InstallInterfaces(Core::System& system) {
    std::make_shared<LM>(system.GetLogManager(), system.Memory())
        ->InstallAsService(system.ServiceManager());
}

} // namespace Service::LM