mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-10-31 11:40:52 +00:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8a142b490f | |||
| 943f1fc760 | |||
| 072da77516 | |||
| 035f4611cb | |||
| ea92c081b7 | |||
| 69665063a9 | |||
| b4d5760014 | |||
| 0731f40f4d | |||
| 3e6a5566cf | |||
| d89e02d3ac | |||
| a2aa4d97e1 | |||
| 26a03d2473 | |||
| b7c1ded159 | |||
| cbd4cf2d8c | |||
| a3debcf731 | |||
| 5239cbe2a7 | |||
| 0e11fe8b5e | |||
| 0689f73147 | |||
| a95efaf18f | |||
| 58968bd127 | |||
| 05f36d990c |
@@ -1,5 +1,4 @@
|
||||
- [ ] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions).
|
||||
- [ ] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md).
|
||||
- [ ] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability.
|
||||
|
||||
-------------------
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
# Build directory
|
||||
/[Bb]uild*/
|
||||
doc-build/
|
||||
out/
|
||||
AppDir/
|
||||
uruntime
|
||||
|
||||
|
||||
+8
-31
@@ -16,15 +16,14 @@ Eden is free, open-source, copyleft software, licensed under the terms of the [G
|
||||
|
||||
### Policies
|
||||
|
||||
- We are trialing a slightly relaxed AI policy to allow high-quality contributors to use AI *responsibly*. Please read our [detailed AI policy](docs/policies/AI.md) for more info.
|
||||
- Usage of any form of profanity or otherwise unsavory language is generally discouraged.
|
||||
- This is primarily because it rarely helps to actually understand what's going on.
|
||||
- Remember that your comments should be focused and actually address what's happening. With very few exceptions, expletives are actively detrimental at best.
|
||||
- New code must follow the same general style as the surrounding codebase. Exceptions may be granted in certain cases.
|
||||
- AI usage is allowed, but we reserve the right to close and rework your PR if you don't fully understand the changes you're making.
|
||||
- As a common courtesy, please disclose your AI usage under the PR description, as `Assisted-by: <AI model> (<how it helped>)`.
|
||||
- Usage of any form of profanity or otherwise unsavory language is discouraged but not strictly disallowed.
|
||||
- New code must follow the same style as the surrounding codebase. Exceptions may be granted in certain cases.
|
||||
- Maintainers reserve the right to change your patches and pull requests at will. We will try to avoid this.
|
||||
- You should generally respect all decisions made by the [code owners](docs/CODEOWNERS) in your particular subsystem.
|
||||
- However, if you feel they are overstepping or are incorrect, don't be afraid to stand your ground! Maintainers are not always correct.
|
||||
- While we do *not* adhere to the terms of a formal code of conduct, you will generally be expected to respect other developers, contributors, and community members.
|
||||
- While we do *not* adhere to the terms of a formal code of conduct, you are expected to treat other developers, contributors, and community members respectfully.
|
||||
- You **must** have basic knowledge of [Git](https://git-scm.com/learn). Knowing how to manage your branches and follow proper fork policies is a necessity.
|
||||
|
||||
### Where do I start?
|
||||
@@ -38,7 +37,8 @@ You may also search for open issues on [GitHub](https://github.com/eden-emulator
|
||||
There are five primary ways to contribute.
|
||||
|
||||
- Submit pull requests directly to our source tree
|
||||
- You must first request an account on our Forgejo. See [Signup](#how-do-i-sign-up)
|
||||
- You must first [create an account](https://git.eden-emu.dev/user/sign_up).
|
||||
- You may use an internal account, or you may use a GitHub/Codeberg account linked to our instance.
|
||||
- Submit pull requests to our [GitHub mirror](https://github.com/eden-emulator/Issue-Reports)
|
||||
- Note that this is subject to being removed by DMCA, so don't rely on this.
|
||||
- Submit pull requests to our [Codeberg mirror](https://codeberg.org/eden-emu/eden)
|
||||
@@ -50,31 +50,8 @@ There are five primary ways to contribute.
|
||||
|
||||
To test your changes, ensure to read the [build documentation](./docs/Build.md) for your specific platform(s) to ensure everything compiles and works properly. You should also make sure that your branch is up-to-date with the upstream `master` branch before opening a pull request.
|
||||
|
||||
### How do I sign up?
|
||||
|
||||
<details>
|
||||
<summary>To sign up and begin contributing... (click to open)</summary>
|
||||
|
||||
Email [crueter@crueter.xyz](mailto:crueter@crueter.xyz) with the following format:
|
||||
|
||||
```txt
|
||||
Subject: [Eden Git] Registration Request
|
||||
Username: <Your Desired Username>
|
||||
Email: <Your Desired Email>
|
||||
I wish to sign up because... <your reason here>
|
||||
```
|
||||
|
||||
Received mail that does not follow this format will be ignored.
|
||||
|
||||
Once your request is processed, you will receive a confirmation email with your temporary password and some information on Git access and policies. If you do not receive a response within 48 hours, feel free to send another email.
|
||||
|
||||
> [!WARNING]
|
||||
> Some email providers may place the response email in your spam/junk folder; notable offenders include Gmail and Outlook. *Always* ensure to check your Spam or Junk folder.
|
||||
|
||||
</details>
|
||||
|
||||
## Non-code Contributions
|
||||
|
||||
Alongside the other contribution methods listed up top, you can also choose to contribute through documentation, organization, or community guides. These can be done either through the code contribution methods described above, or created externally and shared via our Discord community.
|
||||
|
||||
If you have an external tool/page that you believe would be handy to integrate/link into Eden, please additionally email our developers at [`developers@eden-emu.dev`](mailto:developers@eden-emu.dev). **Do not submit vibe-coded or AI generated tools or applications**.
|
||||
If you have an external tool/page that you believe would be handy to integrate/link into Eden, please additionally email our developers at [`developers@eden-emu.dev`](mailto:developers@eden-emu.dev).
|
||||
|
||||
+2
-2
@@ -351,13 +351,13 @@
|
||||
},
|
||||
"zstd": {
|
||||
"find_args": "MODULE",
|
||||
"hash": "cc5ad4b119a9c2ea57f0b71eeff01113bb506e0d17000159c5409cb8236d22e38c52d5e9e97e7947a4bf1b2dfc44b6c503ab2d9aedbd59458435c6a2849cb029",
|
||||
"hash": "2b006c3c110c38bd2f5896b42d36a38931c8eae261f30552f9a9fd04458d218d8f1a1425f117fd12af545ed77042e4b2d1a1a9b6286c4d0b9d74ef79f20a8f08",
|
||||
"min_version": "1.5",
|
||||
"options": [
|
||||
"ZSTD_BUILD_SHARED OFF"
|
||||
],
|
||||
"repo": "facebook/zstd",
|
||||
"source_subdir": "build/cmake",
|
||||
"version": "b8d6101fba"
|
||||
"version": "33618c8"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Design Overview
|
||||
|
||||
Modern game consoles require heavy power to emulate. This is why the emulator uses an approach known as HLE (High-Level-Emulation), in a nutshell: Instead of accurately emulating every subsystem that forms part of a component, emulate the resulting visible output of said interface instead.
|
||||
Modern game consoles require heavy power to be emulated appropriately. This is why the emulator uses an approach known as HLE (High-Level-Emulation), in a nutshell: Instead of accurately emulating every subsystem that forms part of a component, emulate the resulting visible I/O interface instead.
|
||||
|
||||
For example, take a disk write, instead of emulating a proper SD card we instead use the C++ standard library for I/O. Additionally we use the abstractions provided by the `fs` service to "lie" to programs about certain SD card properties. Notably this includes making up sizes for the fake SD card, giving "realistic" values or expected outputs for a given card, and so on. And instead of writing to an actual SD card, the emulator simply writes to a file.
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
# Subsystem: HLE
|
||||
|
||||
## HOS Kernel
|
||||
# HOS Kernel
|
||||
|
||||
In brief, the HOS kernel is a microkernel, all services and programs run in userspace, the primary way to do communication between these is via `HIPC` (not covered here); otherwise most of the primitives reside in the forms of syscalls invoked via `svc #imm`. The kernel supports both 32-bit and 64-bit programs, and has the capacity to use 32, 36 and 39 bits of address space for spawned processes. Most of the networking stack is based off FreeBSD's network stack.
|
||||
|
||||
@@ -31,52 +29,3 @@ Every process keeps it's own tracking of the following structures:
|
||||
The emulator willingly restricts itself to only use 4 threads (to emulate 4 cores), this is because most existing applications do not benefit greatly from the added core count, and in fact can be detrimental due to extra contention. This translates equitatively to about 4 `ArmInterface` slots for each process, these are then redirected to whatever is the last `pc` of the last thread running on the core is meant to be; proceed to run it, then when returning (due to halt or interruption), proceed to reschedule the thread.
|
||||
|
||||
The scheduler as-is isn't 100% faithful to the original (for example the original is cooperative and not preemptive), and has great timing variance (especially due to the fact the emulator can run in systems with wildly different timings).
|
||||
|
||||
## Services
|
||||
|
||||
Consult [SwitchBrew](https://switchbrew.org/) for per-service methods, and implementation details.
|
||||
|
||||
All services are instatiated implicitly using `ServiceFramework`. To register a new interface or service, you can inherit from said class, providing additionally a template parameter that references `Self`, for example:
|
||||
|
||||
```c++
|
||||
// Follows as:
|
||||
// class MyInterface [final] : public ServiceFramework<MyInterface> { ... };
|
||||
// [final] is optional, but should be used whenever there is no intention of this class itself being inherited.
|
||||
class IFloatingRegistrationRequest final : public ServiceFramework<IFloatingRegistrationRequest> {
|
||||
public:
|
||||
// ctor, you can pass extra parameters here (if so required)
|
||||
explicit IFloatingRegistrationRequest(Core::System& system_)
|
||||
: ServiceFramework{system_, "IFloatingRegistrationRequest"}
|
||||
{}
|
||||
|
||||
// Must be placed after all methods are defined (or declared).
|
||||
// Define here your functions and methods, please order them.
|
||||
// Use FindRequestTipc for TIPC handlers.
|
||||
static constexpr auto functions = CreateStaticMap(
|
||||
FunctionInfo{0, nullptr, "GetSessionId"},
|
||||
FunctionInfo{12, nullptr, "GetAccountId"},
|
||||
FunctionInfo{13, nullptr, "GetLinkedNintendoAccountId"},
|
||||
FunctionInfo{14, nullptr, "GetNickname"},
|
||||
FunctionInfo{15, nullptr, "GetProfileImage"},
|
||||
FunctionInfo{16, nullptr, "GetProfileLargeImage", MakeVersionGate({18,0,0})},
|
||||
FunctionInfo{21, nullptr, "LoadIdTokenCache"},
|
||||
FunctionInfo{100, nullptr, "RegisterUser"},
|
||||
FunctionInfo{101, nullptr, "RegisterUserWithUid"},
|
||||
FunctionInfo{102, nullptr, "RegisterNetworkServiceAccountAsync", MakeVersionGate({4,0,0})},
|
||||
FunctionInfo{103, nullptr, "RegisterNetworkServiceAccountWithUidAsync", MakeVersionGate({4,0,0})},
|
||||
FunctionInfo{110, nullptr, "SetSystemProgramIdentification"},
|
||||
FunctionInfo{111, nullptr, "EnsureIdTokenCacheAsync"}
|
||||
);
|
||||
std::optional<FunctionInfoBase> FindRequest(u32 key) override {
|
||||
return HandlerTableGenerateWithFind(key, functions);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Try to keep service structures local, that is, don't place them on header files if they're only going to be used by a specific service.
|
||||
|
||||
In each `.cpp` file that uses `D<...>/C<...>` CMIF wrapper helpers, remember to include the corresponding instancer, so you don't face linker errors:
|
||||
```c++
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
```
|
||||
This will properly instatiate the corresponding wrappers and decompose the provided arguments in the wiring order.
|
||||
+1
-1
@@ -21,7 +21,7 @@ This contains documentation created by developers, build instructions, guideline
|
||||
- Subsystems:
|
||||
- **[Design Overview](./DesignOverview.md)**
|
||||
- **[Dynarmic](./dynarmic/README.md)**
|
||||
- **[Subsystem: HLE](./SubsystemHLE.md)**
|
||||
- **[HOS Kernel](./HosKernel.md)**
|
||||
- **[Settings](./Settings.md)**
|
||||
|
||||
## Policies
|
||||
|
||||
@@ -1,203 +0,0 @@
|
||||
# AI Policy
|
||||
|
||||
> [!WARNING]
|
||||
> We are trialing a slightly relaxed AI policy to allow high-quality contributors to use AI *responsibly*.
|
||||
> This policy is subject to change at any point in time, so check back frequently.
|
||||
>
|
||||
> This banner will be removed once we have finalized our revised policy.
|
||||
|
||||
- [AI Policy](#ai-policy)
|
||||
- [TL;DR](#tldr)
|
||||
- [Definitions](#definitions)
|
||||
- [Scope](#scope)
|
||||
- [Introduction](#introduction)
|
||||
- [Requirements](#requirements)
|
||||
- [Sign-off, Authorship, and Copyright](#sign-off-authorship-and-copyright)
|
||||
- [Permitted Usage](#permitted-usage)
|
||||
- [Recommended Prior Discussion](#recommended-prior-discussion)
|
||||
- [Forbidden Usage](#forbidden-usage)
|
||||
- [Human Effort Denial of Service](#human-effort-denial-of-service)
|
||||
- [Disclosure](#disclosure)
|
||||
- [Codebase Ingestion](#codebase-ingestion)
|
||||
- [Enforcement](#enforcement)
|
||||
- [Addendum: AI Commit Messages](#addendum-ai-commit-messages)
|
||||
- [References](#references)
|
||||
|
||||
## TL;DR
|
||||
|
||||
AI-assisted contributions are welcome, provided you take responsibility for them.
|
||||
|
||||
- You **must** disclose any AI or LLM usage in your pull request description *and* commit message.
|
||||
- You **must** be able to explain, defend, and revise every line of code you submit.
|
||||
- Commit messages, PR descriptions, issues, and comments **must** be written by you. Verbatim AI output is not acceptable.
|
||||
- Undisclosed AI usage will result in your contribution being rejected.
|
||||
- Low-quality contributions, disclosed or not, will be reworked or rejected.
|
||||
- Spamming automated PRs, comments, or issues is treated as a Denial of Service (DoS) attack on our reviewers; see [Human Effort Denial of Service](#human-effort-denial-of-service).
|
||||
|
||||
## Definitions
|
||||
|
||||
An *AI or LLM-based tool* is any piece of software that generates code, text, or other content through machine learning models. This includes, but is not limited to: chat assistants, agentic coding tools/harnesses, inline code completion suggestions you have accepted into the code, and AI-driven explanation/refactoring features.
|
||||
|
||||
For the purposes of this policy, basic deterministic/static development tools (such as clang-tidy, git, compilers, etc.) are not considered AI tools.
|
||||
|
||||
Terms such as "substantially", "large-scale", "majority", and "low-quality" are intentionally left vague, and will be interpreted at the maintainers' discretion. When in doubt, ask first.
|
||||
|
||||
## Scope
|
||||
|
||||
This policy applies to all code contributions, alongside issues and pull requests surrounding this codebase. This includes:
|
||||
|
||||
- Commit messages
|
||||
- PR descriptions
|
||||
- Code review comments
|
||||
- Issue/PR comments
|
||||
- Patches submitted via e-mail
|
||||
|
||||
Areas that are not directly related to code--such as our surrounding communities--are not covered by the terms of this policy. Additionally, spelling/grammar checking via AI or LLM-based tools is not covered under this document.
|
||||
|
||||
## Introduction
|
||||
|
||||
In the right hands, AI and LLM-based tools are incredibly useful for getting features and bugfixes out the door as fast as possible. At the same time, reviewer bandwidth is a scarce resource. We are therefore open to AI-assisted contributions, provided they are produced and disclosed properly.
|
||||
|
||||
The goal of this document is *not* to set arbitrary restrictions, but rather to keep our development healthy and stable, while still allowing contributors to use the tools they find helpful. A contribution must be worth more to the project than the time it takes to review it.
|
||||
|
||||
Throughout this document, **must** and **must not** are inflexible, binding requirements. Refusal to follow these is treated as a violation of the terms outlined in this document.
|
||||
|
||||
## Requirements
|
||||
|
||||
These apply to all contributions, whether AI-assisted or not. AI-assisted contributions also carry additional disclosure requirements as outlined in [Disclosure](#disclosure).
|
||||
|
||||
1. *Disclosure*. Any and all usage of AI or LLM-based tools within any contribution **must** be explicitly marked and disclosed as appropriate.
|
||||
2. *Responsibility*. The human submitter of any contribution is held wholly responsible for the accuracy, completeness, and intent of what is submitted. You **must** be able to explain, defend, and revise your code during review.
|
||||
3. *Review*. All code **must** be thoroughly reviewed by the author before opening a PR or marking it ready for review.
|
||||
4. *Testing*. All code changes **must** be tested directly by the human author.
|
||||
5. *Quality*. All submitted code is held to a strict standard of excellence. Low-quality AI-generated content does not uphold this standard.
|
||||
6. *Licensing*. All code **must** be compatible with the GPLv3 or later. You **must** warrant that you have the right to submit it under those terms, and that it was not copied from work published under an incompatible license.
|
||||
|
||||
## Sign-off, Authorship, and Copyright
|
||||
|
||||
AI agents **must not** add `Signed-off-by:` tags. The human submitter **must** sign off on all changes.
|
||||
|
||||
Similarly, AI agents cannot hold authorship or copyright over code, and **must not** add `Co-authored-by:` or `Co-developed-by:` tags. The human submitter **must** author all changes.
|
||||
|
||||
## Permitted Usage
|
||||
|
||||
This is a non-exhaustive list of permitted uses of AI and LLM-based tools, provided they are disclosed properly.
|
||||
|
||||
- Drafting issues and pull requests, provided the final text and submitted code are substantially your own.
|
||||
- Debugging issues, bugs, glitches, and crashes, whether pre-existing or introduced by your own changes.
|
||||
- Reviewing your own changes before submitting a PR.
|
||||
- Research, brainstorming, and codebase searching/understanding.
|
||||
- Applying tedious but not particularly large changes, such as mass-migrating specific classes to polyfills or abstractions.
|
||||
|
||||
## Recommended Prior Discussion
|
||||
|
||||
Some usage cases are not necessarily forbidden nor permitted. These should be discussed with maintainers in an issue or e-mail *before* submission. Maintainers and reviewers may also comment on this during the review/submission phase.
|
||||
|
||||
- Generating boilerplate/scaffolding for new code.
|
||||
- Writing unit tests.
|
||||
- Large-scale refactors primarily driven by an AI agent.
|
||||
- Any contribution where an AI agent or model was responsible for the majority of the implementation.
|
||||
|
||||
## Forbidden Usage
|
||||
|
||||
This is a non-exhaustive list of strictly forbidden uses of AI and LLM-based tools.
|
||||
|
||||
- Vibecoding, or changes entirely authored by AI agents without human intervention or understanding.
|
||||
- If you don't choose to put in the necessary effort to understand every line of code you submitted, neither will we.
|
||||
- Fully AI-generated commit messages, PR descriptions, issues, or comments. See [Addendum: AI Commit Messages](#addendum-ai-commit-messages).
|
||||
- Submission of AI-assisted work that is not disclosed per the [Disclosure](#disclosure) requirements.
|
||||
- Low-quality submissions that fail to satisfy our standard of code excellence.
|
||||
- Submitting secrets, credentials, private user data, or unpublished security reports to third-party AI services.
|
||||
- This includes console keys, encryption material, and private vulnerability disclosures.
|
||||
- Verbatim AI code reviews (e.g. Codex/Copilot reviews).
|
||||
|
||||
## Human Effort Denial of Service
|
||||
|
||||
Using automated tools and AI to submit PRs, issues, and comments that we have to carefully review and handle is considered a [Denial-of-service attack](https://en.wikipedia.org/wiki/Denial-of-service_attack) on our human effort.
|
||||
|
||||
It takes very little effort on your side (an LLM prompt) to generate a large amount of effort on ours (careful and thorough code review). Please respect our time and don't do that.
|
||||
|
||||
## Disclosure
|
||||
|
||||
How you disclose AI usage is up to you. However, it **must** be explicit, easy to identify, and placed both within the commit message *and* the surrounding PR description. For patches submitted by e-mail, the cover letter counts as the PR description. We recommend an `Assisted-by:` footer:
|
||||
|
||||
```txt
|
||||
Assisted-by: <model> (<what it was used for>)
|
||||
```
|
||||
|
||||
For instance:
|
||||
|
||||
```txt
|
||||
Assisted-by: Claude Opus 5.5 (initial draft and code review)
|
||||
```
|
||||
|
||||
Contributions without a commit message (e.g. issues/comments) should instead use a plain sentence in the text body such as `I used <model> to help with <X>`. PRs and commit messages may opt to use this format as well.
|
||||
|
||||
Multi-commit series/squashes **must** maintain the trailer. Maintainers will handle this for merges to master, but you are responsible for ensuring the disclosure survives into the final commit/PR body of squashes within your branches.
|
||||
|
||||
Regardless, what matters is that reviewers can tell *at a glance* where and how AI was involved in your contribution.
|
||||
|
||||
## Codebase Ingestion
|
||||
|
||||
Ingestion of this codebase by LLMs for any purpose--such as training or prompt context--is permitted *for now*. This may change at any point as litigation and court rulings around AI and code copyright proceed.
|
||||
|
||||
AI models may have ingested AGPLv3 or otherwise copyleft-incompatible code and may regurgitate it. You remain responsible for ensuring that all code you submit is compatible with the GPLv3 or later.
|
||||
|
||||
## Enforcement
|
||||
|
||||
- If we suspect undisclosed AI usage in a contribution, we will ask for disclosure.
|
||||
- Refusal to provide disclosure will result in rejection of the contribution, and your PR or issue will be closed. Maintainers may choose to rework it themselves if the change is worth having.
|
||||
- Accounts that spam us with repeated automated PRs or comments will be blocked or permanently suspended from our Git instance.
|
||||
- Maintainers reserve the right to close your issues and pull requests if you don't follow the guidelines and procedures outlined in this document, and refuse or fail to make changes as necessary to comply.
|
||||
- Repeated failures to comply may result in loss of contribution privileges.
|
||||
|
||||
## Addendum: AI Commit Messages
|
||||
|
||||
The patchset for pull request [#3422](https://git.eden-emu.dev/eden-emu/eden/pulls/3422) was fed into a dedicated code AI model, and it produced the following:
|
||||
|
||||
```txt
|
||||
profile_manager: Refactor user deletion to use index instead of UUID
|
||||
|
||||
This commit improves the user profile deletion flow in the following ways:
|
||||
|
||||
1. **UI layer (ConfigureProfileManager)**:
|
||||
- Replaces UUID-based deletion with index-based deletion
|
||||
- Passes the selected row index from the tree view to the confirmation dialog
|
||||
- Emits deleteUser(int index) signal from ConfigureProfileManagerDeleteDialog
|
||||
- Removes lambda capture and std::function callback in favor of direct signal/slot connection
|
||||
|
||||
2. **Delete dialog**:
|
||||
- Changes SetInfo() signature to accept index instead of accept callback
|
||||
- Stores index internally and emits it via deleteUser signal on acceptance
|
||||
|
||||
3. **Core ProfileManager**:
|
||||
- Refactors RemoveUser(UUID) → RemoveProfileAtIndex(index)
|
||||
- Removes duplicated stable_partition + save logic from RemoveUser()
|
||||
- Centralizes profile removal and save-file writing in RemoveProfileAtIndex()
|
||||
|
||||
4. **Minor follow-up**:
|
||||
- Adds profile_manager.ResetUserSaveFile() call in PopulateUserList() to ensure consistent state when refreshing the user list
|
||||
|
||||
These changes eliminate redundant code, reduce the risk of UUID → index mismatch bugs, and make the deletion path more straightforward and maintainable.
|
||||
|
||||
Fixes: potential inconsistency when user order changes between UI and backend
|
||||
```
|
||||
|
||||
This:
|
||||
|
||||
- Is needlessly verbose (nobody cares about most of these details)
|
||||
- Doesn't address the actual purpose of the PR (fixing a double-deletion bug in the profile manager)
|
||||
- Has unicode arrows (this is bad for command-line editors)
|
||||
- Uses corporate and word-salad language that pads out the message to make it look like a lot changed
|
||||
|
||||
A good commit message should be concise, descriptive, and convey the *intent* behind the change, such as the bug being fixed or the feature being added. It should *not* be a detailed changelog of every individual byte that's changed.
|
||||
|
||||
## References
|
||||
|
||||
This policy document has been adapted from the AI policies of numerous other free and open-source projects, whether restrictive or permissive.
|
||||
|
||||
- [Gitea](https://github.com/go-gitea/gitea/blob/main/CONTRIBUTING.md#ai-contribution-policy)
|
||||
- The [Linux kernel](https://kernel.org/doc/html/next/process/coding-assistants.html)
|
||||
- [Gentoo Linux](https://wiki.gentoo.org/wiki/Project:Council/AI_policy)
|
||||
- [cURL](https://curl.se/dev/contribute.html#on-ai-use-in-curl)
|
||||
- [FastAPI](https://tiangolo.com/open-source/contributing/#automated-code-and-ai)
|
||||
@@ -45,12 +45,13 @@ Another option would be to launch the game in Eden and close it - then go into t
|
||||
***INFO***: Make sure you select the correct directory or it will not work, the screen should show the **cheats** sub-directory.
|
||||
|
||||
</aside>
|
||||
2. You should now see the cheat appear in the **Add-ons** screen.
|
||||
3. Launch the game and confirm that the cheat is applied.
|
||||
|
||||
9. You should now see the cheat appear in the **Add-ons** screen.
|
||||
10. Launch the game and confirm that the cheat is applied.
|
||||
|
||||
### Step 2: Multiple Cheats
|
||||
|
||||
In order to install multiple cheats, you must repeat the steps above with the new cheat, creating a new directory with the name of the cheat and cheats directory. You **cannot** install multiple cheats with a single file.
|
||||
In order to install multiple cheats, you must repeat the steps above with the new cheat, creating a new directory with the name of the cheat and cheats directory.
|
||||
|
||||
Community Member [Ninjistix](https://github.com/Ninjistix) created a utility (Windows or anything that can run Python) that can take a file with multiple cheats and create the files/structure for you with a provided Build ID. To download and run it, see the [GitHub Project](https://github.com/Ninjistix/nxCheat_Splitter) page.
|
||||
|
||||
@@ -122,7 +123,7 @@ Another option would be to launch the game in Eden and close it - then go into t
|
||||
|
||||
### Step 2: Multiple Cheats
|
||||
|
||||
In order to install multiple cheats, you must repeat the steps above with the new cheat, creating a new directory with the name of the cheat and cheats directory. You **cannot** install multiple cheats with a single file.
|
||||
In order to install multiple cheats, you must repeat the steps above with the new cheat, creating a new directory with the name of the cheat and cheats directory.
|
||||
|
||||
Community Member [Ninjistix](https://github.com/Ninjistix) created a utility (Windows or anything that can run Python) that can take a file with multiple cheats and create the files/structure for you with a provided Build ID. To download and run it, see the [GitHub Project](https://github.com/Ninjistix/nxCheat_Splitter) page.
|
||||
|
||||
@@ -154,3 +155,11 @@ Cheats are enabled by default, but can be disabled so they don't affect gameplay
|
||||
3. *Select/Deselect* the name of the cheat you wish to enable/disable.
|
||||
4. Click **OK** to close the window.
|
||||
5. Launch the game to confirm the cheat is/is not active.
|
||||
|
||||
### Runtime Cheat Controls
|
||||
|
||||
* While a game is running, open **Cheats** from the menu bar to toggle individual entries from the loaded cheat files. The menu stays open while toggling entries and is hidden when the running game has no cheats. Runtime changes apply to the current game session only.
|
||||
|
||||
* Use **Configure > System > Core > Enable cheats by default** to choose whether regular cheats start enabled. The setting can also be overridden for an individual game from its **System** settings.
|
||||
|
||||
* Master Code entries (`{}` blocks) are always enabled and appear as disabled and checked items in the runtime menu.
|
||||
|
||||
@@ -34,6 +34,13 @@ import org.yuzu.yuzu_emu.applets.web.WebBrowser
|
||||
* with the native side of the Yuzu code.
|
||||
*/
|
||||
object NativeLibrary {
|
||||
@Keep
|
||||
class RuntimeCheat(
|
||||
val id: Int,
|
||||
val name: String,
|
||||
val enabled: Boolean,
|
||||
val isMaster: Boolean
|
||||
)
|
||||
@Keep
|
||||
data class UpdateResult(
|
||||
var tag: String = "",
|
||||
@@ -197,6 +204,9 @@ object NativeLibrary {
|
||||
*/
|
||||
external fun isPaused(): Boolean
|
||||
|
||||
external fun getRuntimeCheats(): Array<RuntimeCheat>
|
||||
external fun setRuntimeCheatEnabled(id: Int, enabled: Boolean): Boolean
|
||||
|
||||
/**
|
||||
* Returns the performance stats for the current game
|
||||
*/
|
||||
|
||||
+1
-1
@@ -13,10 +13,10 @@ enum class BooleanSetting(override val key: String) : AbstractBooleanSetting {
|
||||
FASTMEM("cpuopt_fastmem"),
|
||||
FASTMEM_EXCLUSIVES("cpuopt_fastmem_exclusives"),
|
||||
CORE_SYNC_CORE_SPEED("sync_core_speed"),
|
||||
ENABLE_CHEATS_BY_DEFAULT("enable_cheats_by_default"),
|
||||
RENDERER_USE_SPEED_LIMIT("use_speed_limit"),
|
||||
USE_CUSTOM_CPU_TICKS("use_custom_cpu_ticks"),
|
||||
SKIP_CPU_INNER_INVALIDATION("skip_cpu_inner_invalidation"),
|
||||
NCE_INVALIDATION_GPU_READBACK("nce_invalidation_gpu_readback"),
|
||||
FIX_BLOOM_EFFECTS("fix_bloom_effects"),
|
||||
EMULATE_BGR565("emulate_bgr565"),
|
||||
RESCALE_HACK("rescale_hack"),
|
||||
|
||||
+7
-7
@@ -316,6 +316,13 @@ abstract class SettingsItem(
|
||||
descriptionId = R.string.use_sync_core_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.ENABLE_CHEATS_BY_DEFAULT,
|
||||
titleId = R.string.enable_cheats_by_default,
|
||||
descriptionId = R.string.enable_cheats_by_default_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SingleChoiceSetting(
|
||||
IntSetting.REGION_INDEX,
|
||||
@@ -859,13 +866,6 @@ abstract class SettingsItem(
|
||||
descriptionId = R.string.skip_cpu_inner_invalidation_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.NCE_INVALIDATION_GPU_READBACK,
|
||||
titleId = R.string.nce_invalidation_gpu_readback,
|
||||
descriptionId = R.string.nce_invalidation_gpu_readback_description
|
||||
)
|
||||
)
|
||||
put(
|
||||
SwitchSetting(
|
||||
BooleanSetting.FIX_BLOOM_EFFECTS,
|
||||
|
||||
+1
-1
@@ -510,6 +510,7 @@ class SettingsFragmentPresenter(
|
||||
add(IntSetting.FAST_CPU_TIME.key)
|
||||
add(IntSetting.FAST_GPU_TIME.key)
|
||||
add(BooleanSetting.CORE_SYNC_CORE_SPEED.key)
|
||||
add(BooleanSetting.ENABLE_CHEATS_BY_DEFAULT.key)
|
||||
|
||||
add(IntSetting.MEMORY_LAYOUT.key)
|
||||
add(BooleanSetting.USE_CUSTOM_CPU_TICKS.key)
|
||||
@@ -554,7 +555,6 @@ class SettingsFragmentPresenter(
|
||||
add(HeaderSetting(R.string.hacks))
|
||||
|
||||
add(BooleanSetting.SKIP_CPU_INNER_INVALIDATION.key)
|
||||
add(BooleanSetting.NCE_INVALIDATION_GPU_READBACK.key)
|
||||
add(BooleanSetting.FIX_BLOOM_EFFECTS.key)
|
||||
add(BooleanSetting.EMULATE_BGR565.key)
|
||||
add(BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key)
|
||||
|
||||
@@ -734,6 +734,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
|
||||
binding.inGameMenu.menu.findItem(R.id.menu_quick_settings)?.isVisible =
|
||||
BooleanSetting.ENABLE_QUICK_SETTINGS.getBoolean()
|
||||
binding.inGameMenu.menu.findItem(R.id.menu_cheats)?.isVisible = false
|
||||
|
||||
binding.pausedIcon.setOnClickListener {
|
||||
if (this::emulationState.isInitialized && emulationState.isPaused) {
|
||||
@@ -817,6 +818,12 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
|
||||
R.id.menu_load_amiibo -> handleLoadAmiiboSelection()
|
||||
|
||||
R.id.menu_cheats -> {
|
||||
binding.drawerLayout.closeDrawer(binding.inGameMenu)
|
||||
showRuntimeCheatDialog()
|
||||
true
|
||||
}
|
||||
|
||||
R.id.menu_controls -> {
|
||||
val action = HomeNavigationDirections.actionGlobalSettingsActivity(
|
||||
null,
|
||||
@@ -962,6 +969,8 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
|
||||
emulationState.updateSurface()
|
||||
|
||||
binding.inGameMenu.menu.findItem(R.id.menu_cheats)?.isVisible =
|
||||
NativeLibrary.getRuntimeCheats().isNotEmpty()
|
||||
updateShowStatsOverlay()
|
||||
updateSocOverlay()
|
||||
|
||||
@@ -987,6 +996,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
}
|
||||
emulationViewModel.isEmulationStopping.collect(viewLifecycleOwner) {
|
||||
if (it) {
|
||||
binding.inGameMenu.menu.findItem(R.id.menu_cheats)?.isVisible = false
|
||||
binding.loadingText.setText(R.string.shutting_down)
|
||||
ViewUtils.showView(binding.loadingIndicator)
|
||||
ViewUtils.hideView(binding.inputContainer)
|
||||
@@ -1119,6 +1129,45 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
|
||||
NativePostProcessing.persist()
|
||||
}
|
||||
|
||||
private fun showRuntimeCheatDialog() {
|
||||
val cheats = NativeLibrary.getRuntimeCheats()
|
||||
if (cheats.isEmpty()) return
|
||||
|
||||
val names = cheats.map { it.name.ifEmpty { getString(R.string.unnamed_cheat) } }.toTypedArray()
|
||||
lateinit var dialog: androidx.appcompat.app.AlertDialog
|
||||
dialog = MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(R.string.cheats)
|
||||
.setMultiChoiceItems(names, cheats.map { it.enabled }.toBooleanArray()) { _, which, enabled ->
|
||||
if (cheats[which].isMaster) {
|
||||
dialog.listView.setItemChecked(which, true)
|
||||
} else if (!NativeLibrary.setRuntimeCheatEnabled(cheats[which].id, enabled)) {
|
||||
dialog.listView.setItemChecked(which, !enabled)
|
||||
}
|
||||
}
|
||||
.setNegativeButton(R.string.disable_all_cheats) { _, _ ->
|
||||
cheats.forEach {
|
||||
if (!it.isMaster) NativeLibrary.setRuntimeCheatEnabled(it.id, false)
|
||||
}
|
||||
}
|
||||
.setNeutralButton(R.string.enable_all_cheats) { _, _ ->
|
||||
cheats.forEach {
|
||||
if (!it.isMaster) NativeLibrary.setRuntimeCheatEnabled(it.id, true)
|
||||
}
|
||||
}
|
||||
.setPositiveButton(R.string.done, null)
|
||||
.create()
|
||||
dialog.setOnShowListener {
|
||||
val listView = dialog.listView
|
||||
fun updateMasterVisuals() = repeat(listView.childCount) { index ->
|
||||
listView.getChildAt(index).alpha =
|
||||
if (cheats[listView.firstVisiblePosition + index].isMaster) 0.38f else 1f
|
||||
}
|
||||
listView.setOnScrollChangeListener { _, _, _, _, _ -> updateMasterVisuals() }
|
||||
updateMasterVisuals()
|
||||
}
|
||||
dialog.show()
|
||||
}
|
||||
|
||||
private fun addQuickSettings() {
|
||||
binding.quickSettingsSheet.apply {
|
||||
val container = binding.quickSettingsSheet.findViewById<ViewGroup>(R.id.quick_settings_container)
|
||||
|
||||
@@ -100,7 +100,7 @@ class Game(
|
||||
|
||||
companion object {
|
||||
val extensions: Set<String> = HashSet(
|
||||
listOf("xci", "nsp", "nca", "nro")
|
||||
listOf("xci", "nsp", "nca", "nro", "nsz", "xcz")
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,7 +109,7 @@ object GameHelper {
|
||||
|
||||
// File extensions considered as external content, buuut should
|
||||
// be done better imo.
|
||||
private val externalContentExtensions = setOf("nsp", "xci")
|
||||
private val externalContentExtensions = setOf("nsp", "xci", "nsz", "xcz")
|
||||
|
||||
private fun scanContentContainersRecursive(
|
||||
files: Array<MinimalDocumentFile>,
|
||||
|
||||
@@ -76,7 +76,9 @@ jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsValid(JNIEnv* env, jobj
|
||||
auto const file_type = loader->GetFileType();
|
||||
if (file_type == Loader::FileType::Unknown || file_type == Loader::FileType::Error)
|
||||
return false;
|
||||
if ((file_type == Loader::FileType::NSP || file_type == Loader::FileType::XCI) && !Loader::IsBootableGameContainer(file, file_type))
|
||||
if ((file_type == Loader::FileType::NSP || file_type == Loader::FileType::XCI ||
|
||||
file_type == Loader::FileType::NSZ || file_type == Loader::FileType::XCZ) &&
|
||||
!Loader::IsBootableGameContainer(file, file_type))
|
||||
return false;
|
||||
u64 program_id = 0;
|
||||
return loader->ReadProgramId(program_id) == Loader::ResultStatus::Success;
|
||||
|
||||
@@ -67,6 +67,7 @@ extern "C" {
|
||||
#include "core/file_sys/submission_package.h"
|
||||
#include "core/file_sys/vfs/vfs.h"
|
||||
#include "core/file_sys/vfs/vfs_real.h"
|
||||
#include "core/memory/dmnt_cheat_types.h"
|
||||
#include "core/frontend/applets/cabinet.h"
|
||||
#include "core/frontend/applets/controller.h"
|
||||
#include "core/frontend/applets/error.h"
|
||||
@@ -946,6 +947,31 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isPaused(JNIEnv* env, jclass claz
|
||||
return static_cast<jboolean>(EmulationSession::GetInstance().IsPaused());
|
||||
}
|
||||
|
||||
jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getRuntimeCheats(JNIEnv* env, jclass clazz) {
|
||||
const auto cheats = EmulationSession::GetInstance().System().GetRuntimeCheats();
|
||||
const auto runtime_cheat_class = env->FindClass("org/yuzu/yuzu_emu/NativeLibrary$RuntimeCheat");
|
||||
const auto constructor = env->GetMethodID(runtime_cheat_class, "<init>", "(ILjava/lang/String;ZZ)V");
|
||||
auto result = env->NewObjectArray(static_cast<jsize>(cheats.size()), runtime_cheat_class, nullptr);
|
||||
for (jsize i = 0; i < static_cast<jsize>(cheats.size()); ++i) {
|
||||
const auto& cheat = cheats[i];
|
||||
const auto name = Common::Android::ToJString(env, cheat.name);
|
||||
const auto item = env->NewObject(runtime_cheat_class, constructor, static_cast<jint>(cheat.id), name,
|
||||
static_cast<jboolean>(cheat.enabled),
|
||||
static_cast<jboolean>(cheat.is_master));
|
||||
env->SetObjectArrayElement(result, i, item);
|
||||
env->DeleteLocalRef(name);
|
||||
env->DeleteLocalRef(item);
|
||||
}
|
||||
env->DeleteLocalRef(runtime_cheat_class);
|
||||
return result;
|
||||
}
|
||||
|
||||
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_setRuntimeCheatEnabled(JNIEnv* env, jclass clazz,
|
||||
jint id, jboolean enabled) {
|
||||
return static_cast<jboolean>(EmulationSession::GetInstance().System().SetCheatEnabled(
|
||||
static_cast<u32>(id), static_cast<bool>(enabled)));
|
||||
}
|
||||
|
||||
jbyteArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getAppletCaptureBuffer(JNIEnv* env, jclass clazz) {
|
||||
using namespace VideoCore::Capture;
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
|
||||
android:viewportWidth="212"
|
||||
android:viewportHeight="212"
|
||||
android:width="212dp"
|
||||
android:height="212dp">
|
||||
<group
|
||||
android:translateX="6"
|
||||
android:translateY="6">
|
||||
<path
|
||||
android:pathData="M58 168v-98a50 50 0 0 1 50 -50h20"
|
||||
android:strokeColor="#FFFFFF"
|
||||
android:strokeWidth="25" />
|
||||
<path
|
||||
android:pathData="M58 168v-30a50 50 0 0 1 50 -50h20"
|
||||
android:strokeColor="#FFFFFF"
|
||||
android:strokeWidth="25" />
|
||||
<path
|
||||
android:pathData="M160 20A18 18 0 0 1 124 20A18 18 0 0 1 160 20Z"
|
||||
android:strokeColor="#FFFFFF"
|
||||
android:strokeWidth="15" />
|
||||
<path
|
||||
android:pathData="M160 88A18 18 0 0 1 124 88A18 18 0 0 1 160 88Z"
|
||||
android:strokeColor="#FFFFFF"
|
||||
android:strokeWidth="15" />
|
||||
<path
|
||||
android:pathData="M76 180A18 18 0 0 1 40 180A18 18 0 0 1 76 180Z"
|
||||
android:strokeColor="#FFFFFF"
|
||||
android:strokeWidth="15" />
|
||||
</group>
|
||||
</vector>
|
||||
@@ -1,10 +0,0 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="98dp"
|
||||
android:height="96dp"
|
||||
android:viewportWidth="98"
|
||||
android:viewportHeight="96">
|
||||
<path
|
||||
android:fillColor="?attr/colorControlNormal"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M48.854,0C21.839,0 0,22 0,49.217c0,21.756 13.993,40.172 33.405,46.69 2.427,0.49 3.316,-1.059 3.316,-2.362 0,-1.141 -0.08,-5.052 -0.08,-9.127 -13.59,2.934 -16.42,-5.867 -16.42,-5.867 -2.184,-5.704 -5.42,-7.17 -5.42,-7.17 -4.448,-3.015 0.324,-3.015 0.324,-3.015 4.934,0.326 7.523,5.052 7.523,5.052 4.367,7.496 11.404,5.378 14.235,4.074 0.404,-3.178 1.699,-5.378 3.074,-6.6 -10.839,-1.141 -22.243,-5.378 -22.243,-24.283 0,-5.378 1.94,-9.778 5.014,-13.2 -0.485,-1.222 -2.184,-6.275 0.486,-13.038 0,0 4.125,-1.304 13.426,5.052a46.97,46.97 0,0 1,12.214 -1.63c4.125,0 8.33,0.571 12.213,1.63 9.302,-6.356 13.427,-5.052 13.427,-5.052 2.67,6.763 0.97,11.816 0.485,13.038 3.155,3.422 5.015,7.822 5.015,13.2 0,18.905 -11.404,23.06 -22.324,24.283 1.78,1.548 3.316,4.481 3.316,9.126 0,6.6 -0.08,11.897 -0.08,13.526 0,1.304 0.89,2.853 3.316,2.364 19.412,-6.52 33.405,-24.935 33.405,-46.691C97.707,22 75.788,0 48.854,0z" />
|
||||
</vector>
|
||||
@@ -250,7 +250,7 @@
|
||||
style="@style/EdenButton.Secondary"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="56dp"
|
||||
app:icon="@drawable/ic_github"
|
||||
app:icon="@drawable/ic_forgejo"
|
||||
app:iconGravity="textStart"
|
||||
app:iconSize="24dp"
|
||||
app:iconPadding="0dp" />
|
||||
|
||||
@@ -259,7 +259,7 @@
|
||||
android:layout_height="56dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginStart="8dp"
|
||||
app:icon="@drawable/ic_github"
|
||||
app:icon="@drawable/ic_forgejo"
|
||||
app:iconSize="24dp"
|
||||
app:iconGravity="textStart"
|
||||
app:iconPadding="0dp"
|
||||
|
||||
@@ -43,6 +43,10 @@
|
||||
android:icon="@drawable/ic_nfc"
|
||||
android:title="@string/load_amiibo" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_cheats"
|
||||
android:icon="@drawable/ic_code"
|
||||
android:title="@string/cheats" />
|
||||
|
||||
<item
|
||||
android:id="@+id/menu_overlay_controls"
|
||||
|
||||
@@ -587,8 +587,6 @@
|
||||
<string name="fast_gpu_time_description">يجعل اللعبة تعتقد أن عمل وحدة معالجة الرسومات ينتهي بشكل أسرع مما هو عليه في الواقع، لذلك تتوقف عن خفض الدقة ومسافة العرض لتتناسب مع سرعات جهاز Switch.</string>
|
||||
<string name="skip_cpu_inner_invalidation">تخطي إبطال صلاحية وحدة المعالجة المركزية الداخلية</string>
|
||||
<string name="skip_cpu_inner_invalidation_description">يتخطى بعض عمليات إبطال ذاكرة التخزين المؤقتة من جانب وحدة المعالجة المركزية أثناء تحديثات الذاكرة، مما يقلل من استخدام وحدة المعالجة المركزية ويحسن أداءها. قد يتسبب ذلك في حدوث أعطال أو تعطل في بعض الألعاب.</string>
|
||||
<string name="nce_invalidation_gpu_readback">إعادة قراءة وحدة معالجة الرسومات قبل إبطال صلاحية NCE</string>
|
||||
<string name="nce_invalidation_gpu_readback_description">إصلاح مؤقت. يعالج مشكلة تعطل لعبة Ender Magnolia (وغيرها من ألعاب UE). قد يؤدي إلى انخفاض في الأداء. يجري العمل على تحسينه.</string>
|
||||
<string name="fix_bloom_effects">إصلاح تأثيرات التوهج</string>
|
||||
<string name="fix_bloom_effects_description">يقلل من ضبابية التوهج في LA/EOW (Adreno A6XX - A7XX/ Turnip)، ويزيل التوهج في Burnout. تحذير: قد يسبب تشوهات رسومية في ألعاب أخرى.</string>
|
||||
<string name="emulate_bgr565">محاكاة BGR565</string>
|
||||
|
||||
@@ -577,8 +577,6 @@
|
||||
<string name="fast_gpu_time_description">讓遊戲誤以為 GPU 工作能更快完成,避免遊戲為了配合 Switch 的時脈而降低解析度與渲染距離</string>
|
||||
<string name="skip_cpu_inner_invalidation">跳過 CPU 內部失效處理</string>
|
||||
<string name="skip_cpu_inner_invalidation_description">在記憶體更新期間跳過某些 CPU 端快取的失效處理,減少 CPU 使用率並提高其性能。可能會導致某些遊戲出現故障或當機</string>
|
||||
<string name="nce_invalidation_gpu_readback">在 NCE 無效化前進行 GPU 回讀</string>
|
||||
<string name="nce_invalidation_gpu_readback_description">(暫時性功能)修復 \"終結者瑪格諾莉亞:霧中綻放\" 及其它使用虛幻引擎之遊戲中的當機問題,可能會降低效能。此功能正在改善中</string>
|
||||
<string name="fix_bloom_effects">修正光暈特效</string>
|
||||
<string name="fix_bloom_effects_description">在 \"薩爾達傳說:織夢島\" 和 \"薩爾達傳說:智慧的再現\" 中減少光暈模糊的問題並移除 \"橫衝直撞:狂飆樂園重製版\" 中的光暈效果(適用於 Adreno A6XX - A7XX/ Turnip)。警告:可能會在其它遊戲中導致圖形異常</string>
|
||||
<string name="emulate_bgr565">模擬 BGR565</string>
|
||||
|
||||
@@ -593,10 +593,8 @@
|
||||
<string name="fast_gpu_time_description">Makes the game believe GPU work finishes faster than it does, so it stops lowering resolution and render distance to fit the Switch\'s clocks.</string>
|
||||
<string name="skip_cpu_inner_invalidation">Skip CPU Inner Invalidation</string>
|
||||
<string name="skip_cpu_inner_invalidation_description">Skips certain CPU-side cache invalidations during memory updates, reducing CPU usage and improving it\'s performance. This may cause glitches or crashes on some games.</string>
|
||||
<string name="nce_invalidation_gpu_readback">GPU Readback Before NCE Invalidation</string>
|
||||
<string name="nce_invalidation_gpu_readback_description">Temporary. Fix Ender Magnolia (and other UE titles) crashes. May reduce performance. Improvement in progress.</string>
|
||||
<string name="fix_bloom_effects">Fix Bloom Effects</string>
|
||||
<string name="fix_bloom_effects_description">Reduces bloom blur in LA/EOW (Adreno A6XX - A7XX/ Turnip), removes bloom in Burnout. Warning: may cause graphical artifacts in other games.</string>
|
||||
<string name="fix_bloom_effects_description">Removes bloom in Burnout.</string>
|
||||
<string name="emulate_bgr565">Emulate BGR565</string>
|
||||
<string name="emulate_bgr565_description">Fixes problems with inverted colors in games or strange artifacts or strange shadows.</string>
|
||||
<string name="rescale_hack">Enable Legacy Rescale Pass</string>
|
||||
@@ -842,6 +840,12 @@
|
||||
<string name="preferences_graphics">Graphics</string>
|
||||
<string name="preferences_graphics_description">Accuracy level, resolution, shader cache</string>
|
||||
<string name="quick_settings">Quick Settings</string>
|
||||
<string name="cheats">Cheats</string>
|
||||
<string name="enable_all_cheats">Enable All Cheats</string>
|
||||
<string name="disable_all_cheats">Disable All Cheats</string>
|
||||
<string name="unnamed_cheat">Unnamed Cheat</string>
|
||||
<string name="enable_cheats_by_default">Enable cheats by default</string>
|
||||
<string name="enable_cheats_by_default_description">Enable regular cheats when a game starts</string>
|
||||
<string name="enable_quick_settings">Enable Quick Settings</string>
|
||||
<string name="enable_quick_settings_description">Allow access to quick settings menu via swipe and menu button</string>
|
||||
<string name="preferences_audio">Audio</string>
|
||||
|
||||
@@ -418,6 +418,10 @@ void SetGlobalFilter(const Filter& filter) {
|
||||
logging_instance->filter = filter;
|
||||
}
|
||||
|
||||
bool IsMessageEnabled(Class log_class, Level log_level) {
|
||||
return logging_instance && logging_instance->filter.CheckMessage(log_class, log_level);
|
||||
}
|
||||
|
||||
void SetColorConsoleBackendEnabled(bool enabled) {
|
||||
if (logging_instance)
|
||||
logging_instance->color_console_backend.enabled = enabled;
|
||||
|
||||
@@ -138,6 +138,7 @@ void Stop();
|
||||
|
||||
/// The global filter will prevent any messages from even being processed if they are filtered.
|
||||
void SetGlobalFilter(const Filter& filter);
|
||||
[[nodiscard]] bool IsMessageEnabled(Class log_class, Level log_level);
|
||||
void SetColorConsoleBackendEnabled(bool enabled);
|
||||
|
||||
} // namespace Common::Log
|
||||
|
||||
@@ -247,6 +247,7 @@ struct Values {
|
||||
|
||||
SwitchableSetting<bool> sync_core_speed{linkage, false, "sync_core_speed", Category::Core,
|
||||
Specialization::Default};
|
||||
SwitchableSetting<bool> enable_cheats_by_default{linkage, true, "enable_cheats_by_default", Category::Core};
|
||||
|
||||
// Cpu
|
||||
SwitchableSetting<CpuBackend, true> cpu_backend{linkage,
|
||||
@@ -639,8 +640,6 @@ struct Values {
|
||||
Specialization::Default,
|
||||
true,
|
||||
true};
|
||||
SwitchableSetting<bool> nce_invalidation_gpu_readback{
|
||||
linkage, false, "nce_invalidation_gpu_readback", Category::RendererHacks};
|
||||
SwitchableSetting<bool> async_presentation{linkage,
|
||||
#ifdef __ANDROID__
|
||||
true,
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -46,4 +49,10 @@ std::vector<u8> DecompressDataZSTD(std::span<const u8> compressed) {
|
||||
return decompressed;
|
||||
}
|
||||
|
||||
std::size_t DecompressDataZSTD(std::span<const u8> compressed, std::span<u8> output) {
|
||||
const std::size_t result =
|
||||
ZSTD_decompress(output.data(), output.size(), compressed.data(), compressed.size());
|
||||
return ZSTD_isError(result) ? 0 : result;
|
||||
}
|
||||
|
||||
} // namespace Common::Compression
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -42,4 +45,15 @@ namespace Common::Compression {
|
||||
*/
|
||||
[[nodiscard]] std::vector<u8> DecompressDataZSTD(std::span<const u8> compressed);
|
||||
|
||||
/**
|
||||
* Decompresses a single Zstandard frame into a caller-provided buffer of known size.
|
||||
*
|
||||
* @param compressed the compressed source memory region.
|
||||
* @param output the destination buffer. Its size is the maximum number of bytes to write.
|
||||
*
|
||||
* @return the number of bytes written, or 0 if the frame is invalid or doesn't fit. An empty
|
||||
* frame also returns 0.
|
||||
*/
|
||||
[[nodiscard]] std::size_t DecompressDataZSTD(std::span<const u8> compressed, std::span<u8> output);
|
||||
|
||||
} // namespace Common::Compression
|
||||
|
||||
+71
-1
@@ -33,6 +33,8 @@ add_library(core STATIC
|
||||
crypto/encryption_layer.h
|
||||
crypto/key_manager.cpp
|
||||
crypto/key_manager.h
|
||||
crypto/ncz_decompressor.cpp
|
||||
crypto/ncz_decompressor.h
|
||||
crypto/partition_data_manager.cpp
|
||||
crypto/partition_data_manager.h
|
||||
crypto/xts_encryption_layer.cpp
|
||||
@@ -444,18 +446,28 @@ add_library(core STATIC
|
||||
hle/service/am/process_creation.h
|
||||
hle/service/am/process_holder.cpp
|
||||
hle/service/am/process_holder.h
|
||||
hle/service/am/service/all_system_applet_proxies_service.cpp
|
||||
hle/service/am/service/all_system_applet_proxies_service.h
|
||||
hle/service/am/service/applet_common_functions.cpp
|
||||
hle/service/am/service/applet_common_functions.h
|
||||
hle/service/am/service/application_accessor.cpp
|
||||
hle/service/am/service/application_accessor.h
|
||||
hle/service/am/service/application_creator.cpp
|
||||
hle/service/am/service/application_creator.h
|
||||
hle/service/am/service/application_functions.cpp
|
||||
hle/service/am/service/application_functions.h
|
||||
hle/service/am/service/application_proxy.cpp
|
||||
hle/service/am/service/application_proxy.h
|
||||
hle/service/am/service/application_proxy_service.cpp
|
||||
hle/service/am/service/application_proxy_service.h
|
||||
hle/service/am/service/audio_controller.cpp
|
||||
hle/service/am/service/audio_controller.h
|
||||
hle/service/am/service/common_state_getter.cpp
|
||||
hle/service/am/service/common_state_getter.h
|
||||
hle/service/am/service/cradle_firmware_updater.cpp
|
||||
hle/service/am/service/cradle_firmware_updater.h
|
||||
hle/service/am/service/debug_functions.cpp
|
||||
hle/service/am/service/debug_functions.h
|
||||
hle/service/am/service/display_controller.cpp
|
||||
hle/service/am/service/display_controller.h
|
||||
hle/service/am/service/global_state_controller.cpp
|
||||
@@ -464,14 +476,28 @@ add_library(core STATIC
|
||||
hle/service/am/service/home_menu_functions.h
|
||||
hle/service/am/service/library_applet_accessor.cpp
|
||||
hle/service/am/service/library_applet_accessor.h
|
||||
hle/service/am/service/library_applet_creator.cpp
|
||||
hle/service/am/service/library_applet_creator.h
|
||||
hle/service/am/service/library_applet_proxy.cpp
|
||||
hle/service/am/service/library_applet_proxy.h
|
||||
hle/service/am/service/library_applet_self_accessor.cpp
|
||||
hle/service/am/service/library_applet_self_accessor.h
|
||||
hle/service/am/service/lock_accessor.cpp
|
||||
hle/service/am/service/lock_accessor.h
|
||||
hle/service/am/service/overlay_functions.cpp
|
||||
hle/service/am/service/overlay_functions.h
|
||||
hle/service/am/service/overlay_applet_proxy.cpp
|
||||
hle/service/am/service/overlay_applet_proxy.h
|
||||
hle/service/am/service/process_winding_controller.cpp
|
||||
hle/service/am/service/process_winding_controller.h
|
||||
hle/service/am/service/self_controller.cpp
|
||||
hle/service/am/service/self_controller.h
|
||||
hle/service/am/service/storage.cpp
|
||||
hle/service/am/service/storage.h
|
||||
hle/service/am/service/storage_accessor.cpp
|
||||
hle/service/am/service/storage_accessor.h
|
||||
hle/service/am/service/system_applet_proxy.cpp
|
||||
hle/service/am/service/system_applet_proxy.h
|
||||
hle/service/am/service/window_controller.cpp
|
||||
hle/service/am/service/window_controller.h
|
||||
hle/service/am/window_system.cpp
|
||||
@@ -556,8 +582,20 @@ add_library(core STATIC
|
||||
hle/service/btdrv/btdrv.h
|
||||
hle/service/btm/btm.cpp
|
||||
hle/service/btm/btm.h
|
||||
hle/service/btm/btm_debug.cpp
|
||||
hle/service/btm/btm_debug.h
|
||||
hle/service/btm/btm_system.cpp
|
||||
hle/service/btm/btm_system.h
|
||||
hle/service/btm/btm_system_core.cpp
|
||||
hle/service/btm/btm_system_core.h
|
||||
hle/service/btm/btm_user.cpp
|
||||
hle/service/btm/btm_user.h
|
||||
hle/service/btm/btm_user_core.cpp
|
||||
hle/service/btm/btm_user_core.h
|
||||
hle/service/caps/caps.cpp
|
||||
hle/service/caps/caps.h
|
||||
hle/service/caps/caps_a.cpp
|
||||
hle/service/caps/caps_a.h
|
||||
hle/service/caps/caps_c.cpp
|
||||
hle/service/caps/caps_c.h
|
||||
hle/service/caps/caps_manager.cpp
|
||||
@@ -582,6 +620,10 @@ add_library(core STATIC
|
||||
hle/service/eupld/eupld.h
|
||||
hle/service/fatal/fatal.cpp
|
||||
hle/service/fatal/fatal.h
|
||||
hle/service/fatal/fatal_p.cpp
|
||||
hle/service/fatal/fatal_p.h
|
||||
hle/service/fatal/fatal_u.cpp
|
||||
hle/service/fatal/fatal_u.h
|
||||
hle/service/fgm/fgm.cpp
|
||||
hle/service/fgm/fgm.h
|
||||
hle/service/filesystem/filesystem.cpp
|
||||
@@ -613,6 +655,8 @@ add_library(core STATIC
|
||||
hle/service/filesystem/save_data_controller.h
|
||||
hle/service/friend/friend.cpp
|
||||
hle/service/friend/friend.h
|
||||
hle/service/friend/friend_interface.cpp
|
||||
hle/service/friend/friend_interface.h
|
||||
hle/service/glue/arp.cpp
|
||||
hle/service/glue/arp.h
|
||||
hle/service/glue/bgtc.cpp
|
||||
@@ -681,6 +725,8 @@ add_library(core STATIC
|
||||
hle/service/ldn/monitor_service.h
|
||||
hle/service/ldn/sf_monitor_service.cpp
|
||||
hle/service/ldn/sf_monitor_service.h
|
||||
hle/service/ldn/sf_service.cpp
|
||||
hle/service/ldn/sf_service.h
|
||||
hle/service/ldn/sf_service_monitor.cpp
|
||||
hle/service/ldn/sf_service_monitor.h
|
||||
hle/service/ldn/system_local_communication_service.cpp
|
||||
@@ -869,6 +915,8 @@ add_library(core STATIC
|
||||
hle/service/olsc/native_handle_holder.h
|
||||
hle/service/olsc/olsc_service_for_application.cpp
|
||||
hle/service/olsc/olsc_service_for_application.h
|
||||
hle/service/olsc/olsc_service_for_system_service.cpp
|
||||
hle/service/olsc/olsc_service_for_system_service.h
|
||||
hle/service/olsc/olsc.cpp
|
||||
hle/service/olsc/olsc.h
|
||||
hle/service/olsc/remote_storage_controller.cpp
|
||||
@@ -898,8 +946,14 @@ add_library(core STATIC
|
||||
hle/service/os/process.h
|
||||
hle/service/pcie/pcie.cpp
|
||||
hle/service/pcie/pcie.h
|
||||
hle/service/pctl/parental_control_service_factory.cpp
|
||||
hle/service/pctl/parental_control_service_factory.h
|
||||
hle/service/pctl/parental_control_service.cpp
|
||||
hle/service/pctl/parental_control_service.h
|
||||
hle/service/pctl/pctl.cpp
|
||||
hle/service/pctl/pctl.h
|
||||
hle/service/pctl/pctl_results.h
|
||||
hle/service/pctl/pctl_types.h
|
||||
hle/service/pcv/pcv.cpp
|
||||
hle/service/pcv/pcv.h
|
||||
hle/service/pm/pm.cpp
|
||||
@@ -909,8 +963,18 @@ add_library(core STATIC
|
||||
hle/service/psc/ovln/ovln_types.h
|
||||
hle/service/psc/ovln/receiver_service.cpp
|
||||
hle/service/psc/ovln/receiver_service.h
|
||||
hle/service/psc/ovln/receiver.cpp
|
||||
hle/service/psc/ovln/receiver.h
|
||||
hle/service/psc/ovln/sender_service.cpp
|
||||
hle/service/psc/ovln/sender_service.h
|
||||
hle/service/psc/ovln/sender.cpp
|
||||
hle/service/psc/ovln/sender.h
|
||||
hle/service/psc/pm_control.cpp
|
||||
hle/service/psc/pm_control.h
|
||||
hle/service/psc/pm_module.cpp
|
||||
hle/service/psc/pm_module.h
|
||||
hle/service/psc/pm_service.cpp
|
||||
hle/service/psc/pm_service.h
|
||||
hle/service/psc/psc.cpp
|
||||
hle/service/psc/psc.h
|
||||
hle/service/psc/time/alarms.cpp
|
||||
@@ -961,6 +1025,10 @@ add_library(core STATIC
|
||||
hle/service/ptm/ts.h
|
||||
hle/service/ro/ro.cpp
|
||||
hle/service/ro/ro.h
|
||||
hle/service/ro/ro_nro_utils.cpp
|
||||
hle/service/ro/ro_nro_utils.h
|
||||
hle/service/ro/ro_results.h
|
||||
hle/service/ro/ro_types.h
|
||||
hle/service/server_manager.cpp
|
||||
hle/service/server_manager.h
|
||||
hle/service/service.cpp
|
||||
@@ -989,6 +1057,8 @@ add_library(core STATIC
|
||||
hle/service/set/system_settings_server.h
|
||||
hle/service/sm/sm.cpp
|
||||
hle/service/sm/sm.h
|
||||
hle/service/sm/sm_controller.cpp
|
||||
hle/service/sm/sm_controller.h
|
||||
hle/service/sockets/bsd.cpp
|
||||
hle/service/sockets/bsd.h
|
||||
hle/service/sockets/nsd.cpp
|
||||
@@ -1154,7 +1224,7 @@ target_link_libraries(core PRIVATE
|
||||
RenderDoc::API
|
||||
ZLIB::ZLIB)
|
||||
|
||||
target_link_libraries(core PUBLIC httplib::httplib zstd::zstd frozen::frozen-headers)
|
||||
target_link_libraries(core PUBLIC httplib::httplib zstd::zstd)
|
||||
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
target_compile_definitions(core PUBLIC ENABLE_WEB_SERVICE)
|
||||
|
||||
@@ -165,10 +165,13 @@ bool ArmNce::HandleGuestAccessFault(GuestContext* guest_ctx, void* raw_info, voi
|
||||
const Common::ProcessAddress addr =
|
||||
(reinterpret_cast<u64>(info->si_addr) & ~Memory::YUZU_PAGEMASK);
|
||||
auto& memory = guest_ctx->parent->m_running_thread->GetOwnerProcess()->GetMemory();
|
||||
if (memory.InvalidateNCE(addr, Memory::YUZU_PAGESIZE)) {
|
||||
// We handled the access successfully and are returning to guest code.
|
||||
const auto result = memory.InvalidateNCE(addr, Memory::YUZU_PAGESIZE);
|
||||
if (result == Memory::NCEAccessFaultAction::Retry) {
|
||||
return true;
|
||||
}
|
||||
if (result == Memory::NCEAccessFaultAction::Instruction) {
|
||||
return HandleGuestAlignmentFault(guest_ctx, raw_info, raw_context);
|
||||
}
|
||||
|
||||
// We couldn't handle the access.
|
||||
return HandleFailedGuestFault(guest_ctx, raw_info, raw_context);
|
||||
@@ -369,8 +372,8 @@ void ArmNce::SetContext(const Kernel::Svc::ThreadContext& ctx) {
|
||||
}
|
||||
|
||||
void ArmNce::SignalInterrupt(Kernel::KThread* thread) {
|
||||
// Add break loop condition.
|
||||
m_guest_ctx.esr_el1.fetch_or(static_cast<u64>(HaltReason::BreakLoop));
|
||||
constexpr u64 break_loop = static_cast<u64>(HaltReason::BreakLoop);
|
||||
if ((m_guest_ctx.esr_el1.fetch_or(break_loop) & break_loop) != 0) return;
|
||||
|
||||
auto* params = &thread->GetNativeExecutionParameters();
|
||||
LockThreadParameters(params);
|
||||
|
||||
+17
-34
@@ -4,7 +4,6 @@
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include "game_settings.h"
|
||||
@@ -249,30 +248,12 @@ struct System::Impl {
|
||||
}
|
||||
}
|
||||
|
||||
void NotifyNVDECChannelOpen(u64 process_id) {
|
||||
std::scoped_lock lock{nvdec_active_mutex};
|
||||
++nvdec_active_channels[process_id];
|
||||
}
|
||||
|
||||
void NotifyNVDECChannelClose(u64 process_id) {
|
||||
std::scoped_lock lock{nvdec_active_mutex};
|
||||
const auto it = nvdec_active_channels.find(process_id);
|
||||
if (it == nvdec_active_channels.end()) {
|
||||
return;
|
||||
}
|
||||
if (--it->second == 0) {
|
||||
nvdec_active_channels.erase(it);
|
||||
}
|
||||
void SetNVDECActive(bool is_nvdec_active) {
|
||||
nvdec_active = is_nvdec_active;
|
||||
}
|
||||
|
||||
bool GetNVDECActive() {
|
||||
std::scoped_lock lock{nvdec_active_mutex};
|
||||
return !nvdec_active_channels.empty();
|
||||
}
|
||||
|
||||
bool IsNVDECActiveForProcess(u64 process_id) {
|
||||
std::scoped_lock lock{nvdec_active_mutex};
|
||||
return nvdec_active_channels.contains(process_id);
|
||||
return nvdec_active;
|
||||
}
|
||||
|
||||
void InitializeDebugger(System& system, u16 port) {
|
||||
@@ -528,8 +509,6 @@ struct System::Impl {
|
||||
|
||||
mutable std::mutex suspend_guard;
|
||||
std::mutex general_channel_mutex;
|
||||
std::mutex nvdec_active_mutex;
|
||||
std::unordered_map<u64, u32> nvdec_active_channels;
|
||||
std::atomic_bool is_paused{};
|
||||
std::atomic_bool is_shutting_down{};
|
||||
std::atomic_bool is_powered_on{};
|
||||
@@ -537,6 +516,7 @@ struct System::Impl {
|
||||
bool extended_memory_layout : 1 = false;
|
||||
bool exit_locked : 1 = false;
|
||||
bool exit_requested : 1 = false;
|
||||
bool nvdec_active : 1 = false;
|
||||
|
||||
void EnsureGeneralChannelInitialized(System& system) {
|
||||
if (!general_channel_event) {
|
||||
@@ -600,22 +580,14 @@ void System::UnstallApplication() {
|
||||
impl->UnstallApplication();
|
||||
}
|
||||
|
||||
void System::NotifyNVDECChannelOpen(u64 process_id) {
|
||||
impl->NotifyNVDECChannelOpen(process_id);
|
||||
}
|
||||
|
||||
void System::NotifyNVDECChannelClose(u64 process_id) {
|
||||
impl->NotifyNVDECChannelClose(process_id);
|
||||
void System::SetNVDECActive(bool is_nvdec_active) {
|
||||
impl->SetNVDECActive(is_nvdec_active);
|
||||
}
|
||||
|
||||
bool System::GetNVDECActive() {
|
||||
return impl->GetNVDECActive();
|
||||
}
|
||||
|
||||
bool System::IsNVDECActiveForProcess(u64 process_id) {
|
||||
return impl->IsNVDECActiveForProcess(process_id);
|
||||
}
|
||||
|
||||
void System::InitializeDebugger() {
|
||||
impl->InitializeDebugger(*this, Settings::values.gdbstub_port.GetValue());
|
||||
}
|
||||
@@ -814,6 +786,17 @@ void System::RegisterCheatList(const std::vector<Memory::CheatEntry>& list,
|
||||
impl->cheat_engine->SetMainMemoryParameters(main_region_begin, main_region_size);
|
||||
}
|
||||
|
||||
std::vector<Memory::RuntimeCheatInfo> System::GetRuntimeCheats() const {
|
||||
if (!impl->cheat_engine) {
|
||||
return {};
|
||||
}
|
||||
return impl->cheat_engine->GetCheats();
|
||||
}
|
||||
|
||||
bool System::SetCheatEnabled(u32 cheat_id, bool enabled) {
|
||||
return impl->cheat_engine && impl->cheat_engine->SetCheatEnabled(cheat_id, enabled);
|
||||
}
|
||||
|
||||
void System::SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set) {
|
||||
impl->frontend_applets.SetFrontendAppletSet(std::move(set));
|
||||
}
|
||||
|
||||
+4
-3
@@ -46,6 +46,7 @@ enum class ResultStatus : u16;
|
||||
|
||||
namespace Core::Memory {
|
||||
struct CheatEntry;
|
||||
struct RuntimeCheatInfo;
|
||||
class Memory;
|
||||
} // namespace Core::Memory
|
||||
|
||||
@@ -191,10 +192,8 @@ public:
|
||||
std::unique_lock<std::mutex> StallApplication();
|
||||
void UnstallApplication();
|
||||
|
||||
void NotifyNVDECChannelOpen(u64 process_id);
|
||||
void NotifyNVDECChannelClose(u64 process_id);
|
||||
void SetNVDECActive(bool is_nvdec_active);
|
||||
[[nodiscard]] bool GetNVDECActive();
|
||||
[[nodiscard]] bool IsNVDECActiveForProcess(u64 process_id);
|
||||
|
||||
/**
|
||||
* Initialize the debugger.
|
||||
@@ -344,6 +343,8 @@ public:
|
||||
void RegisterCheatList(const std::vector<Memory::CheatEntry>& list,
|
||||
const std::array<u8, 0x20>& build_id, u64 main_region_begin,
|
||||
u64 main_region_size);
|
||||
[[nodiscard]] std::vector<Memory::RuntimeCheatInfo> GetRuntimeCheats() const;
|
||||
bool SetCheatEnabled(u32 cheat_id, bool enabled);
|
||||
|
||||
void SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set);
|
||||
|
||||
|
||||
@@ -0,0 +1,472 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <zstd.h>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging.h"
|
||||
#include "common/zstd_compression.h"
|
||||
#include "core/crypto/aes_util.h"
|
||||
#include "core/crypto/key_manager.h"
|
||||
#include "core/crypto/ncz_decompressor.h"
|
||||
#include "core/file_sys/vfs/vfs.h"
|
||||
|
||||
namespace Core::Crypto {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr u64 HeaderSize = 0x4000;
|
||||
constexpr std::size_t SectionWire = 0x40;
|
||||
constexpr std::size_t BlockFixed = 0x18;
|
||||
constexpr std::size_t Chunk = 0x100000;
|
||||
// Upper bound on NCZ section entries (64 bytes each, so the table is at most 4 MiB). A base NCA
|
||||
// has a handful of sections, but nsz stores an update's patch (BKTR) data one entry per
|
||||
// subsection, which is thousands of them.
|
||||
constexpr u64 MaxSectionCount = 0x10000;
|
||||
constexpr std::array<u8, 8> SectionsMagic{'N', 'C', 'Z', 'S', 'E', 'C', 'T', 'N'};
|
||||
constexpr std::array<u8, 8> BlockMagic{'N', 'C', 'Z', 'B', 'L', 'O', 'C', 'K'};
|
||||
|
||||
struct Section {
|
||||
s64 offset, size;
|
||||
u64 crypto_type;
|
||||
Key128 key, counter;
|
||||
bool Ctr() const { return crypto_type == 3 || crypto_type == 4; }
|
||||
};
|
||||
|
||||
struct BlockHeader {
|
||||
u32 exponent;
|
||||
u64 decompressed_size;
|
||||
std::vector<u32> sizes;
|
||||
};
|
||||
|
||||
u64 Le(const u8* p, std::size_t n) {
|
||||
u64 v = 0;
|
||||
for (std::size_t i = n; i-- > 0;) v = (v << 8) | p[i];
|
||||
return v;
|
||||
}
|
||||
|
||||
// Mirrors nsz AESCTR.seek(): upper 8 bytes = stored counter, lower 8 = absolute NCA offset / 16.
|
||||
void SetIv(Key128& iv, const Key128& base, u64 off) {
|
||||
iv = base;
|
||||
u64 blk = off >> 4;
|
||||
for (std::size_t i = 0; i < 8; ++i) { iv[15 - i] = static_cast<u8>(blk & 0xFF); blk >>= 8; }
|
||||
}
|
||||
|
||||
// Parse header + section table + optional block header. Returns payload_start.
|
||||
std::optional<std::pair<std::vector<Section>, std::optional<BlockHeader>>> ParseHeader(
|
||||
const FileSys::VirtualFile& f, u64& payload_start) {
|
||||
const u64 fsize = f->GetSize();
|
||||
if (fsize < HeaderSize + 16) return std::nullopt;
|
||||
|
||||
const auto head = f->ReadBytes(16, HeaderSize);
|
||||
if (head.size() != 16 || !std::equal(head.begin(), head.begin() + 8, SectionsMagic.begin()))
|
||||
return std::nullopt;
|
||||
const u64 count = Le(head.data() + 8, 8);
|
||||
if (count == 0 || count > MaxSectionCount || count * SectionWire > fsize - HeaderSize - 16)
|
||||
return std::nullopt;
|
||||
|
||||
const auto table = f->ReadBytes(count * SectionWire, HeaderSize + 16);
|
||||
if (table.size() != count * SectionWire) return std::nullopt;
|
||||
|
||||
std::vector<Section> sections;
|
||||
sections.reserve(count + 1);
|
||||
for (u64 i = 0; i < count; ++i) {
|
||||
const u8* e = table.data() + i * SectionWire;
|
||||
Section s{};
|
||||
s.offset = static_cast<s64>(Le(e, 8));
|
||||
s.size = static_cast<s64>(Le(e + 8, 8));
|
||||
s.crypto_type = Le(e + 16, 8);
|
||||
std::memcpy(s.key.data(), e + 32, 16);
|
||||
std::memcpy(s.counter.data(), e + 48, 16);
|
||||
sections.push_back(s);
|
||||
}
|
||||
|
||||
const u64 block_start = HeaderSize + 16 + count * SectionWire;
|
||||
const auto fixed = f->ReadBytes(BlockFixed, block_start);
|
||||
std::optional<BlockHeader> bh;
|
||||
if (fixed.size() == BlockFixed &&
|
||||
std::equal(fixed.begin(), fixed.begin() + 8, BlockMagic.begin())) {
|
||||
BlockHeader b{};
|
||||
b.exponent = fixed[11];
|
||||
const s32 n = static_cast<s32>(Le(fixed.data() + 12, 4));
|
||||
if (n <= 0) return std::nullopt;
|
||||
b.decompressed_size = Le(fixed.data() + 16, 8);
|
||||
const auto sizes = f->ReadBytes(static_cast<u64>(n) * 4, block_start + BlockFixed);
|
||||
if (sizes.size() != static_cast<u64>(n) * 4) return std::nullopt;
|
||||
b.sizes.resize(n);
|
||||
for (s32 i = 0; i < n; ++i) b.sizes[i] = static_cast<u32>(Le(sizes.data() + i * 4, 4));
|
||||
payload_start = block_start + BlockFixed + static_cast<u64>(n) * 4;
|
||||
bh = std::move(b);
|
||||
} else {
|
||||
payload_start = block_start;
|
||||
}
|
||||
|
||||
if (!sections.empty() && sections[0].offset > static_cast<s64>(HeaderSize)) {
|
||||
Section fake{};
|
||||
fake.offset = static_cast<s64>(HeaderSize);
|
||||
fake.size = sections[0].offset - static_cast<s64>(HeaderSize);
|
||||
sections.insert(sections.begin(), fake);
|
||||
}
|
||||
return std::make_pair(std::move(sections), std::move(bh));
|
||||
}
|
||||
|
||||
// Sequential reader over independently-compressed blocks. Uses a direct-mapped cache (like
|
||||
// NCZVirtualFile) instead of an LRU list: block_index % CacheSlots picks the slot, so a hit is
|
||||
// O(1). Reuses one ZSTD_DCtx for the lifetime of the reader.
|
||||
class BlockReader {
|
||||
public:
|
||||
static constexpr std::size_t CacheSlots = 32;
|
||||
|
||||
BlockReader(FileSys::VirtualFile f, const BlockHeader& bh, u64 payload_start)
|
||||
: source{std::move(f)}, block_size{1ULL << bh.exponent}, sizes{bh.sizes},
|
||||
decompressed_size{bh.decompressed_size} {
|
||||
if (bh.exponent < 14 || bh.exponent > 32 || sizes.empty())
|
||||
throw std::runtime_error("bad NCZBLOCK header");
|
||||
u64 off = payload_start;
|
||||
offsets.reserve(sizes.size());
|
||||
for (u32 s : sizes) { offsets.push_back(off); off += s; }
|
||||
dctx = ZSTD_createDCtx();
|
||||
if (dctx == nullptr) throw std::runtime_error("ZSTD_createDCtx failed");
|
||||
cache.resize(CacheSlots);
|
||||
for (auto& slot : cache) slot.id = ~0ULL;
|
||||
}
|
||||
|
||||
~BlockReader() {
|
||||
if (dctx != nullptr) ZSTD_freeDCtx(dctx);
|
||||
}
|
||||
|
||||
BlockReader(const BlockReader&) = delete;
|
||||
BlockReader& operator=(const BlockReader&) = delete;
|
||||
|
||||
std::size_t ReadAt(u64 position, std::span<u8> out) {
|
||||
std::size_t done = 0;
|
||||
while (done < out.size() && position < decompressed_size) {
|
||||
const u64 id = position / block_size;
|
||||
if (id >= sizes.size()) break;
|
||||
const std::vector<u8>* block = GetBlock(id);
|
||||
if (block == nullptr) break;
|
||||
const u64 in = position - id * block_size;
|
||||
if (in >= block->size()) break;
|
||||
const std::size_t n = static_cast<std::size_t>(
|
||||
std::min<u64>(out.size() - done, block->size() - in));
|
||||
std::memcpy(out.data() + done, block->data() + in, n);
|
||||
done += n;
|
||||
position += n;
|
||||
}
|
||||
return done;
|
||||
}
|
||||
|
||||
private:
|
||||
struct Slot {
|
||||
u64 id = ~0ULL;
|
||||
std::vector<u8> data;
|
||||
};
|
||||
|
||||
const std::vector<u8>* GetBlock(u64 id) {
|
||||
Slot& slot = cache[id % CacheSlots];
|
||||
if (slot.id == id) {
|
||||
return &slot.data; // O(1) hit
|
||||
}
|
||||
std::vector<u8> buffer;
|
||||
buffer.swap(slot.data); // reuse existing allocation
|
||||
if (!DecodeBlock(id, buffer)) {
|
||||
return nullptr;
|
||||
}
|
||||
slot.data = std::move(buffer);
|
||||
slot.id = id;
|
||||
return &slot.data;
|
||||
}
|
||||
|
||||
bool DecodeBlock(u64 id, std::vector<u8>& buffer) {
|
||||
u64 want = block_size;
|
||||
if (id + 1 == sizes.size()) {
|
||||
const u64 rem = decompressed_size % block_size;
|
||||
if (rem > 0) want = rem; // avoid the 0-size bug from the original nsz
|
||||
}
|
||||
try { buffer.resize(static_cast<std::size_t>(want)); }
|
||||
catch (const std::bad_alloc&) { return false; }
|
||||
const u32 csize = sizes[id];
|
||||
if (csize < want) {
|
||||
const auto comp = source->ReadBytes(csize, offsets[id]);
|
||||
if (comp.size() != csize) return false;
|
||||
const std::size_t res = ZSTD_decompressDCtx(
|
||||
dctx, buffer.data(), buffer.size(), comp.data(), comp.size());
|
||||
if (ZSTD_isError(res) || res != want) {
|
||||
LOG_ERROR(Crypto, "Failed to decompress NCZBLOCK block {}: {}", id,
|
||||
ZSTD_isError(res) ? ZSTD_getErrorName(res) : "size mismatch");
|
||||
return false;
|
||||
}
|
||||
} else if (source->Read(buffer.data(), buffer.size(), offsets[id]) != buffer.size()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
FileSys::VirtualFile source;
|
||||
u64 block_size;
|
||||
std::vector<u64> offsets;
|
||||
std::vector<u32> sizes;
|
||||
u64 decompressed_size;
|
||||
ZSTD_DCtx* dctx = nullptr;
|
||||
std::vector<Slot> cache; // direct-mapped, CacheSlots entries
|
||||
};
|
||||
|
||||
class BlockNczFile final : public FileSys::VfsFile {
|
||||
public:
|
||||
BlockNczFile(std::string name_, std::vector<u8> hdr_, std::vector<Section> sections_,
|
||||
std::unique_ptr<BlockReader> body_)
|
||||
: name{std::move(name_)}, hdr{std::move(hdr_)}, sections{std::move(sections_)},
|
||||
body{std::move(body_)} {
|
||||
nca_size = HeaderSize;
|
||||
for (const auto& s : sections)
|
||||
nca_size = std::max<u64>(nca_size, static_cast<u64>(s.offset + s.size));
|
||||
}
|
||||
|
||||
std::string GetName() const override { return name; }
|
||||
std::size_t GetSize() const override { return static_cast<std::size_t>(nca_size); }
|
||||
bool Resize(std::size_t) override { return false; }
|
||||
FileSys::VirtualDir GetContainingDirectory() const override { return nullptr; }
|
||||
bool IsWritable() const override { return false; }
|
||||
bool IsReadable() const override { return true; }
|
||||
|
||||
// NCZ stores CTR sections decrypted; this file serves them as-is, and NcaFileSystemDriver
|
||||
// skips its AES layers because of this flag.
|
||||
bool HasDecryptedSections() const override { return true; }
|
||||
|
||||
std::size_t Read(u8* data, std::size_t len, std::size_t off) const override {
|
||||
if (off >= nca_size) return 0;
|
||||
len = static_cast<std::size_t>(std::min<u64>(len, nca_size - off));
|
||||
const u64 end = off + len;
|
||||
u64 pos = off;
|
||||
if (pos < HeaderSize) {
|
||||
const u64 n = std::min<u64>(end, HeaderSize) - pos;
|
||||
std::memcpy(data, hdr.data() + pos, static_cast<std::size_t>(n));
|
||||
pos += n;
|
||||
}
|
||||
std::scoped_lock lock{mutex};
|
||||
// Sections are sorted by offset; find the first one whose stop > pos.
|
||||
auto it = std::lower_bound(
|
||||
sections.begin(), sections.end(), pos, [](const Section& s, u64 p) {
|
||||
const u64 b = std::max<u64>(static_cast<u64>(s.offset), HeaderSize);
|
||||
const u64 e = std::max<u64>(static_cast<u64>(s.offset) + static_cast<u64>(s.size), b);
|
||||
return e <= p;
|
||||
});
|
||||
for (; it != sections.end() && pos < end; ++it) {
|
||||
const auto& s = *it;
|
||||
const u64 begin = std::max<u64>(static_cast<u64>(s.offset), HeaderSize);
|
||||
const u64 stop = std::max<u64>(static_cast<u64>(s.offset + s.size), begin);
|
||||
if (stop <= pos) continue;
|
||||
if (pos < begin) {
|
||||
const u64 g = std::min(end, begin);
|
||||
std::memset(data + (pos - off), 0, static_cast<std::size_t>(g - pos));
|
||||
pos = g;
|
||||
if (pos >= end) break;
|
||||
}
|
||||
const u64 pe = std::min(end, stop);
|
||||
const std::span<u8> piece(data + (pos - off), static_cast<std::size_t>(pe - pos));
|
||||
if (body->ReadAt(pos - HeaderSize, piece) != piece.size())
|
||||
return static_cast<std::size_t>(pos - off);
|
||||
// No CTR here: NCZ body is already decrypted, and NcaFileSystemDriver skips AES.
|
||||
pos = pe;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
std::size_t Write(const u8*, std::size_t, std::size_t) override { return 0; }
|
||||
bool Rename(std::string_view) override { return false; }
|
||||
|
||||
private:
|
||||
const std::string name;
|
||||
const std::vector<u8> hdr;
|
||||
const std::vector<Section> sections;
|
||||
const std::unique_ptr<BlockReader> body;
|
||||
mutable std::mutex mutex;
|
||||
u64 nca_size{};
|
||||
};
|
||||
|
||||
// Solid NCZ: one zstd stream over the whole body. Decoded incrementally into memory, up to the
|
||||
// requested offset, so sequential install reads are O(n) instead of O(n^2).
|
||||
class SolidNczFile final : public FileSys::VfsFile {
|
||||
public:
|
||||
SolidNczFile(std::string name_, FileSys::VirtualFile source_,
|
||||
std::vector<Section> sections_, u64 payload_start_)
|
||||
: name{std::move(name_)}, source{std::move(source_)}, sections{std::move(sections_)},
|
||||
payload_start{payload_start_} {
|
||||
const auto raw_header = source->ReadBytes(HeaderSize, 0);
|
||||
data.assign(raw_header.begin(), raw_header.end());
|
||||
frontier = HeaderSize;
|
||||
}
|
||||
|
||||
~SolidNczFile() override {
|
||||
if (stream != nullptr) ZSTD_freeDStream(stream);
|
||||
}
|
||||
|
||||
std::string GetName() const override { return name; }
|
||||
std::size_t GetSize() const override {
|
||||
u64 size = HeaderSize;
|
||||
for (const auto& s : sections)
|
||||
size = std::max<u64>(size, static_cast<u64>(s.offset + s.size));
|
||||
return static_cast<std::size_t>(size);
|
||||
}
|
||||
bool Resize(std::size_t) override { return false; }
|
||||
FileSys::VirtualDir GetContainingDirectory() const override { return nullptr; }
|
||||
bool IsWritable() const override { return false; }
|
||||
bool IsReadable() const override { return true; }
|
||||
|
||||
std::size_t Read(u8* out, std::size_t len, std::size_t off) const override {
|
||||
std::scoped_lock lock{mutex};
|
||||
const u64 nca_size = GetSize();
|
||||
if (off >= nca_size) return 0;
|
||||
len = static_cast<std::size_t>(std::min<u64>(len, nca_size - off));
|
||||
const u64 needed = off + len;
|
||||
if (needed > frontier && !DecodeTo(needed)) return 0;
|
||||
std::memcpy(out, data.data() + off, len);
|
||||
return len;
|
||||
}
|
||||
|
||||
std::size_t Write(const u8*, std::size_t, std::size_t) override { return 0; }
|
||||
bool Rename(std::string_view) override { return false; }
|
||||
|
||||
private:
|
||||
bool DecodeTo(u64 needed) const {
|
||||
if (stream == nullptr) {
|
||||
stream = ZSTD_createDStream();
|
||||
if (stream == nullptr) return false;
|
||||
ZSTD_DCtx_setParameter(stream, ZSTD_d_windowLogMax, 31);
|
||||
read_pos = payload_start;
|
||||
}
|
||||
|
||||
const u64 file_size = source->GetSize();
|
||||
std::vector<u8> out_buf(Chunk);
|
||||
|
||||
std::size_t index = 0;
|
||||
for (; index < sections.size(); ++index) {
|
||||
const auto& s = sections[index];
|
||||
const u64 begin = std::max<u64>(static_cast<u64>(s.offset), HeaderSize);
|
||||
const u64 end = std::max<u64>(static_cast<u64>(s.offset) + static_cast<u64>(s.size),
|
||||
begin);
|
||||
if (end > frontier) break;
|
||||
}
|
||||
|
||||
for (; index < sections.size() && frontier < needed; ++index) {
|
||||
const auto& s = sections[index];
|
||||
const u64 begin = std::max<u64>(static_cast<u64>(s.offset), HeaderSize);
|
||||
const u64 end = std::max<u64>(static_cast<u64>(s.offset) + static_cast<u64>(s.size),
|
||||
begin);
|
||||
if (end <= frontier) continue;
|
||||
u64 pos = std::max<u64>(begin, frontier);
|
||||
|
||||
std::optional<AESCipher<Key128>> cipher;
|
||||
if (s.Ctr()) cipher.emplace(s.key, Mode::CTR);
|
||||
|
||||
while (pos < end && frontier < needed) {
|
||||
const u64 want = std::min<u64>(end - pos, out_buf.size());
|
||||
std::size_t produced = 0;
|
||||
while (produced < want) {
|
||||
if (in.pos >= in.size) {
|
||||
const u64 remaining = file_size - read_pos;
|
||||
const std::size_t chunk = static_cast<std::size_t>(
|
||||
std::min<u64>(Chunk, remaining));
|
||||
if (chunk == 0) { LOG_ERROR(Crypto, "Solid NCZ: truncated"); return false; }
|
||||
const auto bytes = source->ReadBytes(chunk, read_pos);
|
||||
if (bytes.empty()) { LOG_ERROR(Crypto, "Solid NCZ: truncated"); return false; }
|
||||
read_pos += bytes.size();
|
||||
in_buf.assign(bytes.begin(), bytes.end());
|
||||
in.src = in_buf.data();
|
||||
in.size = in_buf.size();
|
||||
in.pos = 0;
|
||||
}
|
||||
ZSTD_outBuffer outb{out_buf.data() + produced, want - produced, 0};
|
||||
const std::size_t res = ZSTD_decompressStream(stream, &outb, &in);
|
||||
if (ZSTD_isError(res)) {
|
||||
LOG_ERROR(Crypto, "Solid NCZ: zstd error");
|
||||
return false;
|
||||
}
|
||||
produced += outb.pos;
|
||||
}
|
||||
if (cipher) {
|
||||
Key128 iv{};
|
||||
SetIv(iv, s.counter, pos);
|
||||
cipher->SetIV(iv);
|
||||
cipher->Transcode(out_buf.data(), produced, out_buf.data(), Op::Encrypt);
|
||||
}
|
||||
data.insert(data.end(), out_buf.begin(), out_buf.begin() + produced);
|
||||
pos += produced;
|
||||
frontier = pos;
|
||||
}
|
||||
}
|
||||
return frontier >= needed;
|
||||
}
|
||||
|
||||
const std::string name;
|
||||
const FileSys::VirtualFile source;
|
||||
const std::vector<Section> sections;
|
||||
const u64 payload_start;
|
||||
mutable std::mutex mutex;
|
||||
mutable std::vector<u8> data;
|
||||
mutable ZSTD_DStream* stream = nullptr;
|
||||
mutable u64 read_pos = 0;
|
||||
mutable u64 frontier = 0;
|
||||
mutable std::vector<u8> in_buf;
|
||||
mutable ZSTD_inBuffer in{nullptr, 0, 0};
|
||||
};
|
||||
|
||||
// Shared opener: block path always; solid only when allow_solid is true.
|
||||
FileSys::VirtualFile OpenNcz(const FileSys::VirtualFile& f, std::string_view name,
|
||||
bool allow_solid) {
|
||||
if (!f) return nullptr;
|
||||
u64 ps = 0;
|
||||
auto parsed = ParseHeader(f, ps);
|
||||
if (!parsed) return nullptr;
|
||||
auto& [sections, block] = *parsed;
|
||||
|
||||
if (block) {
|
||||
auto hdr = f->ReadBytes(HeaderSize, 0);
|
||||
if (hdr.size() != HeaderSize) return nullptr;
|
||||
std::unique_ptr<BlockReader> body;
|
||||
try { body = std::make_unique<BlockReader>(f, *block, ps); }
|
||||
catch (const std::exception& e) {
|
||||
LOG_ERROR(Crypto, "Failed to open NCZBLOCK: {}", e.what());
|
||||
return nullptr;
|
||||
}
|
||||
return std::make_shared<BlockNczFile>(std::string{name}, std::move(hdr),
|
||||
std::move(sections), std::move(body));
|
||||
}
|
||||
|
||||
if (allow_solid) {
|
||||
return std::make_shared<SolidNczFile>(std::string{name}, f, std::move(sections), ps);
|
||||
}
|
||||
|
||||
LOG_DEBUG(Crypto, "Solid NCZ {} skipped (only NCZBLOCK is supported for play)", name);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
bool IsBlockCompressedNCZ(const FileSys::VirtualFile& f) {
|
||||
if (!f) return false;
|
||||
u64 ps = 0;
|
||||
const auto p = ParseHeader(f, ps);
|
||||
return p && p->second.has_value();
|
||||
}
|
||||
|
||||
FileSys::VirtualFile DecompressNCZ(const FileSys::VirtualFile& f, std::string_view name) {
|
||||
return OpenNcz(f, name, /*allow_solid=*/false);
|
||||
}
|
||||
|
||||
FileSys::VirtualFile DecompressNCZForInstall(const FileSys::VirtualFile& f,
|
||||
std::string_view name) {
|
||||
return OpenNcz(f, name, /*allow_solid=*/true);
|
||||
}
|
||||
|
||||
} // namespace Core::Crypto
|
||||
@@ -0,0 +1,35 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include "core/file_sys/vfs/vfs_types.h"
|
||||
|
||||
namespace Core::Crypto {
|
||||
|
||||
/**
|
||||
* Opens an NCZBLOCK-compressed NCA (nsz -B / .xcz block format) as a VirtualFile backed by
|
||||
* on-demand block decoding. Nothing is written to disk; each read decodes only the blocks it
|
||||
* covers and re-encrypts CTR sections. Solid NCZ is not supported.
|
||||
*
|
||||
* @param ncz_file The raw NCZ payload (e.g. "<id>.ncz" entry from an NSZ/XCZ PFS0).
|
||||
* @param output_name Name to give the returned VirtualFile (e.g. "<id>.nca").
|
||||
*
|
||||
* @return a VirtualFile for the NCA, or nullptr if the NCZ is malformed or not NCZBLOCK.
|
||||
*/
|
||||
[[nodiscard]] FileSys::VirtualFile DecompressNCZ(const FileSys::VirtualFile& ncz_file,
|
||||
std::string_view output_name);
|
||||
|
||||
/**
|
||||
* Returns true if the given file is an NCZ payload in block-compressed (NCZBLOCK) form,
|
||||
* i.e. one that DecompressNCZ() can open. Solid NCZ returns false.
|
||||
*/
|
||||
[[nodiscard]] bool IsBlockCompressedNCZ(const FileSys::VirtualFile& ncz_file);
|
||||
|
||||
// Install to NAND: same as DecompressNCZ, but solid NCZ is decoded on demand too.
|
||||
[[nodiscard]] FileSys::VirtualFile DecompressNCZForInstall(
|
||||
const FileSys::VirtualFile& ncz_file, std::string_view output_name);
|
||||
|
||||
} // namespace Core::Crypto
|
||||
@@ -45,6 +45,7 @@ NCA::NCA(VirtualFile file_, const NCA* base_nca, bool allow_missing_base)
|
||||
// Ensure we have the proper key area keys to continue.
|
||||
const u8 master_key_id = MasterKeyIdForKeyGeneration(reader->GetKeyGeneration());
|
||||
if (!keys.HasKey(Core::Crypto::S128KeyType::KeyArea, master_key_id, reader->GetKeyIndex())) {
|
||||
LOG_ERROR(Loader, "Cannot decrypt {}: keys for gen 0x{:02X}+ required.", file->GetName(), reader->GetKeyGeneration());
|
||||
status = Loader::ResultStatus::ErrorMissingKeyAreaKey;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||
@@ -93,6 +93,11 @@ Result NcaFileSystemDriver::OpenStorageImpl(VirtualFile* out, NcaFsHeaderReader*
|
||||
// Initialize our header reader for the fs index.
|
||||
R_TRY(out_header_reader->Initialize(*m_reader, fs_index));
|
||||
|
||||
// NCZ files serve already-decrypted body data (CTR sections are stored decrypted).
|
||||
// Skip the AES layers so we don't decrypt plaintext twice.
|
||||
const bool is_pre_decrypted =
|
||||
m_reader->GetStorage() && m_reader->GetStorage()->HasDecryptedSections();
|
||||
|
||||
// Declare the storage we're opening.
|
||||
VirtualFile storage;
|
||||
|
||||
@@ -158,7 +163,7 @@ Result NcaFileSystemDriver::OpenStorageImpl(VirtualFile* out, NcaFsHeaderReader*
|
||||
out_header_reader->GetPatchMetaDataHashDataInfo()));
|
||||
}
|
||||
|
||||
if (patch_info.HasAesCtrExTable()) {
|
||||
if (patch_info.HasAesCtrExTable() && !is_pre_decrypted) {
|
||||
// Check the encryption type.
|
||||
ASSERT(out_header_reader->GetEncryptionType() == NcaFsHeader::EncryptionType::None ||
|
||||
out_header_reader->GetEncryptionType() == NcaFsHeader::EncryptionType::AesCtrEx ||
|
||||
@@ -196,32 +201,34 @@ Result NcaFileSystemDriver::OpenStorageImpl(VirtualFile* out, NcaFsHeaderReader*
|
||||
}
|
||||
} else {
|
||||
// Create the appropriate storage for the encryption type.
|
||||
switch (out_header_reader->GetEncryptionType()) {
|
||||
case NcaFsHeader::EncryptionType::None:
|
||||
// If there's no encryption, use the base storage we made previously.
|
||||
break;
|
||||
case NcaFsHeader::EncryptionType::AesXts:
|
||||
R_TRY(this->CreateAesXtsStorage(std::addressof(storage), std::move(storage),
|
||||
fs_data_offset));
|
||||
break;
|
||||
case NcaFsHeader::EncryptionType::AesCtr:
|
||||
R_TRY(this->CreateAesCtrStorage(std::addressof(storage), std::move(storage),
|
||||
fs_data_offset, out_header_reader->GetAesCtrUpperIv(),
|
||||
AlignmentStorageRequirement::None));
|
||||
break;
|
||||
case NcaFsHeader::EncryptionType::AesCtrSkipLayerHash: {
|
||||
// Create the aes ctr storage.
|
||||
VirtualFile aes_ctr_storage;
|
||||
R_TRY(this->CreateAesCtrStorage(std::addressof(aes_ctr_storage), storage,
|
||||
fs_data_offset, out_header_reader->GetAesCtrUpperIv(),
|
||||
AlignmentStorageRequirement::None));
|
||||
if (!is_pre_decrypted) {
|
||||
switch (out_header_reader->GetEncryptionType()) {
|
||||
case NcaFsHeader::EncryptionType::None:
|
||||
// If there's no encryption, use the base storage we made previously.
|
||||
break;
|
||||
case NcaFsHeader::EncryptionType::AesXts:
|
||||
R_TRY(this->CreateAesXtsStorage(std::addressof(storage), std::move(storage),
|
||||
fs_data_offset));
|
||||
break;
|
||||
case NcaFsHeader::EncryptionType::AesCtr:
|
||||
R_TRY(this->CreateAesCtrStorage(std::addressof(storage), std::move(storage),
|
||||
fs_data_offset, out_header_reader->GetAesCtrUpperIv(),
|
||||
AlignmentStorageRequirement::None));
|
||||
break;
|
||||
case NcaFsHeader::EncryptionType::AesCtrSkipLayerHash: {
|
||||
// Create the aes ctr storage.
|
||||
VirtualFile aes_ctr_storage;
|
||||
R_TRY(this->CreateAesCtrStorage(std::addressof(aes_ctr_storage), storage,
|
||||
fs_data_offset, out_header_reader->GetAesCtrUpperIv(),
|
||||
AlignmentStorageRequirement::None));
|
||||
|
||||
// Create region switch storage.
|
||||
R_TRY(this->CreateRegionSwitchStorage(std::addressof(storage), out_header_reader,
|
||||
std::move(storage), std::move(aes_ctr_storage)));
|
||||
} break;
|
||||
default:
|
||||
R_THROW(ResultInvalidNcaFsHeaderEncryptionType);
|
||||
// Create region switch storage.
|
||||
R_TRY(this->CreateRegionSwitchStorage(std::addressof(storage), out_header_reader,
|
||||
std::move(storage), std::move(aes_ctr_storage)));
|
||||
} break;
|
||||
default:
|
||||
R_THROW(ResultInvalidNcaFsHeaderEncryptionType);
|
||||
}
|
||||
}
|
||||
|
||||
// Potentially save storages to our context.
|
||||
@@ -382,21 +389,25 @@ Result NcaFileSystemDriver::OpenIndirectableStorageAsOriginal(
|
||||
}
|
||||
|
||||
// Create the appropriate storage for the encryption type.
|
||||
switch (header_reader->GetEncryptionType()) {
|
||||
case NcaFsHeader::EncryptionType::None:
|
||||
// If there's no encryption, use the base storage we made previously.
|
||||
break;
|
||||
case NcaFsHeader::EncryptionType::AesXts:
|
||||
R_TRY(
|
||||
this->CreateAesXtsStorage(std::addressof(storage), std::move(storage), fs_data_offset));
|
||||
break;
|
||||
case NcaFsHeader::EncryptionType::AesCtr:
|
||||
R_TRY(this->CreateAesCtrStorage(std::addressof(storage), std::move(storage), fs_data_offset,
|
||||
header_reader->GetAesCtrUpperIv(),
|
||||
AlignmentStorageRequirement::CacheBlockSize));
|
||||
break;
|
||||
default:
|
||||
R_THROW(ResultInvalidNcaFsHeaderEncryptionType);
|
||||
const bool is_pre_decrypted =
|
||||
m_reader->GetStorage() && m_reader->GetStorage()->HasDecryptedSections();
|
||||
if (!is_pre_decrypted) {
|
||||
switch (header_reader->GetEncryptionType()) {
|
||||
case NcaFsHeader::EncryptionType::None:
|
||||
// If there's no encryption, use the base storage we made previously.
|
||||
break;
|
||||
case NcaFsHeader::EncryptionType::AesXts:
|
||||
R_TRY(this->CreateAesXtsStorage(std::addressof(storage), std::move(storage),
|
||||
fs_data_offset));
|
||||
break;
|
||||
case NcaFsHeader::EncryptionType::AesCtr:
|
||||
R_TRY(this->CreateAesCtrStorage(std::addressof(storage), std::move(storage),
|
||||
fs_data_offset, header_reader->GetAesCtrUpperIv(),
|
||||
AlignmentStorageRequirement::CacheBlockSize));
|
||||
break;
|
||||
default:
|
||||
R_THROW(ResultInvalidNcaFsHeaderEncryptionType);
|
||||
}
|
||||
}
|
||||
|
||||
// Set output storage.
|
||||
@@ -432,6 +443,11 @@ Result NcaFileSystemDriver::CreateAesCtrStorage(
|
||||
ASSERT(out != nullptr);
|
||||
ASSERT(base_storage != nullptr);
|
||||
|
||||
if (m_reader->GetStorage() && m_reader->GetStorage()->HasDecryptedSections()) {
|
||||
*out = std::move(base_storage);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
// Create the iv.
|
||||
std::array<u8, AesCtrStorage::IvSize> iv{};
|
||||
AesCtrStorage::MakeIv(iv.data(), sizeof(iv), upper_iv.value, offset);
|
||||
@@ -469,6 +485,11 @@ Result NcaFileSystemDriver::CreateAesXtsStorage(VirtualFile* out, VirtualFile ba
|
||||
ASSERT(out != nullptr);
|
||||
ASSERT(base_storage != nullptr);
|
||||
|
||||
if (m_reader->GetStorage() && m_reader->GetStorage()->HasDecryptedSections()) {
|
||||
*out = std::move(base_storage);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
// Create the iv.
|
||||
std::array<u8, AesXtsStorage::IvSize> iv{};
|
||||
AesXtsStorage::MakeAesXtsIv(iv.data(), sizeof(iv), offset, NcaHeader::XtsBlockSize);
|
||||
@@ -809,6 +830,12 @@ Result NcaFileSystemDriver::CreateAesCtrExStorageMetaStorage(
|
||||
// Validate preconditions.
|
||||
ASSERT(out != nullptr);
|
||||
ASSERT(base_storage != nullptr);
|
||||
|
||||
if (m_reader->GetStorage() && m_reader->GetStorage()->HasDecryptedSections()) {
|
||||
*out = std::move(base_storage);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
ASSERT(encryption_type == NcaFsHeader::EncryptionType::None ||
|
||||
encryption_type == NcaFsHeader::EncryptionType::AesCtrEx ||
|
||||
encryption_type == NcaFsHeader::EncryptionType::AesCtrExSkipLayerHash);
|
||||
@@ -871,6 +898,11 @@ Result NcaFileSystemDriver::CreateAesCtrExStorage(
|
||||
ASSERT(meta_storage != nullptr);
|
||||
ASSERT(patch_info.HasAesCtrExTable());
|
||||
|
||||
if (m_reader->GetStorage() && m_reader->GetStorage()->HasDecryptedSections()) {
|
||||
*out = std::move(base_storage);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
// Read the bucket tree header.
|
||||
BucketTree::Header header;
|
||||
std::memcpy(std::addressof(header), patch_info.aes_ctr_ex_header.data(), sizeof(header));
|
||||
|
||||
@@ -104,6 +104,7 @@ public:
|
||||
const NcaCompressionConfiguration& compression_cfg);
|
||||
|
||||
VirtualFile GetSharedBodyStorage();
|
||||
VirtualFile GetStorage() const { return m_body_storage; }
|
||||
u32 GetMagic() const;
|
||||
NcaHeader::DistributionType GetDistributionType() const;
|
||||
NcaHeader::ContentType GetContentType() const;
|
||||
|
||||
@@ -503,10 +503,11 @@ std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(const BuildI
|
||||
for (const auto& subdir : patch_dirs) {
|
||||
if (std::find(disabled.cbegin(), disabled.cend(), subdir->GetName()) == disabled.cend()) {
|
||||
if (auto cheats_dir = FindSubdirectoryCaseless(subdir, "cheats"); cheats_dir != nullptr) {
|
||||
if (auto const res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, true))
|
||||
std::copy(res->begin(), res->end(), std::back_inserter(out));
|
||||
if (auto const res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, false))
|
||||
if (auto const res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, true)) {
|
||||
std::copy(res->begin(), res->end(), std::back_inserter(out));
|
||||
} else if (auto const lower_res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, false)) {
|
||||
std::copy(lower_res->begin(), lower_res->end(), std::back_inserter(out));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "common/random.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/crypto/key_manager.h"
|
||||
#include "core/crypto/ncz_decompressor.h"
|
||||
#include "core/file_sys/card_image.h"
|
||||
#include "core/file_sys/common_funcs.h"
|
||||
#include "core/file_sys/content_archive.h"
|
||||
@@ -158,6 +159,25 @@ static std::shared_ptr<NSP> OpenContainerAsNsp(const VirtualFile& file, Loader::
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Checks that every .ncz entry in the container is NCZBLOCK. Solid NCZ has no random access,
|
||||
// and the whole point of this build is to reject it at scan time so such files never appear
|
||||
// in the game list. Containers without any .ncz (plain NSP/XCI) pass through.
|
||||
static bool ContainerIsFullyBlockCompressed(const std::shared_ptr<NSP>& nsp) {
|
||||
if (!nsp) {
|
||||
return false;
|
||||
}
|
||||
for (const auto& entry : nsp->GetFiles()) {
|
||||
const auto name = entry->GetName();
|
||||
if (name.size() < 4 || name.substr(name.size() - 4) != ".ncz") {
|
||||
continue;
|
||||
}
|
||||
if (!Core::Crypto::IsBlockCompressedNCZ(entry)) {
|
||||
return false; // solid NCZ -> reject the whole container
|
||||
}
|
||||
}
|
||||
return true; // no .ncz at all, or all block-compressed
|
||||
}
|
||||
|
||||
template <typename Callback>
|
||||
bool ForEachContainerEntry(const std::shared_ptr<NSP>& nsp, bool only_content,
|
||||
std::optional<u64> base_program_id, Callback&& on_entry) {
|
||||
@@ -811,7 +831,14 @@ std::vector<ContentProviderEntry> RegisteredCache::ListEntriesFilter(
|
||||
}
|
||||
|
||||
static std::shared_ptr<NCA> GetNCAFromNSPForID(const NSP& nsp, const NcaID& id) {
|
||||
auto file = nsp.GetFile(fmt::format("{}.nca", Common::HexToString(id, false)));
|
||||
const auto id_string = Common::HexToString(id, false);
|
||||
auto file = nsp.GetFile(fmt::format("{}.nca", id_string));
|
||||
if (file == nullptr) {
|
||||
if (auto ncz_file = nsp.GetFile(fmt::format("{}.ncz", id_string))) {
|
||||
file = Core::Crypto::DecompressNCZForInstall(
|
||||
ncz_file, fmt::format("{}.nca", id_string));
|
||||
}
|
||||
}
|
||||
if (file == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1273,6 +1300,12 @@ bool ManualContentProvider::AddEntriesFromContainer(VirtualFile file, bool only_
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reject solid NCZ (.nsz without -B): only block-compressed NCZ is supported.
|
||||
if (!ContainerIsFullyBlockCompressed(nsp)) {
|
||||
LOG_DEBUG(Service_FS, "Skipping solid-compressed container: {}", file->GetName());
|
||||
return false;
|
||||
}
|
||||
|
||||
return ForEachContainerEntry(
|
||||
nsp, only_content, base_program_id,
|
||||
[this](TitleType title_type, ContentRecordType content_type, u64 title_id,
|
||||
@@ -1415,8 +1448,9 @@ void ExternalContentProvider::ScanDirectory(const VirtualDir& dir) {
|
||||
}
|
||||
|
||||
const auto extension = Common::ToLower(filename.substr(dot_pos + 1));
|
||||
|
||||
if (extension == "nsp") {
|
||||
// .xcz is an XCI container, but its updates only work through the NSP/PFS0 path
|
||||
// (DecompressNCZ), not ProcessXCI. So route .xcz here on purpose.
|
||||
if (extension == "nsp" || extension == "nsz" || extension == "xcz") {
|
||||
ProcessNSP(file);
|
||||
} else if (extension == "xci") {
|
||||
ProcessXCI(file);
|
||||
@@ -1434,6 +1468,12 @@ void ExternalContentProvider::ProcessNSP(const VirtualFile& file) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Reject solid NCZ (.nsz without -B): Eden only supports block-compressed NCZ.
|
||||
if (!ContainerIsFullyBlockCompressed(nsp)) {
|
||||
LOG_DEBUG(Service_FS, "Skipping solid-compressed container: {}", file->GetName());
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DEBUG(Service_FS, "Processing NSP file: {}", file->GetName());
|
||||
AddExternalEntriesFromContainer(nsp, entries, versions, multi_version_entries);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "common/hex_util.h"
|
||||
#include "common/logging.h"
|
||||
#include "core/crypto/key_manager.h"
|
||||
#include "core/crypto/ncz_decompressor.h"
|
||||
#include "core/file_sys/common_funcs.h"
|
||||
#include "core/file_sys/content_archive.h"
|
||||
#include "core/file_sys/nca_metadata.h"
|
||||
@@ -246,6 +247,17 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
|
||||
const auto id_string = Common::HexToString(rec.nca_id, false);
|
||||
auto next_file = pfs->GetFile(fmt::format("{}.nca", id_string));
|
||||
|
||||
if (next_file == nullptr) {
|
||||
auto ncz_file = pfs->GetFile(fmt::format("{}.ncz", id_string));
|
||||
if (ncz_file != nullptr) {
|
||||
next_file = Core::Crypto::DecompressNCZ(ncz_file, fmt::format("{}.nca", id_string));
|
||||
if (next_file == nullptr) {
|
||||
LOG_DEBUG(Service_FS, "Skipping solid or unsupported NCZ content {}.ncz", id_string);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (next_file == nullptr) {
|
||||
if (rec.type != ContentRecordType::DeltaFragment) {
|
||||
LOG_WARNING(Service_FS,
|
||||
|
||||
@@ -112,6 +112,9 @@ public:
|
||||
// Returns whether or not the file can be read from.
|
||||
virtual bool IsReadable() const = 0;
|
||||
|
||||
// Returns true if this file serves NCA body data that is already decrypted (e.g. NCZ).
|
||||
virtual bool HasDecryptedSections() const { return false; }
|
||||
|
||||
// The primary method of reading from the file. Reads length bytes into data starting at offset
|
||||
// into file. Returns number of bytes successfully read.
|
||||
virtual std::size_t Read(u8* data, std::size_t length, std::size_t offset = 0) const = 0;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -37,6 +40,10 @@ public:
|
||||
|
||||
std::size_t GetOffset() const;
|
||||
|
||||
bool HasDecryptedSections() const override {
|
||||
return file && file->HasDecryptedSections();
|
||||
}
|
||||
|
||||
private:
|
||||
std::size_t TrimToFit(std::size_t r_size, std::size_t r_offset) const;
|
||||
|
||||
|
||||
+1009
-1018
File diff suppressed because it is too large
Load Diff
@@ -14,6 +14,70 @@ namespace Service::Account {
|
||||
|
||||
class ProfileManager;
|
||||
|
||||
class Module final {
|
||||
public:
|
||||
class Interface : public ServiceFramework<Interface> {
|
||||
public:
|
||||
explicit Interface(std::shared_ptr<Module> module_,
|
||||
std::shared_ptr<ProfileManager> profile_manager_, Core::System& system_,
|
||||
const char* name);
|
||||
~Interface() override;
|
||||
|
||||
void GetUserCount(HLERequestContext& ctx);
|
||||
void GetUserExistence(HLERequestContext& ctx);
|
||||
void ListAllUsers(HLERequestContext& ctx);
|
||||
void ListOpenUsers(HLERequestContext& ctx);
|
||||
void GetLastOpenedUser(HLERequestContext& ctx);
|
||||
void GetProfile(HLERequestContext& ctx);
|
||||
void InitializeApplicationInfo(HLERequestContext& ctx);
|
||||
void InitializeApplicationInfoRestricted(HLERequestContext& ctx);
|
||||
void GetBaasAccountManagerForApplication(HLERequestContext& ctx);
|
||||
void IsUserRegistrationRequestPermitted(HLERequestContext& ctx);
|
||||
void TrySelectUserWithoutInteractionDeprecated(HLERequestContext& ctx);
|
||||
void TrySelectUserWithoutInteraction(HLERequestContext& ctx);
|
||||
void IsUserAccountSwitchLocked(HLERequestContext& ctx);
|
||||
void InitializeApplicationInfoV2(HLERequestContext& ctx);
|
||||
void BeginUserRegistration(HLERequestContext& ctx);
|
||||
void CompleteUserRegistration(HLERequestContext& ctx);
|
||||
void DeleteUser(HLERequestContext& ctx);
|
||||
void SetUserPosition(HLERequestContext& ctx);
|
||||
void GetProfileEditor(HLERequestContext& ctx);
|
||||
void GetBaasAccountAdministrator(HLERequestContext &ctx);
|
||||
void ListQualifiedUsers(HLERequestContext& ctx);
|
||||
void ListOpenContextStoredUsers(HLERequestContext& ctx);
|
||||
void StoreSaveDataThumbnailApplication(HLERequestContext& ctx);
|
||||
void GetBaasAccountManagerForSystemService(HLERequestContext& ctx);
|
||||
void StoreSaveDataThumbnailSystem(HLERequestContext& ctx);
|
||||
void GetPinCodeLength(HLERequestContext& ctx);
|
||||
|
||||
private:
|
||||
Result InitializeApplicationInfoBase();
|
||||
void StoreSaveDataThumbnail(HLERequestContext& ctx, const Common::UUID& uuid,
|
||||
const u64 tid);
|
||||
|
||||
enum class ApplicationType : u32_le {
|
||||
GameCard = 0,
|
||||
Digital = 1,
|
||||
Unknown = 3,
|
||||
};
|
||||
|
||||
struct ApplicationInfo {
|
||||
Service::Glue::ApplicationLaunchProperty launch_property;
|
||||
ApplicationType application_type;
|
||||
|
||||
constexpr explicit operator bool() const {
|
||||
return launch_property.title_id != 0x0;
|
||||
}
|
||||
};
|
||||
|
||||
ApplicationInfo application_info{};
|
||||
|
||||
protected:
|
||||
std::shared_ptr<Module> module;
|
||||
std::shared_ptr<ProfileManager> profile_manager;
|
||||
};
|
||||
};
|
||||
|
||||
void LoopProcess(Core::System& system);
|
||||
|
||||
} // namespace Service::Account
|
||||
|
||||
@@ -12,6 +12,17 @@
|
||||
namespace Service::Account {
|
||||
IAsyncContext::IAsyncContext(Core::System& system_)
|
||||
: ServiceFramework{system_, "IAsyncContext"}, service_context{system_, "IAsyncContext"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IAsyncContext::GetSystemEvent, "GetSystemEvent"},
|
||||
{1, &IAsyncContext::Cancel, "Cancel"},
|
||||
{2, &IAsyncContext::HasDone, "HasDone"},
|
||||
{3, &IAsyncContext::GetResult, "GetResult"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
|
||||
completion_event = service_context.CreateEvent("IAsyncContext:CompletionEvent");
|
||||
}
|
||||
|
||||
|
||||
@@ -33,16 +33,6 @@ protected:
|
||||
|
||||
void MarkComplete();
|
||||
|
||||
std::optional<FunctionInfoBase> FindRequest(u32 key) override {
|
||||
return HandlerTableGenerateWithFind(key, functions);
|
||||
}
|
||||
static constexpr auto functions = CreateStaticMap(
|
||||
FunctionInfo{0, &IAsyncContext::GetSystemEvent, "GetSystemEvent"},
|
||||
FunctionInfo{1, &IAsyncContext::Cancel, "Cancel"},
|
||||
FunctionInfo{2, &IAsyncContext::HasDone, "HasDone"},
|
||||
FunctionInfo{3, &IAsyncContext::GetResult, "GetResult"}
|
||||
);
|
||||
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
|
||||
std::atomic<bool> is_complete{false};
|
||||
|
||||
+8
-1330
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,135 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/am/applet_manager.h"
|
||||
#include "core/hle/service/am/service/all_system_applet_proxies_service.h"
|
||||
#include "core/hle/service/am/service/application_proxy.h"
|
||||
#include "core/hle/service/am/service/library_applet_proxy.h"
|
||||
#include "core/hle/service/am/service/system_applet_proxy.h"
|
||||
#include "core/hle/service/am/service/overlay_applet_proxy.h"
|
||||
#include "core/hle/service/am/window_system.h"
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& system_,
|
||||
WindowSystem& window_system)
|
||||
: ServiceFramework{system_, "appletAE"}, m_window_system{window_system} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{100, D<&IAllSystemAppletProxiesService::OpenSystemAppletProxy>, "OpenSystemAppletProxy"},
|
||||
{110, D<&IAllSystemAppletProxiesService::OpenSystemAppletProxy>, "OpenSystemAppletProxyEx"},
|
||||
{200, D<&IAllSystemAppletProxiesService::OpenLibraryAppletProxyOld>, "OpenLibraryAppletProxyOld"},
|
||||
{201, D<&IAllSystemAppletProxiesService::OpenLibraryAppletProxy>, "OpenLibraryAppletProxy"},
|
||||
{300, D<&IAllSystemAppletProxiesService::OpenOverlayAppletProxy>, "OpenOverlayAppletProxy"},
|
||||
{350, D<&IAllSystemAppletProxiesService::OpenSystemApplicationProxy>, "OpenSystemApplicationProxy"},
|
||||
{400, nullptr, "CreateSelfLibraryAppletCreatorForDevelop"},
|
||||
{410, nullptr, "GetSystemAppletControllerForDebug"},
|
||||
{450, D<&IAllSystemAppletProxiesService::GetSystemProcessCommonFunctions>, "GetSystemProcessCommonFunctions"}, // 19.0.0+
|
||||
{460, D<&IAllSystemAppletProxiesService::GetAppletAlternativeFunctions>, "GetAppletAlternativeFunctions"}, // 20.0.0+
|
||||
{1000, nullptr, "GetDebugFunctions"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IAllSystemAppletProxiesService::~IAllSystemAppletProxiesService() = default;
|
||||
|
||||
Result IAllSystemAppletProxiesService::OpenSystemAppletProxy(
|
||||
Out<SharedPointer<ISystemAppletProxy>> out_system_applet_proxy, ClientProcessId pid,
|
||||
InCopyHandle<Kernel::KProcess> process_handle) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
if (const auto applet = this->GetAppletFromProcessId(pid); applet) {
|
||||
*out_system_applet_proxy = std::make_shared<ISystemAppletProxy>(
|
||||
system, applet, process_handle.Get(), m_window_system);
|
||||
R_SUCCEED();
|
||||
} else {
|
||||
UNIMPLEMENTED();
|
||||
R_THROW(ResultUnknown);
|
||||
}
|
||||
}
|
||||
|
||||
Result IAllSystemAppletProxiesService::OpenLibraryAppletProxy(
|
||||
Out<SharedPointer<ILibraryAppletProxy>> out_library_applet_proxy, ClientProcessId pid,
|
||||
InCopyHandle<Kernel::KProcess> process_handle,
|
||||
InLargeData<AppletAttribute, BufferAttr_HipcMapAlias> attribute) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
if (const auto applet = this->GetAppletFromProcessId(pid); applet) {
|
||||
*out_library_applet_proxy = std::make_shared<ILibraryAppletProxy>(
|
||||
system, applet, process_handle.Get(), m_window_system);
|
||||
R_SUCCEED();
|
||||
} else {
|
||||
UNIMPLEMENTED();
|
||||
R_THROW(ResultUnknown);
|
||||
}
|
||||
}
|
||||
|
||||
Result IAllSystemAppletProxiesService::OpenOverlayAppletProxy(
|
||||
Out<SharedPointer<IOverlayAppletProxy>> out_overlay_applet_proxy, ClientProcessId pid,
|
||||
InCopyHandle<Kernel::KProcess> process_handle) {
|
||||
LOG_WARNING(Service_AM, "called");
|
||||
|
||||
if (const auto applet = this->GetAppletFromProcessId(pid); applet) {
|
||||
*out_overlay_applet_proxy = std::make_shared<IOverlayAppletProxy>(
|
||||
system, applet, process_handle.Get(), m_window_system);
|
||||
R_SUCCEED();
|
||||
} else {
|
||||
UNIMPLEMENTED();
|
||||
R_THROW(ResultUnknown);
|
||||
}
|
||||
}
|
||||
|
||||
Result IAllSystemAppletProxiesService::OpenSystemApplicationProxy(
|
||||
Out<SharedPointer<IApplicationProxy>> out_system_application_proxy, ClientProcessId pid,
|
||||
InCopyHandle<Kernel::KProcess> process_handle) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
if (const auto applet = this->GetAppletFromProcessId(pid); applet) {
|
||||
*out_system_application_proxy = std::make_shared<IApplicationProxy>(
|
||||
system, applet, process_handle.Get(), m_window_system);
|
||||
R_SUCCEED();
|
||||
} else {
|
||||
UNIMPLEMENTED();
|
||||
R_THROW(ResultUnknown);
|
||||
}
|
||||
}
|
||||
|
||||
Result IAllSystemAppletProxiesService::OpenLibraryAppletProxyOld(
|
||||
Out<SharedPointer<ILibraryAppletProxy>> out_library_applet_proxy, ClientProcessId pid,
|
||||
InCopyHandle<Kernel::KProcess> process_handle) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
AppletAttribute attribute{};
|
||||
R_RETURN(
|
||||
this->OpenLibraryAppletProxy(out_library_applet_proxy, pid, process_handle, attribute));
|
||||
}
|
||||
|
||||
Result IAllSystemAppletProxiesService::GetSystemProcessCommonFunctions() {
|
||||
LOG_DEBUG(Service_AM, "(STUBBED) called.");
|
||||
|
||||
// TODO (jarrodnorwell)
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IAllSystemAppletProxiesService::GetAppletAlternativeFunctions() {
|
||||
LOG_DEBUG(Service_AM, "(STUBBED) called.");
|
||||
|
||||
// TODO (maufeat)
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
std::shared_ptr<Applet> IAllSystemAppletProxiesService::GetAppletFromProcessId(
|
||||
ProcessId process_id) {
|
||||
return m_window_system.GetByAppletResourceUserId(process_id.pid);
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
@@ -0,0 +1,56 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/cmif_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/am/service/overlay_applet_proxy.h"
|
||||
|
||||
namespace Service {
|
||||
|
||||
namespace AM {
|
||||
|
||||
struct Applet;
|
||||
struct AppletAttribute;
|
||||
class IApplicationProxy;
|
||||
class ILibraryAppletProxy;
|
||||
class ISystemAppletProxy;
|
||||
class WindowSystem;
|
||||
|
||||
class IAllSystemAppletProxiesService final
|
||||
: public ServiceFramework<IAllSystemAppletProxiesService> {
|
||||
public:
|
||||
explicit IAllSystemAppletProxiesService(Core::System& system_, WindowSystem& window_system);
|
||||
~IAllSystemAppletProxiesService() override;
|
||||
|
||||
private:
|
||||
Result OpenSystemAppletProxy(Out<SharedPointer<ISystemAppletProxy>> out_system_applet_proxy,
|
||||
ClientProcessId pid,
|
||||
InCopyHandle<Kernel::KProcess> process_handle);
|
||||
Result OpenLibraryAppletProxy(Out<SharedPointer<ILibraryAppletProxy>> out_library_applet_proxy,
|
||||
ClientProcessId pid,
|
||||
InCopyHandle<Kernel::KProcess> process_handle,
|
||||
InLargeData<AppletAttribute, BufferAttr_HipcMapAlias> attribute);
|
||||
Result OpenOverlayAppletProxy(Out<SharedPointer<IOverlayAppletProxy>> out_overlay_applet_proxy,
|
||||
ClientProcessId pid, InCopyHandle<Kernel::KProcess> process_handle);
|
||||
Result OpenLibraryAppletProxyOld(
|
||||
Out<SharedPointer<ILibraryAppletProxy>> out_library_applet_proxy, ClientProcessId pid,
|
||||
InCopyHandle<Kernel::KProcess> process_handle);
|
||||
Result OpenSystemApplicationProxy(
|
||||
Out<SharedPointer<IApplicationProxy>> out_system_application_proxy, ClientProcessId pid,
|
||||
InCopyHandle<Kernel::KProcess> process_handle);
|
||||
Result GetSystemProcessCommonFunctions();
|
||||
Result GetAppletAlternativeFunctions();
|
||||
|
||||
private:
|
||||
std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid);
|
||||
|
||||
WindowSystem& m_window_system;
|
||||
};
|
||||
|
||||
} // namespace AM
|
||||
} // namespace Service
|
||||
@@ -0,0 +1,98 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/common_funcs.h"
|
||||
#include "core/hle/service/am/applet.h"
|
||||
#include "core/hle/service/am/service/applet_common_functions.h"
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_,
|
||||
std::shared_ptr<Applet> applet_)
|
||||
: ServiceFramework{system_, "IAppletCommonFunctions"}, applet{std::move(applet_)} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "SetTerminateResult"},
|
||||
{10, nullptr, "ReadThemeStorage"},
|
||||
{11, nullptr, "WriteThemeStorage"},
|
||||
{20, nullptr, "PushToAppletBoundChannel"},
|
||||
{21, nullptr, "TryPopFromAppletBoundChannel"},
|
||||
{40, nullptr, "GetDisplayLogicalResolution"},
|
||||
{42, D<&IAppletCommonFunctions::SetDisplayMagnification>, "SetDisplayMagnification"},
|
||||
{50, D<&IAppletCommonFunctions::SetHomeButtonDoubleClickEnabled>, "SetHomeButtonDoubleClickEnabled"},
|
||||
{51, D<&IAppletCommonFunctions::GetHomeButtonDoubleClickEnabled>, "GetHomeButtonDoubleClickEnabled"},
|
||||
{52, nullptr, "IsHomeButtonShortPressedBlocked"},
|
||||
{60, nullptr, "IsVrModeCurtainRequired"},
|
||||
{61, nullptr, "IsSleepRequiredByHighTemperature"},
|
||||
{62, nullptr, "IsSleepRequiredByLowBattery"},
|
||||
{70, D<&IAppletCommonFunctions::SetCpuBoostRequestPriority>, "SetCpuBoostRequestPriority"},
|
||||
{80, nullptr, "SetHandlingCaptureButtonShortPressedMessageEnabledForApplet"},
|
||||
{81, nullptr, "SetHandlingCaptureButtonLongPressedMessageEnabledForApplet"},
|
||||
{90, nullptr, "OpenNamedChannelAsParent"},
|
||||
{91, nullptr, "OpenNamedChannelAsChild"},
|
||||
{100, nullptr, "SetApplicationCoreUsageMode"},
|
||||
{300, D<&IAppletCommonFunctions::GetCurrentApplicationId>, "GetCurrentApplicationId"},
|
||||
{310, nullptr, "IsSystemAppletHomeMenu"}, //19.0.0+
|
||||
{320, D<&IAppletCommonFunctions::SetGpuTimeSliceBoost>, "SetGpuTimeSliceBoost"}, //19.0.0+
|
||||
{321, nullptr, "SetGpuTimeSliceBoostDueToApplication"}, //19.0.0+
|
||||
{350, D<&IAppletCommonFunctions::Unknown350>, "Unknown350"} //20.0.0+
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IAppletCommonFunctions::~IAppletCommonFunctions() = default;
|
||||
|
||||
Result IAppletCommonFunctions::SetHomeButtonDoubleClickEnabled(
|
||||
bool home_button_double_click_enabled) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, home_button_double_click_enabled={}",
|
||||
home_button_double_click_enabled);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IAppletCommonFunctions::GetHomeButtonDoubleClickEnabled(
|
||||
Out<bool> out_home_button_double_click_enabled) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
*out_home_button_double_click_enabled = false;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IAppletCommonFunctions::SetDisplayMagnification(f32 x, f32 y, f32 width, f32 height) {
|
||||
LOG_DEBUG(Service_AM, "(STUBBED) called, x={}, y={}, width={}, height={}", x, y, width,
|
||||
height);
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->display_magnification = Common::Rectangle<f32>{x, y, x + width, y + height};
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IAppletCommonFunctions::SetCpuBoostRequestPriority(s32 priority) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
std::scoped_lock lk{applet->lock};
|
||||
applet->cpu_boost_request_priority = priority;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IAppletCommonFunctions::GetCurrentApplicationId(Out<u64> out_application_id) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
*out_application_id = FileSys::GetBaseTitleID(system.GetApplicationProcessProgramID());
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IAppletCommonFunctions::SetGpuTimeSliceBoost(s64 time_span) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, time_span={}", time_span);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IAppletCommonFunctions::Unknown350(Out<u16> out_unknown) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
*out_unknown = 0;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
@@ -0,0 +1,33 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/cmif_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
struct Applet;
|
||||
|
||||
class IAppletCommonFunctions final : public ServiceFramework<IAppletCommonFunctions> {
|
||||
public:
|
||||
explicit IAppletCommonFunctions(Core::System& system_, std::shared_ptr<Applet> applet_);
|
||||
~IAppletCommonFunctions() override;
|
||||
|
||||
private:
|
||||
Result SetHomeButtonDoubleClickEnabled(bool home_button_double_click_enabled);
|
||||
Result GetHomeButtonDoubleClickEnabled(Out<bool> out_home_button_double_click_enabled);
|
||||
Result SetDisplayMagnification(f32 x, f32 y, f32 width, f32 height);
|
||||
Result SetCpuBoostRequestPriority(s32 priority);
|
||||
Result GetCurrentApplicationId(Out<u64> out_application_id);
|
||||
Result SetGpuTimeSliceBoost(s64 time_span);
|
||||
Result Unknown350(Out<u16> out_unknown);
|
||||
|
||||
const std::shared_ptr<Applet> applet;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
||||
@@ -18,42 +18,42 @@
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
std::optional<ServiceFrameworkBase::FunctionInfoBase> IApplicationAccessor::FindRequest(u32 key) {
|
||||
static constexpr auto functions = CreateStaticMap(
|
||||
FunctionInfo{0, D<&IApplicationAccessor::GetAppletStateChangedEvent>, "GetAppletStateChangedEvent"},
|
||||
FunctionInfo{1, nullptr, "IsCompleted"},
|
||||
FunctionInfo{10, D<&IApplicationAccessor::Start>, "Start"},
|
||||
FunctionInfo{20, D<&IApplicationAccessor::RequestExit>, "RequestExit"},
|
||||
FunctionInfo{25, D<&IApplicationAccessor::Terminate>, "Terminate"},
|
||||
FunctionInfo{30, D<&IApplicationAccessor::GetResult>, "GetResult"},
|
||||
FunctionInfo{101, D<&IApplicationAccessor::RequestForApplicationToGetForeground>, "RequestForApplicationToGetForeground"},
|
||||
FunctionInfo{110, nullptr, "TerminateAllLibraryApplets"},
|
||||
FunctionInfo{111, nullptr, "AreAnyLibraryAppletsLeft"},
|
||||
FunctionInfo{112, D<&IApplicationAccessor::GetCurrentLibraryApplet>, "GetCurrentLibraryApplet"},
|
||||
FunctionInfo{120, nullptr, "GetApplicationId"},
|
||||
FunctionInfo{121, D<&IApplicationAccessor::PushLaunchParameter>, "PushLaunchParameter"},
|
||||
FunctionInfo{122, D<&IApplicationAccessor::GetApplicationControlProperty>, "GetApplicationControlProperty"},
|
||||
FunctionInfo{123, nullptr, "GetApplicationLaunchProperty"},
|
||||
FunctionInfo{124, nullptr, "GetApplicationLaunchRequestInfo"},
|
||||
FunctionInfo{130, D<&IApplicationAccessor::SetUsers>, "SetUsers"},
|
||||
FunctionInfo{131, D<&IApplicationAccessor::CheckRightsEnvironmentAvailable>, "CheckRightsEnvironmentAvailable"},
|
||||
FunctionInfo{132, D<&IApplicationAccessor::GetNsRightsEnvironmentHandle>, "GetNsRightsEnvironmentHandle"},
|
||||
FunctionInfo{140, nullptr, "GetDesirableUids"},
|
||||
FunctionInfo{150, D<&IApplicationAccessor::ReportApplicationExitTimeout>, "ReportApplicationExitTimeout"},
|
||||
FunctionInfo{160, nullptr, "SetApplicationAttribute"},
|
||||
FunctionInfo{170, nullptr, "HasSaveDataAccessPermission"},
|
||||
FunctionInfo{180, nullptr, "PushToFriendInvitationStorageChannel"},
|
||||
FunctionInfo{190, nullptr, "PushToNotificationStorageChannel"},
|
||||
FunctionInfo{200, nullptr, "RequestApplicationSoftReset"},
|
||||
FunctionInfo{201, nullptr, "RestartApplicationTimer"}
|
||||
);
|
||||
return HandlerTableGenerateWithFind(key, functions);
|
||||
}
|
||||
|
||||
IApplicationAccessor::IApplicationAccessor(Core::System& system_, std::shared_ptr<Applet> applet,
|
||||
WindowSystem& window_system)
|
||||
: ServiceFramework{system_, "IApplicationAccessor"}, m_window_system(window_system),
|
||||
m_applet(std::move(applet)) {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&IApplicationAccessor::GetAppletStateChangedEvent>, "GetAppletStateChangedEvent"},
|
||||
{1, nullptr, "IsCompleted"},
|
||||
{10, D<&IApplicationAccessor::Start>, "Start"},
|
||||
{20, D<&IApplicationAccessor::RequestExit>, "RequestExit"},
|
||||
{25, D<&IApplicationAccessor::Terminate>, "Terminate"},
|
||||
{30, D<&IApplicationAccessor::GetResult>, "GetResult"},
|
||||
{101, D<&IApplicationAccessor::RequestForApplicationToGetForeground>, "RequestForApplicationToGetForeground"},
|
||||
{110, nullptr, "TerminateAllLibraryApplets"},
|
||||
{111, nullptr, "AreAnyLibraryAppletsLeft"},
|
||||
{112, D<&IApplicationAccessor::GetCurrentLibraryApplet>, "GetCurrentLibraryApplet"},
|
||||
{120, nullptr, "GetApplicationId"},
|
||||
{121, D<&IApplicationAccessor::PushLaunchParameter>, "PushLaunchParameter"},
|
||||
{122, D<&IApplicationAccessor::GetApplicationControlProperty>, "GetApplicationControlProperty"},
|
||||
{123, nullptr, "GetApplicationLaunchProperty"},
|
||||
{124, nullptr, "GetApplicationLaunchRequestInfo"},
|
||||
{130, D<&IApplicationAccessor::SetUsers>, "SetUsers"},
|
||||
{131, D<&IApplicationAccessor::CheckRightsEnvironmentAvailable>, "CheckRightsEnvironmentAvailable"},
|
||||
{132, D<&IApplicationAccessor::GetNsRightsEnvironmentHandle>, "GetNsRightsEnvironmentHandle"},
|
||||
{140, nullptr, "GetDesirableUids"},
|
||||
{150, D<&IApplicationAccessor::ReportApplicationExitTimeout>, "ReportApplicationExitTimeout"},
|
||||
{160, nullptr, "SetApplicationAttribute"},
|
||||
{170, nullptr, "HasSaveDataAccessPermission"},
|
||||
{180, nullptr, "PushToFriendInvitationStorageChannel"},
|
||||
{190, nullptr, "PushToNotificationStorageChannel"},
|
||||
{200, nullptr, "RequestApplicationSoftReset"},
|
||||
{201, nullptr, "RestartApplicationTimer"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IApplicationAccessor::~IApplicationAccessor() = default;
|
||||
|
||||
@@ -39,7 +39,6 @@ private:
|
||||
Result GetNsRightsEnvironmentHandle(Out<u64> out_handle);
|
||||
Result ReportApplicationExitTimeout();
|
||||
|
||||
std::optional<FunctionInfoBase> FindRequest(u32 key) override;
|
||||
WindowSystem& m_window_system;
|
||||
const std::shared_ptr<Applet> m_applet;
|
||||
};
|
||||
|
||||
@@ -20,16 +20,6 @@
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
std::optional<ServiceFrameworkBase::FunctionInfoBase> IApplicationCreator::FindRequest(u32 key) {
|
||||
static constexpr auto functions = CreateStaticMap(
|
||||
FunctionInfo{0, D<&IApplicationCreator::CreateApplication>, "CreateApplication"},
|
||||
FunctionInfo{1, nullptr, "PopLaunchRequestedApplication"},
|
||||
FunctionInfo{10, D<&IApplicationCreator::CreateSystemApplication>, "CreateSystemApplication"},
|
||||
FunctionInfo{100, nullptr, "PopFloatingApplicationForDevelopment"}
|
||||
);
|
||||
return HandlerTableGenerateWithFind(key, functions);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
Result CreateGuestApplication(SharedPointer<IApplicationAccessor>* out_application_accessor, Core::System& system, WindowSystem& window_system, u64 program_id) {
|
||||
@@ -64,6 +54,16 @@ Result CreateGuestApplication(SharedPointer<IApplicationAccessor>* out_applicati
|
||||
|
||||
IApplicationCreator::IApplicationCreator(Core::System& system_, WindowSystem& window_system)
|
||||
: ServiceFramework{system_, "IApplicationCreator"}, m_window_system{window_system} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&IApplicationCreator::CreateApplication>, "CreateApplication"},
|
||||
{1, nullptr, "PopLaunchRequestedApplication"},
|
||||
{10, D<&IApplicationCreator::CreateSystemApplication>, "CreateSystemApplication"},
|
||||
{100, nullptr, "PopFloatingApplicationForDevelopment"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IApplicationCreator::~IApplicationCreator() = default;
|
||||
|
||||
@@ -24,7 +24,6 @@ private:
|
||||
Result CreateApplication(Out<SharedPointer<IApplicationAccessor>>, u64 application_id);
|
||||
Result CreateSystemApplication(Out<SharedPointer<IApplicationAccessor>>, u64 application_id);
|
||||
|
||||
std::optional<FunctionInfoBase> FindRequest(u32 key) override;
|
||||
WindowSystem& m_window_system;
|
||||
};
|
||||
|
||||
|
||||
@@ -51,84 +51,83 @@ FileSys::PatchManager::Metadata GetApplicationMetadata(Core::System& system, u64
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
std::optional<ServiceFrameworkBase::FunctionInfoBase> IApplicationFunctions::FindRequest(u32 key) {
|
||||
static constexpr auto functions = CreateStaticMap(
|
||||
FunctionInfo{1, D<&IApplicationFunctions::PopLaunchParameter>, "PopLaunchParameter"},
|
||||
FunctionInfo{10, nullptr, "CreateApplicationAndPushAndRequestToStart"},
|
||||
FunctionInfo{11, nullptr, "CreateApplicationAndPushAndRequestToStartForQuest"},
|
||||
FunctionInfo{12, D<&IApplicationFunctions::CreateApplicationAndRequestToStart>, "CreateApplicationAndRequestToStart"},
|
||||
FunctionInfo{13, nullptr, "CreateApplicationAndRequestToStartForQuest"},
|
||||
FunctionInfo{14, nullptr, "CreateApplicationWithAttributeAndPushAndRequestToStartForQuest"},
|
||||
FunctionInfo{15, nullptr, "CreateApplicationWithAttributeAndRequestToStartForQuest"},
|
||||
FunctionInfo{20, D<&IApplicationFunctions::EnsureSaveData>, "EnsureSaveData"},
|
||||
FunctionInfo{21, D<&IApplicationFunctions::GetDesiredLanguage>, "GetDesiredLanguage"},
|
||||
FunctionInfo{22, D<&IApplicationFunctions::SetTerminateResult>, "SetTerminateResult"},
|
||||
FunctionInfo{23, D<&IApplicationFunctions::GetDisplayVersion>, "GetDisplayVersion"},
|
||||
FunctionInfo{24, nullptr, "GetLaunchStorageInfoForDebug"},
|
||||
FunctionInfo{25, D<&IApplicationFunctions::ExtendSaveData>, "ExtendSaveData"},
|
||||
FunctionInfo{26, D<&IApplicationFunctions::GetSaveDataSize>, "GetSaveDataSize"},
|
||||
FunctionInfo{27, D<&IApplicationFunctions::CreateCacheStorage>, "CreateCacheStorage"},
|
||||
FunctionInfo{28, D<&IApplicationFunctions::GetSaveDataSizeMax>, "GetSaveDataSizeMax"},
|
||||
FunctionInfo{29, D<&IApplicationFunctions::GetCacheStorageMax>, "GetCacheStorageMax"},
|
||||
FunctionInfo{30, D<&IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed>, "BeginBlockingHomeButtonShortAndLongPressed"},
|
||||
FunctionInfo{31, D<&IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed>, "EndBlockingHomeButtonShortAndLongPressed"},
|
||||
FunctionInfo{32, D<&IApplicationFunctions::BeginBlockingHomeButton>, "BeginBlockingHomeButton"},
|
||||
FunctionInfo{33, D<&IApplicationFunctions::EndBlockingHomeButton>, "EndBlockingHomeButton"},
|
||||
FunctionInfo{34, nullptr, "SelectApplicationLicense"},
|
||||
FunctionInfo{35, nullptr, "GetDeviceSaveDataSizeMax"},
|
||||
FunctionInfo{36, nullptr, "GetLimitedApplicationLicense"},
|
||||
FunctionInfo{37, nullptr, "GetLimitedApplicationLicenseUpgradableEvent"},
|
||||
FunctionInfo{40, D<&IApplicationFunctions::NotifyRunning>, "NotifyRunning"},
|
||||
FunctionInfo{50, D<&IApplicationFunctions::GetPseudoDeviceId>, "GetPseudoDeviceId"},
|
||||
FunctionInfo{60, D<&IApplicationFunctions::SetMediaPlaybackStateForApplication>, "SetMediaPlaybackStateForApplication"},
|
||||
FunctionInfo{65, D<&IApplicationFunctions::IsGamePlayRecordingSupported>, "IsGamePlayRecordingSupported"},
|
||||
FunctionInfo{66, D<&IApplicationFunctions::InitializeGamePlayRecording>, "InitializeGamePlayRecording"},
|
||||
FunctionInfo{67, D<&IApplicationFunctions::SetGamePlayRecordingState>, "SetGamePlayRecordingState"},
|
||||
FunctionInfo{68, nullptr, "RequestFlushGamePlayingMovieForDebug"},
|
||||
FunctionInfo{70, nullptr, "RequestToShutdown"},
|
||||
FunctionInfo{71, nullptr, "RequestToReboot"},
|
||||
FunctionInfo{72, nullptr, "RequestToSleep"},
|
||||
FunctionInfo{80, nullptr, "ExitAndRequestToShowThanksMessage"},
|
||||
FunctionInfo{90, D<&IApplicationFunctions::EnableApplicationCrashReport>, "EnableApplicationCrashReport"},
|
||||
FunctionInfo{100, D<&IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer>, "InitializeApplicationCopyrightFrameBuffer"},
|
||||
FunctionInfo{101, D<&IApplicationFunctions::SetApplicationCopyrightImage>, "SetApplicationCopyrightImage"},
|
||||
FunctionInfo{102, D<&IApplicationFunctions::SetApplicationCopyrightVisibility>, "SetApplicationCopyrightVisibility"},
|
||||
FunctionInfo{110, D<&IApplicationFunctions::QueryApplicationPlayStatistics>, "QueryApplicationPlayStatistics"},
|
||||
FunctionInfo{111, D<&IApplicationFunctions::QueryApplicationPlayStatisticsByUid>, "QueryApplicationPlayStatisticsByUid"},
|
||||
FunctionInfo{120, D<&IApplicationFunctions::ExecuteProgram>, "ExecuteProgram"},
|
||||
FunctionInfo{121, D<&IApplicationFunctions::ClearUserChannel>, "ClearUserChannel"},
|
||||
FunctionInfo{122, D<&IApplicationFunctions::UnpopToUserChannel>, "UnpopToUserChannel"},
|
||||
FunctionInfo{123, D<&IApplicationFunctions::GetPreviousProgramIndex>, "GetPreviousProgramIndex"},
|
||||
FunctionInfo{124, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
|
||||
FunctionInfo{130, D<&IApplicationFunctions::GetGpuErrorDetectedSystemEvent>, "GetGpuErrorDetectedSystemEvent"},
|
||||
FunctionInfo{131, nullptr, "SetDelayTimeToAbortOnGpuError"},
|
||||
FunctionInfo{140, D<&IApplicationFunctions::GetFriendInvitationStorageChannelEvent>, "GetFriendInvitationStorageChannelEvent"},
|
||||
FunctionInfo{141, D<&IApplicationFunctions::TryPopFromFriendInvitationStorageChannel>, "TryPopFromFriendInvitationStorageChannel"},
|
||||
FunctionInfo{150, D<&IApplicationFunctions::GetNotificationStorageChannelEvent>, "GetNotificationStorageChannelEvent"},
|
||||
FunctionInfo{151, nullptr, "TryPopFromNotificationStorageChannel"},
|
||||
FunctionInfo{160, D<&IApplicationFunctions::GetHealthWarningDisappearedSystemEvent>, "GetHealthWarningDisappearedSystemEvent"},
|
||||
FunctionInfo{170, nullptr, "SetHdcpAuthenticationActivated"},
|
||||
FunctionInfo{180, nullptr, "GetLaunchRequiredVersion"},
|
||||
FunctionInfo{181, nullptr, "UpgradeLaunchRequiredVersion"},
|
||||
FunctionInfo{190, nullptr, "SendServerMaintenanceOverlayNotification"},
|
||||
FunctionInfo{200, nullptr, "GetLastApplicationExitReason"},
|
||||
FunctionInfo{210, D<&IApplicationFunctions::GetUnknownEvent210>, "Unknown210"},
|
||||
FunctionInfo{220, nullptr, "Unknown220"}, // [20.0.0+]
|
||||
FunctionInfo{300, nullptr, "CreateMovieWriter"}, // [19.0.0+]
|
||||
FunctionInfo{310, nullptr, "Unknown310"}, // [20.0.0+]
|
||||
FunctionInfo{320, nullptr, "Unknown320"}, // [20.0.0+]
|
||||
FunctionInfo{330, D<&IApplicationFunctions::Unknown330>, "Unknown330"}, // [20.0.0+]
|
||||
FunctionInfo{500, nullptr, "StartContinuousRecordingFlushForDebug"},
|
||||
FunctionInfo{1000, nullptr, "CreateMovieMaker"},
|
||||
FunctionInfo{1001, D<&IApplicationFunctions::PrepareForJit>, "PrepareForJit"}
|
||||
);
|
||||
return HandlerTableGenerateWithFind(key, functions);
|
||||
}
|
||||
|
||||
IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet)
|
||||
: ServiceFramework{system_, "IApplicationFunctions"}
|
||||
, m_applet{std::move(applet)}
|
||||
{}
|
||||
: ServiceFramework{system_, "IApplicationFunctions"}, m_applet{std::move(applet)} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{1, D<&IApplicationFunctions::PopLaunchParameter>, "PopLaunchParameter"},
|
||||
{10, nullptr, "CreateApplicationAndPushAndRequestToStart"},
|
||||
{11, nullptr, "CreateApplicationAndPushAndRequestToStartForQuest"},
|
||||
{12, D<&IApplicationFunctions::CreateApplicationAndRequestToStart>, "CreateApplicationAndRequestToStart"},
|
||||
{13, nullptr, "CreateApplicationAndRequestToStartForQuest"},
|
||||
{14, nullptr, "CreateApplicationWithAttributeAndPushAndRequestToStartForQuest"},
|
||||
{15, nullptr, "CreateApplicationWithAttributeAndRequestToStartForQuest"},
|
||||
{20, D<&IApplicationFunctions::EnsureSaveData>, "EnsureSaveData"},
|
||||
{21, D<&IApplicationFunctions::GetDesiredLanguage>, "GetDesiredLanguage"},
|
||||
{22, D<&IApplicationFunctions::SetTerminateResult>, "SetTerminateResult"},
|
||||
{23, D<&IApplicationFunctions::GetDisplayVersion>, "GetDisplayVersion"},
|
||||
{24, nullptr, "GetLaunchStorageInfoForDebug"},
|
||||
{25, D<&IApplicationFunctions::ExtendSaveData>, "ExtendSaveData"},
|
||||
{26, D<&IApplicationFunctions::GetSaveDataSize>, "GetSaveDataSize"},
|
||||
{27, D<&IApplicationFunctions::CreateCacheStorage>, "CreateCacheStorage"},
|
||||
{28, D<&IApplicationFunctions::GetSaveDataSizeMax>, "GetSaveDataSizeMax"},
|
||||
{29, D<&IApplicationFunctions::GetCacheStorageMax>, "GetCacheStorageMax"},
|
||||
{30, D<&IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed>, "BeginBlockingHomeButtonShortAndLongPressed"},
|
||||
{31, D<&IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed>, "EndBlockingHomeButtonShortAndLongPressed"},
|
||||
{32, D<&IApplicationFunctions::BeginBlockingHomeButton>, "BeginBlockingHomeButton"},
|
||||
{33, D<&IApplicationFunctions::EndBlockingHomeButton>, "EndBlockingHomeButton"},
|
||||
{34, nullptr, "SelectApplicationLicense"},
|
||||
{35, nullptr, "GetDeviceSaveDataSizeMax"},
|
||||
{36, nullptr, "GetLimitedApplicationLicense"},
|
||||
{37, nullptr, "GetLimitedApplicationLicenseUpgradableEvent"},
|
||||
{40, D<&IApplicationFunctions::NotifyRunning>, "NotifyRunning"},
|
||||
{50, D<&IApplicationFunctions::GetPseudoDeviceId>, "GetPseudoDeviceId"},
|
||||
{60, D<&IApplicationFunctions::SetMediaPlaybackStateForApplication>, "SetMediaPlaybackStateForApplication"},
|
||||
{65, D<&IApplicationFunctions::IsGamePlayRecordingSupported>, "IsGamePlayRecordingSupported"},
|
||||
{66, D<&IApplicationFunctions::InitializeGamePlayRecording>, "InitializeGamePlayRecording"},
|
||||
{67, D<&IApplicationFunctions::SetGamePlayRecordingState>, "SetGamePlayRecordingState"},
|
||||
{68, nullptr, "RequestFlushGamePlayingMovieForDebug"},
|
||||
{70, nullptr, "RequestToShutdown"},
|
||||
{71, nullptr, "RequestToReboot"},
|
||||
{72, nullptr, "RequestToSleep"},
|
||||
{80, nullptr, "ExitAndRequestToShowThanksMessage"},
|
||||
{90, D<&IApplicationFunctions::EnableApplicationCrashReport>, "EnableApplicationCrashReport"},
|
||||
{100, D<&IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer>, "InitializeApplicationCopyrightFrameBuffer"},
|
||||
{101, D<&IApplicationFunctions::SetApplicationCopyrightImage>, "SetApplicationCopyrightImage"},
|
||||
{102, D<&IApplicationFunctions::SetApplicationCopyrightVisibility>, "SetApplicationCopyrightVisibility"},
|
||||
{110, D<&IApplicationFunctions::QueryApplicationPlayStatistics>, "QueryApplicationPlayStatistics"},
|
||||
{111, D<&IApplicationFunctions::QueryApplicationPlayStatisticsByUid>, "QueryApplicationPlayStatisticsByUid"},
|
||||
{120, D<&IApplicationFunctions::ExecuteProgram>, "ExecuteProgram"},
|
||||
{121, D<&IApplicationFunctions::ClearUserChannel>, "ClearUserChannel"},
|
||||
{122, D<&IApplicationFunctions::UnpopToUserChannel>, "UnpopToUserChannel"},
|
||||
{123, D<&IApplicationFunctions::GetPreviousProgramIndex>, "GetPreviousProgramIndex"},
|
||||
{124, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
|
||||
{130, D<&IApplicationFunctions::GetGpuErrorDetectedSystemEvent>, "GetGpuErrorDetectedSystemEvent"},
|
||||
{131, nullptr, "SetDelayTimeToAbortOnGpuError"},
|
||||
{140, D<&IApplicationFunctions::GetFriendInvitationStorageChannelEvent>, "GetFriendInvitationStorageChannelEvent"},
|
||||
{141, D<&IApplicationFunctions::TryPopFromFriendInvitationStorageChannel>, "TryPopFromFriendInvitationStorageChannel"},
|
||||
{150, D<&IApplicationFunctions::GetNotificationStorageChannelEvent>, "GetNotificationStorageChannelEvent"},
|
||||
{151, nullptr, "TryPopFromNotificationStorageChannel"},
|
||||
{160, D<&IApplicationFunctions::GetHealthWarningDisappearedSystemEvent>, "GetHealthWarningDisappearedSystemEvent"},
|
||||
{170, nullptr, "SetHdcpAuthenticationActivated"},
|
||||
{180, nullptr, "GetLaunchRequiredVersion"},
|
||||
{181, nullptr, "UpgradeLaunchRequiredVersion"},
|
||||
{190, nullptr, "SendServerMaintenanceOverlayNotification"},
|
||||
{200, nullptr, "GetLastApplicationExitReason"},
|
||||
{210, D<&IApplicationFunctions::GetUnknownEvent210>, "Unknown210"},
|
||||
{220, nullptr, "Unknown220"}, // [20.0.0+]
|
||||
{300, nullptr, "CreateMovieWriter"}, // [19.0.0+]
|
||||
{310, nullptr, "Unknown310"}, // [20.0.0+]
|
||||
{320, nullptr, "Unknown320"}, // [20.0.0+]
|
||||
{330, D<&IApplicationFunctions::Unknown330>, "Unknown330"}, // [20.0.0+]
|
||||
{500, nullptr, "StartContinuousRecordingFlushForDebug"},
|
||||
{1000, nullptr, "CreateMovieMaker"},
|
||||
{1001, D<&IApplicationFunctions::PrepareForJit>, "PrepareForJit"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IApplicationFunctions::~IApplicationFunctions() = default;
|
||||
|
||||
|
||||
@@ -84,7 +84,6 @@ private:
|
||||
Result GetUnknownEvent210(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result Unknown330(Out<u8> out);
|
||||
Result PrepareForJit();
|
||||
std::optional<FunctionInfoBase> FindRequest(u32 key) override;
|
||||
|
||||
const std::shared_ptr<Applet> m_applet;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/am/service/applet_common_functions.h"
|
||||
#include "core/hle/service/am/service/application_functions.h"
|
||||
#include "core/hle/service/am/service/application_proxy.h"
|
||||
#include "core/hle/service/am/service/audio_controller.h"
|
||||
#include "core/hle/service/am/service/common_state_getter.h"
|
||||
#include "core/hle/service/am/service/debug_functions.h"
|
||||
#include "core/hle/service/am/service/display_controller.h"
|
||||
#include "core/hle/service/am/service/library_applet_creator.h"
|
||||
#include "core/hle/service/am/service/process_winding_controller.h"
|
||||
#include "core/hle/service/am/service/self_controller.h"
|
||||
#include "core/hle/service/am/service/window_controller.h"
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
IApplicationProxy::IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet,
|
||||
Kernel::KProcess* process, WindowSystem& window_system)
|
||||
: ServiceFramework{system_, "IApplicationProxy"},
|
||||
m_window_system{window_system}, m_process{process}, m_applet{std::move(applet)} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&IApplicationProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
|
||||
{1, D<&IApplicationProxy::GetSelfController>, "GetSelfController"},
|
||||
{2, D<&IApplicationProxy::GetWindowController>, "GetWindowController"},
|
||||
{3, D<&IApplicationProxy::GetAudioController>, "GetAudioController"},
|
||||
{4, D<&IApplicationProxy::GetDisplayController>, "GetDisplayController"},
|
||||
{10, D<&IApplicationProxy::GetProcessWindingController>, "GetProcessWindingController"},
|
||||
{11, D<&IApplicationProxy::GetLibraryAppletCreator>, "GetLibraryAppletCreator"},
|
||||
{20, D<&IApplicationProxy::GetApplicationFunctions>, "GetApplicationFunctions"},
|
||||
{1000, D<&IApplicationProxy::GetDebugFunctions>, "GetDebugFunctions"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IApplicationProxy::~IApplicationProxy() = default;
|
||||
|
||||
Result IApplicationProxy::GetAudioController(
|
||||
Out<SharedPointer<IAudioController>> out_audio_controller) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_audio_controller = std::make_shared<IAudioController>(system);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationProxy::GetDisplayController(
|
||||
Out<SharedPointer<IDisplayController>> out_display_controller) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_display_controller = std::make_shared<IDisplayController>(system, m_applet);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationProxy::GetProcessWindingController(
|
||||
Out<SharedPointer<IProcessWindingController>> out_process_winding_controller) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_process_winding_controller = std::make_shared<IProcessWindingController>(system, m_applet);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationProxy::GetDebugFunctions(
|
||||
Out<SharedPointer<IDebugFunctions>> out_debug_functions) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_debug_functions = std::make_shared<IDebugFunctions>(system);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationProxy::GetWindowController(
|
||||
Out<SharedPointer<IWindowController>> out_window_controller) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_window_controller = std::make_shared<IWindowController>(system, m_applet, m_window_system);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationProxy::GetSelfController(
|
||||
Out<SharedPointer<ISelfController>> out_self_controller) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_self_controller = std::make_shared<ISelfController>(system, m_applet, m_process);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationProxy::GetCommonStateGetter(
|
||||
Out<SharedPointer<ICommonStateGetter>> out_common_state_getter) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_common_state_getter = std::make_shared<ICommonStateGetter>(system, m_applet);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationProxy::GetLibraryAppletCreator(
|
||||
Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_library_applet_creator =
|
||||
std::make_shared<ILibraryAppletCreator>(system, m_applet, m_window_system);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IApplicationProxy::GetApplicationFunctions(
|
||||
Out<SharedPointer<IApplicationFunctions>> out_application_functions) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_application_functions = std::make_shared<IApplicationFunctions>(system, m_applet);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
@@ -0,0 +1,52 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/cmif_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
struct Applet;
|
||||
class IAudioController;
|
||||
class IApplicationFunctions;
|
||||
class ICommonStateGetter;
|
||||
class IDebugFunctions;
|
||||
class IDisplayController;
|
||||
class ILibraryAppletCreator;
|
||||
class IProcessWindingController;
|
||||
class ISelfController;
|
||||
class IWindowController;
|
||||
class WindowSystem;
|
||||
|
||||
class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
|
||||
public:
|
||||
explicit IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet,
|
||||
Kernel::KProcess* process, WindowSystem& window_system);
|
||||
~IApplicationProxy();
|
||||
|
||||
private:
|
||||
Result GetAudioController(Out<SharedPointer<IAudioController>> out_audio_controller);
|
||||
Result GetDisplayController(Out<SharedPointer<IDisplayController>> out_display_controller);
|
||||
Result GetProcessWindingController(
|
||||
Out<SharedPointer<IProcessWindingController>> out_process_winding_controller);
|
||||
Result GetDebugFunctions(Out<SharedPointer<IDebugFunctions>> out_debug_functions);
|
||||
Result GetWindowController(Out<SharedPointer<IWindowController>> out_window_controller);
|
||||
Result GetSelfController(Out<SharedPointer<ISelfController>> out_self_controller);
|
||||
Result GetCommonStateGetter(Out<SharedPointer<ICommonStateGetter>> out_common_state_getter);
|
||||
Result GetLibraryAppletCreator(
|
||||
Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator);
|
||||
Result GetApplicationFunctions(
|
||||
Out<SharedPointer<IApplicationFunctions>> out_application_functions);
|
||||
|
||||
private:
|
||||
WindowSystem& m_window_system;
|
||||
Kernel::KProcess* const m_process;
|
||||
const std::shared_ptr<Applet> m_applet;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
||||
@@ -0,0 +1,47 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applet_manager.h"
|
||||
#include "core/hle/service/am/service/application_proxy.h"
|
||||
#include "core/hle/service/am/service/application_proxy_service.h"
|
||||
#include "core/hle/service/am/window_system.h"
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
IApplicationProxyService::IApplicationProxyService(Core::System& system_,
|
||||
WindowSystem& window_system)
|
||||
: ServiceFramework{system_, "appletOE"}, m_window_system{window_system} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&IApplicationProxyService::OpenApplicationProxy>, "OpenApplicationProxy"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IApplicationProxyService::~IApplicationProxyService() = default;
|
||||
|
||||
Result IApplicationProxyService::OpenApplicationProxy(
|
||||
Out<SharedPointer<IApplicationProxy>> out_application_proxy, ClientProcessId pid,
|
||||
InCopyHandle<Kernel::KProcess> process_handle) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
if (const auto applet = this->GetAppletFromProcessId(pid)) {
|
||||
*out_application_proxy = std::make_shared<IApplicationProxy>(
|
||||
system, applet, process_handle.Get(), m_window_system);
|
||||
R_SUCCEED();
|
||||
} else {
|
||||
UNIMPLEMENTED();
|
||||
R_THROW(ResultUnknown);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Applet> IApplicationProxyService::GetAppletFromProcessId(ProcessId process_id) {
|
||||
return m_window_system.GetByAppletResourceUserId(process_id.pid);
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
@@ -0,0 +1,36 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/cmif_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service {
|
||||
|
||||
namespace AM {
|
||||
|
||||
struct Applet;
|
||||
class IApplicationProxy;
|
||||
class WindowSystem;
|
||||
|
||||
class IApplicationProxyService final : public ServiceFramework<IApplicationProxyService> {
|
||||
public:
|
||||
explicit IApplicationProxyService(Core::System& system_, WindowSystem& window_system);
|
||||
~IApplicationProxyService() override;
|
||||
|
||||
private:
|
||||
Result OpenApplicationProxy(Out<SharedPointer<IApplicationProxy>> out_application_proxy,
|
||||
ClientProcessId pid, InCopyHandle<Kernel::KProcess> process_handle);
|
||||
|
||||
private:
|
||||
std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid);
|
||||
|
||||
WindowSystem& m_window_system;
|
||||
};
|
||||
|
||||
} // namespace AM
|
||||
} // namespace Service
|
||||
@@ -9,20 +9,20 @@
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
std::optional<ServiceFrameworkBase::FunctionInfoBase> IAudioController::FindRequest(u32 key) {
|
||||
static constexpr auto functions = CreateStaticMap(
|
||||
FunctionInfo{0, D<&IAudioController::SetExpectedMasterVolume>, "SetExpectedMasterVolume"},
|
||||
FunctionInfo{1, D<&IAudioController::GetMainAppletExpectedMasterVolume>, "GetMainAppletExpectedMasterVolume"},
|
||||
FunctionInfo{2, D<&IAudioController::GetLibraryAppletExpectedMasterVolume>, "GetLibraryAppletExpectedMasterVolume"},
|
||||
FunctionInfo{3, D<&IAudioController::ChangeMainAppletMasterVolume>, "ChangeMainAppletMasterVolume"},
|
||||
FunctionInfo{4, D<&IAudioController::SetTransparentVolumeRate>, "SetTransparentVolumeRate"},
|
||||
FunctionInfo{5, nullptr, "Unknown5", MakeVersionGate({20,0,0})}
|
||||
);
|
||||
return HandlerTableGenerateWithFind(key, functions);
|
||||
}
|
||||
|
||||
IAudioController::IAudioController(Core::System& system_)
|
||||
: ServiceFramework{system_, "IAudioController"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&IAudioController::SetExpectedMasterVolume>, "SetExpectedMasterVolume"},
|
||||
{1, D<&IAudioController::GetMainAppletExpectedMasterVolume>, "GetMainAppletExpectedMasterVolume"},
|
||||
{2, D<&IAudioController::GetLibraryAppletExpectedMasterVolume>, "GetLibraryAppletExpectedMasterVolume"},
|
||||
{3, D<&IAudioController::ChangeMainAppletMasterVolume>, "ChangeMainAppletMasterVolume"},
|
||||
{4, D<&IAudioController::SetTransparentVolumeRate>, "SetTransparentVolumeRate"},
|
||||
{5, nullptr, "Unknown5"}, //20.0.0+
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IAudioController::~IAudioController() = default;
|
||||
|
||||
@@ -23,7 +23,6 @@ private:
|
||||
Result ChangeMainAppletMasterVolume(f32 volume, s64 fade_time_ns);
|
||||
Result SetTransparentVolumeRate(f32 transparent_volume_rate);
|
||||
|
||||
std::optional<FunctionInfoBase> FindRequest(u32 key) override;
|
||||
static constexpr float MinAllowedVolume = 0.0f;
|
||||
static constexpr float MaxAllowedVolume = 1.0f;
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "core/hle/service/am/am_results.h"
|
||||
#include "core/hle/service/am/applet.h"
|
||||
#include "core/hle/service/am/service/common_state_getter.h"
|
||||
#include "core/hle/service/am/service/lock_accessor.h"
|
||||
#include "core/hle/service/am/service/storage.h"
|
||||
#include "core/hle/service/apm/apm_interface.h"
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
@@ -17,147 +18,77 @@
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
std::optional<ServiceFrameworkBase::FunctionInfoBase> ICommonStateGetter::FindRequest(u32 key) {
|
||||
static constexpr auto functions = CreateStaticMap(
|
||||
FunctionInfo{0, D<&ICommonStateGetter::GetEventHandle>, "GetEventHandle"},
|
||||
FunctionInfo{1, D<&ICommonStateGetter::ReceiveMessage>, "ReceiveMessage"},
|
||||
FunctionInfo{2, nullptr, "GetThisAppletKind"},
|
||||
FunctionInfo{3, nullptr, "AllowToEnterSleep"},
|
||||
FunctionInfo{4, nullptr, "DisallowToEnterSleep"},
|
||||
FunctionInfo{5, D<&ICommonStateGetter::GetOperationMode>, "GetOperationMode"},
|
||||
FunctionInfo{6, D<&ICommonStateGetter::GetPerformanceMode>, "GetPerformanceMode"},
|
||||
FunctionInfo{7, nullptr, "GetCradleStatus"},
|
||||
FunctionInfo{8, D<&ICommonStateGetter::GetBootMode>, "GetBootMode"},
|
||||
FunctionInfo{9, D<&ICommonStateGetter::GetCurrentFocusState>, "GetCurrentFocusState"},
|
||||
FunctionInfo{10, D<&ICommonStateGetter::RequestToAcquireSleepLock>, "RequestToAcquireSleepLock"},
|
||||
FunctionInfo{11, D<&ICommonStateGetter::ReleaseSleepLock>, "ReleaseSleepLock"},
|
||||
FunctionInfo{12, D<&ICommonStateGetter::ReleaseSleepLockTransiently>, "ReleaseSleepLockTransiently"},
|
||||
FunctionInfo{13, D<&ICommonStateGetter::GetAcquiredSleepLockEvent>, "GetAcquiredSleepLockEvent"},
|
||||
FunctionInfo{14, nullptr, "GetWakeupCount", MakeVersionGate({11,0,0})},
|
||||
FunctionInfo{15, nullptr, "Unknown15", MakeVersionGate({19,0,0})},
|
||||
FunctionInfo{20, D<&ICommonStateGetter::PushToGeneralChannel>, "PushToGeneralChannel"},
|
||||
FunctionInfo{30, D<&ICommonStateGetter::GetHomeButtonReaderLockAccessor>, "GetHomeButtonReaderLockAccessor"},
|
||||
FunctionInfo{31, D<&ICommonStateGetter::GetReaderLockAccessorEx>, "GetReaderLockAccessorEx", MakeVersionGate({2,0,0})},
|
||||
FunctionInfo{32, D<&ICommonStateGetter::GetWriterLockAccessorEx>, "GetWriterLockAccessorEx", MakeVersionGate({7,0,0})},
|
||||
FunctionInfo{40, nullptr, "GetCradleFwVersion", MakeVersionGate({2,0,0})},
|
||||
FunctionInfo{50, D<&ICommonStateGetter::IsVrModeEnabled>, "IsVrModeEnabled", MakeVersionGate({3,0,0})},
|
||||
FunctionInfo{51, D<&ICommonStateGetter::SetVrModeEnabled>, "SetVrModeEnabled", MakeVersionGate({3,0,0})},
|
||||
FunctionInfo{52, D<&ICommonStateGetter::SetLcdBacklighOffEnabled>, "SetLcdBacklighOffEnabled", MakeVersionGate({4,0,0})},
|
||||
FunctionInfo{53, D<&ICommonStateGetter::BeginVrModeEx>, "BeginVrModeEx", MakeVersionGate({7,0,0})},
|
||||
FunctionInfo{54, D<&ICommonStateGetter::EndVrModeEx>, "EndVrModeEx", MakeVersionGate({7,0,0})},
|
||||
FunctionInfo{55, D<&ICommonStateGetter::IsInControllerFirmwareUpdateSection>, "IsInControllerFirmwareUpdateSection", MakeVersionGate({3,0,0})},
|
||||
FunctionInfo{59, nullptr, "SetVrPositionForDebug", MakeVersionGate({1,0,0})},
|
||||
FunctionInfo{60, D<&ICommonStateGetter::GetDefaultDisplayResolution>, "GetDefaultDisplayResolution"},
|
||||
FunctionInfo{61, D<&ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent>, "GetDefaultDisplayResolutionChangeEvent"},
|
||||
FunctionInfo{62, D<&ICommonStateGetter::GetHdcpAuthenticationState>, "GetHdcpAuthenticationState"},
|
||||
FunctionInfo{63, D<&ICommonStateGetter::GetHdcpAuthenticationStateChangeEvent>, "GetHdcpAuthenticationStateChangeEvent"},
|
||||
FunctionInfo{64, nullptr, "SetTvPowerStateMatchingMode"},
|
||||
FunctionInfo{65, nullptr, "GetApplicationIdByContentActionName"},
|
||||
FunctionInfo{66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"},
|
||||
FunctionInfo{67, nullptr, "CancelCpuBoostMode"},
|
||||
FunctionInfo{68, D<&ICommonStateGetter::GetBuiltInDisplayType>, "GetBuiltInDisplayType"},
|
||||
FunctionInfo{80, D<&ICommonStateGetter::PerformSystemButtonPressingIfInFocus>, "PerformSystemButtonPressingIfInFocus"},
|
||||
FunctionInfo{90, nullptr, "SetPerformanceConfigurationChangedNotification"},
|
||||
FunctionInfo{91, nullptr, "GetCurrentPerformanceConfiguration"},
|
||||
FunctionInfo{100, D<&ICommonStateGetter::SetHandlingHomeButtonShortPressedEnabled>, "SetHandlingHomeButtonShortPressedEnabled"},
|
||||
FunctionInfo{110, nullptr, "OpenMyGpuErrorHandler"},
|
||||
FunctionInfo{120, D<&ICommonStateGetter::GetAppletLaunchedHistory>, "GetAppletLaunchedHistory", MakeVersionGate({13,0,0})},
|
||||
FunctionInfo{130, D<&ICommonStateGetter::EnableStartupLogoDisappearedMessage>, "EnableStartupLogoDisappearedMessage", MakeVersionGate({21,0,0})},
|
||||
FunctionInfo{200, D<&ICommonStateGetter::GetOperationModeSystemInfo>, "GetOperationModeSystemInfo"},
|
||||
FunctionInfo{300, D<&ICommonStateGetter::GetSettingsPlatformRegion>, "GetSettingsPlatformRegion"},
|
||||
FunctionInfo{400, nullptr, "ActivateMigrationService"},
|
||||
FunctionInfo{401, nullptr, "DeactivateMigrationService"},
|
||||
FunctionInfo{500, nullptr, "DisableSleepTillShutdown"},
|
||||
FunctionInfo{501, nullptr, "SuppressDisablingSleepTemporarily"},
|
||||
FunctionInfo{502, nullptr, "IsSleepEnabled"},
|
||||
FunctionInfo{503, nullptr, "IsDisablingSleepSuppressed"},
|
||||
FunctionInfo{600, nullptr, "SetHidInputMagnificationForApplication", MakeVersionGate({20,0,0})},
|
||||
FunctionInfo{610, D<&ICommonStateGetter::Unknown610>, "Unknown610", MakeVersionGate({21,0,0})},
|
||||
FunctionInfo{611, D<&ICommonStateGetter::Unknown611>, "Unknown611", MakeVersionGate({22,0,0})},
|
||||
FunctionInfo{900, D<&ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled>, "SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled", MakeVersionGate({11,0,0})},
|
||||
FunctionInfo{910, nullptr, "GetLaunchRequiredTick", MakeVersionGate({17,0,0})},
|
||||
FunctionInfo{1000, D<&ICommonStateGetter::BeginVrMode3d>, "BeginVrMode3d", MakeVersionGate({19,0,0})},
|
||||
FunctionInfo{1001, D<&ICommonStateGetter::EndVrMode3d>, "EndVrMode3d", MakeVersionGate({19,0,0})},
|
||||
FunctionInfo{1002, D<&ICommonStateGetter::IsVrModeEnabled3d>, "IsVrModeEnabled3d", MakeVersionGate({19,0,0})},
|
||||
FunctionInfo{1003, D<&ICommonStateGetter::GetVrLaboGoggleViewport>, "GetVrLaboGoggleViewport", MakeVersionGate({21,0,0})},
|
||||
FunctionInfo{1004, D<&ICommonStateGetter::GetPanelPhysicalSizeForSpecificTitle>, "GetPanelPhysicalSizeForSpecificTitle", MakeVersionGate({21,0,0})},
|
||||
FunctionInfo{1005, D<&ICommonStateGetter::GetPanelResolutionForSpecificTitle>, "GetPanelResolutionForSpecificTitle", MakeVersionGate({21,0,0})}
|
||||
);
|
||||
return HandlerTableGenerateWithFind(key, functions);
|
||||
}
|
||||
|
||||
class ILockAccessor final : public ServiceFramework<ILockAccessor> {
|
||||
public:
|
||||
explicit ILockAccessor(Core::System& system_)
|
||||
: ServiceFramework{system_, "ILockAccessor"}, m_context{system_, "ILockAccessor"},
|
||||
m_event{m_context} {
|
||||
m_event.Signal(system.Kernel());
|
||||
}
|
||||
~ILockAccessor() override = default;
|
||||
|
||||
Result TryLock(Out<bool> out_is_locked, OutCopyHandle<Kernel::KReadableEvent> out_handle, bool return_handle) {
|
||||
LOG_INFO(Service_AM, "called, return_handle={}", return_handle);
|
||||
|
||||
{
|
||||
std::scoped_lock lk{m_mutex};
|
||||
if (m_is_locked) {
|
||||
*out_is_locked = false;
|
||||
} else {
|
||||
m_is_locked = true;
|
||||
*out_is_locked = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (return_handle) {
|
||||
*out_handle = m_event.GetHandle();
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result Unlock() {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
{
|
||||
std::scoped_lock lk{m_mutex};
|
||||
m_is_locked = false;
|
||||
}
|
||||
|
||||
m_event.Signal(system.Kernel());
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result GetEvent(OutCopyHandle<Kernel::KReadableEvent> out_handle) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
*out_handle = m_event.GetHandle();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IsLocked(Out<bool> out_is_locked) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
std::scoped_lock lk{m_mutex};
|
||||
*out_is_locked = m_is_locked;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
private:
|
||||
std::optional<FunctionInfoBase> FindRequest(u32 key) override {
|
||||
return HandlerTableGenerateWithFind(key, functions);
|
||||
}
|
||||
static constexpr auto functions = CreateStaticMap(
|
||||
FunctionInfo{1, D<&ILockAccessor::TryLock>, "TryLock"},
|
||||
FunctionInfo{2, D<&ILockAccessor::Unlock>, "Unlock"},
|
||||
FunctionInfo{3, D<&ILockAccessor::GetEvent>, "GetEvent"},
|
||||
FunctionInfo{4, D<&ILockAccessor::IsLocked>, "IsLocked"}
|
||||
);
|
||||
KernelHelpers::ServiceContext m_context;
|
||||
Event m_event;
|
||||
std::mutex m_mutex{};
|
||||
bool m_is_locked{};
|
||||
};
|
||||
|
||||
ICommonStateGetter::ICommonStateGetter(Core::System& system_, std::shared_ptr<Applet> applet)
|
||||
: ServiceFramework{system_, "ICommonStateGetter"}, m_applet{std::move(applet)} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&ICommonStateGetter::GetEventHandle>, "GetEventHandle"},
|
||||
{1, D<&ICommonStateGetter::ReceiveMessage>, "ReceiveMessage"},
|
||||
{2, nullptr, "GetThisAppletKind"},
|
||||
{3, nullptr, "AllowToEnterSleep"},
|
||||
{4, nullptr, "DisallowToEnterSleep"},
|
||||
{5, D<&ICommonStateGetter::GetOperationMode>, "GetOperationMode"},
|
||||
{6, D<&ICommonStateGetter::GetPerformanceMode>, "GetPerformanceMode"},
|
||||
{7, nullptr, "GetCradleStatus"},
|
||||
{8, D<&ICommonStateGetter::GetBootMode>, "GetBootMode"},
|
||||
{9, D<&ICommonStateGetter::GetCurrentFocusState>, "GetCurrentFocusState"},
|
||||
{10, D<&ICommonStateGetter::RequestToAcquireSleepLock>, "RequestToAcquireSleepLock"},
|
||||
{11, D<&ICommonStateGetter::ReleaseSleepLock>, "ReleaseSleepLock"},
|
||||
{12, D<&ICommonStateGetter::ReleaseSleepLockTransiently>, "ReleaseSleepLockTransiently"},
|
||||
{13, D<&ICommonStateGetter::GetAcquiredSleepLockEvent>, "GetAcquiredSleepLockEvent"},
|
||||
{14, nullptr, "GetWakeupCount"}, //11.0.0+
|
||||
{15, nullptr, "Unknown15"}, //19.0.0+
|
||||
{20, D<&ICommonStateGetter::PushToGeneralChannel>, "PushToGeneralChannel"},
|
||||
{30, D<&ICommonStateGetter::GetHomeButtonReaderLockAccessor>, "GetHomeButtonReaderLockAccessor"},
|
||||
{31, D<&ICommonStateGetter::GetReaderLockAccessorEx>, "GetReaderLockAccessorEx"}, //2.0.0+
|
||||
{32, D<&ICommonStateGetter::GetWriterLockAccessorEx>, "GetWriterLockAccessorEx"}, //7.0.0+
|
||||
{40, nullptr, "GetCradleFwVersion"}, //2.0.0+
|
||||
{50, D<&ICommonStateGetter::IsVrModeEnabled>, "IsVrModeEnabled"}, //3.0.0+
|
||||
{51, D<&ICommonStateGetter::SetVrModeEnabled>, "SetVrModeEnabled"}, //3.0.0+
|
||||
{52, D<&ICommonStateGetter::SetLcdBacklighOffEnabled>, "SetLcdBacklighOffEnabled"}, //4.0.0+
|
||||
{53, D<&ICommonStateGetter::BeginVrModeEx>, "BeginVrModeEx"}, //7.0.0+
|
||||
{54, D<&ICommonStateGetter::EndVrModeEx>, "EndVrModeEx"}, //7.0.0+
|
||||
{55, D<&ICommonStateGetter::IsInControllerFirmwareUpdateSection>, "IsInControllerFirmwareUpdateSection"}, //3.0.0+
|
||||
{59, nullptr, "SetVrPositionForDebug"}, //1.0.0+
|
||||
{60, D<&ICommonStateGetter::GetDefaultDisplayResolution>, "GetDefaultDisplayResolution"},
|
||||
{61, D<&ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent>, "GetDefaultDisplayResolutionChangeEvent"},
|
||||
{62, D<&ICommonStateGetter::GetHdcpAuthenticationState>, "GetHdcpAuthenticationState"},
|
||||
{63, D<&ICommonStateGetter::GetHdcpAuthenticationStateChangeEvent>, "GetHdcpAuthenticationStateChangeEvent"},
|
||||
{64, nullptr, "SetTvPowerStateMatchingMode"},
|
||||
{65, nullptr, "GetApplicationIdByContentActionName"},
|
||||
{66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"},
|
||||
{67, nullptr, "CancelCpuBoostMode"},
|
||||
{68, D<&ICommonStateGetter::GetBuiltInDisplayType>, "GetBuiltInDisplayType"},
|
||||
{80, D<&ICommonStateGetter::PerformSystemButtonPressingIfInFocus>, "PerformSystemButtonPressingIfInFocus"},
|
||||
{90, nullptr, "SetPerformanceConfigurationChangedNotification"},
|
||||
{91, nullptr, "GetCurrentPerformanceConfiguration"},
|
||||
{100, D<&ICommonStateGetter::SetHandlingHomeButtonShortPressedEnabled>, "SetHandlingHomeButtonShortPressedEnabled"},
|
||||
{110, nullptr, "OpenMyGpuErrorHandler"},
|
||||
{120, D<&ICommonStateGetter::GetAppletLaunchedHistory>, "GetAppletLaunchedHistory"}, //13.0.0+
|
||||
{130, D<&ICommonStateGetter::EnableStartupLogoDisappearedMessage>, "EnableStartupLogoDisappearedMessage"}, //21.0.0+
|
||||
{200, D<&ICommonStateGetter::GetOperationModeSystemInfo>, "GetOperationModeSystemInfo"},
|
||||
{300, D<&ICommonStateGetter::GetSettingsPlatformRegion>, "GetSettingsPlatformRegion"},
|
||||
{400, nullptr, "ActivateMigrationService"},
|
||||
{401, nullptr, "DeactivateMigrationService"},
|
||||
{500, nullptr, "DisableSleepTillShutdown"},
|
||||
{501, nullptr, "SuppressDisablingSleepTemporarily"},
|
||||
{502, nullptr, "IsSleepEnabled"},
|
||||
{503, nullptr, "IsDisablingSleepSuppressed"},
|
||||
{600, nullptr, "SetHidInputMagnificationForApplication"}, //20.0.0+
|
||||
{610, D<&ICommonStateGetter::Unknown610>, "Unknown610"}, //21.0.0+
|
||||
{611, D<&ICommonStateGetter::Unknown611>, "Unknown611"}, //22.0.0+
|
||||
{900, D<&ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled>, "SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled"}, //11.0.0+
|
||||
{910, nullptr, "GetLaunchRequiredTick"}, //17.0.0+
|
||||
{1000, D<&ICommonStateGetter::BeginVrMode3d>, "BeginVrMode3d"}, //19.0.0+
|
||||
{1001, D<&ICommonStateGetter::EndVrMode3d>, "EndVrMode3d"}, //19.0.0+
|
||||
{1002, D<&ICommonStateGetter::IsVrModeEnabled3d>, "IsVrModeEnabled3d"}, //19.0.0+
|
||||
{1003, D<&ICommonStateGetter::GetVrLaboGoggleViewport>, "GetVrLaboGoggleViewport"}, //21.0.0+
|
||||
{1004, D<&ICommonStateGetter::GetPanelPhysicalSizeForSpecificTitle>, "GetPanelPhysicalSizeForSpecificTitle"}, //21.0.0+
|
||||
{1005, D<&ICommonStateGetter::GetPanelResolutionForSpecificTitle>, "GetPanelResolutionForSpecificTitle"}, //21.0.0+
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
ICommonStateGetter::~ICommonStateGetter() = default;
|
||||
|
||||
@@ -76,7 +76,6 @@ private:
|
||||
|
||||
void SetCpuBoostMode(HLERequestContext& ctx);
|
||||
|
||||
std::optional<FunctionInfoBase> FindRequest(u32 key) override;
|
||||
const std::shared_ptr<Applet> m_applet;
|
||||
};
|
||||
|
||||
|
||||
@@ -9,21 +9,22 @@
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
std::optional<ServiceFrameworkBase::FunctionInfoBase> ICradleFirmwareUpdater::FindRequest(u32 key) {
|
||||
static constexpr auto functions = CreateStaticMap(
|
||||
FunctionInfo{0, D<&ICradleFirmwareUpdater::StartUpdate>, "StartUpdate"},
|
||||
FunctionInfo{1, D<&ICradleFirmwareUpdater::FinishUpdate>, "FinishUpdate"},
|
||||
FunctionInfo{2, D<&ICradleFirmwareUpdater::GetCradleDeviceInfo>, "GetCradleDeviceInfo"},
|
||||
FunctionInfo{3, D<&ICradleFirmwareUpdater::GetCradleDeviceInfoChangeEvent>, "GetCradleDeviceInfoChangeEvent"},
|
||||
FunctionInfo{4, nullptr, "GetUpdateProgressInfo"},
|
||||
FunctionInfo{5, nullptr, "GetLastInternalResult"}
|
||||
);
|
||||
return HandlerTableGenerateWithFind(key, functions);
|
||||
}
|
||||
|
||||
ICradleFirmwareUpdater::ICradleFirmwareUpdater(Core::System& system_)
|
||||
: ServiceFramework{system_, "ICradleFirmwareUpdater"},
|
||||
m_context{system, "ICradleFirmwareUpdater"}, m_cradle_device_info_event{m_context} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&ICradleFirmwareUpdater::StartUpdate>, "StartUpdate"},
|
||||
{1, D<&ICradleFirmwareUpdater::FinishUpdate>, "FinishUpdate"},
|
||||
{2, D<&ICradleFirmwareUpdater::GetCradleDeviceInfo>, "GetCradleDeviceInfo"},
|
||||
{3, D<&ICradleFirmwareUpdater::GetCradleDeviceInfoChangeEvent>, "GetCradleDeviceInfoChangeEvent"},
|
||||
{4, nullptr, "GetUpdateProgressInfo"},
|
||||
{5, nullptr, "GetLastInternalResult"},
|
||||
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
ICradleFirmwareUpdater::~ICradleFirmwareUpdater() = default;
|
||||
|
||||
@@ -33,7 +33,6 @@ private:
|
||||
Result GetCradleDeviceInfoChangeEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
|
||||
private:
|
||||
std::optional<FunctionInfoBase> FindRequest(u32 key) override;
|
||||
KernelHelpers::ServiceContext m_context;
|
||||
Event m_cradle_device_info_event;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/am/service/debug_functions.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
IDebugFunctions::IDebugFunctions(Core::System& system_)
|
||||
: ServiceFramework{system_, "IDebugFunctions"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "NotifyMessageToHomeMenuForDebug"},
|
||||
{1, nullptr, "OpenMainApplication"},
|
||||
{10, nullptr, "PerformSystemButtonPressing"},
|
||||
{20, nullptr, "InvalidateTransitionLayer"},
|
||||
{30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"},
|
||||
{31, nullptr, "RequestLaunchApplicationByApplicationLaunchInfoForDebug"},
|
||||
{40, nullptr, "GetAppletResourceUsageInfo"},
|
||||
{50, nullptr, "AddSystemProgramIdAndAppletIdForDebug"},
|
||||
{51, nullptr, "AddOperationConfirmedLibraryAppletIdForDebug"},
|
||||
{100, nullptr, "SetCpuBoostModeForApplet"},
|
||||
{101, nullptr, "CancelCpuBoostModeForApplet"},
|
||||
{110, nullptr, "PushToAppletBoundChannelForDebug"},
|
||||
{111, nullptr, "TryPopFromAppletBoundChannelForDebug"},
|
||||
{120, nullptr, "AlarmSettingNotificationEnableAppEventReserve"},
|
||||
{121, nullptr, "AlarmSettingNotificationDisableAppEventReserve"},
|
||||
{122, nullptr, "AlarmSettingNotificationPushAppEventNotify"},
|
||||
{130, nullptr, "FriendInvitationSetApplicationParameter"},
|
||||
{131, nullptr, "FriendInvitationClearApplicationParameter"},
|
||||
{132, nullptr, "FriendInvitationPushApplicationParameter"},
|
||||
{140, nullptr, "RestrictPowerOperationForSecureLaunchModeForDebug"},
|
||||
{200, nullptr, "CreateFloatingLibraryAppletAccepterForDebug"},
|
||||
{300, nullptr, "TerminateAllRunningApplicationsForDebug"},
|
||||
{900, nullptr, "GetGrcProcessLaunchedSystemEvent"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IDebugFunctions::~IDebugFunctions() = default;
|
||||
|
||||
} // namespace Service::AM
|
||||
@@ -0,0 +1,19 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class IDebugFunctions final : public ServiceFramework<IDebugFunctions> {
|
||||
public:
|
||||
explicit IDebugFunctions(Core::System& system_);
|
||||
~IDebugFunctions() override;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
||||
@@ -12,42 +12,42 @@
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
std::optional<ServiceFrameworkBase::FunctionInfoBase> IDisplayController::FindRequest(u32 key) {
|
||||
static constexpr auto functions = CreateStaticMap(
|
||||
FunctionInfo{0, nullptr, "GetLastForegroundCaptureImage"},
|
||||
FunctionInfo{1, nullptr, "UpdateLastForegroundCaptureImage"},
|
||||
FunctionInfo{2, nullptr, "GetLastApplicationCaptureImage"},
|
||||
FunctionInfo{3, nullptr, "GetCallerAppletCaptureImage"},
|
||||
FunctionInfo{4, nullptr, "UpdateCallerAppletCaptureImage"},
|
||||
FunctionInfo{5, D<&IDisplayController::GetLastForegroundCaptureImageEx>, "GetLastForegroundCaptureImageEx"},
|
||||
FunctionInfo{6, nullptr, "GetLastApplicationCaptureImageEx"},
|
||||
FunctionInfo{7, D<&IDisplayController::GetCallerAppletCaptureImageEx>, "GetCallerAppletCaptureImageEx"},
|
||||
FunctionInfo{8, D<&IDisplayController::TakeScreenShotOfOwnLayer>, "TakeScreenShotOfOwnLayer"},
|
||||
FunctionInfo{9, nullptr, "CopyBetweenCaptureBuffers"},
|
||||
FunctionInfo{10, nullptr, "AcquireLastApplicationCaptureBuffer"},
|
||||
FunctionInfo{11, nullptr, "ReleaseLastApplicationCaptureBuffer"},
|
||||
FunctionInfo{12, nullptr, "AcquireLastForegroundCaptureBuffer"},
|
||||
FunctionInfo{13, nullptr, "ReleaseLastForegroundCaptureBuffer"},
|
||||
FunctionInfo{14, nullptr, "AcquireCallerAppletCaptureBuffer"},
|
||||
FunctionInfo{15, nullptr, "ReleaseCallerAppletCaptureBuffer"},
|
||||
FunctionInfo{16, nullptr, "AcquireLastApplicationCaptureBufferEx"},
|
||||
FunctionInfo{17, nullptr, "AcquireLastForegroundCaptureBufferEx"},
|
||||
FunctionInfo{18, nullptr, "AcquireCallerAppletCaptureBufferEx"},
|
||||
FunctionInfo{20, D<&IDisplayController::ClearCaptureBuffer>, "ClearCaptureBuffer"},
|
||||
FunctionInfo{21, nullptr, "ClearAppletTransitionBuffer"},
|
||||
FunctionInfo{22, D<&IDisplayController::AcquireLastApplicationCaptureSharedBuffer>, "AcquireLastApplicationCaptureSharedBuffer"},
|
||||
FunctionInfo{23, D<&IDisplayController::ReleaseLastApplicationCaptureSharedBuffer>, "ReleaseLastApplicationCaptureSharedBuffer"},
|
||||
FunctionInfo{24, D<&IDisplayController::AcquireLastForegroundCaptureSharedBuffer>, "AcquireLastForegroundCaptureSharedBuffer"},
|
||||
FunctionInfo{25, D<&IDisplayController::ReleaseLastForegroundCaptureSharedBuffer>, "ReleaseLastForegroundCaptureSharedBuffer"},
|
||||
FunctionInfo{26, D<&IDisplayController::AcquireCallerAppletCaptureSharedBuffer>, "AcquireCallerAppletCaptureSharedBuffer"},
|
||||
FunctionInfo{27, D<&IDisplayController::ReleaseCallerAppletCaptureSharedBuffer>, "ReleaseCallerAppletCaptureSharedBuffer"},
|
||||
FunctionInfo{28, nullptr, "TakeScreenShotOfOwnLayerEx"}
|
||||
);
|
||||
return HandlerTableGenerateWithFind(key, functions);
|
||||
}
|
||||
|
||||
IDisplayController::IDisplayController(Core::System& system_, std::shared_ptr<Applet> applet_)
|
||||
: ServiceFramework{system_, "IDisplayController"}, applet(std::move(applet_)) {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetLastForegroundCaptureImage"},
|
||||
{1, nullptr, "UpdateLastForegroundCaptureImage"},
|
||||
{2, nullptr, "GetLastApplicationCaptureImage"},
|
||||
{3, nullptr, "GetCallerAppletCaptureImage"},
|
||||
{4, nullptr, "UpdateCallerAppletCaptureImage"},
|
||||
{5, D<&IDisplayController::GetLastForegroundCaptureImageEx>, "GetLastForegroundCaptureImageEx"},
|
||||
{6, nullptr, "GetLastApplicationCaptureImageEx"},
|
||||
{7, D<&IDisplayController::GetCallerAppletCaptureImageEx>, "GetCallerAppletCaptureImageEx"},
|
||||
{8, D<&IDisplayController::TakeScreenShotOfOwnLayer>, "TakeScreenShotOfOwnLayer"},
|
||||
{9, nullptr, "CopyBetweenCaptureBuffers"},
|
||||
{10, nullptr, "AcquireLastApplicationCaptureBuffer"},
|
||||
{11, nullptr, "ReleaseLastApplicationCaptureBuffer"},
|
||||
{12, nullptr, "AcquireLastForegroundCaptureBuffer"},
|
||||
{13, nullptr, "ReleaseLastForegroundCaptureBuffer"},
|
||||
{14, nullptr, "AcquireCallerAppletCaptureBuffer"},
|
||||
{15, nullptr, "ReleaseCallerAppletCaptureBuffer"},
|
||||
{16, nullptr, "AcquireLastApplicationCaptureBufferEx"},
|
||||
{17, nullptr, "AcquireLastForegroundCaptureBufferEx"},
|
||||
{18, nullptr, "AcquireCallerAppletCaptureBufferEx"},
|
||||
{20, D<&IDisplayController::ClearCaptureBuffer>, "ClearCaptureBuffer"},
|
||||
{21, nullptr, "ClearAppletTransitionBuffer"},
|
||||
{22, D<&IDisplayController::AcquireLastApplicationCaptureSharedBuffer>, "AcquireLastApplicationCaptureSharedBuffer"},
|
||||
{23, D<&IDisplayController::ReleaseLastApplicationCaptureSharedBuffer>, "ReleaseLastApplicationCaptureSharedBuffer"},
|
||||
{24, D<&IDisplayController::AcquireLastForegroundCaptureSharedBuffer>, "AcquireLastForegroundCaptureSharedBuffer"},
|
||||
{25, D<&IDisplayController::ReleaseLastForegroundCaptureSharedBuffer>, "ReleaseLastForegroundCaptureSharedBuffer"},
|
||||
{26, D<&IDisplayController::AcquireCallerAppletCaptureSharedBuffer>, "AcquireCallerAppletCaptureSharedBuffer"},
|
||||
{27, D<&IDisplayController::ReleaseCallerAppletCaptureSharedBuffer>, "ReleaseCallerAppletCaptureSharedBuffer"},
|
||||
{28, nullptr, "TakeScreenShotOfOwnLayerEx"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IDisplayController::~IDisplayController() = default;
|
||||
|
||||
@@ -35,7 +35,6 @@ private:
|
||||
Out<s32> out_fbshare_layer_index);
|
||||
Result ReleaseLastApplicationCaptureSharedBuffer();
|
||||
|
||||
std::optional<FunctionInfoBase> FindRequest(u32 key) override;
|
||||
const std::shared_ptr<Applet> applet;
|
||||
};
|
||||
|
||||
|
||||
@@ -10,28 +10,28 @@
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
std::optional<ServiceFrameworkBase::FunctionInfoBase> IGlobalStateController::FindRequest(u32 key) {
|
||||
static constexpr auto functions = CreateStaticMap(
|
||||
FunctionInfo{0, nullptr, "RequestToEnterSleep"},
|
||||
FunctionInfo{1, nullptr, "EnterSleep"},
|
||||
FunctionInfo{2, nullptr, "StartSleepSequence"},
|
||||
FunctionInfo{3, D<&IGlobalStateController::StartShutdownSequence>, "StartShutdownSequence"},
|
||||
FunctionInfo{4, D<&IGlobalStateController::StartRebootSequence>, "StartRebootSequence"},
|
||||
FunctionInfo{9, nullptr, "IsAutoPowerDownRequested"},
|
||||
FunctionInfo{10, D<&IGlobalStateController::LoadAndApplyIdlePolicySettings>, "LoadAndApplyIdlePolicySettings"},
|
||||
FunctionInfo{11, nullptr, "NotifyCecSettingsChanged"},
|
||||
FunctionInfo{12, nullptr, "SetDefaultHomeButtonLongPressTime"},
|
||||
FunctionInfo{13, nullptr, "UpdateDefaultDisplayResolution"},
|
||||
FunctionInfo{14, D<&IGlobalStateController::ShouldSleepOnBoot>, "ShouldSleepOnBoot"},
|
||||
FunctionInfo{15, D<&IGlobalStateController::GetHdcpAuthenticationFailedEvent>, "GetHdcpAuthenticationFailedEvent"},
|
||||
FunctionInfo{30, D<&IGlobalStateController::OpenCradleFirmwareUpdater>, "OpenCradleFirmwareUpdater"}
|
||||
);
|
||||
return HandlerTableGenerateWithFind(key, functions);
|
||||
}
|
||||
|
||||
IGlobalStateController::IGlobalStateController(Core::System& system_)
|
||||
: ServiceFramework{system_, "IGlobalStateController"},
|
||||
m_context{system_, "IGlobalStateController"}, m_hdcp_authentication_failed_event{m_context} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "RequestToEnterSleep"},
|
||||
{1, nullptr, "EnterSleep"},
|
||||
{2, nullptr, "StartSleepSequence"},
|
||||
{3, D<&IGlobalStateController::StartShutdownSequence>, "StartShutdownSequence"},
|
||||
{4, D<&IGlobalStateController::StartRebootSequence>, "StartRebootSequence"},
|
||||
{9, nullptr, "IsAutoPowerDownRequested"},
|
||||
{10, D<&IGlobalStateController::LoadAndApplyIdlePolicySettings>, "LoadAndApplyIdlePolicySettings"},
|
||||
{11, nullptr, "NotifyCecSettingsChanged"},
|
||||
{12, nullptr, "SetDefaultHomeButtonLongPressTime"},
|
||||
{13, nullptr, "UpdateDefaultDisplayResolution"},
|
||||
{14, D<&IGlobalStateController::ShouldSleepOnBoot>, "ShouldSleepOnBoot"},
|
||||
{15, D<&IGlobalStateController::GetHdcpAuthenticationFailedEvent>, "GetHdcpAuthenticationFailedEvent"},
|
||||
{30, D<&IGlobalStateController::OpenCradleFirmwareUpdater>, "OpenCradleFirmwareUpdater"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
Result IGlobalStateController::StartShutdownSequence() {
|
||||
|
||||
@@ -26,9 +26,9 @@ private:
|
||||
Result LoadAndApplyIdlePolicySettings();
|
||||
Result ShouldSleepOnBoot(Out<bool> out_should_sleep_on_boot);
|
||||
Result GetHdcpAuthenticationFailedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result OpenCradleFirmwareUpdater(Out<SharedPointer<ICradleFirmwareUpdater>> out_cradle_firmware_updater);
|
||||
Result OpenCradleFirmwareUpdater(
|
||||
Out<SharedPointer<ICradleFirmwareUpdater>> out_cradle_firmware_updater);
|
||||
|
||||
std::optional<FunctionInfoBase> FindRequest(u32 key) override;
|
||||
KernelHelpers::ServiceContext m_context;
|
||||
Event m_hdcp_authentication_failed_event;
|
||||
};
|
||||
|
||||
@@ -14,31 +14,31 @@
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
std::optional<ServiceFrameworkBase::FunctionInfoBase> IHomeMenuFunctions::FindRequest(u32 key) {
|
||||
static constexpr auto functions = CreateStaticMap(
|
||||
FunctionInfo{10, D<&IHomeMenuFunctions::RequestToGetForeground>, "RequestToGetForeground"},
|
||||
FunctionInfo{11, D<&IHomeMenuFunctions::LockForeground>, "LockForeground"},
|
||||
FunctionInfo{12, D<&IHomeMenuFunctions::UnlockForeground>, "UnlockForeground"},
|
||||
FunctionInfo{20, D<&IHomeMenuFunctions::PopFromGeneralChannel>, "PopFromGeneralChannel"},
|
||||
FunctionInfo{21, D<&IHomeMenuFunctions::GetPopFromGeneralChannelEvent>, "GetPopFromGeneralChannelEvent"},
|
||||
FunctionInfo{30, nullptr, "GetHomeButtonWriterLockAccessor"},
|
||||
FunctionInfo{31, nullptr, "GetWriterLockAccessorEx"},
|
||||
FunctionInfo{40, D<&IHomeMenuFunctions::IsSleepEnabled>, "IsSleepEnabled"},
|
||||
FunctionInfo{41, D<&IHomeMenuFunctions::IsRebootEnabled>, "IsRebootEnabled"},
|
||||
FunctionInfo{50, nullptr, "LaunchSystemApplet"},
|
||||
FunctionInfo{51, nullptr, "LaunchStarter"},
|
||||
FunctionInfo{100, nullptr, "PopRequestLaunchApplicationForDebug"},
|
||||
FunctionInfo{110, D<&IHomeMenuFunctions::IsForceTerminateApplicationDisabledForDebug>, "IsForceTerminateApplicationDisabledForDebug"},
|
||||
FunctionInfo{200, nullptr, "LaunchDevMenu"},
|
||||
FunctionInfo{1000, nullptr, "SetLastApplicationExitReason"}
|
||||
);
|
||||
return HandlerTableGenerateWithFind(key, functions);
|
||||
}
|
||||
|
||||
IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_, std::shared_ptr<Applet> applet,
|
||||
WindowSystem& window_system)
|
||||
: ServiceFramework{system_, "IHomeMenuFunctions"}, m_window_system{window_system},
|
||||
m_applet{std::move(applet)}, m_context{system, "IHomeMenuFunctions"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{10, D<&IHomeMenuFunctions::RequestToGetForeground>, "RequestToGetForeground"},
|
||||
{11, D<&IHomeMenuFunctions::LockForeground>, "LockForeground"},
|
||||
{12, D<&IHomeMenuFunctions::UnlockForeground>, "UnlockForeground"},
|
||||
{20, D<&IHomeMenuFunctions::PopFromGeneralChannel>, "PopFromGeneralChannel"},
|
||||
{21, D<&IHomeMenuFunctions::GetPopFromGeneralChannelEvent>, "GetPopFromGeneralChannelEvent"},
|
||||
{30, nullptr, "GetHomeButtonWriterLockAccessor"},
|
||||
{31, nullptr, "GetWriterLockAccessorEx"},
|
||||
{40, D<&IHomeMenuFunctions::IsSleepEnabled>, "IsSleepEnabled"},
|
||||
{41, D<&IHomeMenuFunctions::IsRebootEnabled>, "IsRebootEnabled"},
|
||||
{50, nullptr, "LaunchSystemApplet"},
|
||||
{51, nullptr, "LaunchStarter"},
|
||||
{100, nullptr, "PopRequestLaunchApplicationForDebug"},
|
||||
{110, D<&IHomeMenuFunctions::IsForceTerminateApplicationDisabledForDebug>, "IsForceTerminateApplicationDisabledForDebug"},
|
||||
{200, nullptr, "LaunchDevMenu"},
|
||||
{1000, nullptr, "SetLastApplicationExitReason"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IHomeMenuFunctions::~IHomeMenuFunctions() = default;
|
||||
|
||||
@@ -34,7 +34,6 @@ private:
|
||||
Result IsForceTerminateApplicationDisabledForDebug(
|
||||
Out<bool> out_is_force_terminate_application_disabled_for_debug);
|
||||
|
||||
std::optional<FunctionInfoBase> FindRequest(u32 key) override;
|
||||
WindowSystem& m_window_system;
|
||||
const std::shared_ptr<Applet> m_applet;
|
||||
KernelHelpers::ServiceContext m_context;
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
static void EnableSingleUserPlay(const std::shared_ptr<LibraryAppletStorage>& impl) {
|
||||
namespace {
|
||||
|
||||
void EnableSingleUserPlay(const std::shared_ptr<LibraryAppletStorage>& impl) {
|
||||
constexpr s64 DisplayOptionsOffset = 0x90;
|
||||
constexpr s64 IsSkipEnabledOffset = 1;
|
||||
constexpr s64 ShowSkipButtonOffset = 4;
|
||||
@@ -27,7 +29,7 @@ static void EnableSingleUserPlay(const std::shared_ptr<LibraryAppletStorage>& im
|
||||
impl->Write(DisplayOptionsOffset + ShowSkipButtonOffset, &enabled, sizeof(enabled));
|
||||
}
|
||||
|
||||
static void ReplaceEmptyUuidWithCurrentUser(const std::shared_ptr<LibraryAppletStorage>& impl) {
|
||||
void ReplaceEmptyUuidWithCurrentUser(const std::shared_ptr<LibraryAppletStorage>& impl) {
|
||||
Frontend::UiReturnArg return_arg{};
|
||||
impl->Read(0, &return_arg, sizeof(return_arg));
|
||||
|
||||
@@ -45,40 +47,42 @@ static void ReplaceEmptyUuidWithCurrentUser(const std::shared_ptr<LibraryAppletS
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<ServiceFrameworkBase::FunctionInfoBase> ILibraryAppletAccessor::FindRequest(u32 key) {
|
||||
static constexpr auto functions = CreateStaticMap(
|
||||
FunctionInfo{0, D<&ILibraryAppletAccessor::GetAppletStateChangedEvent>, "GetAppletStateChangedEvent"},
|
||||
FunctionInfo{1, D<&ILibraryAppletAccessor::IsCompleted>, "IsCompleted"},
|
||||
FunctionInfo{10, D<&ILibraryAppletAccessor::Start>, "Start"},
|
||||
FunctionInfo{20, D<&ILibraryAppletAccessor::RequestExit>, "RequestExit"},
|
||||
FunctionInfo{25, D<&ILibraryAppletAccessor::Terminate>, "Terminate"},
|
||||
FunctionInfo{30, D<&ILibraryAppletAccessor::GetResult>, "GetResult"},
|
||||
FunctionInfo{50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"},
|
||||
FunctionInfo{60, D<&ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero>, "PresetLibraryAppletGpuTimeSliceZero", MakeVersionGate({10,0,0})},
|
||||
FunctionInfo{80, nullptr, "RequestForLibraryAppletToGetForeground", MakeVersionGate({19,0,0})},
|
||||
FunctionInfo{81, nullptr, "GetCurrentChildLibraryApplet", MakeVersionGate({19,0,0})},
|
||||
FunctionInfo{90, D<&ILibraryAppletAccessor::Unknown90>, "Unknown90", MakeVersionGate({20,0,0})},
|
||||
FunctionInfo{100, D<&ILibraryAppletAccessor::PushInData>, "PushInData"},
|
||||
FunctionInfo{101, D<&ILibraryAppletAccessor::PopOutData>, "PopOutData"},
|
||||
FunctionInfo{102, nullptr, "PushExtraStorage"},
|
||||
FunctionInfo{103, D<&ILibraryAppletAccessor::PushInteractiveInData>, "PushInteractiveInData"},
|
||||
FunctionInfo{104, D<&ILibraryAppletAccessor::PopInteractiveOutData>, "PopInteractiveOutData"},
|
||||
FunctionInfo{105, D<&ILibraryAppletAccessor::GetPopOutDataEvent>, "GetPopOutDataEvent"},
|
||||
FunctionInfo{106, D<&ILibraryAppletAccessor::GetPopInteractiveOutDataEvent>, "GetPopInteractiveOutDataEvent"},
|
||||
FunctionInfo{110, nullptr, "NeedsToExitProcess"},
|
||||
FunctionInfo{120, D<&ILibraryAppletAccessor::GetLibraryAppletInfo>, "GetLibraryAppletInfo"},
|
||||
FunctionInfo{150, nullptr, "RequestForAppletToGetForeground"},
|
||||
FunctionInfo{160, D<&ILibraryAppletAccessor::GetIndirectLayerConsumerHandle>, "GetIndirectLayerConsumerHandle", MakeVersionGate({2,0,0})},
|
||||
FunctionInfo{170, D<&ILibraryAppletAccessor::Unknown170>, "Unknown170", MakeVersionGate({22,0,0})}
|
||||
);
|
||||
return HandlerTableGenerateWithFind(key, functions);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
ILibraryAppletAccessor::ILibraryAppletAccessor(Core::System& system_,
|
||||
std::shared_ptr<AppletDataBroker> broker,
|
||||
std::shared_ptr<Applet> applet)
|
||||
: ServiceFramework{system_, "ILibraryAppletAccessor"}, m_broker{std::move(broker)},
|
||||
m_applet{std::move(applet)} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&ILibraryAppletAccessor::GetAppletStateChangedEvent>, "GetAppletStateChangedEvent"},
|
||||
{1, D<&ILibraryAppletAccessor::IsCompleted>, "IsCompleted"},
|
||||
{10, D<&ILibraryAppletAccessor::Start>, "Start"},
|
||||
{20, D<&ILibraryAppletAccessor::RequestExit>, "RequestExit"},
|
||||
{25, D<&ILibraryAppletAccessor::Terminate>, "Terminate"},
|
||||
{30, D<&ILibraryAppletAccessor::GetResult>, "GetResult"},
|
||||
{50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"},
|
||||
{60, D<&ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero>, "PresetLibraryAppletGpuTimeSliceZero"}, //10.0.0+
|
||||
{80, nullptr, "RequestForLibraryAppletToGetForeground"}, //19.0.0+
|
||||
{81, nullptr, "GetCurrentChildLibraryApplet"}, //19.0.0+
|
||||
{90, D<&ILibraryAppletAccessor::Unknown90>, "Unknown90"}, //20.0.0+
|
||||
{100, D<&ILibraryAppletAccessor::PushInData>, "PushInData"},
|
||||
{101, D<&ILibraryAppletAccessor::PopOutData>, "PopOutData"},
|
||||
{102, nullptr, "PushExtraStorage"},
|
||||
{103, D<&ILibraryAppletAccessor::PushInteractiveInData>, "PushInteractiveInData"},
|
||||
{104, D<&ILibraryAppletAccessor::PopInteractiveOutData>, "PopInteractiveOutData"},
|
||||
{105, D<&ILibraryAppletAccessor::GetPopOutDataEvent>, "GetPopOutDataEvent"},
|
||||
{106, D<&ILibraryAppletAccessor::GetPopInteractiveOutDataEvent>, "GetPopInteractiveOutDataEvent"},
|
||||
{110, nullptr, "NeedsToExitProcess"},
|
||||
{120, D<&ILibraryAppletAccessor::GetLibraryAppletInfo>, "GetLibraryAppletInfo"},
|
||||
{150, nullptr, "RequestForAppletToGetForeground"},
|
||||
{160, D<&ILibraryAppletAccessor::GetIndirectLayerConsumerHandle>, "GetIndirectLayerConsumerHandle"}, //2.0.0+
|
||||
{170, D<&ILibraryAppletAccessor::Unknown170>, "Unknown170"}, //22.0.0+
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
ILibraryAppletAccessor::~ILibraryAppletAccessor() = default;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/am/service/library_applet_self_accessor.h"
|
||||
#include "core/hle/service/cmif_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
@@ -15,26 +16,6 @@ class AppletDataBroker;
|
||||
struct Applet;
|
||||
class IStorage;
|
||||
|
||||
struct LibraryAppletInfo {
|
||||
AppletId applet_id;
|
||||
LibraryAppletMode library_applet_mode;
|
||||
};
|
||||
static_assert(sizeof(LibraryAppletInfo) == 0x8, "LibraryAppletInfo has incorrect size.");
|
||||
|
||||
struct ErrorCode {
|
||||
u32 category;
|
||||
u32 number;
|
||||
};
|
||||
static_assert(sizeof(ErrorCode) == 0x8, "ErrorCode has incorrect size.");
|
||||
|
||||
struct ErrorContext {
|
||||
u8 type;
|
||||
INSERT_PADDING_BYTES_NOINIT(0x7);
|
||||
std::array<u8, 0x1f4> data;
|
||||
Result result;
|
||||
};
|
||||
static_assert(sizeof(ErrorContext) == 0x200, "ErrorContext has incorrect size.");
|
||||
|
||||
class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {
|
||||
public:
|
||||
explicit ILibraryAppletAccessor(Core::System& system_, std::shared_ptr<AppletDataBroker> broker,
|
||||
@@ -68,7 +49,6 @@ private:
|
||||
void FrontendExecuteInteractive();
|
||||
void FrontendRequestExit();
|
||||
|
||||
std::optional<FunctionInfoBase> FindRequest(u32 key) override;
|
||||
const std::shared_ptr<AppletDataBroker> m_broker;
|
||||
const std::shared_ptr<Applet> m_applet;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,287 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "core/hle/kernel/k_transfer_memory.h"
|
||||
#include "core/hle/service/am/applet_data_broker.h"
|
||||
#include "core/hle/service/am/applet_manager.h"
|
||||
#include "core/hle/service/am/frontend/applets.h"
|
||||
#include "core/hle/service/am/library_applet_storage.h"
|
||||
#include "core/hle/service/am/process_creation.h"
|
||||
#include "core/hle/service/am/service/library_applet_accessor.h"
|
||||
#include "core/hle/service/am/service/library_applet_creator.h"
|
||||
|
||||
#include "core/hle/api_version.h"
|
||||
#include "core/hle/service/am/service/storage.h"
|
||||
#include "core/hle/service/am/window_system.h"
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
namespace {
|
||||
|
||||
bool ShouldCreateGuestApplet(AppletId applet_id) {
|
||||
#define X(Name, name) \
|
||||
if (applet_id == AppletId::Name && \
|
||||
Settings::values.name##_applet_mode.GetValue() != Settings::AppletMode::LLE) { \
|
||||
return false; \
|
||||
}
|
||||
|
||||
X(Cabinet, cabinet)
|
||||
X(Controller, controller)
|
||||
X(DataErase, data_erase)
|
||||
X(Error, error)
|
||||
X(NetConnect, net_connect)
|
||||
X(ProfileSelect, player_select)
|
||||
X(SoftwareKeyboard, swkbd)
|
||||
X(MiiEdit, mii_edit)
|
||||
X(Web, web)
|
||||
X(Shop, shop)
|
||||
X(PhotoViewer, photo_viewer)
|
||||
X(OfflineWeb, offline_web)
|
||||
X(LoginShare, login_share)
|
||||
X(WebAuth, wifi_web_auth)
|
||||
X(MyPage, my_page)
|
||||
|
||||
#undef X
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
AppletProgramId AppletIdToProgramId(AppletId applet_id) {
|
||||
switch (applet_id) {
|
||||
case AppletId::OverlayDisplay:
|
||||
return AppletProgramId::OverlayDisplay;
|
||||
case AppletId::QLaunch:
|
||||
return AppletProgramId::QLaunch;
|
||||
case AppletId::Starter:
|
||||
return AppletProgramId::Starter;
|
||||
case AppletId::Auth:
|
||||
return AppletProgramId::Auth;
|
||||
case AppletId::Cabinet:
|
||||
return AppletProgramId::Cabinet;
|
||||
case AppletId::Controller:
|
||||
return AppletProgramId::Controller;
|
||||
case AppletId::DataErase:
|
||||
return AppletProgramId::DataErase;
|
||||
case AppletId::Error:
|
||||
return AppletProgramId::Error;
|
||||
case AppletId::NetConnect:
|
||||
return AppletProgramId::NetConnect;
|
||||
case AppletId::ProfileSelect:
|
||||
return AppletProgramId::ProfileSelect;
|
||||
case AppletId::SoftwareKeyboard:
|
||||
return AppletProgramId::SoftwareKeyboard;
|
||||
case AppletId::MiiEdit:
|
||||
return AppletProgramId::MiiEdit;
|
||||
case AppletId::Web:
|
||||
return AppletProgramId::Web;
|
||||
case AppletId::Shop:
|
||||
return AppletProgramId::Shop;
|
||||
case AppletId::PhotoViewer:
|
||||
return AppletProgramId::PhotoViewer;
|
||||
case AppletId::Settings:
|
||||
return AppletProgramId::Settings;
|
||||
case AppletId::OfflineWeb:
|
||||
return AppletProgramId::OfflineWeb;
|
||||
case AppletId::LoginShare:
|
||||
return AppletProgramId::LoginShare;
|
||||
case AppletId::WebAuth:
|
||||
return AppletProgramId::WebAuth;
|
||||
case AppletId::MyPage:
|
||||
return AppletProgramId::MyPage;
|
||||
default:
|
||||
return static_cast<AppletProgramId>(0);
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system,
|
||||
WindowSystem& window_system,
|
||||
std::shared_ptr<Applet> caller_applet,
|
||||
AppletId applet_id,
|
||||
LibraryAppletMode mode) {
|
||||
const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id));
|
||||
if (program_id == 0) {
|
||||
// Unknown applet
|
||||
return {};
|
||||
}
|
||||
|
||||
auto process = CreateProcess(system, program_id, 1, HLE::ApiVersion::HOS_VERSION_MAJOR);
|
||||
if (process) {
|
||||
const auto applet = std::make_shared<Applet>(system, std::move(process), false);
|
||||
applet->program_id = program_id;
|
||||
applet->applet_id = applet_id;
|
||||
applet->type = AppletType::LibraryApplet;
|
||||
applet->library_applet_mode = mode;
|
||||
applet->window_visible = mode != LibraryAppletMode::AllForegroundInitiallyHidden;
|
||||
|
||||
auto broker = std::make_shared<AppletDataBroker>(system);
|
||||
applet->caller_applet = caller_applet;
|
||||
applet->caller_applet_broker = broker;
|
||||
{
|
||||
std::scoped_lock lk{caller_applet->lock};
|
||||
caller_applet->child_applets.push_back(applet);
|
||||
}
|
||||
window_system.TrackApplet(applet, false);
|
||||
return std::make_shared<ILibraryAppletAccessor>(system, broker, applet);
|
||||
}
|
||||
// Couldn't initialize the guest process
|
||||
return {};
|
||||
}
|
||||
|
||||
std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(Core::System& system,
|
||||
WindowSystem& window_system,
|
||||
std::shared_ptr<Applet> caller_applet,
|
||||
AppletId applet_id,
|
||||
LibraryAppletMode mode) {
|
||||
const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id));
|
||||
|
||||
auto process = std::make_unique<Process>(system);
|
||||
auto applet = std::make_shared<Applet>(system, std::move(process), false);
|
||||
applet->program_id = program_id;
|
||||
applet->applet_id = applet_id;
|
||||
applet->type = AppletType::LibraryApplet;
|
||||
applet->library_applet_mode = mode;
|
||||
|
||||
auto storage = std::make_shared<AppletDataBroker>(system);
|
||||
applet->caller_applet = caller_applet;
|
||||
applet->caller_applet_broker = storage;
|
||||
applet->frontend = system.GetFrontendAppletHolder().GetApplet(applet, applet_id, mode);
|
||||
{
|
||||
std::scoped_lock lk{caller_applet->lock};
|
||||
caller_applet->child_applets.push_back(applet);
|
||||
}
|
||||
return std::make_shared<ILibraryAppletAccessor>(system, storage, applet);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet,
|
||||
WindowSystem& window_system)
|
||||
: ServiceFramework{system_, "ILibraryAppletCreator"},
|
||||
m_window_system{window_system}, m_applet{std::move(applet)} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&ILibraryAppletCreator::CreateLibraryApplet>, "CreateLibraryApplet"},
|
||||
{1, nullptr, "TerminateAllLibraryApplets"},
|
||||
{2, nullptr, "AreAnyLibraryAppletsLeft"},
|
||||
{3, D<&ILibraryAppletCreator::CreateLibraryAppletEx>, "CreateLibraryAppletEx"},
|
||||
{10, D<&ILibraryAppletCreator::CreateStorage>, "CreateStorage"},
|
||||
{11, D<&ILibraryAppletCreator::CreateTransferMemoryStorage>, "CreateTransferMemoryStorage"},
|
||||
{12, D<&ILibraryAppletCreator::CreateHandleStorage>, "CreateHandleStorage"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
ILibraryAppletCreator::~ILibraryAppletCreator() = default;
|
||||
|
||||
Result ILibraryAppletCreator::CreateLibraryApplet(
|
||||
Out<SharedPointer<ILibraryAppletAccessor>> out_library_applet_accessor, AppletId applet_id,
|
||||
LibraryAppletMode library_applet_mode) {
|
||||
LOG_DEBUG(Service_AM, "called with applet_id={} applet_mode={}", applet_id,
|
||||
library_applet_mode);
|
||||
|
||||
std::shared_ptr<ILibraryAppletAccessor> library_applet;
|
||||
if (ShouldCreateGuestApplet(applet_id)) {
|
||||
library_applet =
|
||||
CreateGuestApplet(system, m_window_system, m_applet, applet_id, library_applet_mode);
|
||||
}
|
||||
if (!library_applet) {
|
||||
library_applet =
|
||||
CreateFrontendApplet(system, m_window_system, m_applet, applet_id, library_applet_mode);
|
||||
}
|
||||
if (!library_applet) {
|
||||
LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id);
|
||||
R_THROW(ResultUnknown);
|
||||
}
|
||||
|
||||
// Applet is created, can now be launched.
|
||||
m_applet->library_applet_launchable_event.Signal(system.Kernel());
|
||||
*out_library_applet_accessor = library_applet;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletCreator::CreateLibraryAppletEx(
|
||||
Out<SharedPointer<ILibraryAppletAccessor>> out_library_applet_accessor, AppletId applet_id,
|
||||
LibraryAppletMode library_applet_mode, u64 thread_id) {
|
||||
LOG_DEBUG(Service_AM, "called with applet_id={} applet_mode={} thread_id={}", applet_id,
|
||||
library_applet_mode, thread_id);
|
||||
|
||||
std::shared_ptr<ILibraryAppletAccessor> library_applet;
|
||||
if (ShouldCreateGuestApplet(applet_id)) {
|
||||
library_applet =
|
||||
CreateGuestApplet(system, m_window_system, m_applet, applet_id, library_applet_mode);
|
||||
}
|
||||
if (!library_applet) {
|
||||
library_applet =
|
||||
CreateFrontendApplet(system, m_window_system, m_applet, applet_id, library_applet_mode);
|
||||
}
|
||||
if (!library_applet) {
|
||||
LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id);
|
||||
R_THROW(ResultUnknown);
|
||||
}
|
||||
|
||||
// Applet is created, can now be launched.
|
||||
m_applet->library_applet_launchable_event.Signal(system.Kernel());
|
||||
*out_library_applet_accessor = library_applet;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletCreator::CreateStorage(Out<SharedPointer<IStorage>> out_storage, s64 size) {
|
||||
LOG_DEBUG(Service_AM, "called, size={}", size);
|
||||
|
||||
if (size <= 0) {
|
||||
LOG_ERROR(Service_AM, "size is less than or equal to 0");
|
||||
R_THROW(ResultUnknown);
|
||||
}
|
||||
|
||||
*out_storage = std::make_shared<IStorage>(system, AM::CreateStorage(std::vector<u8>(size)));
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletCreator::CreateTransferMemoryStorage(
|
||||
Out<SharedPointer<IStorage>> out_storage, bool is_writable, s64 size,
|
||||
InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle) {
|
||||
LOG_DEBUG(Service_AM, "called, is_writable={} size={}", is_writable, size);
|
||||
|
||||
if (size <= 0) {
|
||||
LOG_ERROR(Service_AM, "size is less than or equal to 0");
|
||||
R_THROW(ResultUnknown);
|
||||
}
|
||||
|
||||
if (!transfer_memory_handle) {
|
||||
LOG_ERROR(Service_AM, "transfer_memory_handle is null");
|
||||
R_THROW(ResultUnknown);
|
||||
}
|
||||
|
||||
*out_storage = std::make_shared<IStorage>(
|
||||
system, AM::CreateTransferMemoryStorage(system.Kernel(), transfer_memory_handle->GetOwner()->GetMemory(),
|
||||
transfer_memory_handle.Get(), is_writable, size));
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletCreator::CreateHandleStorage(
|
||||
Out<SharedPointer<IStorage>> out_storage, s64 size,
|
||||
InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle) {
|
||||
LOG_DEBUG(Service_AM, "called, size={}", size);
|
||||
|
||||
if (size <= 0) {
|
||||
LOG_ERROR(Service_AM, "size is less than or equal to 0");
|
||||
R_THROW(ResultUnknown);
|
||||
}
|
||||
|
||||
if (!transfer_memory_handle) {
|
||||
LOG_ERROR(Service_AM, "transfer_memory_handle is null");
|
||||
R_THROW(ResultUnknown);
|
||||
}
|
||||
|
||||
*out_storage = std::make_shared<IStorage>(
|
||||
system, AM::CreateHandleStorage(system.Kernel(), transfer_memory_handle->GetOwner()->GetMemory(),
|
||||
transfer_memory_handle.Get(), size));
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
@@ -0,0 +1,44 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/am/am_types.h"
|
||||
#include "core/hle/service/cmif_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
struct Applet;
|
||||
class ILibraryAppletAccessor;
|
||||
class IStorage;
|
||||
class WindowSystem;
|
||||
|
||||
class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
|
||||
public:
|
||||
explicit ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet,
|
||||
WindowSystem& window_system);
|
||||
~ILibraryAppletCreator() override;
|
||||
|
||||
private:
|
||||
Result CreateLibraryApplet(
|
||||
Out<SharedPointer<ILibraryAppletAccessor>> out_library_applet_accessor, AppletId applet_id,
|
||||
LibraryAppletMode library_applet_mode);
|
||||
Result CreateLibraryAppletEx(
|
||||
Out<SharedPointer<ILibraryAppletAccessor>> out_library_applet_accessor, AppletId applet_id,
|
||||
LibraryAppletMode library_applet_mode, u64 thread_id);
|
||||
Result CreateStorage(Out<SharedPointer<IStorage>> out_storage, s64 size);
|
||||
Result CreateTransferMemoryStorage(
|
||||
Out<SharedPointer<IStorage>> out_storage, bool is_writable, s64 size,
|
||||
InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle);
|
||||
Result CreateHandleStorage(Out<SharedPointer<IStorage>> out_storage, s64 size,
|
||||
InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle);
|
||||
|
||||
WindowSystem& m_window_system;
|
||||
const std::shared_ptr<Applet> m_applet;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
||||
@@ -0,0 +1,137 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/am/service/applet_common_functions.h"
|
||||
#include "core/hle/service/am/service/audio_controller.h"
|
||||
#include "core/hle/service/am/service/common_state_getter.h"
|
||||
#include "core/hle/service/am/service/debug_functions.h"
|
||||
#include "core/hle/service/am/service/display_controller.h"
|
||||
#include "core/hle/service/am/service/global_state_controller.h"
|
||||
#include "core/hle/service/am/service/home_menu_functions.h"
|
||||
#include "core/hle/service/am/service/library_applet_creator.h"
|
||||
#include "core/hle/service/am/service/library_applet_proxy.h"
|
||||
#include "core/hle/service/am/service/library_applet_self_accessor.h"
|
||||
#include "core/hle/service/am/service/process_winding_controller.h"
|
||||
#include "core/hle/service/am/service/self_controller.h"
|
||||
#include "core/hle/service/am/service/window_controller.h"
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
ILibraryAppletProxy::ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
|
||||
Kernel::KProcess* process, WindowSystem& window_system)
|
||||
: ServiceFramework{system_, "ILibraryAppletProxy"},
|
||||
m_window_system{window_system}, m_process{process}, m_applet{std::move(applet)} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&ILibraryAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
|
||||
{1, D<&ILibraryAppletProxy::GetSelfController>, "GetSelfController"},
|
||||
{2, D<&ILibraryAppletProxy::GetWindowController>, "GetWindowController"},
|
||||
{3, D<&ILibraryAppletProxy::GetAudioController>, "GetAudioController"},
|
||||
{4, D<&ILibraryAppletProxy::GetDisplayController>, "GetDisplayController"},
|
||||
{10, D<&ILibraryAppletProxy::GetProcessWindingController>, "GetProcessWindingController"},
|
||||
{11, D<&ILibraryAppletProxy::GetLibraryAppletCreator>, "GetLibraryAppletCreator"},
|
||||
{20, D<&ILibraryAppletProxy::OpenLibraryAppletSelfAccessor>, "OpenLibraryAppletSelfAccessor"},
|
||||
{21, D<&ILibraryAppletProxy::GetAppletCommonFunctions>, "GetAppletCommonFunctions"},
|
||||
{22, D<&ILibraryAppletProxy::GetHomeMenuFunctions>, "GetHomeMenuFunctions"},
|
||||
{23, D<&ILibraryAppletProxy::GetGlobalStateController>, "GetGlobalStateController"},
|
||||
{1000, D<&ILibraryAppletProxy::GetDebugFunctions>, "GetDebugFunctions"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
ILibraryAppletProxy::~ILibraryAppletProxy() = default;
|
||||
|
||||
Result ILibraryAppletProxy::GetAudioController(
|
||||
Out<SharedPointer<IAudioController>> out_audio_controller) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_audio_controller = std::make_shared<IAudioController>(system);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletProxy::GetDisplayController(
|
||||
Out<SharedPointer<IDisplayController>> out_display_controller) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_display_controller = std::make_shared<IDisplayController>(system, m_applet);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletProxy::GetProcessWindingController(
|
||||
Out<SharedPointer<IProcessWindingController>> out_process_winding_controller) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_process_winding_controller = std::make_shared<IProcessWindingController>(system, m_applet);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletProxy::GetDebugFunctions(
|
||||
Out<SharedPointer<IDebugFunctions>> out_debug_functions) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_debug_functions = std::make_shared<IDebugFunctions>(system);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletProxy::GetWindowController(
|
||||
Out<SharedPointer<IWindowController>> out_window_controller) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_window_controller = std::make_shared<IWindowController>(system, m_applet, m_window_system);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletProxy::GetSelfController(
|
||||
Out<SharedPointer<ISelfController>> out_self_controller) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_self_controller = std::make_shared<ISelfController>(system, m_applet, m_process);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletProxy::GetCommonStateGetter(
|
||||
Out<SharedPointer<ICommonStateGetter>> out_common_state_getter) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_common_state_getter = std::make_shared<ICommonStateGetter>(system, m_applet);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletProxy::GetLibraryAppletCreator(
|
||||
Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_library_applet_creator =
|
||||
std::make_shared<ILibraryAppletCreator>(system, m_applet, m_window_system);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletProxy::OpenLibraryAppletSelfAccessor(
|
||||
Out<SharedPointer<ILibraryAppletSelfAccessor>> out_library_applet_self_accessor) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_library_applet_self_accessor =
|
||||
std::make_shared<ILibraryAppletSelfAccessor>(system, m_applet);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletProxy::GetAppletCommonFunctions(
|
||||
Out<SharedPointer<IAppletCommonFunctions>> out_applet_common_functions) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_applet_common_functions = std::make_shared<IAppletCommonFunctions>(system, m_applet);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletProxy::GetHomeMenuFunctions(
|
||||
Out<SharedPointer<IHomeMenuFunctions>> out_home_menu_functions) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_home_menu_functions =
|
||||
std::make_shared<IHomeMenuFunctions>(system, m_applet, m_window_system);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletProxy::GetGlobalStateController(
|
||||
Out<SharedPointer<IGlobalStateController>> out_global_state_controller) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_global_state_controller = std::make_shared<IGlobalStateController>(system);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
@@ -0,0 +1,59 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/cmif_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
struct Applet;
|
||||
class IAppletCommonFunctions;
|
||||
class IAudioController;
|
||||
class ICommonStateGetter;
|
||||
class IDebugFunctions;
|
||||
class IDisplayController;
|
||||
class IHomeMenuFunctions;
|
||||
class IGlobalStateController;
|
||||
class ILibraryAppletCreator;
|
||||
class ILibraryAppletSelfAccessor;
|
||||
class IProcessWindingController;
|
||||
class ISelfController;
|
||||
class IWindowController;
|
||||
class WindowSystem;
|
||||
|
||||
class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
|
||||
public:
|
||||
explicit ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
|
||||
Kernel::KProcess* process, WindowSystem& window_system);
|
||||
~ILibraryAppletProxy();
|
||||
|
||||
private:
|
||||
Result GetAudioController(Out<SharedPointer<IAudioController>> out_audio_controller);
|
||||
Result GetDisplayController(Out<SharedPointer<IDisplayController>> out_display_controller);
|
||||
Result GetProcessWindingController(
|
||||
Out<SharedPointer<IProcessWindingController>> out_process_winding_controller);
|
||||
Result GetDebugFunctions(Out<SharedPointer<IDebugFunctions>> out_debug_functions);
|
||||
Result GetWindowController(Out<SharedPointer<IWindowController>> out_window_controller);
|
||||
Result GetSelfController(Out<SharedPointer<ISelfController>> out_self_controller);
|
||||
Result GetCommonStateGetter(Out<SharedPointer<ICommonStateGetter>> out_common_state_getter);
|
||||
Result GetLibraryAppletCreator(
|
||||
Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator);
|
||||
Result OpenLibraryAppletSelfAccessor(
|
||||
Out<SharedPointer<ILibraryAppletSelfAccessor>> out_library_applet_self_accessor);
|
||||
Result GetAppletCommonFunctions(
|
||||
Out<SharedPointer<IAppletCommonFunctions>> out_applet_common_functions);
|
||||
Result GetHomeMenuFunctions(Out<SharedPointer<IHomeMenuFunctions>> out_home_menu_functions);
|
||||
Result GetGlobalStateController(
|
||||
Out<SharedPointer<IGlobalStateController>> out_global_state_controller);
|
||||
|
||||
WindowSystem& m_window_system;
|
||||
Kernel::KProcess* const m_process;
|
||||
const std::shared_ptr<Applet> m_applet;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
||||
@@ -0,0 +1,332 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/core_timing.h"
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "core/hle/service/acc/profile_manager.h"
|
||||
#include "core/hle/service/am/applet_data_broker.h"
|
||||
#include "core/hle/service/am/applet_manager.h"
|
||||
#include "core/hle/service/am/frontend/applets.h"
|
||||
#include "core/hle/service/am/service/library_applet_self_accessor.h"
|
||||
#include "core/hle/service/am/service/storage.h"
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/hle/service/glue/glue_manager.h"
|
||||
#include "core/hle/service/ns/application_manager_interface.h"
|
||||
#include "core/hle/service/ns/service_getter_interface.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
namespace {
|
||||
|
||||
AppletIdentityInfo GetCallerIdentity(Applet& applet) {
|
||||
if (const auto caller_applet = applet.caller_applet.lock(); caller_applet) {
|
||||
// TODO: is this actually the application ID?
|
||||
return {
|
||||
.applet_id = caller_applet->applet_id,
|
||||
.application_id = caller_applet->program_id,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
.applet_id = AppletId::QLaunch,
|
||||
.application_id = 0x0100000000001000ull,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_,
|
||||
std::shared_ptr<Applet> applet)
|
||||
: ServiceFramework{system_, "ILibraryAppletSelfAccessor"}, m_applet{std::move(applet)},
|
||||
m_broker{m_applet->caller_applet_broker} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&ILibraryAppletSelfAccessor::PopInData>, "PopInData"},
|
||||
{1, D<&ILibraryAppletSelfAccessor::PushOutData>, "PushOutData"},
|
||||
{2, D<&ILibraryAppletSelfAccessor::PopInteractiveInData>, "PopInteractiveInData"},
|
||||
{3, D<&ILibraryAppletSelfAccessor::PushInteractiveOutData>, "PushInteractiveOutData"},
|
||||
{5, D<&ILibraryAppletSelfAccessor::GetPopInDataEvent>, "GetPopInDataEvent"},
|
||||
{6, D<&ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent>, "GetPopInteractiveInDataEvent"},
|
||||
{10, D<&ILibraryAppletSelfAccessor::ExitProcessAndReturn>, "ExitProcessAndReturn"},
|
||||
{11, D<&ILibraryAppletSelfAccessor::GetLibraryAppletInfo>, "GetLibraryAppletInfo"},
|
||||
{12, D<&ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo>, "GetMainAppletIdentityInfo"},
|
||||
{13, D<&ILibraryAppletSelfAccessor::CanUseApplicationCore>, "CanUseApplicationCore"},
|
||||
{14, D<&ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo>, "GetCallerAppletIdentityInfo"},
|
||||
{15, D<&ILibraryAppletSelfAccessor::GetMainAppletApplicationControlProperty>, "GetMainAppletApplicationControlProperty"},
|
||||
{16, D<&ILibraryAppletSelfAccessor::GetMainAppletStorageId>, "GetMainAppletStorageId"},
|
||||
{17, D<&ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfoStack>, "GetCallerAppletIdentityInfoStack"},
|
||||
{18, nullptr, "GetNextReturnDestinationAppletIdentityInfo"},
|
||||
{19, D<&ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout>, "GetDesirableKeyboardLayout"},
|
||||
{20, nullptr, "PopExtraStorage"},
|
||||
{25, nullptr, "GetPopExtraStorageEvent"},
|
||||
{30, D<&ILibraryAppletSelfAccessor::UnpopInData>, "UnpopInData"},
|
||||
{31, nullptr, "UnpopExtraStorage"},
|
||||
{40, nullptr, "GetIndirectLayerProducerHandle"},
|
||||
{50, D<&ILibraryAppletSelfAccessor::ReportVisibleError>, "ReportVisibleError"},
|
||||
{51, D<&ILibraryAppletSelfAccessor::ReportVisibleErrorWithErrorContext>, "ReportVisibleErrorWithErrorContext"},
|
||||
{60, D<&ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage>, "GetMainAppletApplicationDesiredLanguage"},
|
||||
{70, D<&ILibraryAppletSelfAccessor::GetCurrentApplicationId>, "GetCurrentApplicationId"},
|
||||
{80, nullptr, "RequestExitToSelf"},
|
||||
{90, nullptr, "CreateApplicationAndPushAndRequestToLaunch"},
|
||||
{100, nullptr, "CreateGameMovieTrimmer"},
|
||||
{101, nullptr, "ReserveResourceForMovieOperation"},
|
||||
{102, nullptr, "UnreserveResourceForMovieOperation"},
|
||||
{110, D<&ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers>, "GetMainAppletAvailableUsers"},
|
||||
{120, nullptr, "GetLaunchStorageInfoForDebug"},
|
||||
{130, nullptr, "GetGpuErrorDetectedSystemEvent"},
|
||||
{140, nullptr, "SetApplicationMemoryReservation"},
|
||||
{150, D<&ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually>, "ShouldSetGpuTimeSliceManually"},
|
||||
{160, D<&ILibraryAppletSelfAccessor::GetLibraryAppletInfoEx>, "GetLibraryAppletInfoEx"},
|
||||
};
|
||||
// clang-format on
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default;
|
||||
|
||||
Result ILibraryAppletSelfAccessor::PopInData(Out<SharedPointer<IStorage>> out_storage) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
R_RETURN(m_broker->GetInData().Pop(system.Kernel(), out_storage));
|
||||
}
|
||||
|
||||
Result ILibraryAppletSelfAccessor::PushOutData(SharedPointer<IStorage> storage) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
m_broker->GetOutData().Push(system.Kernel(), storage);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletSelfAccessor::PopInteractiveInData(Out<SharedPointer<IStorage>> out_storage) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
R_RETURN(m_broker->GetInteractiveInData().Pop(system.Kernel(), out_storage));
|
||||
}
|
||||
|
||||
Result ILibraryAppletSelfAccessor::PushInteractiveOutData(SharedPointer<IStorage> storage) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
m_broker->GetInteractiveOutData().Push(system.Kernel(), storage);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletSelfAccessor::GetPopInDataEvent(
|
||||
OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
*out_event = m_broker->GetInData().GetEvent();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent(
|
||||
OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
*out_event = m_broker->GetInteractiveInData().GetEvent();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletSelfAccessor::GetLibraryAppletInfo(
|
||||
Out<LibraryAppletInfo> out_library_applet_info) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
*out_library_applet_info = {
|
||||
.applet_id = m_applet->applet_id,
|
||||
.library_applet_mode = m_applet->library_applet_mode,
|
||||
};
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(
|
||||
Out<AppletIdentityInfo> out_identity_info) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
*out_identity_info = {
|
||||
.applet_id = AppletId::QLaunch,
|
||||
.application_id = 0x0100000000001000ull,
|
||||
};
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletSelfAccessor::CanUseApplicationCore(Out<bool> out_can_use_application_core) {
|
||||
// TODO: This appears to read the NPDM from state and check the core mask of the applet.
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
*out_can_use_application_core = false;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletSelfAccessor::GetMainAppletApplicationControlProperty(
|
||||
OutLargeData<std::array<u8, 0x4000>, BufferAttr_HipcMapAlias> out_nacp) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
// TODO: this should be the main applet, not the caller applet
|
||||
const auto application = GetCallerIdentity(*m_applet);
|
||||
std::vector<u8> nacp;
|
||||
const auto result =
|
||||
system.GetARPManager().GetControlProperty(&nacp, application.application_id);
|
||||
|
||||
if (R_SUCCEEDED(result)) {
|
||||
std::memcpy(out_nacp->data(), nacp.data(), (std::min)(nacp.size(), out_nacp->size()));
|
||||
}
|
||||
|
||||
R_RETURN(result);
|
||||
}
|
||||
|
||||
Result ILibraryAppletSelfAccessor::GetMainAppletStorageId(Out<FileSys::StorageId> out_storage_id) {
|
||||
LOG_INFO(Service_AM, "(STUBBED) called");
|
||||
*out_storage_id = FileSys::StorageId::NandUser;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletSelfAccessor::ExitProcessAndReturn() {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
if (const auto caller_applet = m_applet->caller_applet.lock(); caller_applet) {
|
||||
m_applet->process->Terminate();
|
||||
} else {
|
||||
system.GetUserChannel() = m_applet->user_channel_launch_parameter;
|
||||
system.ExecuteProgram(0);
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(
|
||||
Out<AppletIdentityInfo> out_identity_info) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
*out_identity_info = GetCallerIdentity(*m_applet);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfoStack(
|
||||
Out<s32> out_count, OutArray<AppletIdentityInfo, BufferAttr_HipcMapAlias> out_identity_info) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
std::shared_ptr<Applet> applet = m_applet;
|
||||
*out_count = 0;
|
||||
|
||||
do {
|
||||
if (*out_count >= static_cast<s32>(out_identity_info.size())) {
|
||||
break;
|
||||
}
|
||||
out_identity_info[(*out_count)++] = GetCallerIdentity(*applet);
|
||||
} while ((applet = applet->caller_applet.lock()));
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout(Out<u32> out_desirable_layout) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
*out_desirable_layout = 0;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletSelfAccessor::ReportVisibleError(ErrorCode error_code) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, error {}-{}", error_code.category,
|
||||
error_code.number);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletSelfAccessor::ReportVisibleErrorWithErrorContext(
|
||||
ErrorCode error_code, InLargeData<ErrorContext, BufferAttr_HipcMapAlias> error_context) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called, error {}-{}", error_code.category,
|
||||
error_code.number);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletSelfAccessor::UnpopInData(SharedPointer<IStorage> storage) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
m_broker->GetInData().Unpop(system.Kernel(), storage);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage(
|
||||
Out<u64> out_desired_language) {
|
||||
// FIXME: this is copied from IApplicationFunctions::GetDesiredLanguage
|
||||
// FIXME: all of this stuff belongs to ns
|
||||
auto identity = GetCallerIdentity(*m_applet);
|
||||
|
||||
// TODO(bunnei): This should be configurable
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
|
||||
// Get supported languages from NACP, if possible
|
||||
// Default to 0 (all languages supported)
|
||||
u32 supported_languages = 0;
|
||||
|
||||
const auto res = FileSys::PatchManager::GetMetadataFromBaseOrUpdate(system, identity.application_id);
|
||||
|
||||
if (res.first != nullptr) {
|
||||
supported_languages = res.first->GetSupportedLanguages();
|
||||
}
|
||||
|
||||
// Call IApplicationManagerInterface implementation.
|
||||
auto& service_manager = system.ServiceManager();
|
||||
auto ns_am2 = service_manager.GetService<NS::IServiceGetterInterface>("ns:am2");
|
||||
|
||||
std::shared_ptr<NS::IApplicationManagerInterface> app_man;
|
||||
R_TRY(ns_am2->GetApplicationManagerInterface(&app_man));
|
||||
|
||||
// Get desired application language
|
||||
NS::ApplicationLanguage desired_language{};
|
||||
R_TRY(app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages));
|
||||
|
||||
// Convert to settings language code.
|
||||
u64 language_code{};
|
||||
R_TRY(app_man->ConvertApplicationLanguageToLanguageCode(&language_code, desired_language));
|
||||
|
||||
LOG_DEBUG(Service_AM, "got desired_language={:016X}", language_code);
|
||||
|
||||
*out_desired_language = language_code;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletSelfAccessor::GetCurrentApplicationId(Out<u64> out_application_id) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
|
||||
// TODO: this should be the main applet, not the caller applet
|
||||
const auto main_applet = GetCallerIdentity(*m_applet);
|
||||
*out_application_id = main_applet.application_id;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers(
|
||||
Out<bool> out_can_select_any_user, Out<s32> out_users_count,
|
||||
OutArray<Common::UUID, BufferAttr_HipcMapAlias> out_users) {
|
||||
const Service::Account::ProfileManager manager{};
|
||||
|
||||
*out_can_select_any_user = false;
|
||||
*out_users_count = -1;
|
||||
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
if (manager.GetUserCount() > 0) {
|
||||
*out_can_select_any_user = true;
|
||||
*out_users_count = static_cast<s32>(manager.GetUserCount());
|
||||
|
||||
const auto users = manager.GetAllUsers();
|
||||
for (size_t i = 0; i < users.size() && i < out_users.size(); i++) {
|
||||
out_users[i] = users[i];
|
||||
}
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually(
|
||||
Out<bool> out_should_set_gpu_time_slice_manually) {
|
||||
LOG_INFO(Service_AM, "(STUBBED) called");
|
||||
*out_should_set_gpu_time_slice_manually = false;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILibraryAppletSelfAccessor::GetLibraryAppletInfoEx(
|
||||
Out<LibraryAppletInfo> out_library_applet_info) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
*out_library_applet_info = {
|
||||
.applet_id = m_applet->applet_id,
|
||||
.library_applet_mode = m_applet->library_applet_mode,
|
||||
};
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
@@ -0,0 +1,87 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/uuid.h"
|
||||
#include "core/hle/service/am/am_types.h"
|
||||
#include "core/hle/service/cmif_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace FileSys {
|
||||
enum class StorageId : u8;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
class KReadableEvent;
|
||||
}
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class AppletDataBroker;
|
||||
struct Applet;
|
||||
class IStorage;
|
||||
|
||||
struct LibraryAppletInfo {
|
||||
AppletId applet_id;
|
||||
LibraryAppletMode library_applet_mode;
|
||||
};
|
||||
static_assert(sizeof(LibraryAppletInfo) == 0x8, "LibraryAppletInfo has incorrect size.");
|
||||
|
||||
struct ErrorCode {
|
||||
u32 category;
|
||||
u32 number;
|
||||
};
|
||||
static_assert(sizeof(ErrorCode) == 0x8, "ErrorCode has incorrect size.");
|
||||
|
||||
struct ErrorContext {
|
||||
u8 type;
|
||||
INSERT_PADDING_BYTES_NOINIT(0x7);
|
||||
std::array<u8, 0x1f4> data;
|
||||
Result result;
|
||||
};
|
||||
static_assert(sizeof(ErrorContext) == 0x200, "ErrorContext has incorrect size.");
|
||||
|
||||
class ILibraryAppletSelfAccessor final : public ServiceFramework<ILibraryAppletSelfAccessor> {
|
||||
public:
|
||||
explicit ILibraryAppletSelfAccessor(Core::System& system_, std::shared_ptr<Applet> applet);
|
||||
~ILibraryAppletSelfAccessor() override;
|
||||
|
||||
private:
|
||||
Result PopInData(Out<SharedPointer<IStorage>> out_storage);
|
||||
Result PushOutData(SharedPointer<IStorage> storage);
|
||||
Result PopInteractiveInData(Out<SharedPointer<IStorage>> out_storage);
|
||||
Result PushInteractiveOutData(SharedPointer<IStorage> storage);
|
||||
Result GetPopInDataEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result GetPopInteractiveInDataEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result GetLibraryAppletInfo(Out<LibraryAppletInfo> out_library_applet_info);
|
||||
Result GetMainAppletIdentityInfo(Out<AppletIdentityInfo> out_identity_info);
|
||||
Result CanUseApplicationCore(Out<bool> out_can_use_application_core);
|
||||
Result GetMainAppletApplicationControlProperty(
|
||||
OutLargeData<std::array<u8, 0x4000>, BufferAttr_HipcMapAlias> out_nacp);
|
||||
Result GetMainAppletStorageId(Out<FileSys::StorageId> out_storage_id);
|
||||
Result ExitProcessAndReturn();
|
||||
Result GetCallerAppletIdentityInfo(Out<AppletIdentityInfo> out_identity_info);
|
||||
Result GetCallerAppletIdentityInfoStack(
|
||||
Out<s32> out_count,
|
||||
OutArray<AppletIdentityInfo, BufferAttr_HipcMapAlias> out_identity_info);
|
||||
Result GetDesirableKeyboardLayout(Out<u32> out_desirable_layout);
|
||||
Result ReportVisibleError(ErrorCode error_code);
|
||||
Result ReportVisibleErrorWithErrorContext(
|
||||
ErrorCode error_code, InLargeData<ErrorContext, BufferAttr_HipcMapAlias> error_context);
|
||||
Result UnpopInData(SharedPointer<IStorage> storage);
|
||||
Result GetMainAppletApplicationDesiredLanguage(Out<u64> out_desired_language);
|
||||
Result GetCurrentApplicationId(Out<u64> out_application_id);
|
||||
Result GetMainAppletAvailableUsers(Out<bool> out_can_select_any_user, Out<s32> out_users_count,
|
||||
OutArray<Common::UUID, BufferAttr_HipcMapAlias> out_users);
|
||||
Result ShouldSetGpuTimeSliceManually(Out<bool> out_should_set_gpu_time_slice_manually);
|
||||
Result GetLibraryAppletInfoEx(Out<LibraryAppletInfo> out_library_applet_info);
|
||||
|
||||
const std::shared_ptr<Applet> m_applet;
|
||||
const std::shared_ptr<AppletDataBroker> m_broker;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
||||
@@ -0,0 +1,78 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/service/am/service/lock_accessor.h"
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
ILockAccessor::ILockAccessor(Core::System& system_)
|
||||
: ServiceFramework{system_, "ILockAccessor"}, m_context{system_, "ILockAccessor"},
|
||||
m_event{m_context} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{1, D<&ILockAccessor::TryLock>, "TryLock"},
|
||||
{2, D<&ILockAccessor::Unlock>, "Unlock"},
|
||||
{3, D<&ILockAccessor::GetEvent>, "GetEvent"},
|
||||
{4, D<&ILockAccessor::IsLocked>, "IsLocked"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
|
||||
m_event.Signal(system.Kernel());
|
||||
}
|
||||
|
||||
ILockAccessor::~ILockAccessor() = default;
|
||||
|
||||
Result ILockAccessor::TryLock(Out<bool> out_is_locked,
|
||||
OutCopyHandle<Kernel::KReadableEvent> out_handle,
|
||||
bool return_handle) {
|
||||
LOG_INFO(Service_AM, "called, return_handle={}", return_handle);
|
||||
|
||||
{
|
||||
std::scoped_lock lk{m_mutex};
|
||||
if (m_is_locked) {
|
||||
*out_is_locked = false;
|
||||
} else {
|
||||
m_is_locked = true;
|
||||
*out_is_locked = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (return_handle) {
|
||||
*out_handle = m_event.GetHandle();
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILockAccessor::Unlock() {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
|
||||
{
|
||||
std::scoped_lock lk{m_mutex};
|
||||
m_is_locked = false;
|
||||
}
|
||||
|
||||
m_event.Signal(system.Kernel());
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILockAccessor::GetEvent(OutCopyHandle<Kernel::KReadableEvent> out_handle) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
*out_handle = m_event.GetHandle();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ILockAccessor::IsLocked(Out<bool> out_is_locked) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
std::scoped_lock lk{m_mutex};
|
||||
*out_is_locked = m_is_locked;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
@@ -0,0 +1,35 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/cmif_types.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/os/event.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class ILockAccessor final : public ServiceFramework<ILockAccessor> {
|
||||
public:
|
||||
explicit ILockAccessor(Core::System& system_);
|
||||
~ILockAccessor() override;
|
||||
|
||||
private:
|
||||
Result TryLock(Out<bool> out_is_locked, OutCopyHandle<Kernel::KReadableEvent> out_handle,
|
||||
bool return_handle);
|
||||
Result Unlock();
|
||||
Result GetEvent(OutCopyHandle<Kernel::KReadableEvent> out_handle);
|
||||
Result IsLocked(Out<bool> out_is_locked);
|
||||
|
||||
private:
|
||||
KernelHelpers::ServiceContext m_context;
|
||||
Event m_event;
|
||||
std::mutex m_mutex{};
|
||||
bool m_is_locked{};
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
||||
@@ -0,0 +1,120 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "core/hle/service/am/service/common_state_getter.h"
|
||||
#include "core/hle/service/am/service/display_controller.h"
|
||||
#include "core/hle/service/am/service/global_state_controller.h"
|
||||
#include "core/hle/service/am/service/audio_controller.h"
|
||||
#include "core/hle/service/am/service/applet_common_functions.h"
|
||||
#include "core/hle/service/am/service/overlay_applet_proxy.h"
|
||||
#include "core/hle/service/am/service/library_applet_creator.h"
|
||||
#include "core/hle/service/am/service/process_winding_controller.h"
|
||||
#include "core/hle/service/am/service/self_controller.h"
|
||||
#include "core/hle/service/am/service/window_controller.h"
|
||||
#include "core/hle/service/am/service/debug_functions.h"
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
|
||||
namespace Service::AM {
|
||||
IOverlayAppletProxy::IOverlayAppletProxy(Core::System &system_, std::shared_ptr<Applet> applet,
|
||||
Kernel::KProcess *process, WindowSystem &window_system)
|
||||
: ServiceFramework{system_, "IOverlayAppletProxy"},
|
||||
m_window_system{window_system}, m_process{process}, m_applet{std::move(applet)} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&IOverlayAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
|
||||
{1, D<&IOverlayAppletProxy::GetSelfController>, "GetSelfController"},
|
||||
{2, D<&IOverlayAppletProxy::GetWindowController>, "GetWindowController"},
|
||||
{3, D<&IOverlayAppletProxy::GetAudioController>, "GetAudioController"},
|
||||
{4, D<&IOverlayAppletProxy::GetDisplayController>, "GetDisplayController"},
|
||||
{10, D<&IOverlayAppletProxy::GetProcessWindingController>, "GetProcessWindingController"},
|
||||
{11, D<&IOverlayAppletProxy::GetLibraryAppletCreator>, "GetLibraryAppletCreator"},
|
||||
{20, D<&IOverlayAppletProxy::GetOverlayFunctions>, "GetOverlayFunctions"},
|
||||
{21, D<&IOverlayAppletProxy::GetAppletCommonFunctions>, "GetAppletCommonFunctions"},
|
||||
{23, D<&IOverlayAppletProxy::GetGlobalStateController>, "GetGlobalStateController"},
|
||||
{1000, D<&IOverlayAppletProxy::GetDebugFunctions>, "GetDebugFunctions"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IOverlayAppletProxy::~IOverlayAppletProxy() = default;
|
||||
|
||||
Result IOverlayAppletProxy::GetCommonStateGetter(
|
||||
Out<SharedPointer<ICommonStateGetter> > out_common_state_getter) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_common_state_getter = std::make_shared<ICommonStateGetter>(system, m_applet);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IOverlayAppletProxy::GetSelfController(
|
||||
Out<SharedPointer<ISelfController> > out_self_controller) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_self_controller = std::make_shared<ISelfController>(system, m_applet, m_process);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IOverlayAppletProxy::GetWindowController(
|
||||
Out<SharedPointer<IWindowController> > out_window_controller) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_window_controller = std::make_shared<IWindowController>(system, m_applet, m_window_system);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IOverlayAppletProxy::GetAudioController(
|
||||
Out<SharedPointer<IAudioController> > out_audio_controller) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_audio_controller = std::make_shared<IAudioController>(system);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IOverlayAppletProxy::GetDisplayController(
|
||||
Out<SharedPointer<IDisplayController> > out_display_controller) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_display_controller = std::make_shared<IDisplayController>(system, m_applet);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IOverlayAppletProxy::GetProcessWindingController(
|
||||
Out<SharedPointer<IProcessWindingController> > out_process_winding_controller) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_process_winding_controller = std::make_shared<IProcessWindingController>(system, m_applet);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IOverlayAppletProxy::GetLibraryAppletCreator(
|
||||
Out<SharedPointer<ILibraryAppletCreator> > out_library_applet_creator) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_library_applet_creator =
|
||||
std::make_shared<ILibraryAppletCreator>(system, m_applet, m_window_system);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IOverlayAppletProxy::GetOverlayFunctions(
|
||||
Out<SharedPointer<IOverlayFunctions> > out_overlay_functions) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_overlay_functions = std::make_shared<IOverlayFunctions>(system, m_applet);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IOverlayAppletProxy::GetAppletCommonFunctions(
|
||||
Out<SharedPointer<IAppletCommonFunctions> > out_applet_common_functions) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_applet_common_functions = std::make_shared<IAppletCommonFunctions>(system, m_applet);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IOverlayAppletProxy::GetGlobalStateController(
|
||||
Out<SharedPointer<IGlobalStateController> > out_global_state_controller) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_global_state_controller = std::make_shared<IGlobalStateController>(system);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IOverlayAppletProxy::GetDebugFunctions(
|
||||
Out<SharedPointer<IDebugFunctions> > out_debug_functions) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_debug_functions = std::make_shared<IDebugFunctions>(system);
|
||||
R_SUCCEED();
|
||||
}
|
||||
} // namespace Service::AM
|
||||
@@ -0,0 +1,55 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/cmif_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/am/service/overlay_functions.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
struct Applet;
|
||||
class IAppletCommonFunctions;
|
||||
class IAudioController;
|
||||
class ICommonStateGetter;
|
||||
class IDebugFunctions;
|
||||
class IDisplayController;
|
||||
class IHomeMenuFunctions;
|
||||
class IGlobalStateController;
|
||||
class ILibraryAppletCreator;
|
||||
class ILibraryAppletSelfAccessor;
|
||||
class IProcessWindingController;
|
||||
class ISelfController;
|
||||
class IWindowController;
|
||||
class WindowSystem;
|
||||
|
||||
class IOverlayAppletProxy final : public ServiceFramework<IOverlayAppletProxy> {
|
||||
public:
|
||||
explicit IOverlayAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
|
||||
Kernel::KProcess* process, WindowSystem& window_system);
|
||||
~IOverlayAppletProxy();
|
||||
|
||||
private:
|
||||
Result GetCommonStateGetter(Out<SharedPointer<ICommonStateGetter>> out_common_state_getter);
|
||||
Result GetSelfController(Out<SharedPointer<ISelfController>> out_self_controller);
|
||||
Result GetWindowController(Out<SharedPointer<IWindowController>> out_window_controller);
|
||||
Result GetAudioController(Out<SharedPointer<IAudioController>> out_audio_controller);
|
||||
Result GetDisplayController(Out<SharedPointer<IDisplayController>> out_display_controller);
|
||||
Result GetProcessWindingController(
|
||||
Out<SharedPointer<IProcessWindingController>> out_process_winding_controller);
|
||||
Result GetLibraryAppletCreator(
|
||||
Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator);
|
||||
Result GetOverlayFunctions(Out<SharedPointer<IOverlayFunctions>> out_overlay_functions);
|
||||
Result GetAppletCommonFunctions(
|
||||
Out<SharedPointer<IAppletCommonFunctions>> out_applet_common_functions);
|
||||
Result GetGlobalStateController(
|
||||
Out<SharedPointer<IGlobalStateController>> out_global_state_controller);
|
||||
Result GetDebugFunctions(Out<SharedPointer<IDebugFunctions>> out_debug_functions);
|
||||
|
||||
WindowSystem& m_window_system;
|
||||
Kernel::KProcess* const m_process;
|
||||
const std::shared_ptr<Applet> m_applet;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
||||
@@ -8,34 +8,34 @@
|
||||
#include "core/hle/service/am/window_system.h"
|
||||
|
||||
namespace Service::AM {
|
||||
std::optional<ServiceFrameworkBase::FunctionInfoBase> IOverlayFunctions::FindRequest(u32 key) {
|
||||
static constexpr auto functions = CreateStaticMap(
|
||||
FunctionInfo{0, D<&IOverlayFunctions::BeginToWatchShortHomeButtonMessage>, "BeginToWatchShortHomeButtonMessage"},
|
||||
FunctionInfo{1, D<&IOverlayFunctions::EndToWatchShortHomeButtonMessage>, "EndToWatchShortHomeButtonMessage"},
|
||||
FunctionInfo{2, D<&IOverlayFunctions::GetApplicationIdForLogo>, "GetApplicationIdForLogo"},
|
||||
FunctionInfo{3, nullptr, "SetGpuTimeSliceBoost"},
|
||||
FunctionInfo{4, D<&IOverlayFunctions::SetAutoSleepTimeAndDimmingTimeEnabled>, "SetAutoSleepTimeAndDimmingTimeEnabled"},
|
||||
FunctionInfo{5, nullptr, "TerminateApplicationAndSetReason"},
|
||||
FunctionInfo{6, nullptr, "SetScreenShotPermissionGlobally"},
|
||||
FunctionInfo{10, nullptr, "StartShutdownSequenceForOverlay"},
|
||||
FunctionInfo{11, nullptr, "StartRebootSequenceForOverlay"},
|
||||
FunctionInfo{20, D<&IOverlayFunctions::SetHandlingHomeButtonShortPressedEnabled>, "SetHandlingHomeButtonShortPressedEnabled"},
|
||||
FunctionInfo{21, D<&IOverlayFunctions::SetHandlingTouchScreenInputEnabled>, "SetHandlingTouchScreenInputEnabled"},
|
||||
FunctionInfo{30, nullptr, "SetHealthWarningShowingState"},
|
||||
FunctionInfo{31, D<&IOverlayFunctions::IsHealthWarningRequired>, "IsHealthWarningRequired"},
|
||||
FunctionInfo{40, nullptr, "GetApplicationNintendoLogo"},
|
||||
FunctionInfo{41, nullptr, "GetApplicationStartupMovie"},
|
||||
FunctionInfo{50, nullptr, "SetGpuTimeSliceBoostForApplication"},
|
||||
FunctionInfo{60, nullptr, "Unknown60"},
|
||||
FunctionInfo{70, D<&IOverlayFunctions::Unknown70>, "Unknown70"},
|
||||
FunctionInfo{90, nullptr, "SetRequiresGpuResourceUse"},
|
||||
FunctionInfo{101, nullptr, "BeginToObserveHidInputForDevelop"}
|
||||
);
|
||||
return HandlerTableGenerateWithFind(key, functions);
|
||||
}
|
||||
|
||||
IOverlayFunctions::IOverlayFunctions(Core::System &system_, std::shared_ptr<Applet> applet)
|
||||
: ServiceFramework{system_, "IOverlayFunctions"}, m_applet{std::move(applet)} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&IOverlayFunctions::BeginToWatchShortHomeButtonMessage>, "BeginToWatchShortHomeButtonMessage"},
|
||||
{1, D<&IOverlayFunctions::EndToWatchShortHomeButtonMessage>, "EndToWatchShortHomeButtonMessage"},
|
||||
{2, D<&IOverlayFunctions::GetApplicationIdForLogo>, "GetApplicationIdForLogo"},
|
||||
{3, nullptr, "SetGpuTimeSliceBoost"},
|
||||
{4, D<&IOverlayFunctions::SetAutoSleepTimeAndDimmingTimeEnabled>, "SetAutoSleepTimeAndDimmingTimeEnabled"},
|
||||
{5, nullptr, "TerminateApplicationAndSetReason"},
|
||||
{6, nullptr, "SetScreenShotPermissionGlobally"},
|
||||
{10, nullptr, "StartShutdownSequenceForOverlay"},
|
||||
{11, nullptr, "StartRebootSequenceForOverlay"},
|
||||
{20, D<&IOverlayFunctions::SetHandlingHomeButtonShortPressedEnabled>, "SetHandlingHomeButtonShortPressedEnabled"},
|
||||
{21, D<&IOverlayFunctions::SetHandlingTouchScreenInputEnabled>, "SetHandlingTouchScreenInputEnabled"},
|
||||
{30, nullptr, "SetHealthWarningShowingState"},
|
||||
{31, D<&IOverlayFunctions::IsHealthWarningRequired>, "IsHealthWarningRequired"},
|
||||
{40, nullptr, "GetApplicationNintendoLogo"},
|
||||
{41, nullptr, "GetApplicationStartupMovie"},
|
||||
{50, nullptr, "SetGpuTimeSliceBoostForApplication"},
|
||||
{60, nullptr, "Unknown60"},
|
||||
{70, D<&IOverlayFunctions::Unknown70>, "Unknown70"},
|
||||
{90, nullptr, "SetRequiresGpuResourceUse"},
|
||||
{101, nullptr, "BeginToObserveHidInputForDevelop"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IOverlayFunctions::~IOverlayFunctions() = default;
|
||||
|
||||
@@ -6,25 +6,24 @@
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::AM {
|
||||
struct Applet;
|
||||
struct Applet;
|
||||
|
||||
class IOverlayFunctions final : public ServiceFramework<IOverlayFunctions> {
|
||||
public:
|
||||
explicit IOverlayFunctions(Core::System &system_, std::shared_ptr<Applet> applet);
|
||||
~IOverlayFunctions() override;
|
||||
class IOverlayFunctions final : public ServiceFramework<IOverlayFunctions> {
|
||||
public:
|
||||
explicit IOverlayFunctions(Core::System &system_, std::shared_ptr<Applet> applet);
|
||||
~IOverlayFunctions() override;
|
||||
|
||||
private:
|
||||
Result BeginToWatchShortHomeButtonMessage();
|
||||
Result EndToWatchShortHomeButtonMessage();
|
||||
Result GetApplicationIdForLogo(Out<u64> out_application_id);
|
||||
Result SetAutoSleepTimeAndDimmingTimeEnabled(bool enabled);
|
||||
Result IsHealthWarningRequired(Out<bool> is_required);
|
||||
Result SetHandlingHomeButtonShortPressedEnabled(bool enabled);
|
||||
Result SetHandlingTouchScreenInputEnabled(bool enabled);
|
||||
Result Unknown70();
|
||||
private:
|
||||
Result BeginToWatchShortHomeButtonMessage();
|
||||
Result EndToWatchShortHomeButtonMessage();
|
||||
Result GetApplicationIdForLogo(Out<u64> out_application_id);
|
||||
Result SetAutoSleepTimeAndDimmingTimeEnabled(bool enabled);
|
||||
Result IsHealthWarningRequired(Out<bool> is_required);
|
||||
Result SetHandlingHomeButtonShortPressedEnabled(bool enabled);
|
||||
Result SetHandlingTouchScreenInputEnabled(bool enabled);
|
||||
Result Unknown70();
|
||||
|
||||
private:
|
||||
std::optional<FunctionInfoBase> FindRequest(u32 key) override;
|
||||
const std::shared_ptr<Applet> m_applet;
|
||||
};
|
||||
private:
|
||||
const std::shared_ptr<Applet> m_applet;
|
||||
};
|
||||
} // namespace Service::AM
|
||||
|
||||
@@ -13,23 +13,23 @@
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
std::optional<ServiceFrameworkBase::FunctionInfoBase> IProcessWindingController::FindRequest(u32 key) {
|
||||
static constexpr auto functions = CreateStaticMap(
|
||||
FunctionInfo{0, D<&IProcessWindingController::GetLaunchReason>, "GetLaunchReason"},
|
||||
FunctionInfo{11, D<&IProcessWindingController::OpenCallingLibraryApplet>, "OpenCallingLibraryApplet"},
|
||||
FunctionInfo{21, D<&IProcessWindingController::PushContext>, "PushContext"},
|
||||
FunctionInfo{22, D<&IProcessWindingController::PopContext>, "PopContext"},
|
||||
FunctionInfo{23, D<&IProcessWindingController::CancelWindingReservation>, "CancelWindingReservation"},
|
||||
FunctionInfo{30, D<&IProcessWindingController::WindAndDoReserved>, "WindAndDoReserved"},
|
||||
FunctionInfo{40, D<&IProcessWindingController::ReserveToStartAndWaitAndUnwindThis>, "ReserveToStartAndWaitAndUnwindThis"},
|
||||
FunctionInfo{41, D<&IProcessWindingController::ReserveToStartAndWait>, "ReserveToStartAndWait"}
|
||||
);
|
||||
return HandlerTableGenerateWithFind(key, functions);
|
||||
}
|
||||
|
||||
IProcessWindingController::IProcessWindingController(Core::System& system_,
|
||||
std::shared_ptr<Applet> applet)
|
||||
: ServiceFramework{system_, "IProcessWindingController"}, m_applet{std::move(applet)} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&IProcessWindingController::GetLaunchReason>, "GetLaunchReason"},
|
||||
{11, D<&IProcessWindingController::OpenCallingLibraryApplet>, "OpenCallingLibraryApplet"},
|
||||
{21, D<&IProcessWindingController::PushContext>, "PushContext"},
|
||||
{22, D<&IProcessWindingController::PopContext>, "PopContext"},
|
||||
{23, D<&IProcessWindingController::CancelWindingReservation>, "CancelWindingReservation"},
|
||||
{30, D<&IProcessWindingController::WindAndDoReserved>, "WindAndDoReserved"},
|
||||
{40, D<&IProcessWindingController::ReserveToStartAndWaitAndUnwindThis>, "ReserveToStartAndWaitAndUnwindThis"},
|
||||
{41, D<&IProcessWindingController::ReserveToStartAndWait>, "ReserveToStartAndWait"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IProcessWindingController::~IProcessWindingController() = default;
|
||||
|
||||
@@ -33,7 +33,6 @@ private:
|
||||
SharedPointer<ILibraryAppletAccessor> reserved_applet_accessor);
|
||||
Result ReserveToStartAndWait(SharedPointer<ILibraryAppletAccessor> reserved_applet_accessor);
|
||||
|
||||
std::optional<FunctionInfoBase> FindRequest(u32 key) override;
|
||||
const std::shared_ptr<Applet> m_applet;
|
||||
};
|
||||
|
||||
|
||||
@@ -17,66 +17,67 @@
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
std::optional<ServiceFrameworkBase::FunctionInfoBase> ISelfController::FindRequest(u32 key) {
|
||||
static constexpr auto functions = CreateStaticMap(
|
||||
FunctionInfo{0, D<&ISelfController::Exit>, "Exit"},
|
||||
FunctionInfo{1, D<&ISelfController::LockExit>, "LockExit"},
|
||||
FunctionInfo{2, D<&ISelfController::UnlockExit>, "UnlockExit"},
|
||||
FunctionInfo{3, D<&ISelfController::EnterFatalSection>, "EnterFatalSection"},
|
||||
FunctionInfo{4, D<&ISelfController::LeaveFatalSection>, "LeaveFatalSection"},
|
||||
FunctionInfo{9, D<&ISelfController::GetLibraryAppletLaunchableEvent>, "GetLibraryAppletLaunchableEvent"},
|
||||
FunctionInfo{10, D<&ISelfController::SetScreenShotPermission>, "SetScreenShotPermission"},
|
||||
FunctionInfo{11, D<&ISelfController::SetOperationModeChangedNotification>, "SetOperationModeChangedNotification"},
|
||||
FunctionInfo{12, D<&ISelfController::SetPerformanceModeChangedNotification>, "SetPerformanceModeChangedNotification"},
|
||||
FunctionInfo{13, D<&ISelfController::SetFocusHandlingMode>, "SetFocusHandlingMode"},
|
||||
FunctionInfo{14, D<&ISelfController::SetRestartMessageEnabled>, "SetRestartMessageEnabled"},
|
||||
FunctionInfo{15, D<&ISelfController::SetScreenShotAppletIdentityInfo>, "SetScreenShotAppletIdentityInfo"},
|
||||
FunctionInfo{16, D<&ISelfController::SetOutOfFocusSuspendingEnabled>, "SetOutOfFocusSuspendingEnabled"},
|
||||
FunctionInfo{17, nullptr, "SetControllerFirmwareUpdateSection"},
|
||||
FunctionInfo{18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"},
|
||||
FunctionInfo{19, D<&ISelfController::SetAlbumImageOrientation>, "SetAlbumImageOrientation"},
|
||||
FunctionInfo{20, nullptr, "SetDesirableKeyboardLayout"},
|
||||
FunctionInfo{21, nullptr, "GetScreenShotProgramId"},
|
||||
FunctionInfo{40, D<&ISelfController::CreateManagedDisplayLayer>, "CreateManagedDisplayLayer"},
|
||||
FunctionInfo{41, D<&ISelfController::IsSystemBufferSharingEnabled>, "IsSystemBufferSharingEnabled"},
|
||||
FunctionInfo{42, D<&ISelfController::GetSystemSharedLayerHandle>, "GetSystemSharedLayerHandle"},
|
||||
FunctionInfo{43, D<&ISelfController::GetSystemSharedBufferHandle>, "GetSystemSharedBufferHandle"},
|
||||
FunctionInfo{44, D<&ISelfController::CreateManagedDisplaySeparableLayer>, "CreateManagedDisplaySeparableLayer"},
|
||||
FunctionInfo{45, nullptr, "SetManagedDisplayLayerSeparationMode"},
|
||||
FunctionInfo{46, nullptr, "SetRecordingLayerCompositionEnabled"},
|
||||
FunctionInfo{50, D<&ISelfController::SetHandlesRequestToDisplay>, "SetHandlesRequestToDisplay"},
|
||||
FunctionInfo{51, D<&ISelfController::ApproveToDisplay>, "ApproveToDisplay"},
|
||||
FunctionInfo{60, D<&ISelfController::OverrideAutoSleepTimeAndDimmingTime>, "OverrideAutoSleepTimeAndDimmingTime"},
|
||||
FunctionInfo{61, D<&ISelfController::SetMediaPlaybackState>, "SetMediaPlaybackState"},
|
||||
FunctionInfo{62, D<&ISelfController::SetIdleTimeDetectionExtension>, "SetIdleTimeDetectionExtension"},
|
||||
FunctionInfo{63, D<&ISelfController::GetIdleTimeDetectionExtension>, "GetIdleTimeDetectionExtension"},
|
||||
FunctionInfo{64, nullptr, "SetInputDetectionSourceSet"},
|
||||
FunctionInfo{65, D<&ISelfController::ReportUserIsActive>, "ReportUserIsActive"},
|
||||
FunctionInfo{66, nullptr, "GetCurrentIlluminance"},
|
||||
FunctionInfo{67, D<&ISelfController::IsIlluminanceAvailable>, "IsIlluminanceAvailable"},
|
||||
FunctionInfo{68, D<&ISelfController::SetAutoSleepDisabled>, "SetAutoSleepDisabled"},
|
||||
FunctionInfo{69, D<&ISelfController::IsAutoSleepDisabled>, "IsAutoSleepDisabled"},
|
||||
FunctionInfo{70, nullptr, "ReportMultimediaError"},
|
||||
FunctionInfo{71, nullptr, "GetCurrentIlluminanceEx"},
|
||||
FunctionInfo{72, D<&ISelfController::SetInputDetectionPolicy>, "SetInputDetectionPolicy"},
|
||||
FunctionInfo{80, nullptr, "SetWirelessPriorityMode"},
|
||||
FunctionInfo{90, D<&ISelfController::GetAccumulatedSuspendedTickValue>, "GetAccumulatedSuspendedTickValue"},
|
||||
FunctionInfo{91, D<&ISelfController::GetAccumulatedSuspendedTickChangedEvent>, "GetAccumulatedSuspendedTickChangedEvent"},
|
||||
FunctionInfo{100, D<&ISelfController::SetAlbumImageTakenNotificationEnabled>, "SetAlbumImageTakenNotificationEnabled"},
|
||||
FunctionInfo{110, nullptr, "SetApplicationAlbumUserData"},
|
||||
FunctionInfo{120, D<&ISelfController::SaveCurrentScreenshot>, "SaveCurrentScreenshot"},
|
||||
FunctionInfo{130, D<&ISelfController::SetRecordVolumeMuted>, "SetRecordVolumeMuted"},
|
||||
FunctionInfo{230, D<&ISelfController::Unknown230>, "Unknown230"},
|
||||
FunctionInfo{240, D<&ISelfController::Unknown240>, "Unknown240"},
|
||||
FunctionInfo{1000, nullptr, "GetDebugStorageChannel"}
|
||||
);
|
||||
return HandlerTableGenerateWithFind(key, functions);
|
||||
}
|
||||
|
||||
ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet> applet,
|
||||
Kernel::KProcess* process)
|
||||
: ServiceFramework{system_, "ISelfController"}, m_process{process}, m_applet{
|
||||
std::move(applet)} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&ISelfController::Exit>, "Exit"},
|
||||
{1, D<&ISelfController::LockExit>, "LockExit"},
|
||||
{2, D<&ISelfController::UnlockExit>, "UnlockExit"},
|
||||
{3, D<&ISelfController::EnterFatalSection>, "EnterFatalSection"},
|
||||
{4, D<&ISelfController::LeaveFatalSection>, "LeaveFatalSection"},
|
||||
{9, D<&ISelfController::GetLibraryAppletLaunchableEvent>, "GetLibraryAppletLaunchableEvent"},
|
||||
{10, D<&ISelfController::SetScreenShotPermission>, "SetScreenShotPermission"},
|
||||
{11, D<&ISelfController::SetOperationModeChangedNotification>, "SetOperationModeChangedNotification"},
|
||||
{12, D<&ISelfController::SetPerformanceModeChangedNotification>, "SetPerformanceModeChangedNotification"},
|
||||
{13, D<&ISelfController::SetFocusHandlingMode>, "SetFocusHandlingMode"},
|
||||
{14, D<&ISelfController::SetRestartMessageEnabled>, "SetRestartMessageEnabled"},
|
||||
{15, D<&ISelfController::SetScreenShotAppletIdentityInfo>, "SetScreenShotAppletIdentityInfo"},
|
||||
{16, D<&ISelfController::SetOutOfFocusSuspendingEnabled>, "SetOutOfFocusSuspendingEnabled"},
|
||||
{17, nullptr, "SetControllerFirmwareUpdateSection"},
|
||||
{18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"},
|
||||
{19, D<&ISelfController::SetAlbumImageOrientation>, "SetAlbumImageOrientation"},
|
||||
{20, nullptr, "SetDesirableKeyboardLayout"},
|
||||
{21, nullptr, "GetScreenShotProgramId"},
|
||||
{40, D<&ISelfController::CreateManagedDisplayLayer>, "CreateManagedDisplayLayer"},
|
||||
{41, D<&ISelfController::IsSystemBufferSharingEnabled>, "IsSystemBufferSharingEnabled"},
|
||||
{42, D<&ISelfController::GetSystemSharedLayerHandle>, "GetSystemSharedLayerHandle"},
|
||||
{43, D<&ISelfController::GetSystemSharedBufferHandle>, "GetSystemSharedBufferHandle"},
|
||||
{44, D<&ISelfController::CreateManagedDisplaySeparableLayer>, "CreateManagedDisplaySeparableLayer"},
|
||||
{45, nullptr, "SetManagedDisplayLayerSeparationMode"},
|
||||
{46, nullptr, "SetRecordingLayerCompositionEnabled"},
|
||||
{50, D<&ISelfController::SetHandlesRequestToDisplay>, "SetHandlesRequestToDisplay"},
|
||||
{51, D<&ISelfController::ApproveToDisplay>, "ApproveToDisplay"},
|
||||
{60, D<&ISelfController::OverrideAutoSleepTimeAndDimmingTime>, "OverrideAutoSleepTimeAndDimmingTime"},
|
||||
{61, D<&ISelfController::SetMediaPlaybackState>, "SetMediaPlaybackState"},
|
||||
{62, D<&ISelfController::SetIdleTimeDetectionExtension>, "SetIdleTimeDetectionExtension"},
|
||||
{63, D<&ISelfController::GetIdleTimeDetectionExtension>, "GetIdleTimeDetectionExtension"},
|
||||
{64, nullptr, "SetInputDetectionSourceSet"},
|
||||
{65, D<&ISelfController::ReportUserIsActive>, "ReportUserIsActive"},
|
||||
{66, nullptr, "GetCurrentIlluminance"},
|
||||
{67, D<&ISelfController::IsIlluminanceAvailable>, "IsIlluminanceAvailable"},
|
||||
{68, D<&ISelfController::SetAutoSleepDisabled>, "SetAutoSleepDisabled"},
|
||||
{69, D<&ISelfController::IsAutoSleepDisabled>, "IsAutoSleepDisabled"},
|
||||
{70, nullptr, "ReportMultimediaError"},
|
||||
{71, nullptr, "GetCurrentIlluminanceEx"},
|
||||
{72, D<&ISelfController::SetInputDetectionPolicy>, "SetInputDetectionPolicy"},
|
||||
{80, nullptr, "SetWirelessPriorityMode"},
|
||||
{90, D<&ISelfController::GetAccumulatedSuspendedTickValue>, "GetAccumulatedSuspendedTickValue"},
|
||||
{91, D<&ISelfController::GetAccumulatedSuspendedTickChangedEvent>, "GetAccumulatedSuspendedTickChangedEvent"},
|
||||
{100, D<&ISelfController::SetAlbumImageTakenNotificationEnabled>, "SetAlbumImageTakenNotificationEnabled"},
|
||||
{110, nullptr, "SetApplicationAlbumUserData"},
|
||||
{120, D<&ISelfController::SaveCurrentScreenshot>, "SaveCurrentScreenshot"},
|
||||
{130, D<&ISelfController::SetRecordVolumeMuted>, "SetRecordVolumeMuted"},
|
||||
{230, D<&ISelfController::Unknown230>, "Unknown230"},
|
||||
{240, D<&ISelfController::Unknown240>, "Unknown240"},
|
||||
{1000, nullptr, "GetDebugStorageChannel"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
|
||||
std::scoped_lock lk{m_applet->lock};
|
||||
m_applet->display_layer_manager.Initialize(system, m_process, m_applet->applet_id,
|
||||
m_applet->library_applet_mode);
|
||||
|
||||
@@ -70,7 +70,6 @@ private:
|
||||
Result Unknown230(u32 in_val, Out<u16> out_val);
|
||||
Result Unknown240(u32 in_val);
|
||||
|
||||
std::optional<FunctionInfoBase> FindRequest(u32 key) override;
|
||||
Kernel::KProcess* const m_process;
|
||||
const std::shared_ptr<Applet> m_applet;
|
||||
};
|
||||
|
||||
@@ -4,86 +4,22 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/kernel/k_transfer_memory.h"
|
||||
#include "core/hle/service/am/am_results.h"
|
||||
#include "core/hle/service/am/library_applet_storage.h"
|
||||
#include "core/hle/service/am/service/storage.h"
|
||||
#include "core/hle/service/am/service/storage_accessor.h"
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
|
||||
public:
|
||||
explicit IStorageAccessor(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl) : ServiceFramework{system_, "IStorageAccessor"}, m_impl{std::move(impl)} {}
|
||||
~IStorageAccessor() override = default;
|
||||
|
||||
Result GetSize(Out<s64> out_size) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_size = m_impl->GetSize();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result Write(InBuffer<BufferAttr_HipcAutoSelect> buffer, s64 offset) {
|
||||
LOG_DEBUG(Service_AM, "called, offset={} size={}", offset, buffer.size());
|
||||
R_RETURN(m_impl->Write(offset, buffer.data(), buffer.size()));
|
||||
}
|
||||
|
||||
Result Read(OutBuffer<BufferAttr_HipcAutoSelect> out_buffer, s64 offset) {
|
||||
LOG_DEBUG(Service_AM, "called, offset={} size={}", offset, out_buffer.size());
|
||||
R_RETURN(m_impl->Read(offset, out_buffer.data(), out_buffer.size()));
|
||||
}
|
||||
|
||||
std::optional<FunctionInfoBase> FindRequest(u32 key) override {
|
||||
return HandlerTableGenerateWithFind(key, functions);
|
||||
}
|
||||
static constexpr auto functions = CreateStaticMap(
|
||||
FunctionInfo{0, D<&IStorageAccessor::GetSize>, "GetSize"},
|
||||
FunctionInfo{10, D<&IStorageAccessor::Write>, "Write"},
|
||||
FunctionInfo{11, D<&IStorageAccessor::Read>, "Read"}
|
||||
);
|
||||
|
||||
const std::shared_ptr<LibraryAppletStorage> m_impl;
|
||||
};
|
||||
|
||||
class ITransferStorageAccessor final : public ServiceFramework<ITransferStorageAccessor> {
|
||||
public:
|
||||
explicit ITransferStorageAccessor(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl) : ServiceFramework{system_, "ITransferStorageAccessor"}, m_impl{std::move(impl)} {}
|
||||
~ITransferStorageAccessor() override = default;
|
||||
|
||||
Result GetSize(Out<s64> out_size) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_size = m_impl->GetSize();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result GetHandle(Out<s64> out_size, OutCopyHandle<Kernel::KTransferMemory> out_handle) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
*out_size = m_impl->GetSize();
|
||||
*out_handle = m_impl->GetHandle();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
std::optional<FunctionInfoBase> FindRequest(u32 key) override {
|
||||
return HandlerTableGenerateWithFind(key, functions);
|
||||
}
|
||||
static constexpr auto functions = CreateStaticMap(
|
||||
FunctionInfo{0, D<&ITransferStorageAccessor::GetSize>, "GetSize"},
|
||||
FunctionInfo{1, D<&ITransferStorageAccessor::GetHandle>, "GetHandle"}
|
||||
);
|
||||
|
||||
const std::shared_ptr<LibraryAppletStorage> m_impl;
|
||||
};
|
||||
|
||||
std::optional<ServiceFrameworkBase::FunctionInfoBase> IStorage::FindRequest(u32 key) {
|
||||
static constexpr auto functions = CreateStaticMap(
|
||||
FunctionInfo{0, D<&IStorage::Open>, "Open"},
|
||||
FunctionInfo{1, D<&IStorage::OpenTransferStorage>, "OpenTransferStorage"}
|
||||
);
|
||||
return HandlerTableGenerateWithFind(key, functions);
|
||||
}
|
||||
|
||||
IStorage::IStorage(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl)
|
||||
: ServiceFramework{system_, "IStorage"}, m_impl{std::move(impl)} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&IStorage::Open>, "Open"},
|
||||
{1, D<&IStorage::OpenTransferStorage>, "OpenTransferStorage"},
|
||||
};
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IStorage::IStorage(Core::System& system_, std::vector<u8>&& data)
|
||||
|
||||
@@ -32,7 +32,6 @@ private:
|
||||
Result OpenTransferStorage(
|
||||
Out<SharedPointer<ITransferStorageAccessor>> out_transfer_storage_accessor);
|
||||
|
||||
std::optional<FunctionInfoBase> FindRequest(u32 key) override;
|
||||
const std::shared_ptr<LibraryAppletStorage> m_impl;
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "core/hle/kernel/k_transfer_memory.h"
|
||||
#include "core/hle/service/am/library_applet_storage.h"
|
||||
#include "core/hle/service/am/service/storage_accessor.h"
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
IStorageAccessor::IStorageAccessor(Core::System& system_,
|
||||
std::shared_ptr<LibraryAppletStorage> impl)
|
||||
: ServiceFramework{system_, "IStorageAccessor"}, m_impl{std::move(impl)} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&IStorageAccessor::GetSize>, "GetSize"},
|
||||
{10, D<&IStorageAccessor::Write>, "Write"},
|
||||
{11, D<&IStorageAccessor::Read>, "Read"},
|
||||
};
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IStorageAccessor::~IStorageAccessor() = default;
|
||||
|
||||
Result IStorageAccessor::GetSize(Out<s64> out_size) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_size = m_impl->GetSize();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IStorageAccessor::Write(InBuffer<BufferAttr_HipcAutoSelect> buffer, s64 offset) {
|
||||
LOG_DEBUG(Service_AM, "called, offset={} size={}", offset, buffer.size());
|
||||
R_RETURN(m_impl->Write(offset, buffer.data(), buffer.size()));
|
||||
}
|
||||
|
||||
Result IStorageAccessor::Read(OutBuffer<BufferAttr_HipcAutoSelect> out_buffer, s64 offset) {
|
||||
LOG_DEBUG(Service_AM, "called, offset={} size={}", offset, out_buffer.size());
|
||||
R_RETURN(m_impl->Read(offset, out_buffer.data(), out_buffer.size()));
|
||||
}
|
||||
|
||||
ITransferStorageAccessor::ITransferStorageAccessor(Core::System& system_,
|
||||
std::shared_ptr<LibraryAppletStorage> impl)
|
||||
: ServiceFramework{system_, "ITransferStorageAccessor"}, m_impl{std::move(impl)} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&ITransferStorageAccessor::GetSize>, "GetSize"},
|
||||
{1, D<&ITransferStorageAccessor::GetHandle>, "GetHandle"},
|
||||
};
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
ITransferStorageAccessor::~ITransferStorageAccessor() = default;
|
||||
|
||||
Result ITransferStorageAccessor::GetSize(Out<s64> out_size) {
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
*out_size = m_impl->GetSize();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ITransferStorageAccessor::GetHandle(Out<s64> out_size,
|
||||
OutCopyHandle<Kernel::KTransferMemory> out_handle) {
|
||||
LOG_INFO(Service_AM, "called");
|
||||
*out_size = m_impl->GetSize();
|
||||
*out_handle = m_impl->GetHandle();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
@@ -0,0 +1,41 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/am/library_applet_storage.h"
|
||||
#include "core/hle/service/cmif_types.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::AM {
|
||||
|
||||
class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
|
||||
public:
|
||||
explicit IStorageAccessor(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl);
|
||||
~IStorageAccessor() override;
|
||||
|
||||
private:
|
||||
Result GetSize(Out<s64> out_size);
|
||||
Result Write(InBuffer<BufferAttr_HipcAutoSelect> buffer, s64 offset);
|
||||
Result Read(OutBuffer<BufferAttr_HipcAutoSelect> out_buffer, s64 offset);
|
||||
|
||||
const std::shared_ptr<LibraryAppletStorage> m_impl;
|
||||
};
|
||||
|
||||
class ITransferStorageAccessor final : public ServiceFramework<ITransferStorageAccessor> {
|
||||
public:
|
||||
explicit ITransferStorageAccessor(Core::System& system_,
|
||||
std::shared_ptr<LibraryAppletStorage> impl);
|
||||
~ITransferStorageAccessor() override;
|
||||
|
||||
private:
|
||||
Result GetSize(Out<s64> out_size);
|
||||
Result GetHandle(Out<s64> out_size, OutCopyHandle<Kernel::KTransferMemory> out_handle);
|
||||
|
||||
const std::shared_ptr<LibraryAppletStorage> m_impl;
|
||||
};
|
||||
|
||||
} // namespace Service::AM
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user