aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/hle/service/service.h
blob: e75d5008bb053a5c58a34ddf64cb551f23e86a63 (plain)
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

#pragma once

#include <algorithm>
#include <vector>
#include <map>
#include <string>

#include "common/common.h"
#include "common/string_util.h"
#include "core/mem_map.h"

#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/session.h"
#include "core/hle/svc.h"

////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace Service

namespace Service {

static const int kMaxPortSize = 8; ///< Maximum size of a port name (8 characters)

class Manager;

/// Interface to a CTROS service
class Interface  : public Kernel::Session {
    // TODO(yuriks): An "Interface" being a Kernel::Object is mostly non-sense. Interface should be
    // just something that encapsulates a session and acts as a helper to implement service
    // processes.

    friend class Manager;

    /**
     * Creates a function string for logging, complete with the name (or header code, depending 
     * on what's passed in) the port name, and all the cmd_buff arguments.
     */
    std::string MakeFunctionString(const std::string& name, const std::string& port_name, const u32* cmd_buff) {
        // Number of params == bits 0-5 + bits 6-11
        int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F);

        std::string function_string = Common::StringFromFormat("function '%s': port=%s", name.c_str(), port_name.c_str());
        for (int i = 1; i <= num_params; ++i) {
            function_string += Common::StringFromFormat(", cmd_buff[%i]=%u", i, cmd_buff[i]);
        }
        return function_string;
    }

public:
    std::string GetName() const override { return GetPortName(); }

    typedef void (*Function)(Interface*);

    struct FunctionInfo {
        u32         id;
        Function    func;
        std::string name;
    };

    /**
     * Gets the string name used by CTROS for a service
     * @return Port name of service
     */
    virtual std::string GetPortName() const {
        return "[UNKNOWN SERVICE PORT]";
    }

    /// Allocates a new handle for the service
    Handle CreateHandle(Kernel::Object *obj) {
        // TODO(yuriks): Fix error reporting
        Handle handle = Kernel::g_handle_table.Create(obj).ValueOr(INVALID_HANDLE);
        m_handles.push_back(handle);
        return handle;
    }

    /// Frees a handle from the service
    template <class T>
    void DeleteHandle(const Handle handle) {
        Kernel::g_handle_table.Close(handle);
        m_handles.erase(std::remove(m_handles.begin(), m_handles.end(), handle), m_handles.end());
    }

    ResultVal<bool> SyncRequest() override {
        u32* cmd_buff = Kernel::GetCommandBuffer();
        auto itr = m_functions.find(cmd_buff[0]);

        if (itr == m_functions.end() || itr->second.func == nullptr) {
            std::string function_name = (itr == m_functions.end()) ? Common::StringFromFormat("0x%08X", cmd_buff[0]) : itr->second.name;
            LOG_ERROR(Service, "%s %s", "unknown/unimplemented", MakeFunctionString(function_name, GetPortName(), cmd_buff).c_str());

            // TODO(bunnei): Hack - ignore error
            cmd_buff[1] = 0;
            return MakeResult<bool>(false);
        } else {
            LOG_TRACE(Service, "%s", MakeFunctionString(itr->second.name, GetPortName(), cmd_buff).c_str());
        }

        itr->second.func(this);

        return MakeResult<bool>(false); // TODO: Implement return from actual function
    }

protected:

    /**
     * Registers the functions in the service
     */
    void Register(const FunctionInfo* functions, int len) {
        for (int i = 0; i < len; i++) {
            m_functions[functions[i].id] = functions[i];
        }
    }

private:

    std::vector<Handle>         m_handles;
    std::map<u32, FunctionInfo> m_functions;

};

/// Simple class to manage accessing services from ports and UID handles
class Manager {
public:
    /// Add a service to the manager
    void AddService(Interface* service);

    /// Removes a service from the manager
    void DeleteService(const std::string& port_name);

    /// Get a Service Interface from its Handle
    Interface* FetchFromHandle(Handle handle);

    /// Get a Service Interface from its port
    Interface* FetchFromPortName(const std::string& port_name);

private:
    std::vector<Interface*>     m_services;
    std::map<std::string, u32>  m_port_map;
};

/// Initialize ServiceManager
void Init();

/// Shutdown ServiceManager
void Shutdown();


extern Manager* g_manager; ///< Service manager


} // namespace