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
155
156
157
158
159
160
161
162
163
164
165
166
167
|
// Copyright 2014 Citra Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#pragma once
#include <vector>
#include <map>
#include <string>
#include "common/common.h"
#include "common/common_types.h"
#include "core/hle/syscall.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
// Namespace Service
namespace Service {
typedef s32 NativeUID; ///< Native handle for a service
static const int kMaxPortSize = 0x08; ///< Maximum size of a port name (8 characters)
static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header
class Manager;
/// Interface to a CTROS service
class Interface : NonCopyable {
friend class Manager;
public:
Interface() {
}
virtual ~Interface() {
}
typedef void (*Function)(Interface*);
struct FunctionInfo {
u32 id;
Function func;
std::string name;
};
/**
* Gets the UID for the serice
* @return UID of service in native format
*/
NativeUID GetUID() const {
return (NativeUID)m_uid;
}
/**
* 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
Syscall::Handle NewHandle() {
Syscall::Handle handle = (m_handles.size() << 16) | m_uid;
m_handles.push_back(handle);
return handle;
}
/// Frees a handle from the service
void DeleteHandle(Syscall::Handle handle) {
for(auto iter = m_handles.begin(); iter != m_handles.end(); ++iter) {
if(*iter == handle) {
m_handles.erase(iter);
break;
}
}
}
/**
* Called when svcSendSyncRequest is called, loads command buffer and executes comand
* @return Return result of svcSendSyncRequest passed back to user app
*/
Syscall::Result Sync() {
u32* cmd_buff = (u32*)HLE::GetPointer(HLE::CMD_BUFFER_ADDR + kCommandHeaderOffset);
auto itr = m_functions.find(cmd_buff[0]);
if (itr == m_functions.end()) {
ERROR_LOG(OSHLE, "Unknown/unimplemented function: port = %s, command = 0x%08X!",
GetPortName().c_str(), cmd_buff[0]);
return -1;
}
if (itr->second.func == NULL) {
ERROR_LOG(OSHLE, "Unimplemented function: port = %s, name = %s!",
GetPortName().c_str(), itr->second.name.c_str());
return -1;
}
itr->second.func(this);
return 0; // 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:
u32 m_uid;
std::vector<Syscall::Handle> m_handles;
std::map<u32, FunctionInfo> m_functions;
};
/// Simple class to manage accessing services from ports and UID handles
class Manager {
public:
Manager();
~Manager();
/// Add a service to the manager (does not create it though)
void AddService(Interface* service);
/// Removes a service from the manager (does not delete it though)
void DeleteService(std::string port_name);
/// Get a Service Interface from its UID
Interface* FetchFromUID(u32 uid);
/// Get a Service Interface from its port
Interface* FetchFromPortName(std::string port_name);
private:
/// Convert an index into m_services vector into a UID
static u32 GetUIDFromIndex(const int index) {
return index | 0x10000000;
}
/// Convert a UID into an index into m_services
static int GetIndexFromUID(const u32 uid) {
return uid & 0x0FFFFFFF;
}
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
|