summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Chloe Marcec2021-03-27 02:03:18 +1100
committerGravatar Chloe Marcec2021-03-27 02:03:18 +1100
commite9a1f29e936e8da5899c360394f37c7646150e3f (patch)
treecbcd16b15b3e485c2523b41dee5a9e15706ca6fd /src
parentMerge pull request #6101 from ogniK5377/alloc-as-ex (diff)
downloadyuzu-e9a1f29e936e8da5899c360394f37c7646150e3f.tar.gz
yuzu-e9a1f29e936e8da5899c360394f37c7646150e3f.tar.xz
yuzu-e9a1f29e936e8da5899c360394f37c7646150e3f.zip
pctl: Rework how pctl works to be more accurate
Introduces the usage of compatibilities to allow it the module to be closer to how it works on hardware.
Diffstat (limited to 'src')
-rw-r--r--src/core/file_sys/control_metadata.cpp8
-rw-r--r--src/core/file_sys/control_metadata.h2
-rw-r--r--src/core/hle/service/pctl/module.cpp247
-rw-r--r--src/core/hle/service/pctl/module.h19
-rw-r--r--src/core/hle/service/pctl/pctl.cpp5
-rw-r--r--src/core/hle/service/pctl/pctl.h3
6 files changed, 253 insertions, 31 deletions
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp
index b0a130345..f66759815 100644
--- a/src/core/file_sys/control_metadata.cpp
+++ b/src/core/file_sys/control_metadata.cpp
@@ -100,6 +100,14 @@ u64 NACP::GetDeviceSaveDataSize() const {
100 return raw.device_save_data_size; 100 return raw.device_save_data_size;
101} 101}
102 102
103u32 NACP::GetParentalControlFlag() const {
104 return raw.parental_control;
105}
106
107const std::array<u8, 0x20>& NACP::GetRatingAge() const {
108 return raw.rating_age;
109}
110
103std::vector<u8> NACP::GetRawBytes() const { 111std::vector<u8> NACP::GetRawBytes() const {
104 std::vector<u8> out(sizeof(RawNACP)); 112 std::vector<u8> out(sizeof(RawNACP));
105 std::memcpy(out.data(), &raw, sizeof(RawNACP)); 113 std::memcpy(out.data(), &raw, sizeof(RawNACP));
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h
index 403c4219a..dd9837cf5 100644
--- a/src/core/file_sys/control_metadata.h
+++ b/src/core/file_sys/control_metadata.h
@@ -114,6 +114,8 @@ public:
114 std::vector<u8> GetRawBytes() const; 114 std::vector<u8> GetRawBytes() const;
115 bool GetUserAccountSwitchLock() const; 115 bool GetUserAccountSwitchLock() const;
116 u64 GetDeviceSaveDataSize() const; 116 u64 GetDeviceSaveDataSize() const;
117 u32 GetParentalControlFlag() const;
118 const std::array<u8, 0x20>& GetRatingAge() const;
117 119
118private: 120private:
119 RawNACP raw{}; 121 RawNACP raw{};
diff --git a/src/core/hle/service/pctl/module.cpp b/src/core/hle/service/pctl/module.cpp
index f9089bf2f..2f0edde2a 100644
--- a/src/core/hle/service/pctl/module.cpp
+++ b/src/core/hle/service/pctl/module.cpp
@@ -3,16 +3,30 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "core/core.h"
7#include "core/file_sys/control_metadata.h"
8#include "core/file_sys/patch_manager.h"
6#include "core/hle/ipc_helpers.h" 9#include "core/hle/ipc_helpers.h"
10#include "core/hle/kernel/process.h"
7#include "core/hle/service/pctl/module.h" 11#include "core/hle/service/pctl/module.h"
8#include "core/hle/service/pctl/pctl.h" 12#include "core/hle/service/pctl/pctl.h"
9 13
10namespace Service::PCTL { 14namespace Service::PCTL {
11 15
16namespace Error {
17
18constexpr ResultCode ResultNoFreeCommunication{ErrorModule::PCTL, 101};
19constexpr ResultCode ResultStereoVisionRestricted{ErrorModule::PCTL, 104};
20constexpr ResultCode ResultNoCapatability{ErrorModule::PCTL, 131};
21constexpr ResultCode ResultNoRestrictionEnabled{ErrorModule::PCTL, 181};
22
23} // namespace Error
24
12class IParentalControlService final : public ServiceFramework<IParentalControlService> { 25class IParentalControlService final : public ServiceFramework<IParentalControlService> {
13public: 26public:
14 explicit IParentalControlService(Core::System& system_) 27 explicit IParentalControlService(Core::System& system_, Capability capability)
15 : ServiceFramework{system_, "IParentalControlService"} { 28 : ServiceFramework{system_, "IParentalControlService"}, system(system_),
29 capability(capability) {
16 // clang-format off 30 // clang-format off
17 static const FunctionInfo functions[] = { 31 static const FunctionInfo functions[] = {
18 {1, &IParentalControlService::Initialize, "Initialize"}, 32 {1, &IParentalControlService::Initialize, "Initialize"},
@@ -28,13 +42,13 @@ public:
28 {1010, nullptr, "IsRestrictedSystemSettingsEntered"}, 42 {1010, nullptr, "IsRestrictedSystemSettingsEntered"},
29 {1011, nullptr, "RevertRestrictedSystemSettingsEntered"}, 43 {1011, nullptr, "RevertRestrictedSystemSettingsEntered"},
30 {1012, nullptr, "GetRestrictedFeatures"}, 44 {1012, nullptr, "GetRestrictedFeatures"},
31 {1013, nullptr, "ConfirmStereoVisionPermission"}, 45 {1013, &IParentalControlService::ConfirmStereoVisionPermission, "ConfirmStereoVisionPermission"},
32 {1014, nullptr, "ConfirmPlayableApplicationVideoOld"}, 46 {1014, nullptr, "ConfirmPlayableApplicationVideoOld"},
33 {1015, nullptr, "ConfirmPlayableApplicationVideo"}, 47 {1015, nullptr, "ConfirmPlayableApplicationVideo"},
34 {1016, nullptr, "ConfirmShowNewsPermission"}, 48 {1016, nullptr, "ConfirmShowNewsPermission"},
35 {1017, nullptr, "EndFreeCommunication"}, 49 {1017, nullptr, "EndFreeCommunication"},
36 {1018, nullptr, "IsFreeCommunicationAvailable"}, 50 {1018, &IParentalControlService::IsFreeCommunicationAvailable, "IsFreeCommunicationAvailable"},
37 {1031, nullptr, "IsRestrictionEnabled"}, 51 {1031, &IParentalControlService::IsRestrictionEnabled, "IsRestrictionEnabled"},
38 {1032, nullptr, "GetSafetyLevel"}, 52 {1032, nullptr, "GetSafetyLevel"},
39 {1033, nullptr, "SetSafetyLevel"}, 53 {1033, nullptr, "SetSafetyLevel"},
40 {1034, nullptr, "GetSafetyLevelSettings"}, 54 {1034, nullptr, "GetSafetyLevelSettings"},
@@ -119,62 +133,234 @@ public:
119 } 133 }
120 134
121private: 135private:
136 bool CheckFreeCommunicationPermissionImpl() {
137 if (states.temporary_unlocked) {
138 return true;
139 }
140 if ((states.application_info.parental_control_flag & 1) == 0) {
141 return true;
142 }
143 if (pin_code[0] == '\0') {
144 return true;
145 }
146 if (!settings.is_free_communication_default_on) {
147 return true;
148 }
149 // TODO(ogniK): Check for blacklisted/exempted applications
150 return true;
151 }
152
153 bool ConfirmStereoVisionPermissionImpl() {
154 if (states.temporary_unlocked) {
155 return true;
156 }
157 if (pin_code[0] == '\0') {
158 return true;
159 }
160 if (!settings.is_stero_vision_restricted) {
161 return false;
162 }
163 return true;
164 }
165
166 void SetStereoVisionRestrictionImpl(bool is_restricted) {
167 if (settings.disabled) {
168 return;
169 }
170
171 if (pin_code[0] == '\0') {
172 return;
173 }
174 settings.is_stero_vision_restricted = is_restricted;
175 }
176
122 void Initialize(Kernel::HLERequestContext& ctx) { 177 void Initialize(Kernel::HLERequestContext& ctx) {
123 LOG_WARNING(Service_PCTL, "(STUBBED) called"); 178 LOG_DEBUG(Service_PCTL, "called");
179 IPC::ResponseBuilder rb{ctx, 2};
180
181 if (False(capability & (Capability::Application | Capability::System))) {
182 LOG_ERROR(Service_PCTL, "Invalid capability! capability={:X}",
183 static_cast<s32>(capability));
184 return;
185 }
186
187 // TODO(ogniK): Recovery
188
189 const auto tid = system.CurrentProcess()->GetTitleID();
190 if (tid != 0) {
191 const FileSys::PatchManager pm{tid, system.GetFileSystemController(),
192 system.GetContentProvider()};
193 const auto control = pm.GetControlMetadata();
194 if (control.first) {
195 states.tid_from_event = 0;
196 states.launch_time_valid = false;
197 states.is_suspended = false;
198 states.free_communication = false;
199 states.stereo_vision = false;
200 states.application_info = ApplicationInfo{
201 .tid = tid,
202 .age_rating = control.first->GetRatingAge(),
203 .parental_control_flag = control.first->GetParentalControlFlag(),
204 .capability = capability,
205 };
206
207 if (False(capability & (Capability::System | Capability::Recovery))) {
208 // TODO(ogniK): Signal application launch event
209 }
210 }
211 }
124 212
125 IPC::ResponseBuilder rb{ctx, 2, 0, 0};
126 rb.Push(RESULT_SUCCESS); 213 rb.Push(RESULT_SUCCESS);
127 } 214 }
128 215
129 void CheckFreeCommunicationPermission(Kernel::HLERequestContext& ctx) { 216 void CheckFreeCommunicationPermission(Kernel::HLERequestContext& ctx) {
130 LOG_WARNING(Service_PCTL, "(STUBBED) called"); 217 LOG_DEBUG(Service_PCTL, "called");
218
219 IPC::ResponseBuilder rb{ctx, 2};
220 if (!CheckFreeCommunicationPermissionImpl()) {
221 rb.Push(Error::ResultNoFreeCommunication);
222 } else {
223 rb.Push(RESULT_SUCCESS);
224 }
225
226 states.free_communication = true;
227 }
228
229 void ConfirmStereoVisionPermission(Kernel::HLERequestContext& ctx) {
230 LOG_DEBUG(Service_PCTL, "called");
231 states.stereo_vision = true;
131 232
132 IPC::ResponseBuilder rb{ctx, 2}; 233 IPC::ResponseBuilder rb{ctx, 2};
133 rb.Push(RESULT_SUCCESS); 234 rb.Push(RESULT_SUCCESS);
134 } 235 }
135 236
136 void ConfirmStereoVisionRestrictionConfigurable(Kernel::HLERequestContext& ctx) { 237 void IsFreeCommunicationAvailable(Kernel::HLERequestContext& ctx) {
137 LOG_WARNING(Service_PCTL, "(STUBBED) called"); 238 LOG_WARNING(Service_PCTL, "(STUBBED) called");
138 239
139 IPC::ResponseBuilder rb{ctx, 2}; 240 IPC::ResponseBuilder rb{ctx, 2};
241 if (!CheckFreeCommunicationPermissionImpl()) {
242 rb.Push(Error::ResultNoFreeCommunication);
243 } else {
244 rb.Push(RESULT_SUCCESS);
245 }
246 }
247
248 void IsRestrictionEnabled(Kernel::HLERequestContext& ctx) {
249 LOG_DEBUG(Service_PCTL, "called");
250
251 IPC::ResponseBuilder rb{ctx, 3};
252 if (False(capability & (Capability::Status | Capability::Recovery))) {
253 LOG_ERROR(Service_PCTL, "Application does not have Status or Recovery capabilities!");
254 rb.Push(Error::ResultNoCapatability);
255 rb.Push(false);
256 return;
257 }
258
259 rb.Push(pin_code[0] != '\0');
260 }
261
262 void ConfirmStereoVisionRestrictionConfigurable(Kernel::HLERequestContext& ctx) {
263 LOG_DEBUG(Service_PCTL, "called");
264
265 IPC::ResponseBuilder rb{ctx, 2};
266
267 if (False(capability & Capability::SteroVision)) {
268 LOG_ERROR(Service_PCTL, "Application does not have SteroVision capability!");
269 rb.Push(Error::ResultNoCapatability);
270 return;
271 }
272
273 if (pin_code[0] == '\0') {
274 rb.Push(Error::ResultNoRestrictionEnabled);
275 return;
276 }
277
140 rb.Push(RESULT_SUCCESS); 278 rb.Push(RESULT_SUCCESS);
141 } 279 }
142 280
143 void IsStereoVisionPermitted(Kernel::HLERequestContext& ctx) { 281 void IsStereoVisionPermitted(Kernel::HLERequestContext& ctx) {
144 LOG_WARNING(Service_PCTL, "(STUBBED) called"); 282 LOG_DEBUG(Service_PCTL, "called");
145 283
146 IPC::ResponseBuilder rb{ctx, 3}; 284 IPC::ResponseBuilder rb{ctx, 3};
147 rb.Push(RESULT_SUCCESS); 285 if (!ConfirmStereoVisionPermissionImpl()) {
148 rb.Push(true); 286 rb.Push(Error::ResultStereoVisionRestricted);
287 rb.Push(false);
288 } else {
289 rb.Push(RESULT_SUCCESS);
290 rb.Push(true);
291 }
149 } 292 }
150 293
151 void SetStereoVisionRestriction(Kernel::HLERequestContext& ctx) { 294 void SetStereoVisionRestriction(Kernel::HLERequestContext& ctx) {
152 IPC::RequestParser rp{ctx}; 295 IPC::RequestParser rp{ctx};
153 const auto can_use = rp.Pop<bool>(); 296 const auto can_use = rp.Pop<bool>();
154 LOG_WARNING(Service_PCTL, "(STUBBED) called, can_use={}", can_use); 297 LOG_DEBUG(Service_PCTL, "called, can_use={}", can_use);
155
156 can_use_stereo_vision = can_use;
157 298
158 IPC::ResponseBuilder rb{ctx, 2}; 299 IPC::ResponseBuilder rb{ctx, 2};
300 if (False(capability & Capability::SteroVision)) {
301 LOG_ERROR(Service_PCTL, "Application does not have SteroVision capability!");
302 rb.Push(Error::ResultNoCapatability);
303 return;
304 }
305
306 SetStereoVisionRestrictionImpl(can_use);
159 rb.Push(RESULT_SUCCESS); 307 rb.Push(RESULT_SUCCESS);
160 } 308 }
161 309
162 void GetStereoVisionRestriction(Kernel::HLERequestContext& ctx) { 310 void GetStereoVisionRestriction(Kernel::HLERequestContext& ctx) {
163 LOG_WARNING(Service_PCTL, "(STUBBED) called"); 311 LOG_DEBUG(Service_PCTL, "called");
164 312
165 IPC::ResponseBuilder rb{ctx, 3}; 313 IPC::ResponseBuilder rb{ctx, 3};
314 if (False(capability & Capability::SteroVision)) {
315 LOG_ERROR(Service_PCTL, "Application does not have SteroVision capability!");
316 rb.Push(Error::ResultNoCapatability);
317 rb.Push(false);
318 return;
319 }
320
166 rb.Push(RESULT_SUCCESS); 321 rb.Push(RESULT_SUCCESS);
167 rb.Push(can_use_stereo_vision); 322 rb.Push(settings.is_stero_vision_restricted);
168 } 323 }
169 324
170 void ResetConfirmedStereoVisionPermission(Kernel::HLERequestContext& ctx) { 325 void ResetConfirmedStereoVisionPermission(Kernel::HLERequestContext& ctx) {
171 LOG_WARNING(Service_PCTL, "(STUBBED) called"); 326 LOG_DEBUG(Service_PCTL, "called");
327
328 states.stereo_vision = false;
172 329
173 IPC::ResponseBuilder rb{ctx, 2}; 330 IPC::ResponseBuilder rb{ctx, 2};
174 rb.Push(RESULT_SUCCESS); 331 rb.Push(RESULT_SUCCESS);
175 } 332 }
176 333
334 struct ApplicationInfo {
335 u64 tid{};
336 std::array<u8, 32> age_rating{};
337 u32 parental_control_flag{};
338 Capability capability{};
339 };
340
341 struct States {
342 u64 current_tid{};
343 ApplicationInfo application_info{};
344 u64 tid_from_event{};
345 bool launch_time_valid{};
346 bool is_suspended{};
347 bool temporary_unlocked{};
348 bool free_communication{};
349 bool stereo_vision{};
350 };
351
352 struct ParentalControlSettings {
353 bool is_stero_vision_restricted{};
354 bool is_free_communication_default_on{};
355 bool disabled{};
356 };
357
358 States states{};
359 ParentalControlSettings settings{};
360 std::array<char, 8> pin_code{};
177 bool can_use_stereo_vision = true; 361 bool can_use_stereo_vision = true;
362 Core::System& system;
363 Capability capability{};
178}; 364};
179 365
180void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) { 366void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) {
@@ -182,7 +368,9 @@ void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) {
182 368
183 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 369 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
184 rb.Push(RESULT_SUCCESS); 370 rb.Push(RESULT_SUCCESS);
185 rb.PushIpcInterface<IParentalControlService>(system); 371 // TODO(ogniK): Get TID from process
372
373 rb.PushIpcInterface<IParentalControlService>(system, capability);
186} 374}
187 375
188void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) { 376void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) {
@@ -190,21 +378,28 @@ void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext
190 378
191 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 379 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
192 rb.Push(RESULT_SUCCESS); 380 rb.Push(RESULT_SUCCESS);
193 rb.PushIpcInterface<IParentalControlService>(system); 381 rb.PushIpcInterface<IParentalControlService>(system, capability);
194} 382}
195 383
196Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_, 384Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_,
197 const char* name) 385 const char* name, Capability capability)
198 : ServiceFramework{system_, name}, module{std::move(module_)} {} 386 : ServiceFramework{system_, name}, module{std::move(module_)}, capability(capability) {}
199 387
200Module::Interface::~Interface() = default; 388Module::Interface::~Interface() = default;
201 389
202void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { 390void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
203 auto module = std::make_shared<Module>(); 391 auto module = std::make_shared<Module>();
204 std::make_shared<PCTL>(system, module, "pctl")->InstallAsService(service_manager); 392 std::make_shared<PCTL>(system, module, "pctl",
205 std::make_shared<PCTL>(system, module, "pctl:a")->InstallAsService(service_manager); 393 Capability::Application | Capability::SnsPost | Capability::Status |
206 std::make_shared<PCTL>(system, module, "pctl:r")->InstallAsService(service_manager); 394 Capability::SteroVision)
207 std::make_shared<PCTL>(system, module, "pctl:s")->InstallAsService(service_manager); 395 ->InstallAsService(service_manager);
396 // TODO(ogniK): Implement remaining capabilities
397 std::make_shared<PCTL>(system, module, "pctl:a", Capability::None)
398 ->InstallAsService(service_manager);
399 std::make_shared<PCTL>(system, module, "pctl:r", Capability::None)
400 ->InstallAsService(service_manager);
401 std::make_shared<PCTL>(system, module, "pctl:s", Capability::None)
402 ->InstallAsService(service_manager);
208} 403}
209 404
210} // namespace Service::PCTL 405} // namespace Service::PCTL
diff --git a/src/core/hle/service/pctl/module.h b/src/core/hle/service/pctl/module.h
index 4c7e09a3b..cdba11d60 100644
--- a/src/core/hle/service/pctl/module.h
+++ b/src/core/hle/service/pctl/module.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "common/common_funcs.h"
7#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
8 9
9namespace Core { 10namespace Core {
@@ -12,12 +13,23 @@ class System;
12 13
13namespace Service::PCTL { 14namespace Service::PCTL {
14 15
16enum class Capability : s32 {
17 None = 0x0,
18 Application = 1 << 0,
19 SnsPost = 1 << 1,
20 Recovery = 1 << 6,
21 Status = 1 << 8,
22 SteroVision = 1 << 9,
23 System = 1 << 15,
24};
25DECLARE_ENUM_FLAG_OPERATORS(Capability);
26
15class Module final { 27class Module final {
16public: 28public:
17 class Interface : public ServiceFramework<Interface> { 29 class Interface : public ServiceFramework<Interface> {
18 public: 30 public:
19 explicit Interface(Core::System& system_, std::shared_ptr<Module> module_, 31 explicit Interface(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
20 const char* name); 32 Capability capability);
21 ~Interface() override; 33 ~Interface() override;
22 34
23 void CreateService(Kernel::HLERequestContext& ctx); 35 void CreateService(Kernel::HLERequestContext& ctx);
@@ -25,6 +37,9 @@ public:
25 37
26 protected: 38 protected:
27 std::shared_ptr<Module> module; 39 std::shared_ptr<Module> module;
40
41 private:
42 Capability capability{};
28 }; 43 };
29}; 44};
30 45
diff --git a/src/core/hle/service/pctl/pctl.cpp b/src/core/hle/service/pctl/pctl.cpp
index 16dd34f90..e4d155c86 100644
--- a/src/core/hle/service/pctl/pctl.cpp
+++ b/src/core/hle/service/pctl/pctl.cpp
@@ -6,8 +6,9 @@
6 6
7namespace Service::PCTL { 7namespace Service::PCTL {
8 8
9PCTL::PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name) 9PCTL::PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
10 : Interface{system_, std::move(module_), name} { 10 Capability capability)
11 : Interface{system_, std::move(module_), name, capability} {
11 static const FunctionInfo functions[] = { 12 static const FunctionInfo functions[] = {
12 {0, &PCTL::CreateService, "CreateService"}, 13 {0, &PCTL::CreateService, "CreateService"},
13 {1, &PCTL::CreateServiceWithoutInitialize, "CreateServiceWithoutInitialize"}, 14 {1, &PCTL::CreateServiceWithoutInitialize, "CreateServiceWithoutInitialize"},
diff --git a/src/core/hle/service/pctl/pctl.h b/src/core/hle/service/pctl/pctl.h
index 275d23007..fd0a1e486 100644
--- a/src/core/hle/service/pctl/pctl.h
+++ b/src/core/hle/service/pctl/pctl.h
@@ -14,7 +14,8 @@ namespace Service::PCTL {
14 14
15class PCTL final : public Module::Interface { 15class PCTL final : public Module::Interface {
16public: 16public:
17 explicit PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name); 17 explicit PCTL(Core::System& system_, std::shared_ptr<Module> module_, const char* name,
18 Capability capability);
18 ~PCTL() override; 19 ~PCTL() override;
19}; 20};
20 21