Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb9a477115 | ||
|
|
2bf443fb3c | ||
|
|
ca25cff7fa | ||
|
|
d59f0b5900 | ||
|
|
5403c3bdd8 | ||
|
|
e962de8373 |
No files matched your search
@@ -12,7 +12,7 @@ jobs:
|
||||
|
||||
# Minimal devkitA64 container
|
||||
container:
|
||||
image: devkitpro/devkita64:20260219
|
||||
image: devkitpro/devkita64:20251231
|
||||
|
||||
steps:
|
||||
- name: Checkout repository and submodules # needed for hoc-clk
|
||||
@@ -55,7 +55,7 @@ jobs:
|
||||
echo $GITHUB_SHA >> dist/.commit
|
||||
|
||||
- name: Clone Libnx
|
||||
run: git clone https://github.com/switchbrew/libnx.git --depth=1 --single-branch -b v4.12.0
|
||||
run: git clone https://github.com/switchbrew/libnx.git
|
||||
|
||||
- name: Clone Atmosphere
|
||||
run: git clone --depth=1 --single-branch https://github.com/Atmosphere-NX/Atmosphere.git atmosphere -b $(cat ams_ver.txt)
|
||||
@@ -70,27 +70,20 @@ jobs:
|
||||
cp -rf Source/Atmosphere/stratosphere/loader/source/* build/stratosphere/loader/source/
|
||||
|
||||
- name: Cache ccache
|
||||
uses: actions/cache@v5.0.5
|
||||
uses: actions/cache@v5.0.3
|
||||
with:
|
||||
path: .ccache
|
||||
key: ccache-${{ runner.os }}-devkitpro-ams-${{ hashFiles('ams_ver.txt') }}
|
||||
path: /root/.cache/ccache
|
||||
key: ccache-${{ runner.os }}-devkitpro-ams-${{ hashFiles('ams_ver.txt') }} # last key was utter garbage, stick to ams versions,
|
||||
restore-keys: |
|
||||
ccache-${{ runner.os }}-devkitpro-
|
||||
|
||||
- name: Configure ccache
|
||||
run: |
|
||||
export CCACHE_DIR="$GITHUB_WORKSPACE/.ccache"
|
||||
export CCACHE_COMPILERCHECK=content
|
||||
export CCACHE_NOHASHDIR=true
|
||||
echo "CCACHE_DIR=$GITHUB_WORKSPACE/.ccache" >> $GITHUB_ENV
|
||||
echo "CCACHE_BASEDIR=$GITHUB_WORKSPACE" >> $GITHUB_ENV
|
||||
echo "CCACHE_COMPILERCHECK=content" >> $GITHUB_ENV
|
||||
echo "CCACHE_NOHASHDIR=true" >> $GITHUB_ENV
|
||||
export CCACHE_DIR=/root/.cache/ccache
|
||||
echo "CCACHE_DIR=/root/.cache/ccache" >> $GITHUB_ENV
|
||||
ccache --set-config=max_size=10G
|
||||
ccache --set-config=compiler_check=content
|
||||
ccache --set-config=hash_dir=false
|
||||
ccache -s
|
||||
ls -lah "$GITHUB_WORKSPACE/.ccache"
|
||||
ccache --zero-stats
|
||||
|
||||
- name: Build Libnx
|
||||
shell: bash
|
||||
@@ -109,7 +102,6 @@ jobs:
|
||||
|
||||
ROOT_DIR="$GITHUB_WORKSPACE/Source/hoc-clk"
|
||||
DIST_DIR="$ROOT_DIR/dist"
|
||||
echo "DIST_DIR="$ROOT_DIR/dist"" >> $GITHUB_ENV
|
||||
|
||||
mkdir -p "$DIST_DIR"
|
||||
|
||||
@@ -170,11 +162,8 @@ jobs:
|
||||
hactool -t kip1 out/nintendo_nx_arm64_armv8a/release/loader.kip --uncompress=hoc.kip
|
||||
cp hoc.kip ../../../dist/atmosphere/kips/hoc.kip
|
||||
|
||||
- name: ccache stat
|
||||
run: |
|
||||
ccache --show-stats
|
||||
ccache -s
|
||||
ccache --show-config
|
||||
- name: ccache stats
|
||||
run: ccache --show-stats
|
||||
|
||||
# -------------------------------------------------
|
||||
# Upload ZIP artifact
|
||||
@@ -183,5 +172,5 @@ jobs:
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: horizon-oc-zeus-dist
|
||||
path: $DIST_DIR
|
||||
compression-level: 6
|
||||
path: dist/
|
||||
compression-level: 3
|
||||
@@ -4,7 +4,3 @@
|
||||
build/
|
||||
__pycache__/
|
||||
build
|
||||
*.dksh
|
||||
Source/hekate
|
||||
dist/*
|
||||
!dist/.gitignore
|
||||
@@ -1,3 +1,11 @@
|
||||
[submodule "Source/Horizon-OC-Monitor/lib/Atmosphere-libs"]
|
||||
path = Source/Horizon-OC-Monitor/lib/Atmosphere-libs
|
||||
url = https://github.com/Atmosphere-NX/Atmosphere-libs
|
||||
branch = master
|
||||
[submodule "Source/Horizon-OC-Monitor/lib/libultrahand"]
|
||||
path = Source/Horizon-OC-Monitor/lib/libultrahand
|
||||
url = https://github.com/ppkantorski/libultrahand
|
||||
branch = main
|
||||
[submodule "Source/hoc-clk/overlay/lib/libultrahand"]
|
||||
path = Source/hoc-clk/overlay/lib/libultrahand
|
||||
url = https://github.com/ppkantorski/libultrahand
|
||||
|
||||
@@ -2,6 +2,8 @@ Horizon OC Compilation Instructions
|
||||
|
||||
1. Install devkitpro (https://devkitpro.org/wiki/Getting_Started) with switch-dev
|
||||
2. Set up a development enviorment for compiling Atmosphere (https://github.com/Atmosphere-NX/Atmosphere/blob/master/docs/building.md)
|
||||
3. Clone the Horizon OC develop branch (``git clone https://github.com/Horizon-OC/Horizon-OC.git --recurse-submodules``)
|
||||
4. Run ``./build.sh`` in the root directory
|
||||
- If you want to compile with extensions, append ``--ext``
|
||||
3. Git clone atmosphere (git clone https://github.com/Atmosphere-NX/Atmosphere.git)
|
||||
4. Clone the Horizon OC develop branch (``git clone https://github.com/Horizon-OC/Horizon-OC.git --recurse-submodules``)
|
||||
5. Create a new folder named ``build`` in the horizon oc repo
|
||||
6. Copy atmosphere files into that build folder
|
||||
7. Run ./build.sh in the root directory
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
> **THIS TOOL CAN BE DANGEROUS IF MISUSED. PROCEED WITH CAUTION.**
|
||||
> Due to the design of Horizon OS, **overclocking RAM can cause NAND OR SD CORRUPTION.**
|
||||
> Ensure you have a **full NAND, PRODINFO, EMUMMC and SD backup** before proceeding.
|
||||
> Ensure you have a **full NAND, PROINFO, EMUMMC and SD backup** before proceeding.
|
||||
|
||||
---
|
||||
|
||||
@@ -72,12 +72,6 @@ It enables advanced CPU, GPU, and RAM tuning with user-friendly configuration to
|
||||
|
||||
---
|
||||
|
||||
## Donating
|
||||
|
||||
We don't accept donations. Put your spare cash into a charity instead :)
|
||||
|
||||
---
|
||||
|
||||
## Building from Source
|
||||
|
||||
Refer to COMPILATION.md
|
||||
@@ -143,8 +137,7 @@ Refer to COMPILATION.md
|
||||
* 665
|
||||
|
||||
### CPU clocks (mhz)
|
||||
* 2805 → mariko absolute max, dangerous
|
||||
* 2703
|
||||
* 2703 → mariko absolute max, dangerous
|
||||
* 2601 → unsafe
|
||||
* 2499
|
||||
* 2397 → mariko safe max with UV (low speedo)
|
||||
@@ -167,9 +160,9 @@ Refer to COMPILATION.md
|
||||
* 612 → sleep mode
|
||||
|
||||
### GPU clocks (mhz)
|
||||
* 1536 → absolute max clock on mariko. Dangerous
|
||||
* 1497 → max mariko unsafe clock
|
||||
* 1382 → Max mariko "safe" clock
|
||||
* 1536 → absolute max clock on mariko. very dangerous
|
||||
* 1459
|
||||
* 1382
|
||||
* 1305
|
||||
* 1267 → NVIDIA T214(mariko) rating
|
||||
* 1228 → mariko High UV safe clock
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
This contains a diff all modifications done to exosphere
|
||||
@@ -1,57 +0,0 @@
|
||||
131,156c131,159
|
||||
< #define AMS_SECMON_FOREACH_DEVICE_REGION(HANDLER, ...) \
|
||||
< HANDLER(GicDistributor, Empty, UINT64_C(0x50041000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
< HANDLER(GicCpuInterface, GicDistributor, UINT64_C(0x50042000), UINT64_C(0x2000), true, ## __VA_ARGS__) \
|
||||
< HANDLER(Uart, GicCpuInterface, UINT64_C(0x70006000), UINT64_C(0x1000), false, ## __VA_ARGS__) \
|
||||
< HANDLER(ClkRst, Uart, UINT64_C(0x60006000), UINT64_C(0x1000), false, ## __VA_ARGS__) \
|
||||
< HANDLER(RtcPmc, ClkRst, UINT64_C(0x7000E000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
< HANDLER(Timer, RtcPmc, UINT64_C(0x60005000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
< HANDLER(System, Timer, UINT64_C(0x6000C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
< HANDLER(SecurityEngine, System, UINT64_C(0x70012000), UINT64_C(0x2000), true, ## __VA_ARGS__) \
|
||||
< HANDLER(SecurityEngine2, SecurityEngine, UINT64_C(0x70412000), UINT64_C(0x2000), true, ## __VA_ARGS__) \
|
||||
< HANDLER(SysCtr0, SecurityEngine2, UINT64_C(0x700F0000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
< HANDLER(MemoryController, SysCtr0, UINT64_C(0x70019000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
< HANDLER(FuseKFuse, MemoryController, UINT64_C(0x7000F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
< HANDLER(ApbMisc, FuseKFuse, UINT64_C(0x70000000), UINT64_C(0x4000), true, ## __VA_ARGS__) \
|
||||
< HANDLER(FlowController, ApbMisc, UINT64_C(0x60007000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
< HANDLER(BootloaderParams, FlowController, UINT64_C(0x40000000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
< HANDLER(I2c5, BootloaderParams, UINT64_C(0x7000D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
< HANDLER(Gpio, I2c5, UINT64_C(0x6000D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
< HANDLER(I2c1, Gpio, UINT64_C(0x7000C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
< HANDLER(ExceptionVectors, I2c1, UINT64_C(0x6000F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
< HANDLER(MemoryController0, ExceptionVectors, UINT64_C(0x7001C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
< HANDLER(MemoryController1, MemoryController0, UINT64_C(0x7001D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
< HANDLER(Sdmmc, MemoryController1, UINT64_C(0x700B0000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
< HANDLER(Disp1, Sdmmc, UINT64_C(0x54200000), UINT64_C(0x3000), true, ## __VA_ARGS__) \
|
||||
< HANDLER(Dsi, Disp1, UINT64_C(0x54300000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
< HANDLER(MipiCal, Dsi, UINT64_C(0x700E3000), UINT64_C(0x1000), true, ## __VA_ARGS__)
|
||||
---
|
||||
> #define AMS_SECMON_FOREACH_DEVICE_REGION(HANDLER, ...) \
|
||||
> HANDLER(GicDistributor, Empty, UINT64_C(0x50041000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
> HANDLER(GicCpuInterface, GicDistributor, UINT64_C(0x50042000), UINT64_C(0x2000), true, ## __VA_ARGS__) \
|
||||
> HANDLER(Uart, GicCpuInterface, UINT64_C(0x70006000), UINT64_C(0x1000), false, ## __VA_ARGS__) \
|
||||
> HANDLER(ClkRst, Uart, UINT64_C(0x60006000), UINT64_C(0x1000), false, ## __VA_ARGS__) \
|
||||
> HANDLER(RtcPmc, ClkRst, UINT64_C(0x7000E000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
> HANDLER(Timer, RtcPmc, UINT64_C(0x60005000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
> HANDLER(System, Timer, UINT64_C(0x6000C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
> HANDLER(SecurityEngine, System, UINT64_C(0x70012000), UINT64_C(0x2000), true, ## __VA_ARGS__) \
|
||||
> HANDLER(SecurityEngine2, SecurityEngine, UINT64_C(0x70412000), UINT64_C(0x2000), true, ## __VA_ARGS__) \
|
||||
> HANDLER(SysCtr0, SecurityEngine2, UINT64_C(0x700F0000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
> HANDLER(MemoryController, SysCtr0, UINT64_C(0x70019000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
> HANDLER(ExternalMemoryController, MemoryController, UINT64_C(0x7001b000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
> HANDLER(FuseKFuse, ExternalMemoryController, UINT64_C(0x7000F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
> HANDLER(ApbMisc, FuseKFuse, UINT64_C(0x70000000), UINT64_C(0x4000), true, ## __VA_ARGS__) \
|
||||
> HANDLER(FlowController, ApbMisc, UINT64_C(0x60007000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
> HANDLER(BootloaderParams, FlowController, UINT64_C(0x40000000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
> HANDLER(I2c5, BootloaderParams, UINT64_C(0x7000D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
> HANDLER(Gpio, I2c5, UINT64_C(0x6000D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
> HANDLER(I2c1, Gpio, UINT64_C(0x7000C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
> HANDLER(ExceptionVectors, I2c1, UINT64_C(0x6000F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
> HANDLER(MemoryController0, ExceptionVectors, UINT64_C(0x7001C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
> HANDLER(MemoryController1, MemoryController0, UINT64_C(0x7001D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
> HANDLER(ExternalMemoryController0, MemoryController1, UINT64_C(0x7001E000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
> HANDLER(ExternalMemoryController1, ExternalMemoryController0, UINT64_C(0x7001F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
> HANDLER(Sdmmc, ExternalMemoryController1, UINT64_C(0x700B0000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
> HANDLER(Disp1, Sdmmc, UINT64_C(0x54200000), UINT64_C(0x3000), true, ## __VA_ARGS__) \
|
||||
> HANDLER(Dsi, Disp1, UINT64_C(0x54300000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
> HANDLER(MipiCal, Dsi, UINT64_C(0x700E3000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
@@ -1,29 +0,0 @@
|
||||
1221c1221
|
||||
< const auto target_fw = GetTargetFirmware();
|
||||
---
|
||||
> // const auto target_fw = GetTargetFirmware();
|
||||
1223,1226c1223,1226
|
||||
< if (target_fw >= TargetFirmware_2_0_0) {
|
||||
< /* Set the PMC secure. */
|
||||
< reg::ReadWrite(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0, SLAVE_SECURITY_REG_BITS_ENUM(0, PMC, ENABLE));
|
||||
< }
|
||||
---
|
||||
> // if (target_fw >= TargetFirmware_2_0_0) {
|
||||
> // /* Set the PMC secure. */ I REFUSE
|
||||
> // reg::ReadWrite(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0, SLAVE_SECURITY_REG_BITS_ENUM(0, PMC, ENABLE));
|
||||
> // }
|
||||
1228,1233c1228,1234
|
||||
< if (target_fw >= TargetFirmware_4_0_0) {
|
||||
< /* Set the MC secure. */
|
||||
< reg::ReadWrite(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG1_0, SLAVE_SECURITY_REG_BITS_ENUM(1, MC0, ENABLE),
|
||||
< SLAVE_SECURITY_REG_BITS_ENUM(1, MC1, ENABLE),
|
||||
< SLAVE_SECURITY_REG_BITS_ENUM(1, MCB, ENABLE));
|
||||
< }
|
||||
---
|
||||
> // if (target_fw >= TargetFirmware_4_0_0) {
|
||||
> // /* Set the MC secure. */ I REFUSE
|
||||
> // reg::ReadWrite(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG1_0, SLAVE_SECURITY_REG_BITS_ENUM(1, MC0, ENABLE),
|
||||
> // SLAVE_SECURITY_REG_BITS_ENUM(1, MC1, ENABLE),
|
||||
> // SLAVE_SECURITY_REG_BITS_ENUM(1, MCB, ENABLE));
|
||||
> // }
|
||||
> return;
|
||||
@@ -1,2 +0,0 @@
|
||||
154a155
|
||||
> { 0xF0000005, Restriction_None, SmcShowError },
|
||||
@@ -1,9 +0,0 @@
|
||||
160c160
|
||||
< /* Validate that the bpmp is appropriately halted. */
|
||||
---
|
||||
> /* Horizon-OC: Halt BPMP here as hoc-clk may be running it, and if it's running there will be a panic. */
|
||||
161a162,165
|
||||
> reg::Write(FLOW_CTLR + FLOW_CTLR_HALT_COP_EVENTS, FLOW_REG_BITS_ENUM (HALT_COP_EVENTS_MODE, FLOW_MODE_STOP),
|
||||
> FLOW_REG_BITS_ENUM_SEL(HALT_COP_EVENTS_JTAG, jtag, ENABLED, DISABLED));
|
||||
>
|
||||
> /* Validate that the bpmp is appropriately halted. */
|
||||
@@ -1,22 +0,0 @@
|
||||
100a101,105
|
||||
> #include "secmon_define_emc_access_table.inc"
|
||||
> #include "secmon_define_emc01_access_table.inc"
|
||||
> #include "secmon_define_flow_controller_access_table.inc"
|
||||
> #include "secmon_define_exception_vectors_access_table.inc"
|
||||
> #include "secmon_define_rtc_pmc_access_table.inc"
|
||||
104,107c109,118
|
||||
< { PmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDevicePmc.GetAddress(), PmcAccessTable::Address, PmcAccessTable::Size, },
|
||||
< { McAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceMemoryController.GetAddress(), McAccessTable::Address, McAccessTable::Size, },
|
||||
< { Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController0.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController0.GetAddress(), Mc01AccessTable::Size, },
|
||||
< { Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController1.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController1.GetAddress(), Mc01AccessTable::Size, },
|
||||
---
|
||||
> { PmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDevicePmc.GetAddress(), PmcAccessTable::Address, PmcAccessTable::Size, },
|
||||
> { McAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceMemoryController.GetAddress(), McAccessTable::Address, McAccessTable::Size, },
|
||||
> { EmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExternalMemoryController.GetAddress(), EmcAccessTable::Address, EmcAccessTable::Size, },
|
||||
> { Emc01AccessTable::ReducedAccessTable.data(), Emc01AccessTable::Address + MemoryRegionVirtualDeviceExternalMemoryController0.GetAddress(), Emc01AccessTable::Address + MemoryRegionPhysicalDeviceExternalMemoryController0.GetAddress(), Emc01AccessTable::Size, },
|
||||
> { Emc01AccessTable::ReducedAccessTable.data(), Emc01AccessTable::Address + MemoryRegionVirtualDeviceExternalMemoryController1.GetAddress(), Emc01AccessTable::Address + MemoryRegionPhysicalDeviceExternalMemoryController1.GetAddress(), Emc01AccessTable::Size, },
|
||||
> { FlowControllerAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceFlowController.GetAddress(), FlowControllerAccessTable::Address, FlowControllerAccessTable::Size, },
|
||||
> { ExceptionVectorsAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExceptionVectors.GetAddress(), ExceptionVectorsAccessTable::Address, ExceptionVectorsAccessTable::Size, },
|
||||
> { RtcPmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceRtcPmc.GetAddress(), RtcPmcAccessTable::Address, RtcPmcAccessTable::Size, },
|
||||
> { Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController0.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController0.GetAddress(), Mc01AccessTable::Size, },
|
||||
> { Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController1.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController1.GetAddress(), Mc01AccessTable::Size, },
|
||||
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define __ACCESS_TABLE_NAME__ Emc01AccessTable
|
||||
#define __ACCESS_TABLE_ADDRESS__ 0
|
||||
#define __ACCESS_TABLE_INC__ "secmon_emc01_access_table_data.inc"
|
||||
|
||||
#include "secmon_define_access_table.inc"
|
||||
|
||||
#undef __ACCESS_TABLE_INC__
|
||||
#undef __ACCESS_TABLE_ADDRESS__
|
||||
#undef __ACCESS_TABLE_NAME__
|
||||
@@ -151,9 +151,7 @@ namespace ams::secmon {
|
||||
HANDLER(ExceptionVectors, I2c1, UINT64_C(0x6000F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(MemoryController0, ExceptionVectors, UINT64_C(0x7001C000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(MemoryController1, MemoryController0, UINT64_C(0x7001D000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(ExternalMemoryController0, MemoryController1, UINT64_C(0x7001E000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(ExternalMemoryController1, ExternalMemoryController0, UINT64_C(0x7001F000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(Sdmmc, ExternalMemoryController1, UINT64_C(0x700B0000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(Sdmmc, MemoryController1, UINT64_C(0x700B0000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(Disp1, Sdmmc, UINT64_C(0x54200000), UINT64_C(0x3000), true, ## __VA_ARGS__) \
|
||||
HANDLER(Dsi, Disp1, UINT64_C(0x54300000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
HANDLER(MipiCal, Dsi, UINT64_C(0x700E3000), UINT64_C(0x1000), true, ## __VA_ARGS__) \
|
||||
|
||||
@@ -1,571 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
#include "../secmon_cache.hpp"
|
||||
#include "../secmon_cpu_context.hpp"
|
||||
#include "../secmon_error.hpp"
|
||||
#include "../secmon_misc.hpp"
|
||||
#include "secmon_smc_power_management.hpp"
|
||||
#include "secmon_smc_se_lock.hpp"
|
||||
|
||||
#include "sc7fw_bin.h"
|
||||
|
||||
namespace ams::secmon {
|
||||
|
||||
/* Declare assembly functionality. */
|
||||
void *GetCoreExceptionStackVirtual();
|
||||
|
||||
}
|
||||
|
||||
namespace ams::secmon::smc {
|
||||
|
||||
/* Declare assembly power-management functionality. */
|
||||
void PivotStackAndInvoke(void *stack, void (*function)());
|
||||
void FinalizePowerOff();
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr inline const uintptr_t PMC = MemoryRegionVirtualDevicePmc.GetAddress();
|
||||
constexpr inline const uintptr_t APB_MISC = MemoryRegionVirtualDeviceApbMisc.GetAddress();
|
||||
constexpr inline const uintptr_t GPIO = MemoryRegionVirtualDeviceGpio.GetAddress();
|
||||
constexpr inline const uintptr_t CLK_RST = MemoryRegionVirtualDeviceClkRst.GetAddress();
|
||||
constexpr inline const uintptr_t EVP = secmon::MemoryRegionVirtualDeviceExceptionVectors.GetAddress();
|
||||
constexpr inline const uintptr_t FLOW_CTLR = MemoryRegionVirtualDeviceFlowController.GetAddress();
|
||||
constexpr inline const uintptr_t AHB_ARBC = MemoryRegionVirtualDeviceSystem.GetAddress();
|
||||
|
||||
constexpr inline uintptr_t CommonSmcStackTop = MemoryRegionVirtualTzramVolatileData.GetEndAddress() - (0x80 * (NumCores - 1));
|
||||
|
||||
enum PowerStateType {
|
||||
PowerStateType_StandBy = 0,
|
||||
PowerStateType_PowerDown = 1,
|
||||
};
|
||||
|
||||
enum PowerStateId {
|
||||
PowerStateId_Sc7 = 27,
|
||||
};
|
||||
|
||||
/* http://infocenter.arm.com/help/topic/com.arm.doc.den0022d/Power_State_Coordination_Interface_PDD_v1_1_DEN0022D.pdf Page 46 */
|
||||
struct SuspendCpuPowerState {
|
||||
using StateId = util::BitPack32::Field< 0, 16, PowerStateId>;
|
||||
using StateType = util::BitPack32::Field<16, 1, PowerStateType>;
|
||||
using PowerLevel = util::BitPack32::Field<24, 2, u32>;
|
||||
};
|
||||
|
||||
constinit bool g_charger_hi_z_mode_enabled = false;
|
||||
|
||||
constinit const reg::BitsMask CpuPowerGateStatusMasks[NumCores] = {
|
||||
PMC_REG_BITS_MASK(PWRGATE_STATUS_CE0),
|
||||
PMC_REG_BITS_MASK(PWRGATE_STATUS_CE1),
|
||||
PMC_REG_BITS_MASK(PWRGATE_STATUS_CE2),
|
||||
PMC_REG_BITS_MASK(PWRGATE_STATUS_CE3),
|
||||
};
|
||||
|
||||
constinit const APBDEV_PMC_PWRGATE_TOGGLE_PARTID CpuPowerGateTogglePartitionIds[NumCores] = {
|
||||
APBDEV_PMC_PWRGATE_TOGGLE_PARTID_CE0,
|
||||
APBDEV_PMC_PWRGATE_TOGGLE_PARTID_CE1,
|
||||
APBDEV_PMC_PWRGATE_TOGGLE_PARTID_CE2,
|
||||
APBDEV_PMC_PWRGATE_TOGGLE_PARTID_CE3,
|
||||
};
|
||||
|
||||
bool IsCpuPoweredOn(const reg::BitsMask mask) {
|
||||
return reg::HasValue(PMC + APBDEV_PMC_PWRGATE_STATUS, REG_BITS_VALUE_FROM_MASK(mask, APBDEV_PMC_PWRGATE_STATUS_STATUS_ON));
|
||||
}
|
||||
|
||||
void PowerOnCpu(const reg::BitsMask mask, u32 toggle_partid) {
|
||||
/* If the cpu is already on, we have nothing to do. */
|
||||
if (IsCpuPoweredOn(mask)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Wait until nothing is being powergated. */
|
||||
int timeout = 5000;
|
||||
while (true) {
|
||||
if (reg::HasValue(PMC + APBDEV_PMC_PWRGATE_TOGGLE, PMC_REG_BITS_ENUM(PWRGATE_TOGGLE_START, DISABLE))) {
|
||||
break;
|
||||
}
|
||||
|
||||
util::WaitMicroSeconds(1);
|
||||
if ((--timeout) < 0) {
|
||||
/* NOTE: Nintendo doesn't do any error handling here... */
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Toggle on the cpu partition. */
|
||||
reg::Write(PMC + APBDEV_PMC_PWRGATE_TOGGLE, PMC_REG_BITS_ENUM (PWRGATE_TOGGLE_START, ENABLE),
|
||||
PMC_REG_BITS_VALUE(PWRGATE_TOGGLE_PARTID, toggle_partid));
|
||||
|
||||
/* Wait up to 5000 us for the powergate to complete. */
|
||||
timeout = 5000;
|
||||
while (true) {
|
||||
if (IsCpuPoweredOn(mask)) {
|
||||
break;
|
||||
}
|
||||
|
||||
util::WaitMicroSeconds(1);
|
||||
if ((--timeout) < 0) {
|
||||
/* NOTE: Nintendo doesn't do any error handling here... */
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ResetCpu(int which_core) {
|
||||
reg::Write(CLK_RST + CLK_RST_CONTROLLER_RST_CPUG_CMPLX_SET, REG_BITS_VALUE(which_core + 0x00, 1, 1), /* CPURESETn */
|
||||
REG_BITS_VALUE(which_core + 0x10, 1, 1)); /* CORERESETn */
|
||||
}
|
||||
|
||||
void StartCpu(int which_core) {
|
||||
reg::Write(CLK_RST + CLK_RST_CONTROLLER_RST_CPUG_CMPLX_CLR, REG_BITS_VALUE(which_core + 0x00, 1, 1), /* CPURESETn */
|
||||
REG_BITS_VALUE(which_core + 0x10, 1, 1)); /* CORERESETn */
|
||||
}
|
||||
|
||||
void PowerOffCpuImpl() {
|
||||
/* Get the current core id. */
|
||||
const auto core_id = hw::GetCurrentCoreId();
|
||||
|
||||
/* Configure the flow controller to prepare for shutting down the current core. */
|
||||
flow::SetCpuCsr(core_id, FLOW_CTLR_CPUN_CSR_ENABLE_EXT_POWERGATE_CPU_ONLY);
|
||||
flow::SetHaltCpuEvents(core_id, false);
|
||||
flow::SetCc4Ctrl(core_id, 0);
|
||||
|
||||
/* Save the core's context for restoration on next power-on. */
|
||||
SaveDebugRegisters();
|
||||
SetCoreOff();
|
||||
|
||||
/* Ensure there are no pending memory transactions prior to our power-down. */
|
||||
FlushEntireDataCache();
|
||||
|
||||
/* Finalize our powerdown and wait for an interrupt. */
|
||||
FinalizePowerOff();
|
||||
}
|
||||
|
||||
void ValidateSocStateForSuspend() {
|
||||
/* Validate that all other cores are off. */
|
||||
AMS_ABORT_UNLESS(reg::HasValue(PMC + APBDEV_PMC_PWRGATE_STATUS, PMC_REG_BITS_VALUE(PWRGATE_STATUS_CE123, 0)));
|
||||
|
||||
/* Horizon-OC: Halt BPMP here as hoc-clk may be running it, and if it's running there will be a panic. */
|
||||
const bool jtag = IsJtagEnabled();
|
||||
reg::Write(FLOW_CTLR + FLOW_CTLR_HALT_COP_EVENTS, FLOW_REG_BITS_ENUM (HALT_COP_EVENTS_MODE, FLOW_MODE_STOP),
|
||||
FLOW_REG_BITS_ENUM_SEL(HALT_COP_EVENTS_JTAG, jtag, ENABLED, DISABLED));
|
||||
|
||||
/* Validate that the bpmp is appropriately halted. */
|
||||
AMS_ABORT_UNLESS(reg::Read(FLOW_CTLR + FLOW_CTLR_HALT_COP_EVENTS) == reg::Encode(FLOW_REG_BITS_ENUM (HALT_COP_EVENTS_MODE, FLOW_MODE_STOP),
|
||||
FLOW_REG_BITS_ENUM_SEL(HALT_COP_EVENTS_JTAG, jtag, ENABLED, DISABLED)));
|
||||
|
||||
/* Further validations aren't guaranteed on < 6.0.0. */
|
||||
if (GetTargetFirmware() < TargetFirmware_6_0_0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Validate that USB2, APB-DMA, AHB-DMA are held in reset. */
|
||||
AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_RST_DEVICES_H, CLK_RST_REG_BITS_ENUM(RST_DEVICES_H_SWR_USB2_RST, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(RST_DEVICES_H_SWR_APBDMA_RST, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(RST_DEVICES_H_SWR_AHBDMA_RST, ENABLE)));
|
||||
|
||||
/* Validate that USBD is held in reset. */
|
||||
AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_RST_DEVICES_L, CLK_RST_REG_BITS_ENUM(RST_DEVICES_L_SWR_USBD_RST, ENABLE)));
|
||||
|
||||
/* Validate that AHB-DMA, USB, USB2, COP are not allowed to arbitrate on the AHB. */
|
||||
AMS_ABORT_UNLESS(reg::HasValue(AHB_ARBC + AHB_ARBITRATION_DISABLE, AHB_REG_BITS_ENUM(ARBITRATION_DISABLE_COP, DISABLE),
|
||||
AHB_REG_BITS_ENUM(ARBITRATION_DISABLE_AHBDMA, DISABLE),
|
||||
AHB_REG_BITS_ENUM(ARBITRATION_DISABLE_USB, DISABLE),
|
||||
AHB_REG_BITS_ENUM(ARBITRATION_DISABLE_USB2, DISABLE)));
|
||||
|
||||
/* Validate that the GPIO controller has clock enabled. */
|
||||
AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_CLK_OUT_ENB_L, CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_L_CLK_ENB_GPIO, ENABLE)));
|
||||
|
||||
/* Validate that both FUSE and KFUSE have clock enabled. */
|
||||
AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_CLK_OUT_ENB_H, CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_H_CLK_ENB_FUSE, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_H_CLK_ENB_KFUSE, ENABLE)));
|
||||
|
||||
/* Validate that all of IRAM has clock enabled. */
|
||||
AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_CLK_OUT_ENB_U, CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_U_CLK_ENB_IRAMA, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_U_CLK_ENB_IRAMB, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_U_CLK_ENB_IRAMC, ENABLE),
|
||||
CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_U_CLK_ENB_IRAMD, ENABLE)));
|
||||
|
||||
/* Validate that ACTMON has clock enabled. */
|
||||
AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_CLK_OUT_ENB_V, CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_V_CLK_ENB_ACTMON, ENABLE)));
|
||||
|
||||
/* Validate that ENTROPY has clock enabled. */
|
||||
AMS_ABORT_UNLESS(reg::HasValue(CLK_RST + CLK_RST_CONTROLLER_CLK_OUT_ENB_W, CLK_RST_REG_BITS_ENUM(CLK_OUT_ENB_W_CLK_ENB_ENTROPY, ENABLE)));
|
||||
}
|
||||
|
||||
void GenerateCryptographicallyRandomBytes(void * const dst, int size) {
|
||||
/* Flush the region we're about to fill to ensure consistency with the SE. */
|
||||
hw::FlushDataCache(dst, size);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Generate random bytes. */
|
||||
se::GenerateRandomBytes(dst, size);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Flush to ensure the CPU sees consistent data for the region. */
|
||||
hw::FlushDataCache(dst, size);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
}
|
||||
|
||||
void SaveSecureContextForErista() {
|
||||
/* Generate a random key source. */
|
||||
util::AlignedBuffer<hw::DataCacheLineSize, se::AesBlockSize> key_source;
|
||||
GenerateCryptographicallyRandomBytes(key_source, se::AesBlockSize);
|
||||
|
||||
const u32 * const key_source_32 = reinterpret_cast<const u32 *>(static_cast<u8 *>(key_source));
|
||||
|
||||
/* Ensure that the key source registers are not locked. */
|
||||
AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_KeySourceReadWrite) != pmc::LockState::Locked);
|
||||
|
||||
/* Write the key source, lock writes to the key source, and verify that the key source is write-locked. */
|
||||
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH24, key_source_32[0]);
|
||||
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH25, key_source_32[1]);
|
||||
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH26, key_source_32[2]);
|
||||
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH27, key_source_32[3]);
|
||||
pmc::LockSecureRegister(pmc::SecureRegister_KeySourceWrite);
|
||||
AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_KeySourceWrite) == pmc::LockState::Locked);
|
||||
|
||||
/* Verify the key source is correct in registers, and read-lock the key source registers. */
|
||||
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH24) == key_source_32[0]);
|
||||
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH25) == key_source_32[1]);
|
||||
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH26) == key_source_32[2]);
|
||||
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH27) == key_source_32[3]);
|
||||
pmc::LockSecureRegister(pmc::SecureRegister_KeySourceRead);
|
||||
|
||||
/* Ensure that the key source registers are locked. */
|
||||
AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_KeySourceReadWrite) == pmc::LockState::Locked);
|
||||
|
||||
/* Generate a random kek into keyslot 2. */
|
||||
se::SetRandomKey(pkg1::AesKeySlot_TzramSaveKek);
|
||||
|
||||
/* Verify that the se is in a validate state, context save, and validate again. */
|
||||
{
|
||||
se::ValidateErrStatus();
|
||||
ON_SCOPE_EXIT { se::ValidateErrStatus(); };
|
||||
|
||||
{
|
||||
/* Transition to non-secure mode for the duration of the context save operation. */
|
||||
se::SetSecure(false);
|
||||
ON_SCOPE_EXIT { se::SetSecure(true); };
|
||||
|
||||
/* Get a pointer to the context storage. */
|
||||
se::Context * const context = MemoryRegionVirtualDramSecureDataStoreSecurityEngineState.GetPointer<se::Context>();
|
||||
static_assert(MemoryRegionVirtualDramSecureDataStoreSecurityEngineState.GetSize() == sizeof(*context));
|
||||
|
||||
/* Save the context. */
|
||||
se::SaveContext(context);
|
||||
|
||||
/* Ensure that the cpu sees consistent data. */
|
||||
hw::FlushDataCache(context, sizeof(*context));
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Write the context pointer to pmc scratch, so that the bootrom will restore it on wake. */
|
||||
reg::Write(PMC + APBDEV_PMC_SCRATCH43, MemoryRegionPhysicalDramSecureDataStoreSecurityEngineState.GetAddress());
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear keyslot 3, and then derive the save key. */
|
||||
se::ClearAesKeySlot(pkg1::AesKeySlot_TzramSaveKey);
|
||||
se::SetEncryptedAesKey256(pkg1::AesKeySlot_TzramSaveKey, pkg1::AesKeySlot_TzramSaveKek, key_source, se::AesBlockSize);
|
||||
|
||||
/* Declare a temporary block to be used as both iv and mac. */
|
||||
u32 temp_block[se::AesBlockSize / sizeof(u32)] = {};
|
||||
|
||||
/* Ensure that the SE sees consistent data for tzram. */
|
||||
const void * const tzram_save_src = MemoryRegionVirtualTzramReadOnlyAlias.GetPointer<u8>() + MemoryRegionVirtualTzramVolatileData.GetSize() + MemoryRegionVirtualTzramVolatileStack.GetSize();
|
||||
void * const tzram_save_dst = MemoryRegionVirtualIramSc7Work.GetPointer<void>();
|
||||
constexpr size_t TzramSaveSize = MemoryRegionVirtualDramSecureDataStoreTzram.GetSize();
|
||||
|
||||
hw::FlushDataCache(tzram_save_src, TzramSaveSize);
|
||||
hw::FlushDataCache(tzram_save_dst, TzramSaveSize);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Encrypt tzram using our random key. */
|
||||
se::EncryptAes256Cbc(tzram_save_dst, TzramSaveSize, pkg1::AesKeySlot_TzramSaveKey, tzram_save_src, TzramSaveSize, temp_block, se::AesBlockSize);
|
||||
hw::FlushDataCache(tzram_save_dst, TzramSaveSize);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Copy the data from work space to the secure storage destination. */
|
||||
void * const tzram_store_dst = MemoryRegionVirtualDramSecureDataStoreTzram.GetPointer<void>();
|
||||
std::memcpy(tzram_store_dst, tzram_save_dst, TzramSaveSize);
|
||||
hw::FlushDataCache(tzram_store_dst, TzramSaveSize);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Compute cmac of tzram into our temporary block. */
|
||||
se::ComputeAes256Cmac(temp_block, se::AesBlockSize, pkg1::AesKeySlot_TzramSaveKey, tzram_save_src, TzramSaveSize);
|
||||
|
||||
/* Ensure that the cmac registers are not locked. */
|
||||
AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_CmacReadWrite) != pmc::LockState::Locked);
|
||||
|
||||
/* Write the cmac, lock writes to the cmac, and verify that the cmac is write-locked. */
|
||||
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH112, temp_block[0]);
|
||||
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH113, temp_block[1]);
|
||||
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH114, temp_block[2]);
|
||||
reg::Write(PMC + APBDEV_PMC_SECURE_SCRATCH115, temp_block[3]);
|
||||
pmc::LockSecureRegister(pmc::SecureRegister_CmacWrite);
|
||||
AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_CmacWrite) == pmc::LockState::Locked);
|
||||
|
||||
/* Verify the key source is correct in registers, and read-lock the key source registers. */
|
||||
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH112) == temp_block[0]);
|
||||
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH113) == temp_block[1]);
|
||||
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH114) == temp_block[2]);
|
||||
AMS_ABORT_UNLESS(reg::Read(PMC + APBDEV_PMC_SECURE_SCRATCH115) == temp_block[3]);
|
||||
pmc::LockSecureRegister(pmc::SecureRegister_CmacRead);
|
||||
|
||||
/* Ensure that the key source registers are locked. */
|
||||
AMS_ABORT_UNLESS(pmc::GetSecureRegisterLockState(pmc::SecureRegister_CmacReadWrite) == pmc::LockState::Locked);
|
||||
}
|
||||
|
||||
void SaveSecureContextForMariko() {
|
||||
/* Save security engine context to TZRAM SE carveout (inaccessible to cpu). */
|
||||
se::SaveContextAutomatic();
|
||||
|
||||
/* Save TZRAM to shadow-TZRAM in always-on power domain. */
|
||||
se::SaveTzramAutomatic();
|
||||
}
|
||||
|
||||
void SaveSecureContext() {
|
||||
/* Save the appropriate secure context. */
|
||||
const auto soc_type = GetSocType();
|
||||
if (soc_type == fuse::SocType_Erista) {
|
||||
SaveSecureContextForErista();
|
||||
} else /* if (soc_type == fuse::SocType_Mariko) */ {
|
||||
SaveSecureContextForMariko();
|
||||
}
|
||||
|
||||
/* Save the debug code. */
|
||||
#if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING)
|
||||
{
|
||||
const void * const debug_code_src = MemoryRegionVirtualDebugCode.GetPointer<void>();
|
||||
void * const debug_code_dst = MemoryRegionVirtualDramDebugDataStore.GetPointer<void>();
|
||||
std::memcpy(debug_code_dst, debug_code_src, MemoryRegionVirtualDebugCode.GetSize());
|
||||
hw::FlushDataCache(debug_code_dst, MemoryRegionVirtualDebugCode.GetSize());
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void LoadAndStartSc7BpmpFirmware() {
|
||||
/* Set BPMP reset. */
|
||||
reg::Write(CLK_RST + CLK_RST_CONTROLLER_RST_DEV_L_SET, CLK_RST_REG_BITS_ENUM(RST_DEV_L_SET_SET_COP_RST, ENABLE));
|
||||
|
||||
/* Set the PMC as insecure, so that the BPMP firmware can access it. */
|
||||
reg::ReadWrite(APB_MISC + APB_MISC_SECURE_REGS_APB_SLAVE_SECURITY_ENABLE_REG0_0, SLAVE_SECURITY_REG_BITS_ENUM(0, PMC, DISABLE));
|
||||
|
||||
/* Set the exception vectors for the bpmp. RESET should point to RESET, all others should point to generic exception/panic. */
|
||||
constexpr const u32 Sc7FirmwareResetVector = static_cast<u32>(MemoryRegionPhysicalIramSc7Firmware.GetAddress() + 0x0);
|
||||
constexpr const u32 Sc7FirmwarePanicVector = static_cast<u32>(MemoryRegionPhysicalIramSc7Firmware.GetAddress() + 0x4);
|
||||
|
||||
reg::Write(EVP + EVP_COP_RESET_VECTOR, Sc7FirmwareResetVector);
|
||||
reg::Write(EVP + EVP_COP_UNDEF_VECTOR, Sc7FirmwarePanicVector);
|
||||
reg::Write(EVP + EVP_COP_SWI_VECTOR, Sc7FirmwarePanicVector);
|
||||
reg::Write(EVP + EVP_COP_PREFETCH_ABORT_VECTOR, Sc7FirmwarePanicVector);
|
||||
reg::Write(EVP + EVP_COP_DATA_ABORT_VECTOR, Sc7FirmwarePanicVector);
|
||||
reg::Write(EVP + EVP_COP_RSVD_VECTOR, Sc7FirmwarePanicVector);
|
||||
reg::Write(EVP + EVP_COP_IRQ_VECTOR, Sc7FirmwarePanicVector);
|
||||
reg::Write(EVP + EVP_COP_FIQ_VECTOR, Sc7FirmwarePanicVector);
|
||||
|
||||
/* Disable activity monitor bpmp monitoring, so that we don't panic upon bpmp wake. */
|
||||
actmon::StopMonitoringBpmp();
|
||||
|
||||
/* Load the bpmp firmware. */
|
||||
void * const sc7fw_load_address = MemoryRegionVirtualIramSc7Firmware.GetPointer<void>();
|
||||
std::memcpy(sc7fw_load_address, sc7fw_bin, sc7fw_bin_size);
|
||||
hw::FlushDataCache(sc7fw_load_address, sc7fw_bin_size);
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Ensure that the bpmp firmware was loaded. */
|
||||
AMS_ABORT_UNLESS(crypto::IsSameBytes(sc7fw_load_address, sc7fw_bin, sc7fw_bin_size));
|
||||
|
||||
/* Clear BPMP reset. */
|
||||
reg::Write(CLK_RST + CLK_RST_CONTROLLER_RST_DEV_L_CLR, CLK_RST_REG_BITS_ENUM(RST_DEV_L_CLR_CLR_COP_RST, ENABLE));
|
||||
|
||||
/* Start the bpmp. */
|
||||
reg::Write(FLOW_CTLR + FLOW_CTLR_HALT_COP_EVENTS, FLOW_REG_BITS_ENUM(HALT_COP_EVENTS_MODE, FLOW_MODE_NONE));
|
||||
}
|
||||
|
||||
void SaveSecureContextAndSuspend() {
|
||||
/* Ensure there are no pending memory transactions before we continue */
|
||||
FlushEntireDataCache();
|
||||
hw::DataSynchronizationBarrierInnerShareable();
|
||||
|
||||
/* Save all secure context (security engine state + tzram). */
|
||||
SaveSecureContext();
|
||||
|
||||
/* Load and start the sc7 firmware on the bpmp. */
|
||||
if (GetTargetFirmware() >= TargetFirmware_2_0_0) {
|
||||
LoadAndStartSc7BpmpFirmware();
|
||||
}
|
||||
|
||||
/* Log our suspension. */
|
||||
/* NOTE: Nintendo only does this on dev, but we will always do it. */
|
||||
if (true /* !pkg1::IsProduction() */) {
|
||||
log::Initialize(secmon::GetLogPort(), secmon::GetLogBaudRate(), secmon::GetLogFlags());
|
||||
log::SendText("OYASUMI\n", 8);
|
||||
log::Flush();
|
||||
}
|
||||
|
||||
/* If we're on erista, configure the bootrom to allow our custom warmboot firmware. */
|
||||
if (GetSocType() == fuse::SocType_Erista) {
|
||||
reg::Write(PMC + APBDEV_PMC_SCRATCH31, 0x2202E012);
|
||||
reg::Write(PMC + APBDEV_PMC_SCRATCH32, 0x6001DC28);
|
||||
}
|
||||
|
||||
/* Finalize our powerdown and wait for an interrupt. */
|
||||
FinalizePowerOff();
|
||||
}
|
||||
|
||||
SmcResult SuspendCpuImpl(SmcArguments &args) {
|
||||
/* Decode arguments. */
|
||||
const util::BitPack32 power_state = { static_cast<u32>(args.r[1]) };
|
||||
const uintptr_t entry_point = args.r[2];
|
||||
const uintptr_t context_id = args.r[3];
|
||||
|
||||
const auto state_type = power_state.Get<SuspendCpuPowerState::StateType>();
|
||||
const auto state_id = power_state.Get<SuspendCpuPowerState::StateId>();
|
||||
|
||||
const auto core_id = hw::GetCurrentCoreId();
|
||||
|
||||
/* Validate arguments. */
|
||||
SMC_R_UNLESS(state_type == PowerStateType_PowerDown, PsciDenied);
|
||||
SMC_R_UNLESS(state_id == PowerStateId_Sc7, PsciDenied);
|
||||
|
||||
/* Orchestrate charger transition to Hi-Z mode if needed. */
|
||||
if (IsChargerHiZModeEnabled()) {
|
||||
/* Ensure we can do comms over i2c-1. */
|
||||
clkrst::EnableI2c1Clock();
|
||||
|
||||
/* If the charger isn't in hi-z mode, perform a transition. */
|
||||
if (!charger::IsHiZMode()) {
|
||||
charger::EnterHiZMode();
|
||||
|
||||
/* Wait up to 50ms for the transition to complete. */
|
||||
const auto start_time = util::GetMicroSeconds();
|
||||
auto current_time = start_time;
|
||||
while ((current_time - start_time) <= 50'000) {
|
||||
if (auto intr_status = reg::Read(GPIO + 0x634); (intr_status & 1) == 0) {
|
||||
/* Wait 256 us to ensure the transition completes. */
|
||||
util::WaitMicroSeconds(256);
|
||||
break;
|
||||
}
|
||||
current_time = util::GetMicroSeconds();
|
||||
}
|
||||
}
|
||||
|
||||
/* Disable i2c-1, since we're done communicating over it. */
|
||||
clkrst::DisableI2c1Clock();
|
||||
}
|
||||
|
||||
/* Enable wake event detection. */
|
||||
pmc::EnableWakeEventDetection();
|
||||
|
||||
/* Ensure that i2c-5 is usable for communicating with the pmic. */
|
||||
clkrst::EnableI2c5Clock();
|
||||
i2c::Initialize(i2c::Port_5);
|
||||
|
||||
/* Orchestrate sleep entry with the pmic. */
|
||||
pmic::EnableSleep();
|
||||
|
||||
/* Ensure that the soc is in a state valid for us to suspend. */
|
||||
if (GetTargetFirmware() >= TargetFirmware_2_0_0) {
|
||||
ValidateSocStateForSuspend();
|
||||
}
|
||||
|
||||
/* Configure the pmc for sc7 entry. */
|
||||
pmc::ConfigureForSc7Entry();
|
||||
|
||||
/* Configure the flow controller for sc7 entry. */
|
||||
flow::SetCc4Ctrl(core_id, 0);
|
||||
flow::SetHaltCpuEvents(core_id, false);
|
||||
flow::ClearL2FlushControl();
|
||||
flow::SetCpuCsr(core_id, FLOW_CTLR_CPUN_CSR_ENABLE_EXT_POWERGATE_CPU_TURNOFF_CPURAIL);
|
||||
|
||||
/* Save the entry context. */
|
||||
SetEntryContext(core_id, entry_point, context_id);
|
||||
|
||||
/* Configure the cpu context for reset. */
|
||||
SaveDebugRegisters();
|
||||
SetCoreOff();
|
||||
SetResetExpected(true);
|
||||
|
||||
/* Switch to use the common smc stack (all other cores are off), and perform suspension. */
|
||||
PivotStackAndInvoke(reinterpret_cast<void *>(CommonSmcStackTop), SaveSecureContextAndSuspend);
|
||||
|
||||
/* This code will never be reached. */
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void PowerOffCpu() {
|
||||
/* Get the current core id. */
|
||||
const auto core_id = hw::GetCurrentCoreId();
|
||||
|
||||
/* Note that we're expecting a reset for the current core. */
|
||||
SetResetExpected(true);
|
||||
|
||||
/* If we're on the final core, shut down directly. Otherwise, invoke with special stack. */
|
||||
if (core_id == NumCores - 1) {
|
||||
PowerOffCpuImpl();
|
||||
} else {
|
||||
PivotStackAndInvoke(GetCoreExceptionStackVirtual(), PowerOffCpuImpl);
|
||||
}
|
||||
|
||||
/* This code will never be reached. */
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
SmcResult SmcPowerOffCpu(SmcArguments &args) {
|
||||
AMS_UNUSED(args);
|
||||
|
||||
PowerOffCpu();
|
||||
}
|
||||
|
||||
SmcResult SmcPowerOnCpu(SmcArguments &args) {
|
||||
/* Get and validate the core to power on. */
|
||||
const int which_core = args.r[1];
|
||||
SMC_R_UNLESS(0 <= which_core && which_core < NumCores, PsciInvalidParameters);
|
||||
|
||||
/* Ensure the core isn't already on. */
|
||||
SMC_R_UNLESS(!IsCoreOn(which_core), PsciAlreadyOn);
|
||||
|
||||
/* Save the entry context. */
|
||||
SetEntryContext(which_core, args.r[2], args.r[3]);
|
||||
|
||||
/* Reset the cpu. */
|
||||
ResetCpu(which_core);
|
||||
|
||||
/* Turn on the core. */
|
||||
PowerOnCpu(CpuPowerGateStatusMasks[which_core], CpuPowerGateTogglePartitionIds[which_core]);
|
||||
|
||||
/* Start the core. */
|
||||
StartCpu(which_core);
|
||||
|
||||
return SmcResult::PsciSuccess;
|
||||
}
|
||||
|
||||
SmcResult SmcSuspendCpu(SmcArguments &args) {
|
||||
return LockSecurityEngineAndInvoke(args, SuspendCpuImpl);
|
||||
}
|
||||
|
||||
bool IsChargerHiZModeEnabled() {
|
||||
return g_charger_hi_z_mode_enabled;
|
||||
}
|
||||
|
||||
void SetChargerHiZModeEnabled(bool en) {
|
||||
g_charger_hi_z_mode_enabled = en;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -99,19 +99,16 @@ namespace ams::secmon::smc {
|
||||
#include "secmon_define_pmc_access_table.inc"
|
||||
#include "secmon_define_mc_access_table.inc"
|
||||
#include "secmon_define_emc_access_table.inc"
|
||||
#include "secmon_define_emc01_access_table.inc"
|
||||
#include "secmon_define_rtc_pmc_access_table.inc"
|
||||
#include "secmon_define_mc01_access_table.inc"
|
||||
|
||||
constexpr const AccessTableEntry AccessTables[] = {
|
||||
{ PmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDevicePmc.GetAddress(), PmcAccessTable::Address, PmcAccessTable::Size, },
|
||||
{ McAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceMemoryController.GetAddress(), McAccessTable::Address, McAccessTable::Size, },
|
||||
{ EmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExternalMemoryController.GetAddress(), EmcAccessTable::Address, EmcAccessTable::Size, },
|
||||
{ Emc01AccessTable::ReducedAccessTable.data(), Emc01AccessTable::Address + MemoryRegionVirtualDeviceExternalMemoryController0.GetAddress(), Emc01AccessTable::Address + MemoryRegionPhysicalDeviceExternalMemoryController0.GetAddress(), Emc01AccessTable::Size, },
|
||||
{ Emc01AccessTable::ReducedAccessTable.data(), Emc01AccessTable::Address + MemoryRegionVirtualDeviceExternalMemoryController1.GetAddress(), Emc01AccessTable::Address + MemoryRegionPhysicalDeviceExternalMemoryController1.GetAddress(), Emc01AccessTable::Size, },
|
||||
{ RtcPmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceRtcPmc.GetAddress(), RtcPmcAccessTable::Address, RtcPmcAccessTable::Size, },
|
||||
{ Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController0.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController0.GetAddress(), Mc01AccessTable::Size, },
|
||||
{ Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController1.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController1.GetAddress(), Mc01AccessTable::Size, },
|
||||
{ PmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDevicePmc.GetAddress(), PmcAccessTable::Address, PmcAccessTable::Size, },
|
||||
{ McAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceMemoryController.GetAddress(), McAccessTable::Address, McAccessTable::Size, },
|
||||
{ EmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceExternalMemoryController.GetAddress(), EmcAccessTable::Address, EmcAccessTable::Size, },
|
||||
{ RtcPmcAccessTable::ReducedAccessTable.data(), MemoryRegionVirtualDeviceRtcPmc.GetAddress(), RtcPmcAccessTable::Address, RtcPmcAccessTable::Size, },
|
||||
{ Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController0.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController0.GetAddress(), Mc01AccessTable::Size, },
|
||||
{ Mc01AccessTable::ReducedAccessTable.data(), Mc01AccessTable::Address + MemoryRegionVirtualDeviceMemoryController1.GetAddress(), Mc01AccessTable::Address + MemoryRegionPhysicalDeviceMemoryController1.GetAddress(), Mc01AccessTable::Size, },
|
||||
};
|
||||
|
||||
constexpr bool IsAccessAllowed(const AccessTableEntry &entry, uintptr_t address) {
|
||||
@@ -173,12 +170,12 @@ namespace ams::secmon::smc {
|
||||
/* This is "probably" to fuck with hackers who got access to the SMC and are trying to get control of the */
|
||||
/* BPMP to exploit jamais vu, deja vu, or other related DMA/wake-from-sleep vulnerabilities. */
|
||||
constexpr uintptr_t MC = MemoryRegionPhysicalDeviceMemoryController.GetAddress();
|
||||
// SMC_R_UNLESS((address == (MC + MC_SMMU_AVPC_ASID) || address == (MC + MC_SMMU_PPCS1_ASID)), InvalidArgument);
|
||||
SMC_R_UNLESS((address == (MC + MC_SMMU_AVPC_ASID) || address == (MC + MC_SMMU_PPCS1_ASID)), InvalidArgument);
|
||||
|
||||
// /* For backwards compatibility, we'll allow access to these devices on 1.0.0. */
|
||||
// if (GetTargetFirmware() < TargetFirmware_2_0_0) {
|
||||
/* For backwards compatibility, we'll allow access to these devices on 1.0.0. */
|
||||
if (GetTargetFirmware() < TargetFirmware_2_0_0) {
|
||||
virtual_address = MemoryRegionVirtualDeviceMemoryController.GetAddress() + (address - MC);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
/* Perform the read or write, if we should. */
|
||||
|
||||
@@ -126,7 +126,8 @@ namespace ams::ldr {
|
||||
bool g_is_ptm;
|
||||
|
||||
/* Global Zstd decompression context. */
|
||||
alignas(8) u8 g_zstd_dctx_workspace[util::DecompressZstdWithBicWorkBufferSizeDefault];
|
||||
constexpr size_t ZstdDctxWorkspaceSize = 0x176E8;
|
||||
alignas(8) u8 g_zstd_dctx_workspace[ZstdDctxWorkspaceSize];
|
||||
|
||||
Result ValidateProgramVersion(ncm::ProgramId program_id, u32 version) {
|
||||
/* No version verification is done before 8.1.0. */
|
||||
@@ -180,8 +181,8 @@ namespace ams::ldr {
|
||||
return (MakeProgramInfoFlag(static_cast<const util::BitPack32 *>(meta->aci_kac), meta->aci->kac_size / sizeof(util::BitPack32)) & ProgramInfoFlag_ApplicationTypeMask) == ProgramInfoFlag_Application;
|
||||
}
|
||||
|
||||
Npdm::ProcessAddressSpace GetProcessAddressSpace(const Meta *meta) {
|
||||
return static_cast<Npdm::ProcessAddressSpace>((meta->npdm->flags0 & Npdm::MetaFlag0_ProcessAddressSpaceMask) >> Npdm::MetaFlag0_ProcessAddressSpaceShift);
|
||||
Npdm::AddressSpaceType GetAddressSpaceType(const Meta *meta) {
|
||||
return static_cast<Npdm::AddressSpaceType>((meta->npdm->flags & Npdm::MetaFlag_AddressSpaceTypeMask) >> Npdm::MetaFlag_AddressSpaceTypeShift);
|
||||
}
|
||||
|
||||
Acid::PoolPartition GetPoolPartition(const Meta *meta) {
|
||||
@@ -224,7 +225,7 @@ namespace ams::ldr {
|
||||
/* Read NSO header. */
|
||||
size_t read_size;
|
||||
R_TRY(fs::ReadFile(std::addressof(read_size), file, 0, g_nso_headers + ctx.nso_count, sizeof(NsoHeader)));
|
||||
R_UNLESS_LOG(read_size == sizeof(NsoHeader), ldr::ResultInvalidNso(), "[ldr] NSO header truncated!\n");
|
||||
R_UNLESS(read_size == sizeof(NsoHeader), ldr::ResultInvalidNso());
|
||||
|
||||
/* Note nso is present. */
|
||||
switch (i) {
|
||||
@@ -263,7 +264,7 @@ namespace ams::ldr {
|
||||
|
||||
Result CheckAutoLoad(const AutoLoadModuleContext &ctx, u32 acid_flags) {
|
||||
/* We must always have a main. */
|
||||
R_UNLESS_LOG(ctx.ali.has_main, ldr::ResultInvalidNso(), "[ldr] Missing main!\n");
|
||||
R_UNLESS(ctx.ali.has_main, ldr::ResultInvalidNso());
|
||||
|
||||
/* Validate flags and extents for all present NSOs. */
|
||||
for (int i = 0; i < ctx.nso_count; ++i) {
|
||||
@@ -271,11 +272,11 @@ namespace ams::ldr {
|
||||
|
||||
/* All NSOs must not be --X. */
|
||||
/* This is "probably" not checked on Ounce? */
|
||||
R_UNLESS_LOG((hdr.flags & NsoHeader::Flag_PreventCodeReads) == 0, ldr::ResultInvalidNso(), "[ldr] NSO[%d] --x not allowed!\n", i);
|
||||
R_UNLESS((hdr.flags & NsoHeader::Flag_PreventCodeReads) == 0, ldr::ResultInvalidNso());
|
||||
|
||||
/* Zstd compression only allowed on main, and only when both rtld+sdk are present. */
|
||||
if (i != ctx.main_nso_idx || ctx.rtld_idx < 0 || ctx.sdk_nso_idx < 0) {
|
||||
R_UNLESS_LOG((hdr.flags & NsoHeader::Flag_UseZbicCompression) == 0, ldr::ResultInvalidNso(), "[ldr] NSO[%d] zbic not allowed!\n", i);
|
||||
R_UNLESS((hdr.flags & NsoHeader::Flag_UseZbicCompression) == 0, ldr::ResultInvalidNso());
|
||||
}
|
||||
|
||||
/* NSOs must have page-aligned segments. */
|
||||
@@ -298,13 +299,13 @@ namespace ams::ldr {
|
||||
const bool has_browser_dll = (acid_flags & Acid::AcidFlag_LoadBrowserCoreDll) != 0;
|
||||
if (ctx.ali.has_rtld || ctx.ali.has_sdk) {
|
||||
/* If we have sdk we must have rtld. */
|
||||
R_UNLESS_LOG(ctx.ali.has_rtld, ldr::ResultInvalidNso(), "[ldr] Missing rtld!\n");
|
||||
R_UNLESS(ctx.ali.has_rtld, ldr::ResultInvalidNso());
|
||||
|
||||
/* If we have rtld, we must not have browser core dll. */
|
||||
R_UNLESS_LOG(!has_browser_dll, ldr::ResultInvalidNso(), "[ldr] BrowserCoreDll must not be present!\n");
|
||||
R_UNLESS(!has_browser_dll, ldr::ResultInvalidNso());
|
||||
} else {
|
||||
/* We must not have both subsdk and browser dll. */
|
||||
R_UNLESS_LOG(!(ctx.ali.has_subsdk && has_browser_dll), ldr::ResultInvalidNso(), "[ldr] Can't have both subsdk and BrowserCoreDll!\n");
|
||||
R_UNLESS(!(ctx.ali.has_subsdk && has_browser_dll), ldr::ResultInvalidNso());
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
@@ -393,8 +394,6 @@ namespace ams::ldr {
|
||||
|
||||
/* If the signature check fails, we need to check if this is allowable. */
|
||||
if (!is_signature_valid) {
|
||||
AMS_LOG("[ldr] invalid signature!\n");
|
||||
|
||||
/* We have to enforce signature checks on prod and when we have a signature to check on dev. */
|
||||
R_UNLESS(IsDevelopmentForAcidProductionCheck(), ldr::ResultInvalidNcaSignature());
|
||||
R_UNLESS(!code_verification_data.has_data, ldr::ResultInvalidNcaSignature());
|
||||
@@ -408,56 +407,52 @@ namespace ams::ldr {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result GetCreateProcessParameterFlags(u32 *out, const Meta *meta, const u32 ldr_flags) {
|
||||
const u8 meta_flags0 = meta->npdm->flags0;
|
||||
const u8 meta_flags1 = meta->npdm->flags1;
|
||||
Result GetCreateProcessFlags(u32 *out, const Meta *meta, const u32 ldr_flags) {
|
||||
const u8 meta_flags = meta->npdm->flags;
|
||||
|
||||
u32 flags = 0;
|
||||
|
||||
/* Set Is64Bit. */
|
||||
if (meta_flags0 & Npdm::MetaFlag0_Is64BitInstruction) {
|
||||
flags |= svc::CreateProcessParameterFlag_64Bit;
|
||||
if (meta_flags & Npdm::MetaFlag_Is64Bit) {
|
||||
flags |= svc::CreateProcessFlag_Is64Bit;
|
||||
}
|
||||
|
||||
/* Set ProcessAddressSpace. */
|
||||
switch (GetProcessAddressSpace(meta)) {
|
||||
case Npdm::ProcessAddressSpace_32Bit:
|
||||
flags |= svc::CreateProcessParameterFlag_AddressSpace32Bit;
|
||||
/* Set AddressSpaceType. */
|
||||
switch (GetAddressSpaceType(meta)) {
|
||||
case Npdm::AddressSpaceType_32Bit:
|
||||
flags |= svc::CreateProcessFlag_AddressSpace32Bit;
|
||||
break;
|
||||
case Npdm::ProcessAddressSpace_64Bit36:
|
||||
flags |= svc::CreateProcessParameterFlag_AddressSpace64Bit36;
|
||||
case Npdm::AddressSpaceType_64BitDeprecated:
|
||||
flags |= svc::CreateProcessFlag_AddressSpace64BitDeprecated;
|
||||
break;
|
||||
case Npdm::ProcessAddressSpace_32BitNoReserved:
|
||||
flags |= svc::CreateProcessParameterFlag_AddressSpace32BitNoReserved;
|
||||
case Npdm::AddressSpaceType_32BitWithoutAlias:
|
||||
flags |= svc::CreateProcessFlag_AddressSpace32BitWithoutAlias;
|
||||
break;
|
||||
case Npdm::ProcessAddressSpace_64Bit39:
|
||||
flags |= svc::CreateProcessParameterFlag_AddressSpace64Bit39;
|
||||
break;
|
||||
case Npdm::ProcessAddressSpace_64Bit42:
|
||||
flags |= svc::CreateProcessParameterFlag_AddressSpace64Bit42;
|
||||
case Npdm::AddressSpaceType_64Bit:
|
||||
flags |= svc::CreateProcessFlag_AddressSpace64Bit;
|
||||
break;
|
||||
default:
|
||||
R_THROW(ldr::ResultInvalidMeta());
|
||||
}
|
||||
|
||||
/* Set Enable Debug. */
|
||||
if (ldr_flags & CreateProcessParameterFlag_EnableJitDebug) {
|
||||
flags |= svc::CreateProcessParameterFlag_EnableJitDebug;
|
||||
if (ldr_flags & CreateProcessFlag_EnableDebug) {
|
||||
flags |= svc::CreateProcessFlag_EnableDebug;
|
||||
}
|
||||
|
||||
/* Set Enable ASLR. */
|
||||
if (!(ldr_flags & CreateProcessParameterFlag_DisableAslr)) {
|
||||
flags |= svc::CreateProcessParameterFlag_EnableAslr;
|
||||
if (!(ldr_flags & CreateProcessFlag_DisableAslr)) {
|
||||
flags |= svc::CreateProcessFlag_EnableAslr;
|
||||
}
|
||||
|
||||
/* Set Is Application. */
|
||||
if (IsApplication(meta)) {
|
||||
flags |= svc::CreateProcessParameterFlag_IsApplication;
|
||||
flags |= svc::CreateProcessFlag_IsApplication;
|
||||
|
||||
/* 7.0.0+: Set OptimizeMemoryAllocation if relevant. */
|
||||
if (hos::GetVersion() >= hos::Version_7_0_0) {
|
||||
if (meta_flags0 & Npdm::MetaFlag0_OptimizeMemoryAllocation) {
|
||||
flags |= svc::CreateProcessParameterFlag_OptimizeMemoryAllocation;
|
||||
if (meta_flags & Npdm::MetaFlag_OptimizeMemoryAllocation) {
|
||||
flags |= svc::CreateProcessFlag_OptimizeMemoryAllocation;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -469,19 +464,19 @@ namespace ams::ldr {
|
||||
switch (GetPoolPartition(meta)) {
|
||||
case Acid::PoolPartition_Application:
|
||||
if (IsApplet(meta)) {
|
||||
flags |= svc::CreateProcessParameterFlag_PoolPartitionApplet;
|
||||
flags |= svc::CreateProcessFlag_PoolPartitionApplet;
|
||||
} else {
|
||||
flags |= svc::CreateProcessParameterFlag_PoolPartitionApplication;
|
||||
flags |= svc::CreateProcessFlag_PoolPartitionApplication;
|
||||
}
|
||||
break;
|
||||
case Acid::PoolPartition_Applet:
|
||||
flags |= svc::CreateProcessParameterFlag_PoolPartitionApplet;
|
||||
flags |= svc::CreateProcessFlag_PoolPartitionApplet;
|
||||
break;
|
||||
case Acid::PoolPartition_System:
|
||||
flags |= svc::CreateProcessParameterFlag_PoolPartitionSystem;
|
||||
flags |= svc::CreateProcessFlag_PoolPartitionSystem;
|
||||
break;
|
||||
case Acid::PoolPartition_SystemNonSecure:
|
||||
flags |= svc::CreateProcessParameterFlag_PoolPartitionSystemNonSecure;
|
||||
flags |= svc::CreateProcessFlag_PoolPartitionSystemNonSecure;
|
||||
break;
|
||||
default:
|
||||
R_THROW(ldr::ResultInvalidMeta());
|
||||
@@ -489,23 +484,18 @@ namespace ams::ldr {
|
||||
} else if (hos::GetVersion() >= hos::Version_4_0_0) {
|
||||
/* On 4.0.0+, the corresponding bit was simply "UseSecureMemory". */
|
||||
if (meta->acid->flags & Acid::AcidFlag_DeprecatedUseSecureMemory) {
|
||||
flags |= svc::CreateProcessParameterFlag_DeprecatedUseSecureMemory;
|
||||
flags |= svc::CreateProcessFlag_DeprecatedUseSecureMemory;
|
||||
}
|
||||
}
|
||||
|
||||
/* 11.0.0+/meso Set Disable DAS Merge. */
|
||||
if (meta_flags0 & Npdm::MetaFlag0_DisableDeviceAddressSpaceMerge) {
|
||||
flags |= svc::CreateProcessParameterFlag_DisableDeviceAddressSpaceMerge;
|
||||
/* 11.0.0+/meso Set Disable DAS merge. */
|
||||
if (meta_flags & Npdm::MetaFlag_DisableDeviceAddressSpaceMerge) {
|
||||
flags |= svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge;
|
||||
}
|
||||
|
||||
/* 18.0.0+/meso Set Enable Address Sanitizer . */
|
||||
if (meta_flags0 & Npdm::MetaFlag0_EnableAddressSanitizer) {
|
||||
flags |= svc::CreateProcessParameterFlag_EnableAddressSanitizer;
|
||||
}
|
||||
|
||||
/* 23.0.0+/meso Set Enable Shadow Stack. */
|
||||
if (meta_flags1 & Npdm::MetaFlag1_EnableShadowStack) {
|
||||
flags |= svc::CreateProcessParameterFlag_EnableShadowStack;
|
||||
/* 18.0.0+/meso Set Alias region extra size. */
|
||||
if (meta_flags & Npdm::MetaFlag_EnableAliasRegionExtraSize) {
|
||||
flags |= svc::CreateProcessFlag_EnableAliasRegionExtraSize;
|
||||
}
|
||||
|
||||
*out = flags;
|
||||
@@ -523,7 +513,7 @@ namespace ams::ldr {
|
||||
out->reslimit = resource_limit;
|
||||
|
||||
/* Set flags. */
|
||||
R_TRY(GetCreateProcessParameterFlags(std::addressof(out->flags), meta, flags));
|
||||
R_TRY(GetCreateProcessFlags(std::addressof(out->flags), meta, flags));
|
||||
|
||||
/* 3.0.0+ System Resource Size. */
|
||||
if (hos::GetVersion() >= hos::Version_3_0_0) {
|
||||
@@ -533,7 +523,7 @@ namespace ams::ldr {
|
||||
/* Validate system resource usage. */
|
||||
if (meta->npdm->system_resource_size) {
|
||||
/* Process must be 64-bit. */
|
||||
R_UNLESS((out->flags & svc::CreateProcessParameterFlag_AddressSpace64Bit39), ldr::ResultInvalidMeta());
|
||||
R_UNLESS((out->flags & svc::CreateProcessFlag_AddressSpace64Bit), ldr::ResultInvalidMeta());
|
||||
|
||||
/* Process must be application or applet. */
|
||||
R_UNLESS(IsApplication(meta) || IsApplet(meta), ldr::ResultInvalidMeta());
|
||||
@@ -577,11 +567,6 @@ namespace ams::ldr {
|
||||
out->nso_size[i] = std::max(out->nso_size[i], rw_end);
|
||||
out->nso_size[i] += static_cast<size_t>(ctx.headers[i].bss_size);
|
||||
|
||||
/* Reserve hook arena memory past pcv's bss. */
|
||||
if (g_is_pcv && i == ctx.main_nso_idx) {
|
||||
out->nso_size[i] = util::AlignUp(out->nso_size[i], os::MemoryPageSize) + hoc::pcv::PcvDataArenaSize;
|
||||
}
|
||||
|
||||
const size_t aligned_up_size = util::AlignUp(out->nso_size[i], os::MemoryPageSize) & (AutoLoadModuleSizeMax - 1);
|
||||
R_UNLESS(out->nso_size[i] <= aligned_up_size, ldr::ResultInvalidNso());
|
||||
R_UNLESS(aligned_up_size > 0, ldr::ResultInvalidNso());
|
||||
@@ -606,29 +591,25 @@ namespace ams::ldr {
|
||||
uintptr_t aslr_start = 0;
|
||||
size_t aslr_size = 0;
|
||||
if (hos::GetVersion() >= hos::Version_2_0_0) {
|
||||
switch (out_param->flags & svc::CreateProcessParameterFlag_AddressSpaceMask) {
|
||||
case svc::CreateProcessParameterFlag_AddressSpace32Bit:
|
||||
case svc::CreateProcessParameterFlag_AddressSpace32BitNoReserved:
|
||||
switch (out_param->flags & svc::CreateProcessFlag_AddressSpaceMask) {
|
||||
case svc::CreateProcessFlag_AddressSpace32Bit:
|
||||
case svc::CreateProcessFlag_AddressSpace32BitWithoutAlias:
|
||||
aslr_start = svc::AddressSmallMap32Start;
|
||||
aslr_size = svc::AddressSmallMap32Size;
|
||||
break;
|
||||
case svc::CreateProcessParameterFlag_AddressSpace64Bit36:
|
||||
case svc::CreateProcessFlag_AddressSpace64BitDeprecated:
|
||||
aslr_start = svc::AddressSmallMap36Start;
|
||||
aslr_size = svc::AddressSmallMap36Size;
|
||||
break;
|
||||
case svc::CreateProcessParameterFlag_AddressSpace64Bit39:
|
||||
case svc::CreateProcessFlag_AddressSpace64Bit:
|
||||
aslr_start = svc::AddressMap39Start;
|
||||
aslr_size = svc::AddressMap39Size;
|
||||
break;
|
||||
case svc::CreateProcessParameterFlag_AddressSpace64Bit42:
|
||||
aslr_start = svc::AddressMap42Start;
|
||||
aslr_size = svc::AddressMap42Size;
|
||||
break;
|
||||
AMS_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
} else {
|
||||
/* On 1.0.0, only 2 address space types existed. */
|
||||
if (out_param->flags & svc::CreateProcessParameterFlag_AddressSpace64Bit36) {
|
||||
if (out_param->flags & svc::CreateProcessFlag_AddressSpace64BitDeprecated) {
|
||||
aslr_start = svc::AddressSmallMap36Start;
|
||||
aslr_size = svc::AddressSmallMap36Size;
|
||||
} else {
|
||||
@@ -641,7 +622,7 @@ namespace ams::ldr {
|
||||
/* Set Create Process output. */
|
||||
uintptr_t aslr_slide = 0;
|
||||
size_t free_size = (aslr_size - total_size);
|
||||
if (out_param->flags & svc::CreateProcessParameterFlag_EnableAslr) {
|
||||
if (out_param->flags & svc::CreateProcessFlag_EnableAslr) {
|
||||
aslr_slide = GenerateSecureRandom(free_size / os::MemoryBlockUnitSize) * os::MemoryBlockUnitSize;
|
||||
}
|
||||
|
||||
@@ -663,13 +644,10 @@ namespace ams::ldr {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result LoadAutoLoadModuleSegment(fs::FileHandle file, size_t file_offset, size_t compressed_size, size_t segment_size, bool is_compressed, bool is_zbic, uintptr_t map_base, uintptr_t map_end) {
|
||||
Result LoadAutoLoadModuleSegment(fs::FileHandle file, size_t file_offset, size_t compressed_size, size_t segment_size, bool is_compressed, bool is_zstd, uintptr_t map_base, uintptr_t map_end) {
|
||||
/* Select read size based on compression. */
|
||||
size_t file_size = is_compressed ? compressed_size : segment_size;
|
||||
|
||||
AMS_LOG("[ldr] Loading segment @ 0x%016lx: compressed=%d, file_size=0x%08lx, compressed_size=0x%08lx, segment_size=0x%08lx\n",
|
||||
map_base, is_compressed, file_size, compressed_size, segment_size);
|
||||
|
||||
/* Validate size. */
|
||||
R_UNLESS(file_size <= segment_size, ldr::ResultInvalidNso());
|
||||
R_UNLESS(file_size <= std::numeric_limits<s32>::max(), ldr::ResultInvalidNso());
|
||||
@@ -679,19 +657,19 @@ namespace ams::ldr {
|
||||
uintptr_t load_address = is_compressed ? map_end - compressed_size : map_base;
|
||||
size_t read_size;
|
||||
R_TRY(fs::ReadFile(std::addressof(read_size), file, file_offset, reinterpret_cast<void *>(load_address), file_size));
|
||||
R_UNLESS_LOG(read_size == file_size, ldr::ResultInvalidNso(), "[ldr] Couldn't read segment from file!\n");
|
||||
R_UNLESS(read_size == file_size, ldr::ResultInvalidNso());
|
||||
|
||||
/* Uncompress if necessary. */
|
||||
R_SUCCEED_IF(!is_compressed);
|
||||
|
||||
auto compressed_data_buf = reinterpret_cast<const void *>(load_address);
|
||||
|
||||
if (is_zbic) {
|
||||
bool decompressed = util::DecompressZstdWithBic(reinterpret_cast<void *>(g_zstd_dctx_workspace), sizeof(g_zstd_dctx_workspace), reinterpret_cast<void *>(map_base), static_cast<size_t>(map_end - map_base), segment_size, compressed_data_buf, file_size);
|
||||
R_UNLESS_LOG(decompressed, ldr::ResultInvalidNso(), "[ldr] Failed to decompress segment with zbic!\n");
|
||||
if (is_zstd) {
|
||||
bool decompressed = util::DecompressZstdForLoader(reinterpret_cast<void *>(g_zstd_dctx_workspace), ZstdDctxWorkspaceSize, reinterpret_cast<void *>(map_base), static_cast<size_t>(map_end - map_base), segment_size, compressed_data_buf, file_size);
|
||||
R_UNLESS(decompressed, ldr::ResultInvalidNso());
|
||||
} else {
|
||||
bool decompressed = (util::DecompressLZ4(reinterpret_cast<void *>(map_base), segment_size, compressed_data_buf, file_size) == static_cast<int>(segment_size));
|
||||
R_UNLESS_LOG(decompressed, ldr::ResultInvalidNso(), "[ldr] Failed to decompress segment with lz4!\n");
|
||||
R_UNLESS(decompressed, ldr::ResultInvalidNso());
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
@@ -706,15 +684,12 @@ namespace ams::ldr {
|
||||
crypto::GenerateSha256(hash, sizeof(hash),
|
||||
reinterpret_cast<void *>(map_address + nso_header->segments[segment].dst_offset),
|
||||
nso_header->segments[segment].size);
|
||||
R_UNLESS_LOG(std::memcmp(hash, nso_header->segment_hashes[segment], sizeof(hash)) == 0, ldr::ResultInvalidNso(), "[ldr] Invalid segment hash!\n");
|
||||
R_UNLESS(std::memcmp(hash, nso_header->segment_hashes[segment], sizeof(hash)) == 0, ldr::ResultInvalidNso());
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result LoadAutoLoadModule(os::NativeHandle process_handle, fs::FileHandle file, const NsoHeader *nso_header, uintptr_t nso_address, size_t nso_size, size_t map_size) {
|
||||
const bool is_zbic = (nso_header->flags & NsoHeader::Flag_UseZbicCompression) != 0;
|
||||
|
||||
const size_t module_size = static_cast<size_t>(nso_header->rw_dst_offset) + util::AlignUp(nso_header->rw_size + nso_header->bss_size, os::MemoryPageSize);
|
||||
const size_t arena_size = (nso_size > module_size) ? (nso_size - module_size) : 0;
|
||||
const bool is_zstd = (nso_header->flags & NsoHeader::Flag_UseZbicCompression) != 0;
|
||||
|
||||
/* Map and read data from file. */
|
||||
{
|
||||
@@ -728,11 +703,11 @@ namespace ams::ldr {
|
||||
|
||||
/* Load NSO segments. */
|
||||
R_TRY(LoadAutoLoadModuleSegment(file, nso_header->segments[NsoHeader::Segment_Text].file_offset, nso_header->text_compressed_size, nso_header->text_size,
|
||||
(nso_header->flags & NsoHeader::Flag_CompressedText) != 0, is_zbic, map_address + nso_header->text_dst_offset, map_end));
|
||||
(nso_header->flags & NsoHeader::Flag_CompressedText) != 0, is_zstd, map_address + nso_header->text_dst_offset, map_end));
|
||||
R_TRY(LoadAutoLoadModuleSegment(file, nso_header->segments[NsoHeader::Segment_Ro].file_offset, nso_header->ro_compressed_size, nso_header->ro_size,
|
||||
(nso_header->flags & NsoHeader::Flag_CompressedRo) != 0, is_zbic, map_address + nso_header->ro_dst_offset, map_end));
|
||||
(nso_header->flags & NsoHeader::Flag_CompressedRo) != 0, is_zstd, map_address + nso_header->ro_dst_offset, map_end));
|
||||
R_TRY(LoadAutoLoadModuleSegment(file, nso_header->segments[NsoHeader::Segment_Rw].file_offset, nso_header->rw_compressed_size, nso_header->rw_size,
|
||||
(nso_header->flags & NsoHeader::Flag_CompressedRw) != 0, is_zbic, map_address + nso_header->rw_dst_offset, map_end));
|
||||
(nso_header->flags & NsoHeader::Flag_CompressedRw) != 0, is_zstd, map_address + nso_header->rw_dst_offset, map_end));
|
||||
|
||||
/* Clear unused space to zero. */
|
||||
const size_t text_end = static_cast<size_t>(nso_header->text_dst_offset) + static_cast<size_t>(nso_header->text_size);
|
||||
@@ -755,15 +730,7 @@ namespace ams::ldr {
|
||||
|
||||
/* Apply PCV and PTM patches */
|
||||
if (g_is_pcv) {
|
||||
const size_t text_end = static_cast<size_t>(nso_header->text_size);
|
||||
const size_t rx_end = util::AlignUp(text_end, os::MemoryPageSize);
|
||||
const size_t ro_start = static_cast<size_t>(nso_header->ro_dst_offset);
|
||||
const size_t cave_end = (rx_end < ro_start) ? rx_end : ro_start;
|
||||
const uintptr_t cave = map_address + text_end;
|
||||
const size_t cave_size = (cave_end > text_end) ? (cave_end - text_end) : 0;
|
||||
|
||||
/* module_size is used rather than nso_size to exclude the extra data section. */
|
||||
hoc::pcv::Patch(map_address, module_size, cave, cave_size, nso_address, arena_size ? (map_address + module_size) : 0);
|
||||
hoc::pcv::Patch(map_address, nso_size);
|
||||
}
|
||||
|
||||
if (g_is_ptm) {
|
||||
@@ -774,7 +741,7 @@ namespace ams::ldr {
|
||||
/* Set permissions. */
|
||||
const size_t text_size = util::AlignUp(nso_header->text_size, os::MemoryPageSize);
|
||||
const size_t ro_size = util::AlignUp(nso_header->ro_size, os::MemoryPageSize);
|
||||
const size_t rw_size = util::AlignUp(nso_header->rw_size + nso_header->bss_size, os::MemoryPageSize) + arena_size;
|
||||
const size_t rw_size = util::AlignUp(nso_header->rw_size + nso_header->bss_size, os::MemoryPageSize);
|
||||
if (text_size) {
|
||||
const bool prevent_code_reads = (nso_header->flags & NsoHeader::Flag_PreventCodeReads);
|
||||
R_TRY(os::SetProcessMemoryPermission(process_handle, nso_address + nso_header->text_dst_offset, text_size, prevent_code_reads ? os::MemoryPermission_ExecuteOnly : os::MemoryPermission_ReadExecute));
|
||||
@@ -795,15 +762,14 @@ namespace ams::ldr {
|
||||
|
||||
for (int i = 0; i < ctx.nso_count; i++) {
|
||||
const NsoIndex nso_idx = static_cast<NsoIndex>(ctx.ali.nso_indices[i]);
|
||||
const bool is_zbic = (ctx.headers[i].flags & NsoHeader::Flag_UseZbicCompression) != 0;
|
||||
const size_t map_size = is_zbic ? (total_end - process_info->nso_address[i]) : process_info->nso_size[i];
|
||||
|
||||
AMS_LOG("[ldr] module[%d]: idx=%d, path='%s', zbic=%d\n", i, (int)nso_idx, GetNsoPath(nso_idx), is_zbic);
|
||||
|
||||
fs::FileHandle file;
|
||||
R_TRY(fs::OpenFile(std::addressof(file), GetNsoPath(nso_idx), fs::OpenMode_Read));
|
||||
ON_SCOPE_EXIT { fs::CloseFile(file); };
|
||||
|
||||
const bool is_zstd = (ctx.headers[i].flags & NsoHeader::Flag_UseZbicCompression) != 0;
|
||||
const size_t map_size = is_zstd ? (total_end - process_info->nso_address[i]) : process_info->nso_size[i];
|
||||
|
||||
R_TRY(LoadAutoLoadModule(process_info->process_handle, file, ctx.headers + i,
|
||||
process_info->nso_address[i], process_info->nso_size[i], map_size));
|
||||
}
|
||||
@@ -846,7 +812,7 @@ namespace ams::ldr {
|
||||
/* Set the output handle, and ensure that if we fail after this point we clean it up. */
|
||||
out->process_handle = process_handle;
|
||||
out->code_address = param.code_address;
|
||||
ON_RESULT_FAILURE { R_DISCARD(svc::CloseHandle(process_handle)); };
|
||||
ON_RESULT_FAILURE { svc::CloseHandle(process_handle); };
|
||||
|
||||
/* Load all auto load modules. */
|
||||
R_RETURN(LoadAutoLoadModules(out, ctx, argument));
|
||||
@@ -904,8 +870,8 @@ namespace ams::ldr {
|
||||
os::ProcessId process_id = os::GetProcessId(info.process_handle);
|
||||
|
||||
/* Register new process. */
|
||||
const auto as_type = GetProcessAddressSpace(std::addressof(meta));
|
||||
RoManager::GetInstance().RegisterProcess(pin_id, process_id, meta.aci->program_id, as_type == Npdm::ProcessAddressSpace_64Bit39 || as_type == Npdm::ProcessAddressSpace_64Bit36);
|
||||
const auto as_type = GetAddressSpaceType(std::addressof(meta));
|
||||
RoManager::GetInstance().RegisterProcess(pin_id, process_id, meta.aci->program_id, as_type == Npdm::AddressSpaceType_64Bit || as_type == Npdm::AddressSpaceType_64BitDeprecated);
|
||||
|
||||
/* Register all NSOs. */
|
||||
for (int i = 0; i < ctx.nso_count; i++) {
|
||||
@@ -916,7 +882,7 @@ namespace ams::ldr {
|
||||
/* If we're overriding for HBL, perform HTML document redirection. */
|
||||
if (override_status.IsHbl()) {
|
||||
/* Don't validate result, failure is okay. */
|
||||
R_DISCARD(RedirectHtmlDocumentPathForHbl(loc));
|
||||
RedirectHtmlDocumentPathForHbl(loc);
|
||||
}
|
||||
|
||||
/* Clear the external code for the program. */
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#define DISABLED 0
|
||||
#define DEACTIVATED_GPU_FREQ 2000
|
||||
#define GPU_MIN_MIN_VOLT 480000
|
||||
#define CPU_MAX_MAX_VOLT 1235000
|
||||
#define CPU_MAX_MAX_VOLT 1200000
|
||||
|
||||
namespace ams::ldr::hoc {
|
||||
|
||||
@@ -40,7 +40,7 @@ volatile CustomizeTable C = {
|
||||
|
||||
/* Available: 66MHz step rate, 100MHz step rate, 133MHz step rate and jedec. */
|
||||
/* Jedec freqs are 1333MHz, 1600MHz, 1866MHz, 2133MHz, 2400MHz, 2666MHz, 2933MHz, 3200MHz. */
|
||||
.stepMode = StepMode_Jedec,
|
||||
.stepMode = StepMode_66MHz,
|
||||
|
||||
.marikoEmcMaxClock = 2133000, /* 1866MHz @ 1866tWRL is guaranteed to work on all Mariko units */
|
||||
.marikoEmcVddqVolt = 600000,
|
||||
@@ -59,16 +59,14 @@ volatile CustomizeTable C = {
|
||||
.t7_tWTR = 0,
|
||||
.t8_tREFI = 0,
|
||||
|
||||
/* At 1333WL, for some reason (incorrect ram timing config in mtc table?), tRP causes crashes at high reductions - 2 seems to be the most common limit. */
|
||||
/* This is a lazy workaround until I find the issue... */
|
||||
.t2_tRP_cap = 2,
|
||||
|
||||
/* Frequency where non low timings gets used. */
|
||||
.timingEmcTbreak = DISABLED,
|
||||
.low_t1_tRCD = 0,
|
||||
.low_t2_tRP = 0,
|
||||
.low_t3_tRAS = 0,
|
||||
.low_t4_tRRD = 0,
|
||||
.low_t5_tRFC = 0,
|
||||
.low_t6_tRTW = 0,
|
||||
.low_t7_tWTR = 0,
|
||||
.low_t8_tREFI = 0,
|
||||
.low_t6_tRTW = 0,
|
||||
.low_t7_tWTR = 0,
|
||||
|
||||
.readLatency = {
|
||||
/* 1333 */ 0,
|
||||
@@ -85,7 +83,7 @@ volatile CustomizeTable C = {
|
||||
},
|
||||
|
||||
.eristaCpuUV = 0,
|
||||
.eristaCpuVmin = 825,
|
||||
.eristaCpuVmin = 800,
|
||||
.eristaCpuMaxVolt = 1200,
|
||||
/* Unlocks up to 2397 Mhz CPU, usage is not recommended. */
|
||||
.eristaCpuUnlock = DISABLED,
|
||||
@@ -100,14 +98,13 @@ volatile CustomizeTable C = {
|
||||
/* 1120mV is NVIDIA rating */
|
||||
.marikoCpuMaxVolt = 1120,
|
||||
|
||||
/* Supported values: 1963500, 2091000, 2193000, 2295000, 2397000, 2499000, 2601000, 2703000, 2805000. */
|
||||
/* 1963500 is official rating of T214/Mariko, fully safe. */
|
||||
/* 2091000-2295000 is a slight OC which should work on all units, but no guarantees. */
|
||||
/* 2397000 is the max safe OC for most average units with tuned undervolt. */
|
||||
/* 2499000 should be used with caution. */
|
||||
/* 2601000 exceeds pmic limit on most consoles. */
|
||||
/* 2703000 is potentially dangerous and not advised. */
|
||||
/* 2805000 can only be ran on the best of consoles and may be dangerous due to the voltage requirement */
|
||||
/* Supported values: 1963500, 2091000, 2193000, 2295000, 2397000, 2499000, 2601000, 2703000. */
|
||||
/* 1963500 is official rating of T214/Mariko, fully safe. */
|
||||
/* 2091000-2295000 is a slight OC which should work on all units, but no guarantees. */
|
||||
/* 2397000 is the max safe OC for most average units with tuned undervolt. */
|
||||
/* 2499000 should be used with caution. */
|
||||
/* 2601000 exceeds pmic limit on most consoles. */
|
||||
/* 2703000 is potentially dangerous and not advised. */
|
||||
.marikoCpuMaxClock = 1963500,
|
||||
|
||||
.eristaCpuBoostClock = 1785000, /* Default boost clock */
|
||||
@@ -117,8 +114,9 @@ volatile CustomizeTable C = {
|
||||
.eristaGpuVmin = 810,
|
||||
|
||||
.marikoGpuUV = 2,
|
||||
/* Vmin past 795mV won't work due boot voltage being 800mV. */
|
||||
/* Vmin past 795mV won't work due boot voltage being 800mV (can be adjusted though). */
|
||||
.marikoGpuVmin = 610,
|
||||
.marikoGpuBootVolt = 800, /* Used during boot and when temp is <20°C */
|
||||
.marikoGpuVmax = 800,
|
||||
|
||||
.commonGpuVoltOffset = 0,
|
||||
@@ -158,62 +156,30 @@ volatile CustomizeTable C = {
|
||||
},
|
||||
|
||||
.marikoGpuVoltArray = {
|
||||
AUTO /* 76 */,
|
||||
AUTO /* 153 */,
|
||||
AUTO /* 230 */,
|
||||
AUTO /* 307 */,
|
||||
AUTO /* 384 */,
|
||||
AUTO /* 460 */,
|
||||
AUTO /* 537 */,
|
||||
AUTO /* 614 */,
|
||||
AUTO /* 691 */,
|
||||
AUTO /* 768 */,
|
||||
AUTO /* 844 */,
|
||||
AUTO /* 921 */,
|
||||
AUTO /* 998 */,
|
||||
AUTO /* 1075 */,
|
||||
AUTO /* 1152 (HioPT / High UV only!) */,
|
||||
AUTO /* 1228 (High UV Only!) */,
|
||||
AUTO /* 1267 (High UV Only!) */,
|
||||
AUTO /* 1305 (High UV Only!) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1344 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1382 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1420 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1459 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1497 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1536 (Disabled by default) */,
|
||||
},
|
||||
|
||||
/* Override soc voltage brackets. */
|
||||
.marikoSocVoltArray = {
|
||||
0 /* >= 1866 */,
|
||||
0 /* >= 2000 */,
|
||||
0 /* >= 2133 */,
|
||||
0 /* >= 2200 */,
|
||||
0 /* >= 2266 */,
|
||||
0 /* >= 2333 */,
|
||||
0 /* >= 2400 */,
|
||||
0 /* >= 2433 */,
|
||||
0 /* >= 2466 */,
|
||||
0 /* >= 2533 */,
|
||||
0 /* >= 2566 */,
|
||||
0 /* >= 2600 */,
|
||||
0 /* >= 2666 */,
|
||||
0 /* >= 2700 */,
|
||||
0 /* >= 2733 */,
|
||||
0 /* >= 2766 */,
|
||||
0 /* >= 2800 */,
|
||||
0 /* >= 2833 */,
|
||||
0 /* >= 2900 */,
|
||||
0 /* >= 2933 */,
|
||||
0 /* >= 3000 */,
|
||||
0 /* >= 3033 */,
|
||||
0 /* >= 3100 */,
|
||||
0 /* >= 3133 */,
|
||||
0 /* >= 3166 */,
|
||||
0 /* >= 3200 */,
|
||||
0 /* >= 3266 */,
|
||||
0 /* >= 3333 */,
|
||||
AUTO /* 76 */,
|
||||
AUTO /* 153 */,
|
||||
AUTO /* 230 */,
|
||||
AUTO /* 307 */,
|
||||
AUTO /* 384 */,
|
||||
AUTO /* 460 */,
|
||||
AUTO /* 537 */,
|
||||
AUTO /* 614 */,
|
||||
AUTO /* 691 */,
|
||||
AUTO /* 768 */,
|
||||
AUTO /* 844 */,
|
||||
AUTO /* 921 */,
|
||||
AUTO /* 998 */,
|
||||
AUTO /* 1075 */,
|
||||
AUTO /* 1152 (SLT / HiOPT Only!) */,
|
||||
AUTO /* 1228 (HiOPT Only!) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1267 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1305 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1344 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1382 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1420 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1459 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1497 (Disabled by default) */,
|
||||
DEACTIVATED_GPU_FREQ /* 1536 (Disabled by default) */,
|
||||
},
|
||||
|
||||
/* Advanced. */
|
||||
@@ -319,7 +285,6 @@ volatile CustomizeTable C = {
|
||||
{ 2499000, { 1580725, -35815, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2601000, { 1702903, -36675, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2703000, { 1770375, -37515, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2805000, { 1838820, -37707, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
},
|
||||
|
||||
.marikoCpuDvfsTable1581Tbreak {
|
||||
@@ -348,7 +313,6 @@ volatile CustomizeTable C = {
|
||||
{ 2499000, { 1736856, -35286, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2601000, { 1787838, -35967, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2703000, { 1838820, -36648, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2805000, { 1908891, -37707, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
},
|
||||
|
||||
.marikoCpuDvfsTable1683Tbreak {
|
||||
@@ -377,7 +341,6 @@ volatile CustomizeTable C = {
|
||||
{ 2499000, { 1736856, -35286, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2601000, { 1787838, -35967, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2703000, { 1838820, -36648, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2805000, { 1908891, -37707, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
},
|
||||
|
||||
.marikoCpuDvfsTableExtreme {
|
||||
@@ -406,7 +369,6 @@ volatile CustomizeTable C = {
|
||||
{ 2499000, { 1580725, -35815, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2601000, { 1702903, -36675, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2703000, { 1775375, -37515, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
{ 2805000, { 1838820, -37707, 113, }, { CPU_MAX_MAX_VOLT, } },
|
||||
},
|
||||
|
||||
.eristaGpuDvfsTable = {
|
||||
@@ -437,33 +399,30 @@ volatile CustomizeTable C = {
|
||||
},
|
||||
|
||||
.eristaGpuDvfsTableSLT = {
|
||||
{ 76800, { }, { 700000, } },
|
||||
{ 153600, { }, { 700000, } },
|
||||
{ 192000, { }, { 705000, } },
|
||||
{ 230400, { }, { 710000, } },
|
||||
{ 268800, { }, { 720000, } },
|
||||
{ 307200, { }, { 730000, } },
|
||||
{ 345600, { }, { 740000, } },
|
||||
{ 384000, { }, { 750000, } },
|
||||
{ 422400, { }, { 760000, } },
|
||||
{ 460800, { }, { 770000, } },
|
||||
{ 499200, { }, { 780000, } },
|
||||
{ 537600, { }, { 790000, } },
|
||||
{ 576000, { }, { 800000, } },
|
||||
{ 614400, { }, { 810000, } },
|
||||
{ 652800, { }, { 820000, } },
|
||||
{ 691200, { }, { 830000, } },
|
||||
{ 729600, { }, { 850000, } },
|
||||
{ 768000, { }, { 860000, } },
|
||||
{ 806400, { }, { 875000, } },
|
||||
{ 844800, { }, { 885000, } },
|
||||
{ 883200, { }, { 900000, } },
|
||||
{ 921600, { }, { 910000, } },
|
||||
{ 960000, { }, { 930000, } },
|
||||
// { 998400, { }, { 945000, } },
|
||||
// { 1036800, { }, { } },
|
||||
// { 1152000, { }, { } },
|
||||
// { 1075200, { }, { } },
|
||||
{ 76800, { }, { 814294, 8144, -940, 0, 0, 226, } },
|
||||
{ 115200, { }, { 856185, 8144, -940, 0, 0, 226, } },
|
||||
{ 153600, { }, { 856185, 8144, -940, 0, 0, 226, } },
|
||||
{ 192000, { }, { 908077, 8144, -940, 0, 0, 226, } },
|
||||
{ 230400, { }, { 908077, 8144, -940, 0, 0, 226, } },
|
||||
{ 268800, { }, { 934968, 8144, -940, 0, 0, 226, } },
|
||||
{ 307200, { }, { 934968, 8144, -940, 0, 0, 226, } },
|
||||
{ 345600, { }, { 952860, 8144, -940, 0, 0, 226, } },
|
||||
{ 384000, { }, { 952860, 8144, -940, 0, 0, 226, } },
|
||||
{ 422400, { }, { 978751, 8144, -940, 0, 0, 226, } },
|
||||
{ 460800, { }, { 978751, 8144, -940, 0, 0, 226, } },
|
||||
{ 499200, { }, { 990642, 8144, -940, 0, 0, 226, } },
|
||||
{ 537600, { }, { 990642, 8144, -940, 0, 0, 226, } },
|
||||
{ 576000, { }, { 1017534, 8144, -940, 0, 0, 226, } },
|
||||
{ 614400, { }, { 1017534, 8144, -940, 0, 0, 226, } },
|
||||
{ 652800, { }, { 1042425, 8144, -940, 0, 0, 226, } },
|
||||
{ 691200, { }, { 1042425, 8144, -940, 0, 0, 226, } },
|
||||
{ 729600, { }, { 1066317, 8144, -940, 0, 0, 226, } },
|
||||
{ 768000, { }, { 1066317, 8144, -940, 0, 0, 226, } },
|
||||
{ 806400, { }, { 1093208, 8144, -940, 0, 0, 226, } },
|
||||
{ 844800, { }, { 1093208, 8144, -940, 0, 0, 226, } },
|
||||
{ 883200, { }, { 1118100, 8144, -940, 0, 0, 226, } },
|
||||
{ 921600, { }, { 1118100, 8144, -940, 0, 0, 226, } },
|
||||
{ 960000, { }, { 1156991, 8144, -940, 0, 0, 226, } },
|
||||
},
|
||||
|
||||
.eristaGpuDvfsTableHiOPT = {
|
||||
@@ -519,7 +478,7 @@ volatile CustomizeTable C = {
|
||||
},
|
||||
|
||||
.marikoGpuDvfsTableSLT = {
|
||||
{ 76800, {}, { 590000, } },
|
||||
{ 76800, {}, { 590000, } },
|
||||
{ 153600, {}, { 590000, } },
|
||||
{ 230400, {}, { 590000, } },
|
||||
{ 307200, {}, { 590000, } },
|
||||
@@ -574,15 +533,8 @@ volatile CustomizeTable C = {
|
||||
{ 998400, { }, { 1065665, -16075, -497, -179, 3213, 9 } },
|
||||
{ 1075200, { }, { 1132576, -16093, -648, 0, 1077, 40 } },
|
||||
{ 1152000, { }, { 1180029, -14534, -830, 0, 1469, 110 } },
|
||||
{ 1228800, { }, { 1238293, -16383, -859, 0, 3722, 313 } },
|
||||
{ 1267200, { }, { 1276399, -17475, -867, 0, 3681, 559 } },
|
||||
{ 1305600, { }, { } },
|
||||
{ 1344000, { }, { } },
|
||||
{ 1382400, { }, { } },
|
||||
{ 1420800, { }, { } },
|
||||
{ 1459200, { }, { } },
|
||||
{ 1497600, { }, { } },
|
||||
{ 1536000, { }, { } },
|
||||
// { 1228800, { }, { 1238293, -16383, -859, 0, 3722, 313 } },
|
||||
// { 1267200, { }, { 1276399, -17475, -867, 0, 3681, 559 } },
|
||||
},
|
||||
|
||||
.marikoGpuDvfsTableHighUV = {
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define CUST_REV 7
|
||||
#define KIP_VERSION 260
|
||||
#define CUST_REV 4
|
||||
#define KIP_VERSION 240
|
||||
|
||||
#include "oc_common.hpp"
|
||||
#include "pcv/pcv_common.hpp"
|
||||
@@ -86,15 +86,11 @@ struct CustomizeTable {
|
||||
u32 t7_tWTR;
|
||||
u32 t8_tREFI;
|
||||
|
||||
u32 t2_tRP_cap;
|
||||
|
||||
u32 timingEmcTbreak;
|
||||
u32 low_t1_tRCD;
|
||||
u32 low_t2_tRP;
|
||||
u32 low_t3_tRAS;
|
||||
u32 low_t4_tRRD;
|
||||
u32 low_t5_tRFC;
|
||||
u32 low_t6_tRTW;
|
||||
u32 low_t7_tWTR;
|
||||
u32 low_t8_tREFI;
|
||||
|
||||
u32 readLatency[4];
|
||||
u32 writeLatency[4];
|
||||
@@ -120,13 +116,13 @@ struct CustomizeTable {
|
||||
|
||||
u32 marikoGpuUV;
|
||||
u32 marikoGpuVmin;
|
||||
u32 marikoGpuBootVolt;
|
||||
u32 marikoGpuVmax;
|
||||
|
||||
s32 commonGpuVoltOffset;
|
||||
|
||||
u32 eristaGpuVoltArray[27];
|
||||
u32 marikoGpuVoltArray[24];
|
||||
s32 marikoSocVoltArray[28];
|
||||
|
||||
u32 fineTune_t6_tRTW;
|
||||
u32 fineTune_t7_tWTR;
|
||||
|
||||
@@ -134,27 +134,27 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
|
||||
/* At 1333WL, for some reason (incorrect ram timing config in mtc table?), tRP causes crashes at high reductions - 2 seems to be the most common limit. */
|
||||
/* This is a lazy workaround until I find the issue... */
|
||||
const bool lowFreq = freq < C.timingEmcTbreak;
|
||||
u32 tRPpbIndex = C.t2_tRP;
|
||||
if (WL == WL_1331) {
|
||||
tRPpbIndex = MIN(C.t2_tRP_cap, C.t2_tRP);
|
||||
}
|
||||
|
||||
tRCD = tRCD_values[lowFreq ? C.low_t1_tRCD : C.t1_tRCD];
|
||||
tRPpb = tRP_values[lowFreq ? C.low_t2_tRP : C.t2_tRP];
|
||||
tRAS = tRAS_values[lowFreq ? C.low_t3_tRAS : C.t3_tRAS];
|
||||
tRRD = tRRD_values[lowFreq ? C.low_t4_tRRD : C.t4_tRRD];
|
||||
tRFCpb = tRFC_values[lowFreq ? C.low_t5_tRFC : C.t5_tRFC];
|
||||
tRCD = tRCD_values[C.t1_tRCD];
|
||||
tRPpb = tRP_values[tRPpbIndex];
|
||||
tRAS = tRAS_values[C.t3_tRAS];
|
||||
tRRD = tRRD_values[C.t4_tRRD];
|
||||
tRFCpb = tRFC_values[C.t5_tRFC];
|
||||
u32 tRTW = C.t6_tRTW;
|
||||
u32 tWTR = 10 - tWTR_values[C.t7_tWTR];
|
||||
|
||||
u32 tRTW = lowFreq ? C.low_t6_tRTW : C.t6_tRTW;
|
||||
u32 tWTR = 10 - tWTR_values[lowFreq ? C.low_t7_tWTR : C.t7_tWTR];
|
||||
if (freq < C.timingEmcTbreak) {
|
||||
tRTW = C.low_t6_tRTW;
|
||||
tWTR = 10 - tWTR_values[C.low_t7_tWTR];
|
||||
}
|
||||
|
||||
s32 finetRTW = C.fineTune_t6_tRTW;
|
||||
s32 finetWTR = C.fineTune_t7_tWTR;
|
||||
|
||||
u32 tREFI = lowFreq ? C.low_t8_tREFI : C.t8_tREFI;
|
||||
refresh_raw = 0xFFFF;
|
||||
if (tREFI != 6) {
|
||||
refresh_raw = CEIL(tREFpb_values[tREFI] / tCK_avg) - 0x40;
|
||||
refresh_raw = MIN(refresh_raw, static_cast<u32>(0xFFFF));
|
||||
}
|
||||
|
||||
tRC = tRAS + tRPpb;
|
||||
tRFCab = tRFCpb * 2;
|
||||
tXSR = static_cast<double>(tRFCab + 7.5);
|
||||
|
||||
@@ -130,8 +130,6 @@ namespace ams::ldr::hoc {
|
||||
inline u32 tFAW;
|
||||
inline double tRPab;
|
||||
|
||||
inline u32 refresh_raw;
|
||||
|
||||
inline u32 RL;
|
||||
inline u32 WL;
|
||||
|
||||
|
||||
@@ -24,46 +24,42 @@
|
||||
#define CRASH(msg, ...) { ams::diag::AbortImpl(msg, __PRETTY_FUNCTION__, "", 0); __builtin_unreachable(); }
|
||||
|
||||
#include "customize.hpp"
|
||||
#include "oc_log.hpp"
|
||||
|
||||
#if defined(AMS_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING)
|
||||
#include "oc_log.hpp"
|
||||
#endif
|
||||
|
||||
#define PATCH_OFFSET(offset, value) \
|
||||
static_assert(sizeof(__typeof__(offset)) <= sizeof(u64)); \
|
||||
*(offset) = value;
|
||||
|
||||
namespace ams::ldr {
|
||||
R_DEFINE_ERROR_RESULT(OutOfRange, 1000);
|
||||
R_DEFINE_ERROR_RESULT(InvalidMemPllmEntry, 1001);
|
||||
R_DEFINE_ERROR_RESULT(InvalidMtcMagic, 1002);
|
||||
R_DEFINE_ERROR_RESULT(InvalidMtcTable, 1003);
|
||||
R_DEFINE_ERROR_RESULT(InvalidDvbTable, 1004);
|
||||
R_DEFINE_ERROR_RESULT(InvalidCpuFreqVddEntry, 1005);
|
||||
R_DEFINE_ERROR_RESULT(InvalidCpuVoltDfllEntry, 1006);
|
||||
R_DEFINE_ERROR_RESULT(InvalidCpuDvfs, 1007);
|
||||
R_DEFINE_ERROR_RESULT(InvalidCpuMinVolt, 1008);
|
||||
R_DEFINE_ERROR_RESULT(InvalidGpuDvfs, 1009);
|
||||
R_DEFINE_ERROR_RESULT(InvalidGpuFreqMaxPattern, 1010);
|
||||
R_DEFINE_ERROR_RESULT(InvalidGpuPllEntry, 1011);
|
||||
R_DEFINE_ERROR_RESULT(InvalidRegulatorEntry, 1012);
|
||||
R_DEFINE_ERROR_RESULT(UninitializedPatcher, 1013);
|
||||
R_DEFINE_ERROR_RESULT(UnsuccessfulPatcher, 1014);
|
||||
R_DEFINE_ERROR_RESULT(SafetyCheckFailure, 1015);
|
||||
R_DEFINE_ERROR_RESULT(InvalidMtcTablePattern, 1016);
|
||||
R_DEFINE_ERROR_RESULT(InvalidSocVoltPattern, 1017);
|
||||
R_DEFINE_ERROR_RESULT(InvalidSocVoltLimit, 1018);
|
||||
R_DEFINE_ERROR_RESULT(HookArenaOutOfMemory, 1019);
|
||||
R_DEFINE_ERROR_RESULT(HookPayloadTooLarge, 1020);
|
||||
R_DEFINE_ERROR_RESULT(HookRelocationUnsupported, 1021);
|
||||
R_DEFINE_ERROR_RESULT(HookSiteInvalid, 1022);
|
||||
R_DEFINE_ERROR_RESULT(HookPayloadEscapes, 1023);
|
||||
R_DEFINE_ERROR_RESULT(HookDataOutOfMemory, 1024);
|
||||
R_DEFINE_ERROR_RESULT(HookUnavailable, 1025);
|
||||
R_DEFINE_ERROR_RESULT(OutOfRange, 1000);
|
||||
R_DEFINE_ERROR_RESULT(InvalidMemPllmEntry, 1001);
|
||||
R_DEFINE_ERROR_RESULT(InvalidMtcMagic, 1002);
|
||||
R_DEFINE_ERROR_RESULT(InvalidMtcTable, 1003);
|
||||
R_DEFINE_ERROR_RESULT(InvalidDvbTable, 1004);
|
||||
R_DEFINE_ERROR_RESULT(InvalidCpuFreqVddEntry, 1005);
|
||||
R_DEFINE_ERROR_RESULT(InvalidCpuVoltDfllEntry, 1006);
|
||||
R_DEFINE_ERROR_RESULT(InvalidCpuDvfs, 1007);
|
||||
R_DEFINE_ERROR_RESULT(InvalidCpuMinVolt, 1008);
|
||||
R_DEFINE_ERROR_RESULT(InvalidGpuDvfs, 1009);
|
||||
R_DEFINE_ERROR_RESULT(InvalidGpuFreqMaxPattern, 1010);
|
||||
R_DEFINE_ERROR_RESULT(InvalidGpuPllEntry, 1011);
|
||||
R_DEFINE_ERROR_RESULT(InvalidRegulatorEntry, 1012);
|
||||
R_DEFINE_ERROR_RESULT(UninitializedPatcher, 1013);
|
||||
R_DEFINE_ERROR_RESULT(UnsuccessfulPatcher, 1014);
|
||||
R_DEFINE_ERROR_RESULT(SafetyCheckFailure, 1015);
|
||||
R_DEFINE_ERROR_RESULT(InvalidMtcTablePattern, 1016);
|
||||
R_DEFINE_ERROR_RESULT(InvalidSocVoltPattern, 1017);
|
||||
R_DEFINE_ERROR_RESULT(InvalidSocVoltLimit, 1018);
|
||||
}
|
||||
|
||||
namespace ams::ldr::hoc {
|
||||
template<typename Pointer>
|
||||
struct PatcherEntry {
|
||||
using patternFn = bool(*)(Pointer *ptr);
|
||||
using patcherFn = Result(*)(Pointer *ptr);
|
||||
using patternFn = bool(*)(Pointer* ptr);
|
||||
using patcherFn = Result(*)(Pointer* ptr);
|
||||
|
||||
const char* description;
|
||||
patcherFn patcher_fn = nullptr;
|
||||
|
||||
@@ -126,7 +126,7 @@ namespace ams::ldr::hoc {
|
||||
|
||||
SmcRebootToIramPayload();
|
||||
|
||||
while(true) { }
|
||||
while(true){}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
namespace ams::ldr::hoc {
|
||||
|
||||
Result SmcCopyToIram(uintptr_t dest, const void *src, u32 size);
|
||||
void Log(const char *data, ...);
|
||||
void ViewLog();
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
*/
|
||||
|
||||
#include "pcv.hpp"
|
||||
#include "pcv_hook.hpp"
|
||||
|
||||
namespace ams::ldr::hoc::pcv {
|
||||
|
||||
@@ -44,7 +43,7 @@ namespace ams::ldr::hoc::pcv {
|
||||
constexpr u32 uv_step = 12'500;
|
||||
constexpr u32 uv_min = 600'000;
|
||||
|
||||
auto validator = [](regulator *entry) {
|
||||
auto validator = [](regulator* entry) {
|
||||
R_UNLESS(entry->id == 1, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type == 1, ldr::ResultInvalidRegulatorEntry());
|
||||
R_UNLESS(entry->type_1.volt_reg == 0x17, ldr::ResultInvalidRegulatorEntry());
|
||||
@@ -77,14 +76,14 @@ namespace ams::ldr::hoc::pcv {
|
||||
}
|
||||
|
||||
void SafetyCheck() {
|
||||
struct Validator {
|
||||
struct sValidator {
|
||||
volatile u32 value;
|
||||
u32 min;
|
||||
u32 max;
|
||||
u32 panic;
|
||||
bool value_required = false;
|
||||
|
||||
Result Check() {
|
||||
Result check() {
|
||||
if (!value_required && !value) {
|
||||
R_SUCCEED();
|
||||
}
|
||||
@@ -146,50 +145,40 @@ namespace ams::ldr::hoc::pcv {
|
||||
break;
|
||||
}
|
||||
|
||||
Validator validators[] = {
|
||||
{ C.eristaCpuBoostClock, 1020'000, 2397'000, panic::Cpu, true },
|
||||
{ C.marikoCpuBoostClock, 1020'000, 2805'000, panic::Cpu, true },
|
||||
{ C.eristaCpuMaxVolt, 1000, 1260, panic::Cpu, },
|
||||
{ C.marikoCpuMaxVolt, 1000, 1235, panic::Cpu, },
|
||||
{ eristaCpuDvfsMaxFreq, 1785'000, 2397'000, panic::Cpu, },
|
||||
{ marikoCpuDvfsMaxFreq, 1785'000, 2805'000, panic::Cpu, },
|
||||
{ C.commonEmcMemVolt, 912'500, 1350'000, panic::Emc, }, /* Official vmax for the RAMs is 1400-1500mV */
|
||||
{ C.eristaEmcMaxClock, 1600'000, 2600'000, panic::Emc, },
|
||||
{ C.marikoEmcMaxClock, 1600'000, 3500'000, panic::Emc, },
|
||||
{ C.marikoEmcVddqVolt, 400'000, 750'000, panic::Emc, },
|
||||
{ C.marikoSocVmax, 1000, 1200, panic::Emc, },
|
||||
{ eristaGpuDvfsMaxFreq, 768'000, 1152'000, panic::Gpu, },
|
||||
{ marikoGpuDvfsMaxFreq, 768'000, 1536'000, panic::Gpu, },
|
||||
{ C.marikoGpuVmax, 800, 960, panic::Gpu, },
|
||||
sValidator validators[] = {
|
||||
{ C.eristaCpuBoostClock, 1020'000, 2397'000, panic::Cpu, true },
|
||||
{ C.marikoCpuBoostClock, 1020'000, 2703'000, panic::Cpu, true },
|
||||
{ C.eristaCpuMaxVolt, 1000, 1260, panic::Cpu, },
|
||||
{ C.marikoCpuMaxVolt, 1000, 1200, panic::Cpu, },
|
||||
{ eristaCpuDvfsMaxFreq, 1785'000, 2397'000, panic::Cpu, },
|
||||
{ marikoCpuDvfsMaxFreq, 1785'000, 2703'000, panic::Cpu, },
|
||||
{ C.commonEmcMemVolt, 912'500, 1350'000, panic::Emc, }, /* Official vmax for the RAMs is 1400-1500mV */
|
||||
{ C.eristaEmcMaxClock, 1600'000, 2600'000, panic::Emc, },
|
||||
{ C.marikoEmcMaxClock, 1600'000, 3500'000, panic::Emc, },
|
||||
{ C.marikoEmcVddqVolt, 400'000, 750'000, panic::Emc, },
|
||||
{ C.marikoSocVmax, 1000, 1200, panic::Emc, },
|
||||
{ eristaGpuDvfsMaxFreq, 768'000, 1152'000, panic::Gpu, },
|
||||
{ marikoGpuDvfsMaxFreq, 768'000, 1536'000, panic::Gpu, },
|
||||
{ C.marikoGpuVmax, 800, 960, panic::Gpu, },
|
||||
};
|
||||
|
||||
for (auto &v : validators) {
|
||||
if (R_FAILED(v.Check())) {
|
||||
if (R_FAILED(v.check())) {
|
||||
panic::SmcError(v.panic);
|
||||
CRASH("Validation FAIL");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WriteKipLoadToIram() {
|
||||
const u32 hocMagic = 0x686F634D;
|
||||
constexpr uintptr_t LoadMagicAddress = 0x4003DC00; /* Should be a pretty safe address. */
|
||||
R_DISCARD(SmcCopyToIram(LoadMagicAddress, &hocMagic, sizeof(hocMagic)));
|
||||
}
|
||||
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size, uintptr_t cave, size_t cave_size, uintptr_t nso_address, uintptr_t data_arena) {
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size) {
|
||||
SafetyCheck();
|
||||
|
||||
Hooks().Initialize(mapped_nso, nso_address, cave, cave_size, data_arena);
|
||||
|
||||
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
|
||||
if (isMariko) {
|
||||
mariko::Patch(mapped_nso, nso_size);
|
||||
} else {
|
||||
erista::Patch(mapped_nso, nso_size);
|
||||
}
|
||||
|
||||
WriteKipLoadToIram();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "pcv_common.hpp"
|
||||
#include "pcv_erista.hpp"
|
||||
#include "pcv_mariko.hpp"
|
||||
#include "pcv_hook.hpp"
|
||||
|
||||
namespace ams::ldr::hoc::pcv {
|
||||
|
||||
@@ -203,6 +202,6 @@ namespace ams::ldr::hoc::pcv {
|
||||
Result MemVoltHandler(u32 *ptr); // Used for Erista MEM Vdd2 + EMC Vddq or Mariko MEM Vdd2
|
||||
|
||||
void SafetyCheck();
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size, uintptr_t cave, size_t cave_size, uintptr_t nso_address, uintptr_t data_arena);
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size);
|
||||
|
||||
}
|
||||
@@ -83,28 +83,6 @@ namespace ams::ldr::hoc::pcv {
|
||||
inline auto AsmBlCompareOpcodeOnly = [](u32 ins1, u32 ins2) {
|
||||
return ((ins1 ^ ins2) >> 26) == 0;
|
||||
};
|
||||
|
||||
inline auto AsmIsAdrX0 = [](u32 ins) {
|
||||
return (ins & 0x9F00001Fu) == 0x10000000u;
|
||||
};
|
||||
|
||||
inline auto AsmAdrTarget = [](u32 ins, uintptr_t pc) -> uintptr_t {
|
||||
s64 imm = static_cast<s64>((((ins >> 5) & 0x7FFFFu) << 2) | ((ins >> 29) & 0x3u));
|
||||
imm = (imm << 43) >> 43;
|
||||
return static_cast<uintptr_t>(static_cast<s64>(pc) + imm);
|
||||
};
|
||||
|
||||
inline auto AsmSetAdrTarget = [](u32 ins, uintptr_t pc, uintptr_t target) -> u32 {
|
||||
const s64 delta = static_cast<s64>(target) - static_cast<s64>(pc);
|
||||
const u32 immlo = static_cast<u32>(delta & 0x3);
|
||||
const u32 immhi = static_cast<u32>((delta >> 2) & 0x7FFFF);
|
||||
return (ins & ~((0x3u << 29) | (0x7FFFFu << 5))) | (immlo << 29) | (immhi << 5);
|
||||
};
|
||||
|
||||
inline auto AsmIsLdpX = [](u32 ins) {
|
||||
return (ins & 0xFE400000u) == 0xA8400000u;
|
||||
};
|
||||
|
||||
inline bool AsmComparePrologue(u32 ins1, u32 ins2, u32 ins3, u32 cmp1, u32 cmp2, u32 cmp3) {
|
||||
constexpr u32 StpImmMask = ~((((1u << 7) - 1u) << 15));
|
||||
|
||||
@@ -114,6 +92,7 @@ namespace ams::ldr::hoc::pcv {
|
||||
|
||||
bool secondMatch = (ins2 & StpRegsImmMask) == (cmp2 & StpRegsImmMask);
|
||||
|
||||
|
||||
constexpr u32 MovMask = ~((1u << 5) - 1u);
|
||||
|
||||
bool thirdMatch = (ins3 & MovMask) == (cmp3 & MovMask);
|
||||
@@ -187,25 +166,4 @@ namespace ams::ldr::hoc::pcv {
|
||||
return (ins1 & ClearImm19) == (ins2 & ClearImm19);
|
||||
};
|
||||
|
||||
inline bool AsmIsFramePush(u32 ins) {
|
||||
constexpr u32 FramePushMask = 0xFFC07FFF;
|
||||
constexpr u32 FramePushValue = 0xA9807BFD;
|
||||
return (ins & FramePushMask) == FramePushValue;
|
||||
}
|
||||
|
||||
inline u32 *FindFnPrologue(u32 *ptr, u32 margin, u32 *nsoStart) {
|
||||
for (u32 i = 0; i <= margin; ++i) {
|
||||
u32 *candidate = ptr - i;
|
||||
if (candidate < nsoStart) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (AsmIsFramePush(*candidate)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -48,35 +48,6 @@ namespace ams::ldr::hoc::pcv {
|
||||
u64 dvco_calibration_max;
|
||||
};
|
||||
|
||||
/*
|
||||
struct CvbCpuDfllData {
|
||||
u32 tune0_low;
|
||||
u32 tune0_high;
|
||||
u32 tune1_low;
|
||||
u32 tune1_high;
|
||||
u64 padding;
|
||||
u64 dvco_calibration_max;
|
||||
};
|
||||
|
||||
struct CpuCvbTable {
|
||||
u64 socType;
|
||||
CvbCpuDfllData dfllData;
|
||||
u64 padding[3];
|
||||
u64 unk;
|
||||
u32 tune_high_min_millivolts;
|
||||
u32 tune_high_margin_millivolts;
|
||||
u32 vmin;
|
||||
u32 padding_1[3];
|
||||
u32 pll_min_millivolts;
|
||||
u32 vmax;
|
||||
u32 unkScale;
|
||||
u32 speedoScale;
|
||||
u32 voltageScale;
|
||||
u32 zero;
|
||||
cvb_entry_t cvb_entry[32];
|
||||
};
|
||||
*/
|
||||
|
||||
struct __attribute__((packed)) div_nmp {
|
||||
u8 divn_shift;
|
||||
u8 divn_width;
|
||||
@@ -102,7 +73,7 @@ namespace ams::ldr::hoc::pcv {
|
||||
u32 unk_0;
|
||||
struct div_nmp *div_nmp;
|
||||
u32 unk_1[4];
|
||||
void (*unk_fn)(u64 *unk_struct); // set_defaults?
|
||||
void (*unk_fn)(u64* unk_struct); // set_defaults?
|
||||
};
|
||||
|
||||
struct __attribute__((packed)) dvfs_rail {
|
||||
@@ -119,7 +90,7 @@ namespace ams::ldr::hoc::pcv {
|
||||
|
||||
struct __attribute__((packed)) regulator {
|
||||
u64 id;
|
||||
const char *name;
|
||||
const char* name;
|
||||
u32 type;
|
||||
union {
|
||||
struct {
|
||||
@@ -177,7 +148,7 @@ namespace ams::ldr::hoc::pcv {
|
||||
size_t GetDvfsTableEntryCount(T *table_head) {
|
||||
using NT = std::remove_const_t<std::remove_volatile_t<T>>;
|
||||
|
||||
auto is_empty = [](NT *entry) {
|
||||
auto is_empty = [](NT* entry) {
|
||||
u8 *m = reinterpret_cast<u8 *>(entry);
|
||||
for (size_t i = 0; i < sizeof(NT); i++) {
|
||||
if (*(m + i)) {
|
||||
|
||||
@@ -27,26 +27,6 @@
|
||||
|
||||
namespace ams::ldr::hoc::pcv::erista {
|
||||
|
||||
struct HookPayloadData {
|
||||
struct {
|
||||
EristaMtcTable *mtcTable;
|
||||
u32 mtcCount;
|
||||
} mtcTableAsm;
|
||||
};
|
||||
DEFINE_HOOK_PAYLOAD_PTR(HookPayloadData, e_HookPayloadData);
|
||||
|
||||
namespace {
|
||||
std::vector<u32> newEmcList;
|
||||
u32 *nsoStart;
|
||||
u32 *nsoEnd;
|
||||
|
||||
struct {
|
||||
u32 *getEristaMtcTableFnSite = nullptr;
|
||||
EristaMtcTable *mtcTable = nullptr;
|
||||
bool foundMtcTablePattern = false;
|
||||
} getMtcTableCache;
|
||||
}
|
||||
|
||||
Result CpuVoltDvfs(u32 *ptr) {
|
||||
if (std::memcmp(ptr + 5, cpuVoltDvfsPattern, sizeof(cpuVoltDvfsPattern))) {
|
||||
R_THROW(ldr::ResultInvalidCpuMinVolt());
|
||||
@@ -338,16 +318,7 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
da_covers |= (w_cover << 16);
|
||||
table->burst_mc_regs.mc_emem_arb_da_covers = da_covers;
|
||||
|
||||
constexpr u32 AtomsPerDvfsPulse = 0x7;
|
||||
constexpr u32 McEmcSameFreq = 0x0;
|
||||
constexpr u32 ExpiringSoonSlackThreshold = 0xC;
|
||||
const u32 priorityInversionIsoThreshold = GET_CYCLE_CEIL(7.5);
|
||||
constexpr u32 EmcReqB2bXfer = 0x0;
|
||||
const u32 priorityInversionThreshold = GET_CYCLE_CEIL(22.5);
|
||||
const u32 bc2aaHoldoffThreshold = table->burst_mc_regs.mc_emem_arb_timing_rc + 1;
|
||||
|
||||
const u32 mc_emem_arb_misc0 = (AtomsPerDvfsPulse << 28) | (McEmcSameFreq << 27) | (ExpiringSoonSlackThreshold << 21) | (priorityInversionIsoThreshold << 16) | (EmcReqB2bXfer << 15) | (priorityInversionThreshold << 8) | (bc2aaHoldoffThreshold << 0);
|
||||
table->burst_mc_regs.mc_emem_arb_misc0 = mc_emem_arb_misc0;
|
||||
table->burst_mc_regs.mc_emem_arb_misc0 = (table->burst_mc_regs.mc_emem_arb_misc0 & 0xFFE08000) | (table->burst_mc_regs.mc_emem_arb_timing_rc + 1);
|
||||
|
||||
u32 mpcorer_ptsa_rate = MIN(static_cast<u32>(227), (table->rate_khz / 1600000) * 208);
|
||||
table->la_scale_regs.mc_mll_mpcorer_ptsa_rate = mpcorer_ptsa_rate;
|
||||
@@ -388,14 +359,63 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
table->la_scale_regs.mc_latency_allowance_hc_1 = (table->la_scale_regs.mc_latency_allowance_hc_1 & Mask2) | allowance1;
|
||||
table->la_scale_regs.mc_latency_allowance_vi2_0 = (table->la_scale_regs.mc_latency_allowance_vi2_0 & Mask2) | allowance1;
|
||||
|
||||
table->dram_timings.t_rp = tRP_values[0];
|
||||
const u32 tRFCabStock = tRFC_values[0] * 2;
|
||||
table->dram_timings.t_rfc = tRFCabStock;
|
||||
table->dram_timings.t_rp = tRFCpb;
|
||||
table->dram_timings.t_rfc = tRFCab;
|
||||
table->emc_cfg_2 = 0x11083D;
|
||||
table->min_volt = std::clamp(900 + (C.emcDvbShift * 25), 900, 1050);
|
||||
}
|
||||
|
||||
table->emc_mrw2 = (table->emc_mrw2 & ~0xFFu) | static_cast<u32>(mrw2);
|
||||
table->emc_mrw = (table->emc_mrw & ~0x70u) | 0x40; /* nWR */
|
||||
table->emc_cfg_2 = 0x11083D;
|
||||
table->min_volt = std::clamp(900 + (C.emcDvbShift * 25), 900, 1050);
|
||||
namespace {
|
||||
std::vector<u32> newEmcList;
|
||||
u32 *nsoStart;
|
||||
}
|
||||
|
||||
/* The silicon instructs; the children obey... */
|
||||
void MtcGenerateFreqTables() {
|
||||
newEmcList.clear();
|
||||
newEmcList.reserve(DvfsTableEntryCount);
|
||||
newEmcList.insert(newEmcList.end(), std::begin(EmcListDefault), std::end(EmcListDefault));
|
||||
|
||||
if (C.eristaEmcMaxClock <= EmcClkOSLimit) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* This is scuffed, but Eristas step rate is... weird? */
|
||||
/* 1766MHz seems to cause crashes with other freqs near it... why is anyones guess... */
|
||||
u32 freqsLow[] = { 1633000, 1666000, 1700000, 1733000, 1800000, 1833000, 1862400, };
|
||||
constexpr size_t freqsLowSize = std::size(freqsLow);
|
||||
|
||||
for (size_t i = 0; i < freqsLowSize; ++i) {
|
||||
if (freqsLow[i] <= C.eristaEmcMaxClock) {
|
||||
newEmcList.push_back(freqsLow[i]);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (C.eristaEmcMaxClock <= freqsLow[freqsLowSize - 1]) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* High range. */
|
||||
constexpr u32 StepRate = 38400;
|
||||
while (newEmcList.back() + StepRate < C.eristaEmcMaxClock) {
|
||||
newEmcList.push_back(newEmcList.back() + StepRate);
|
||||
}
|
||||
|
||||
if (newEmcList.back() != C.eristaEmcMaxClock) {
|
||||
newEmcList.push_back(static_cast<u32>(C.eristaEmcMaxClock));
|
||||
}
|
||||
|
||||
constexpr u32 PllmToggleFrequency = 19200;
|
||||
|
||||
/* A step of 19.2khz will cause hangs, crashes and other weirdness. */
|
||||
/* Why? ¯\_(ツ)_/¯ */
|
||||
if (C.eristaEmcMaxClock - newEmcList[newEmcList.size() - 2] <= PllmToggleFrequency) {
|
||||
newEmcList.erase(newEmcList.begin() + newEmcList.size() - 2);
|
||||
}
|
||||
|
||||
newEmcList.resize(std::min(newEmcList.size(), DvfsTableEntryLimit));
|
||||
}
|
||||
|
||||
/* TODO: Template this */
|
||||
@@ -447,7 +467,6 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
}
|
||||
|
||||
void PrepareMtcMemoryRegion(u8 *firstTable, EristaMtcTable *usedTable) {
|
||||
/* Move the table, this is nessasary for NLE */
|
||||
memmove(firstTable, usedTable, erista::MtcFullTableSize);
|
||||
|
||||
/* Clear all other tables. */
|
||||
@@ -463,54 +482,6 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
}
|
||||
}
|
||||
|
||||
/* The silicon instructs; the children obey... */
|
||||
void MtcGenerateFreqTables() {
|
||||
newEmcList.clear();
|
||||
newEmcList.reserve(DvfsTableEntryCount);
|
||||
newEmcList.insert(newEmcList.end(), std::begin(EmcListDefault), std::end(EmcListDefault));
|
||||
|
||||
if (C.eristaEmcMaxClock <= EmcClkOSLimit) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* This is scuffed, but Eristas step rate is... weird? */
|
||||
/* 1766MHz seems to cause crashes with other freqs near it... why is anyones guess... */
|
||||
u32 freqsLow[] = { 1633000, 1666000, 1700000, 1733000, 1800000, 1833000, 1862400, };
|
||||
constexpr size_t freqsLowSize = std::size(freqsLow);
|
||||
|
||||
for (size_t i = 0; i < freqsLowSize; ++i) {
|
||||
if (freqsLow[i] <= C.eristaEmcMaxClock) {
|
||||
newEmcList.push_back(freqsLow[i]);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (C.eristaEmcMaxClock <= freqsLow[freqsLowSize - 1]) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* High range. */
|
||||
constexpr u32 StepRate = 38400;
|
||||
while (newEmcList.back() + StepRate < C.eristaEmcMaxClock) {
|
||||
newEmcList.push_back(newEmcList.back() + StepRate);
|
||||
}
|
||||
|
||||
if (newEmcList.back() != C.eristaEmcMaxClock) {
|
||||
newEmcList.push_back(static_cast<u32>(C.eristaEmcMaxClock));
|
||||
}
|
||||
|
||||
constexpr u32 PllmToggleFrequency = 19200;
|
||||
|
||||
/* A step of 19.2khz will cause hangs, crashes and other weirdness. */
|
||||
/* Why? ¯\_(ツ)_/¯ */
|
||||
if (C.eristaEmcMaxClock - newEmcList[newEmcList.size() - 2] <= PllmToggleFrequency) {
|
||||
newEmcList.erase(newEmcList.begin() + newEmcList.size() - 2);
|
||||
}
|
||||
|
||||
newEmcList.resize(std::min(newEmcList.size(), DvfsTableEntryLimit));
|
||||
}
|
||||
|
||||
Result MemFreqMtcTable(u32 *ptr) {
|
||||
static const DramId dramId = [] {
|
||||
DramId id = GetDramId();
|
||||
@@ -532,7 +503,6 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
u8 *startPtr = reinterpret_cast<u8 *>(ptr) - StartAdjustment;
|
||||
|
||||
EristaMtcTable *table = reinterpret_cast<EristaMtcTable *>(startPtr + mtcOffset);
|
||||
|
||||
R_TRY(MtcValidateAllTables(table, EmcListDefault, EmcListSizeDefault));
|
||||
|
||||
PrepareMtcMemoryRegion(startPtr, table);
|
||||
@@ -542,9 +512,6 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
AbortInvalidMtc("Failed mtc validation");
|
||||
}
|
||||
|
||||
/* Cache the table for hooks. */
|
||||
getMtcTableCache.mtcTable = table;
|
||||
|
||||
if (C.eristaEmcMaxClock <= EmcClkOSLimit) {
|
||||
R_SKIP();
|
||||
}
|
||||
@@ -599,78 +566,56 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
// R_SUCCEED();
|
||||
// }
|
||||
|
||||
HOOK_PAYLOAD_FN EristaMtcTable *GetEristaMtcTableImpl(u32 *count) {
|
||||
const HookPayloadData *data = HOOK_PAYLOAD_PTR(HookPayloadData, e_HookPayloadData);
|
||||
|
||||
*count = data->mtcTableAsm.mtcCount;
|
||||
return data->mtcTableAsm.mtcTable;
|
||||
}
|
||||
|
||||
Result MemMtcTableAsm(u32 *ptr) {
|
||||
/* Return if the pattern was already found. */
|
||||
/* This pattern happens multiple times in this function., we only need to find it once. */
|
||||
R_UNLESS(!getMtcTableCache.foundMtcTablePattern, ldr::ResultInvalidMtcTablePattern());
|
||||
|
||||
/* This is a mess but the compiler made this painful to patch so we must do it this way */
|
||||
constexpr u32 AddrpOffset = 1;
|
||||
constexpr u32 MovOffset = 7;
|
||||
constexpr u32 BlOffset = 5;
|
||||
constexpr u32 MovOffsetOld = 8;
|
||||
constexpr s32 GoodAdrpOffset = -1;
|
||||
constexpr s32 GoodMovOffset = -7;
|
||||
constexpr s32 GoodBlOffset = 1;
|
||||
constexpr u32 MtcGoodBlOpcode = 0x97fe6cfc;
|
||||
|
||||
constexpr u32 MtcBadBlOpcode0 = 0x97ffae64; // bl nn::pcv::GetHardwareType
|
||||
constexpr u32 MtcBadBlOpcode1 = 0x940036d5; // bl nn::pcv::GetHardwareType
|
||||
constexpr u32 MtcBadAdrpAsm = 0xd00000a1; // adrp x1, s_ModuleResetStatus_
|
||||
|
||||
constexpr s32 MtcBadBlOffset0 = 2;
|
||||
constexpr s32 MtcBadBlOffset1 = -1;
|
||||
constexpr s32 MtcBadAdrpOffset = 1;
|
||||
|
||||
/* Ensure we don't dereference memory before nso start. */
|
||||
R_UNLESS(ptr - MovOffset >= nsoStart, ldr::ResultInvalidMtcTablePattern());
|
||||
R_UNLESS(ptr + GoodMovOffset >= nsoStart, ldr::ResultInvalidMtcTablePattern());
|
||||
|
||||
u32 adrp = *(ptr - AddrpOffset);
|
||||
R_UNLESS(AsmCompareAdrpNoImm(adrp, MtcAdrpAsm), ldr::ResultInvalidMtcTablePattern());
|
||||
|
||||
/* Check for the branch instruction above the cbz to ensure we are patching the right location*/
|
||||
u32 bl = *(ptr - BlOffset);
|
||||
R_UNLESS(AsmBlCompareOpcodeOnly(bl, MtcBlIns), ldr::ResultInvalidMtcTablePattern());
|
||||
|
||||
/* Check for the mov that actually sets the mtc table count. */
|
||||
u32 mov = *(ptr - MovOffset);
|
||||
bool foundMov = false;
|
||||
foundMov = asm_compare_no_rd(mov, MtcMovAsm);
|
||||
|
||||
if (!foundMov) {
|
||||
mov = *(ptr + MovOffsetOld);
|
||||
/* Check old firmware offset. */
|
||||
foundMov = asm_compare_no_rd(mov, MtcMovAsm);
|
||||
/* Check for GetHardwareType asm and skip if it is found */
|
||||
/* The pattern will match on the first time, but the location is bad, so it must be skipped */
|
||||
if(AsmCompareAdrpNoImm(*(ptr + MtcBadAdrpOffset), MtcBadAdrpAsm) && AsmBlCompareOpcodeOnly(*(ptr + MtcBadBlOffset0), MtcBadBlOpcode0) && AsmBlCompareOpcodeOnly(*(ptr + MtcBadBlOffset1), MtcBadBlOpcode1)) {
|
||||
R_SKIP();
|
||||
}
|
||||
|
||||
R_UNLESS(foundMov, ldr::ResultInvalidMtcTablePattern());
|
||||
/* We don't check for matching register because both registers must be x0 in order to pass the previous checks. */
|
||||
/* The correct instructions will always be x0 since the mtcTable pointer is returned. */
|
||||
u32 adrp = *(ptr + GoodAdrpOffset);
|
||||
R_UNLESS(AsmCompareAdrpNoImm(adrp, MtcAdrpAsm), ldr::ResultInvalidMtcTablePattern());
|
||||
|
||||
constexpr u32 PrologueWindow = 140;
|
||||
u32 *functionPrologue = FindFnPrologue(ptr, PrologueWindow, nsoStart);
|
||||
R_UNLESS(functionPrologue != nullptr, ldr::ResultInvalidMtcTablePattern());
|
||||
|
||||
getMtcTableCache.getEristaMtcTableFnSite = functionPrologue;
|
||||
getMtcTableCache.foundMtcTablePattern = true;
|
||||
/* Check for the branch instruction above the cbz to ensure we are patching the right location*/
|
||||
u32 bl = *(ptr + GoodBlOffset);
|
||||
R_UNLESS(AsmBlCompareOpcodeOnly(bl, MtcGoodBlOpcode), ldr::ResultInvalidMtcTablePattern());
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result InstallHooks() {
|
||||
R_TRY(Hooks().CheckEnabled());
|
||||
/* Check for the mov that actually sets the mtc table count. */
|
||||
u32 mov = *(ptr + GoodMovOffset);
|
||||
R_UNLESS(asm_compare_no_rd(mov, MtcMovAsm), ldr::ResultInvalidMtcTablePattern());
|
||||
|
||||
R_TRY(Hooks().CopyPayload());
|
||||
/* Patch out the count of the mov to our custom mtc table amount*/
|
||||
u32 movCountPatch = asm_set_rd(asm_set_imm16(MtcMovAsm, newEmcList.size()), asm_get_rd(mov));
|
||||
|
||||
R_UNLESS(getMtcTableCache.getEristaMtcTableFnSite != nullptr && getMtcTableCache.mtcTable != nullptr, ldr::ResultInvalidMtcTablePattern());
|
||||
|
||||
/* Copy the data to the payload. */
|
||||
auto *data = Hooks().BindData(e_HookPayloadData);
|
||||
R_UNLESS(data != nullptr, ldr::ResultHookDataOutOfMemory());
|
||||
|
||||
data->mtcTableAsm.mtcTable = reinterpret_cast<EristaMtcTable *>(Hooks().ToVa(getMtcTableCache.mtcTable));
|
||||
data->mtcTableAsm.mtcCount = newEmcList.size();
|
||||
R_TRY(INSTALL_IMPL_HOOK(getMtcTableCache.getEristaMtcTableFnSite, GetEristaMtcTableImpl));
|
||||
PATCH_OFFSET(ptr + GoodMovOffset, movCountPatch);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size) {
|
||||
nsoStart = reinterpret_cast<u32 *>(mapped_nso);
|
||||
nsoEnd = reinterpret_cast<u32 *>(mapped_nso + nso_size);
|
||||
MtcGenerateFreqTables();
|
||||
|
||||
u32 CpuCvbDefaultMaxFreq = static_cast<u32>(GetDvfsTableLastEntry(CpuCvbTableDefault)->freq);
|
||||
@@ -685,13 +630,13 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
{"GPU Volt Thermals", &GpuVoltThermals, 1, nullptr, GpuVminOfficial },
|
||||
{"GPU Freq Table", GpuFreqCvbTable<false>, 1, nullptr, GpuCvbDefaultMaxFreq },
|
||||
{"GPU Freq Asm", &GpuFreqMaxAsm, 2, &GpuMaxClockPatternFn },
|
||||
{"GPU PLL Max", &GpuFreqPllMax, 1, nullptr, GpuClkPllMax },
|
||||
{"GPU PLL Max", & GpuFreqPllMax, 1, nullptr, GpuClkPllMax },
|
||||
// {"GPU PLL Limit", &GpuFreqPllLimit, 4, nullptr, GpuClkPllLimit },
|
||||
{"MEM Table Asm", &MemMtcTableAsm, 4, &MemMtcGetGetTablePatternFn },
|
||||
{"MEM Freq Mtc", &MemFreqMtcTable, 1, nullptr, EmcClkOSLimit },
|
||||
{"MEM Freq Max", &MemFreqMax, 0, nullptr, EmcClkOSLimit },
|
||||
{"MEM Freq PLLM", &MemFreqPllmLimit, 2, nullptr, EmcClkPllmLimit },
|
||||
{"MEM Volt", &MemVoltHandler, 2, nullptr, MemVoltHOS },
|
||||
{"MEM Table Asm", &MemMtcTableAsm, 4, &MemMtcGetGetTablePatternFn },
|
||||
};
|
||||
|
||||
for (uintptr_t ptr = mapped_nso; ptr <= mapped_nso + nso_size - sizeof(EristaMtcTable); ptr += sizeof(u32)) {
|
||||
@@ -703,18 +648,17 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
}
|
||||
}
|
||||
|
||||
// ViewLog();
|
||||
|
||||
for (auto &entry : patches) {
|
||||
LOGGING("%s Count: %zu\n", entry.description, entry.patched_count);
|
||||
if (R_FAILED(entry.CheckResult())) {
|
||||
// ViewLog();
|
||||
panic::SmcError(panic::Patch);
|
||||
|
||||
CRASH(entry.description);
|
||||
}
|
||||
}
|
||||
|
||||
if (R_FAILED(InstallHooks())) {
|
||||
panic::SmcError(panic::Patch);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -140,12 +140,10 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
MtcTableIndex index;
|
||||
};
|
||||
|
||||
/* TODO: Test 6gb and 8gb. */
|
||||
const inline MtcDramIndex mtcIndexTable[] = {
|
||||
{ ICOSA_4GB_SAMSUNG_K4F6E304HB_MGCH, T210SdevEmcDvfsTableS4gb01, },
|
||||
{ ICOSA_4GB_MICRON_MT53B512M32D2NP_062_WTC, T210SdevEmcDvfsTableS4gb01, },
|
||||
{ ICOSA_6GB_SAMSUNG_K4FHE3D4HM_MGCH, T210SdevEmcDvfsTableS6gb01, },
|
||||
{ ICOSA_8GB_SAMSUNG_K4FBE3D4HM_MGXX, T210SdevEmcDvfsTableS6gb01, },
|
||||
{ ICOSA_4GB_HYNIX_H9HCNNNBPUMLHR_NLE, T210SdevEmcDvfsTableH4gb01, },
|
||||
};
|
||||
|
||||
@@ -153,8 +151,8 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
constexpr u32 MtcMovAsm = 0x52800148;
|
||||
constexpr u32 MtcAdrpAsm = 0xD0000081;
|
||||
constexpr u32 MtcBlIns = 0x97ffae64;
|
||||
constexpr u32 MtcAddAsm = 0x91131821;
|
||||
|
||||
constexpr u32 MtcAddAsm = 0x91131821;
|
||||
|
||||
ALWAYS_INLINE bool MemMtcGetGetTablePatternFn(u32 *ptr) {
|
||||
/* This builds an address that gets returned, so the register must be x0 by convention. */
|
||||
return AsmCompareAddNoImm12(*ptr, MtcAddAsm);
|
||||
@@ -162,4 +160,4 @@ namespace ams::ldr::hoc::pcv::erista {
|
||||
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,364 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Lightos_
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../oc_common.hpp"
|
||||
|
||||
#define HOOK_PAYLOAD_FN __attribute__((section("hoc_hookpayload"), used, noinline, visibility("hidden")))
|
||||
|
||||
/* Inline asm because fuck compilers: GCC refuses to put a variable and a function in the same section. */
|
||||
/* It wants alloc+write for one and alloc+exec for the other. */
|
||||
/* You are supposed to be able to override that by writing the flags into the section name yourself, */
|
||||
/* like section("hoc_hookpayload,\"ax\",%progbits"), instead of letting GCC pick them. */
|
||||
/* But GCC takes that whole string as the name and never reads the flags out of it, so it appends the */
|
||||
/* ones it wanted anyway: the .section directive it emits ends up carrying two sets of flags, and the */
|
||||
/* assembler rejects it. The failure lands in the generated assembly, not in anything we wrote. */
|
||||
/* Therefore we must use inline assembly, which reaches the assembler exactly as written. */
|
||||
#define DEFINE_HOOK_PAYLOAD_PTR(type, name) \
|
||||
asm(".section hoc_hookpayload,\"ax\",%progbits\n" \
|
||||
".balign 8\n" \
|
||||
".global " #name "\n" \
|
||||
".hidden " #name "\n" \
|
||||
#name ": .zero 8\n" \
|
||||
".text\n"); \
|
||||
extern "C" __attribute__((visibility("hidden"))) type *name
|
||||
|
||||
#define HOOK_PAYLOAD_PTR(type, name) \
|
||||
([]() -> type * { \
|
||||
type **_hoc_pp; \
|
||||
__asm__("adr %0, " #name : "=r"(_hoc_pp)); \
|
||||
return *_hoc_pp; \
|
||||
}())
|
||||
|
||||
extern "C" const u8 __start_hoc_hookpayload[];
|
||||
extern "C" const u8 __stop_hoc_hookpayload[];
|
||||
|
||||
namespace ams::ldr::hoc::pcv {
|
||||
|
||||
constexpr size_t HookPageSize = 0x1000;
|
||||
constexpr size_t PcvDataArenaSize = 0x1000;
|
||||
|
||||
inline s64 SignExtend(u64 value, int bits) {
|
||||
const int shift = 64 - bits;
|
||||
return static_cast<s64>(value << shift) >> shift;
|
||||
}
|
||||
|
||||
inline u32 EncodeRelBranch(u32 opc, uintptr_t site_va, uintptr_t target_va) {
|
||||
const s64 delta = static_cast<s64>(target_va) - static_cast<s64>(site_va);
|
||||
AMS_ABORT_UNLESS((delta & 0x3) == 0);
|
||||
AMS_ABORT_UNLESS(delta >= -0x08000000 && delta <= 0x07FFFFFC);
|
||||
return opc | (static_cast<u32>(delta >> 2) & 0x03FFFFFFu);
|
||||
}
|
||||
|
||||
inline u32 EncodeB(uintptr_t site_va, uintptr_t target_va) { return EncodeRelBranch(0x14000000u, site_va, target_va); }
|
||||
inline u32 EncodeBL(uintptr_t site_va, uintptr_t target_va) { return EncodeRelBranch(0x94000000u, site_va, target_va); }
|
||||
|
||||
inline u32 EncodePairSp(bool load, u32 rt1, u32 rt2, s32 imm) {
|
||||
const u32 base = load ? 0xA9400000u : 0xA9000000u;
|
||||
const u32 imm7 = static_cast<u32>((imm / 8) & 0x7F);
|
||||
return base | (imm7 << 15) | (rt2 << 10) | (31u << 5) | rt1;
|
||||
}
|
||||
|
||||
inline u32 EncodeSpAdjust(bool sub, u32 imm12) {
|
||||
const u32 base = sub ? 0xD1000000u : 0x91000000u;
|
||||
return base | ((imm12 & 0xFFFu) << 10) | (31u << 5) | 31u;
|
||||
}
|
||||
|
||||
inline Result RelocateInstruction(u32 insn, uintptr_t old_site_va, uintptr_t new_site_va, u32 *out) {
|
||||
const u32 top6 = insn & 0xFC000000u;
|
||||
if (top6 == 0x14000000u || top6 == 0x94000000u) {
|
||||
const s64 old_imm = SignExtend(static_cast<u64>(insn & 0x03FFFFFFu) << 2, 28);
|
||||
const uintptr_t target = old_site_va + old_imm;
|
||||
*out = EncodeRelBranch(top6, new_site_va, target);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
R_UNLESS((insn & 0xFF000010u) != 0x54000000u, ldr::ResultHookRelocationUnsupported()); /* b.cond */
|
||||
R_UNLESS((insn & 0x7E000000u) != 0x34000000u, ldr::ResultHookRelocationUnsupported()); /* cbz/cbnz */
|
||||
R_UNLESS((insn & 0x7E000000u) != 0x36000000u, ldr::ResultHookRelocationUnsupported()); /* tbz/tbnz */
|
||||
R_UNLESS((insn & 0x1F000000u) != 0x10000000u, ldr::ResultHookRelocationUnsupported()); /* adr/adrp */
|
||||
R_UNLESS((insn & 0x3B000000u) != 0x18000000u, ldr::ResultHookRelocationUnsupported()); /* ldr literal */
|
||||
|
||||
*out = insn;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
class HookContext {
|
||||
private:
|
||||
uintptr_t m_map_base = 0; /* loader-side base of pcv's NSO mapping. */
|
||||
uintptr_t m_va_base = 0; /* pcv-side base of the same memory. */
|
||||
uintptr_t m_cave = 0; /* loader-side cave base. (0 if unavailable) */
|
||||
size_t m_cave_size = 0;
|
||||
uintptr_t m_payload = 0; /* loader-side base of the payload copy. */
|
||||
size_t m_payload_sz = 0;
|
||||
size_t m_used = 0;
|
||||
uintptr_t m_data = 0; /* loader-side data arena base, 0 if none. */
|
||||
size_t m_data_used = 0;
|
||||
public:
|
||||
constexpr HookContext() = default;
|
||||
|
||||
void Initialize(uintptr_t map_base, uintptr_t va_base, uintptr_t cave, size_t cave_size, uintptr_t data) {
|
||||
m_map_base = map_base;
|
||||
m_va_base = va_base;
|
||||
m_cave = cave;
|
||||
m_cave_size = cave_size;
|
||||
m_payload = 0;
|
||||
m_payload_sz = 0;
|
||||
m_used = 0;
|
||||
m_data = data;
|
||||
m_data_used = 0;
|
||||
}
|
||||
|
||||
bool IsEnabled() const { return m_cave != 0 && m_cave_size != 0; }
|
||||
|
||||
Result CheckEnabled() const {
|
||||
R_UNLESS(this->IsEnabled(), ldr::ResultHookUnavailable());
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
size_t CaveSize() const { return m_cave_size; }
|
||||
size_t CaveUsed() const { return m_used; }
|
||||
size_t CaveFree() const { return m_cave_size > m_used ? m_cave_size - m_used : 0; }
|
||||
|
||||
size_t DataSize() const { return m_data != 0 ? PcvDataArenaSize : 0; }
|
||||
size_t DataUsed() const { return m_data_used; }
|
||||
size_t DataFree() const { return this->DataSize() - m_data_used; }
|
||||
|
||||
/* Convert loader mapped address to pcv-side address. */
|
||||
uintptr_t ToVa(const void *loader_ptr) const {
|
||||
return m_va_base + (reinterpret_cast<uintptr_t>(loader_ptr) - m_map_base);
|
||||
}
|
||||
|
||||
uintptr_t CaveVa() const { return ToVa(reinterpret_cast<const void *>(m_cave)); }
|
||||
|
||||
Result CopyPayload() {
|
||||
R_TRY(this->CheckEnabled());
|
||||
|
||||
const size_t size = static_cast<size_t>(__stop_hoc_hookpayload - __start_hoc_hookpayload);
|
||||
|
||||
/* Zero length: Linker garbage collected the payload .(happens when nothing references it) */
|
||||
/* __start_ and _stop_ don't prevent this. */
|
||||
/* Copying here would succeed at first but fail later by jumping to empty memory. */
|
||||
R_UNLESS(size != 0, ldr::ResultUninitializedPatcher());
|
||||
R_UNLESS(size <= m_cave_size, ldr::ResultHookPayloadTooLarge());
|
||||
|
||||
m_payload = m_cave;
|
||||
m_payload_sz = size;
|
||||
std::memcpy(reinterpret_cast<void *>(m_payload), __start_hoc_hookpayload, size);
|
||||
|
||||
m_used = util::AlignUp(size, sizeof(u32));
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
/* pcv-side address of a payload symbol's copy. */
|
||||
uintptr_t PayloadVa(const void *loader_sym) const {
|
||||
const uintptr_t offset = reinterpret_cast<uintptr_t>(loader_sym) - reinterpret_cast<uintptr_t>(__start_hoc_hookpayload);
|
||||
return this->ToVa(reinterpret_cast<void *>(m_payload + offset));
|
||||
}
|
||||
|
||||
/* Loader-side, writable pointer to a payload variable's copy in the cave. */
|
||||
template<typename T>
|
||||
T *PayloadCopyOf(T &loader_sym) const {
|
||||
const uintptr_t offset = reinterpret_cast<uintptr_t>(std::addressof(loader_sym)) - reinterpret_cast<uintptr_t>(__start_hoc_hookpayload);
|
||||
return reinterpret_cast<T *>(m_payload + offset);
|
||||
}
|
||||
|
||||
/* Reserves space in the writable data arena past pcv's .bss. */
|
||||
/* Returns a zeroed, loader-side pointer. */
|
||||
/* The data arena is too far from the cave to be addressed directly by symbol, so we must store a pointer to it in the cave section. */
|
||||
template<typename T>
|
||||
T *DataAlloc() {
|
||||
const size_t size = util::AlignUp(sizeof(T), alignof(T) > 8 ? alignof(T) : 8);
|
||||
if (m_data == 0 || m_data_used + size > PcvDataArenaSize) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
T *p = reinterpret_cast<T *>(m_data + m_data_used);
|
||||
m_data_used += size;
|
||||
|
||||
std::memset(p, 0, sizeof(T));
|
||||
return p;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T *BindData(T *&loader_sym) {
|
||||
T *block = this->DataAlloc<T>();
|
||||
if (block != nullptr) {
|
||||
*this->PayloadCopyOf(loader_sym) = reinterpret_cast<T *>(this->ToVa(block));
|
||||
}
|
||||
return block;
|
||||
}
|
||||
|
||||
/* Replaces the function entirely starting at function prologue. */
|
||||
/* Preserves the function arguments. */
|
||||
Result InstallImpl(u32 *site, const void *fn, uintptr_t *out_orig = nullptr) {
|
||||
R_TRY(this->CheckEnabled());
|
||||
R_UNLESS(site != nullptr, ldr::ResultHookSiteInvalid());
|
||||
R_UNLESS(m_payload != 0, ldr::ResultUninitializedPatcher());
|
||||
R_TRY(this->ValidatePayloadFn(fn));
|
||||
|
||||
if (out_orig != nullptr) {
|
||||
u32 *tramp = this->AllocCode(2);
|
||||
R_UNLESS(tramp != nullptr, ldr::ResultHookArenaOutOfMemory());
|
||||
|
||||
u32 relocated;
|
||||
R_TRY(RelocateInstruction(site[0], this->ToVa(site), this->ToVa(&tramp[0]), std::addressof(relocated)));
|
||||
tramp[0] = relocated;
|
||||
tramp[1] = EncodeB(this->ToVa(&tramp[1]), this->ToVa(site) + sizeof(u32));
|
||||
|
||||
*out_orig = this->ToVa(tramp);
|
||||
}
|
||||
|
||||
site[0] = EncodeB(this->ToVa(site), this->PayloadVa(fn));
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
/* Takes the same arguments as the hooked function, does not replace. */
|
||||
Result InstallIntercept(u32 *site, const void *fn) {
|
||||
R_TRY(this->CheckEnabled());
|
||||
R_UNLESS(site != nullptr, ldr::ResultHookSiteInvalid());
|
||||
R_UNLESS(m_payload != 0, ldr::ResultUninitializedPatcher());
|
||||
R_TRY(this->ValidatePayloadFn(fn));
|
||||
|
||||
/* x0-x7: arguments */
|
||||
/* x8: result pointer */
|
||||
/* x18: platform register */
|
||||
/* x30: return address */
|
||||
/* x29: keeps pairs clean */
|
||||
/* x9-x17: scratch */
|
||||
constexpr u32 FrameSize = 0x60;
|
||||
constexpr u32 Pairs[][2] = { {0, 1}, {2, 3}, {4, 5}, {6, 7}, {8, 18}, {29, 30} };
|
||||
constexpr u32 PairCount = sizeof(Pairs) / sizeof(Pairs[0]);
|
||||
constexpr u32 StubWords = 1 + PairCount + 1 + PairCount + 1 + 1 + 1;
|
||||
|
||||
u32 *stub = this->AllocCode(StubWords);
|
||||
R_UNLESS(stub != nullptr, ldr::ResultHookArenaOutOfMemory());
|
||||
|
||||
u32 i = 0;
|
||||
stub[i++] = EncodeSpAdjust(true, FrameSize);
|
||||
for (u32 p = 0; p < PairCount; ++p) {
|
||||
stub[i++] = EncodePairSp(false, Pairs[p][0], Pairs[p][1], static_cast<s32>(p * 16));
|
||||
}
|
||||
|
||||
stub[i] = EncodeBL(this->ToVa(&stub[i]), this->PayloadVa(fn));
|
||||
++i;
|
||||
|
||||
for (u32 p = 0; p < PairCount; ++p) {
|
||||
stub[i++] = EncodePairSp(true, Pairs[p][0], Pairs[p][1], static_cast<s32>(p * 16));
|
||||
}
|
||||
stub[i++] = EncodeSpAdjust(false, FrameSize);
|
||||
|
||||
u32 relocated;
|
||||
R_TRY(RelocateInstruction(site[0], this->ToVa(site), this->ToVa(&stub[i]), std::addressof(relocated)));
|
||||
stub[i] = relocated;
|
||||
++i;
|
||||
|
||||
stub[i] = EncodeB(this->ToVa(&stub[i]), this->ToVa(site) + sizeof(u32));
|
||||
++i;
|
||||
|
||||
AMS_ABORT_UNLESS(i == StubWords);
|
||||
|
||||
site[0] = EncodeB(this->ToVa(site), this->ToVa(stub));
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
/* Checks entry to first ret that everything still points to valid data. */
|
||||
Result ValidatePayloadFn(const void *fn) const {
|
||||
constexpr u32 MaxInstructions = 512;
|
||||
constexpr u32 RetInsn = 0xD65F03C0u;
|
||||
|
||||
const uintptr_t lo = m_payload;
|
||||
const uintptr_t hi = m_payload + m_payload_sz;
|
||||
|
||||
const u32 *insns = reinterpret_cast<const u32 *>(fn);
|
||||
const uintptr_t base = m_payload + (reinterpret_cast<uintptr_t>(fn) - reinterpret_cast<uintptr_t>(__start_hoc_hookpayload));
|
||||
|
||||
auto check = [&](uintptr_t target) -> Result {
|
||||
if (target < lo || target >= hi) {
|
||||
R_THROW(ldr::ResultHookPayloadEscapes());
|
||||
}
|
||||
R_SUCCEED();
|
||||
};
|
||||
|
||||
for (u32 i = 0; i < MaxInstructions; ++i) {
|
||||
const u32 insn = insns[i];
|
||||
const uintptr_t site = base + i * sizeof(u32);
|
||||
|
||||
if (insn == RetInsn) {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
const u32 top6 = insn & 0xFC000000u;
|
||||
if (top6 == 0x14000000u || top6 == 0x94000000u) { /* b / bl */
|
||||
const uintptr_t target = site + SignExtend(static_cast<u64>(insn & 0x03FFFFFFu) << 2, 28);
|
||||
R_TRY(check(target));
|
||||
} else if ((insn & 0xFF000010u) == 0x54000000u || /* b.cond */
|
||||
(insn & 0x7E000000u) == 0x34000000u || /* cbz / cbnz */
|
||||
(insn & 0x3B000000u) == 0x18000000u) { /* ldr literal */
|
||||
const uintptr_t target = site + SignExtend(static_cast<u64>((insn >> 5) & 0x7FFFFu) << 2, 21);
|
||||
R_TRY(check(target));
|
||||
} else if ((insn & 0x7E000000u) == 0x36000000u) { /* tbz / tbnz */
|
||||
const uintptr_t target = site + SignExtend(static_cast<u64>((insn >> 5) & 0x3FFFu) << 2, 16);
|
||||
R_TRY(check(target));
|
||||
} else if ((insn & 0x9F000000u) == 0x10000000u) { /* adr */
|
||||
const u64 imm = (static_cast<u64>((insn >> 5) & 0x7FFFFu) << 2) | ((insn >> 29) & 0x3u);
|
||||
const uintptr_t target = site + SignExtend(imm, 21);
|
||||
R_TRY(check(target));
|
||||
} else if ((insn & 0x9F000000u) == 0x90000000u) { /* adrp */
|
||||
/* ADRP is page-relative and the cave is at an arbitrary offset, any adrp would point to potential garbage. */
|
||||
R_THROW(ldr::ResultHookPayloadEscapes());
|
||||
}
|
||||
}
|
||||
|
||||
/* No return found. */
|
||||
R_THROW(ldr::ResultHookPayloadEscapes());
|
||||
}
|
||||
private:
|
||||
u32 *AllocCode(size_t words) {
|
||||
const size_t bytes = words * sizeof(u32);
|
||||
if (!this->IsEnabled() || m_used + bytes > m_cave_size) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
u32 *p = reinterpret_cast<u32 *>(m_cave + m_used);
|
||||
m_used += bytes;
|
||||
return p;
|
||||
}
|
||||
};
|
||||
|
||||
inline HookContext &Hooks() {
|
||||
static HookContext s_context;
|
||||
return s_context;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Hook custom impl. Original becomes unreachable. */
|
||||
/* Starts at function entry. Preserves arguments. */
|
||||
#define INSTALL_IMPL_HOOK(site, fn) \
|
||||
(::ams::ldr::hoc::pcv::Hooks().InstallImpl((site), reinterpret_cast<const void *>(&(fn))))
|
||||
|
||||
/* Maintains original function. */
|
||||
/* Starts at function entry. Preserves arguments. */
|
||||
#define INSTALL_IMPL_HOOK_ORIG(site, fn, out_orig) \
|
||||
(::ams::ldr::hoc::pcv::Hooks().InstallImpl((site), reinterpret_cast<const void *>(&(fn)), (out_orig)))
|
||||
|
||||
/* Takes the same arguments as the hooked function, does not replace it and cannot change what it does */
|
||||
/* but it can be placed anywhere, not just at a function entry. */
|
||||
#define INSTALL_INTERC_HOOK(site, fn) \
|
||||
(::ams::ldr::hoc::pcv::Hooks().InstallIntercept((site), reinterpret_cast<const void *>(&(fn))))
|
||||
@@ -35,7 +35,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
}
|
||||
}
|
||||
|
||||
/* Default value is 1050mV. */
|
||||
/* Default value is 800mV. */
|
||||
if (C.marikoGpuVmax) {
|
||||
PATCH_OFFSET(ptr + 1, C.marikoGpuVmax);
|
||||
}
|
||||
@@ -52,9 +52,9 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
R_THROW(ldr::ResultInvalidGpuDvfs());
|
||||
}
|
||||
|
||||
// if (C.marikoGpuBootVolt) {
|
||||
// PATCH_OFFSET(ptr - 3, C.marikoGpuBootVolt);
|
||||
// }
|
||||
if (C.marikoGpuBootVolt) {
|
||||
PATCH_OFFSET(ptr - 3, C.marikoGpuBootVolt);
|
||||
}
|
||||
|
||||
if (C.marikoGpuVmin) {
|
||||
PATCH_OFFSET(ptr, C.marikoGpuVmin);
|
||||
@@ -375,6 +375,12 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
WRITE_PARAM_ALL_REG(table, emc_cfg, 0xF3200000);
|
||||
}
|
||||
|
||||
u32 refresh_raw = 0xFFFF;
|
||||
if (C.t8_tREFI != 6) {
|
||||
refresh_raw = CEIL(tREFpb_values[C.t8_tREFI] / tCK_avg) - 0x40;
|
||||
refresh_raw = MIN(refresh_raw, static_cast<u32>(0xFFFF));
|
||||
}
|
||||
|
||||
u32 trefbw = refresh_raw + 0x40;
|
||||
trefbw = MIN(trefbw, static_cast<u32>(0x3FFF));
|
||||
|
||||
@@ -488,27 +494,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
da_covers |= (w_cover << 16);
|
||||
table->burst_mc_regs.mc_emem_arb_da_covers = da_covers;
|
||||
|
||||
constexpr u32 AtomsPerDvfsPulse = 0x7;
|
||||
constexpr u32 McEmcSameFreq = 0x0;
|
||||
const u32 expiringSoonSlackThreshold = [&] {
|
||||
switch (table->rate_khz) {
|
||||
case 2966000:
|
||||
case 3100000:
|
||||
case 3133000:
|
||||
case 3200000:
|
||||
return 0x12u;
|
||||
default:
|
||||
return 0x13u;
|
||||
}
|
||||
}();
|
||||
|
||||
const u32 priorityInversionIsoThreshold = GET_CYCLE_CEIL(7.5);
|
||||
constexpr u32 EmcReqB2bXfer = 0x0;
|
||||
const u32 priorityInversionThreshold = GET_CYCLE_CEIL(22.5);
|
||||
const u32 bc2aaHoldoffThreshold = table->burst_mc_regs.mc_emem_arb_timing_rc + 1;
|
||||
|
||||
const u32 mc_emem_arb_misc0 = (AtomsPerDvfsPulse << 28) | (McEmcSameFreq << 27) | (expiringSoonSlackThreshold << 21) | (priorityInversionIsoThreshold << 16) | (EmcReqB2bXfer << 15) | (priorityInversionThreshold << 8) | (bc2aaHoldoffThreshold << 0);
|
||||
table->burst_mc_regs.mc_emem_arb_misc0 = mc_emem_arb_misc0;
|
||||
table->burst_mc_regs.mc_emem_arb_misc0 = (table->burst_mc_regs.mc_emem_arb_misc0 & 0xFFE08000) | (table->burst_mc_regs.mc_emem_arb_timing_rc + 1);
|
||||
|
||||
table->la_scale_regs.mc_mll_mpcorer_ptsa_rate = 0x115;
|
||||
|
||||
@@ -550,13 +536,11 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
table->la_scale_regs.mc_latency_allowance_hc_1 = (table->la_scale_regs.mc_latency_allowance_hc_1 & Mask2) | allowance1;
|
||||
table->la_scale_regs.mc_latency_allowance_vi2_0 = (table->la_scale_regs.mc_latency_allowance_vi2_0 & Mask2) | allowance1;
|
||||
|
||||
table->dram_timings.t_rp = tRP_values[0];
|
||||
const u32 tRFCabStock = tRFC_values[0] * 2;
|
||||
table->dram_timings.t_rfc = tRFCabStock;
|
||||
table->dram_timings.t_rp = tRFCpb;
|
||||
table->dram_timings.t_rfc = tRFCab;
|
||||
|
||||
table->dram_timings.rl = RL;
|
||||
table->emc_mrw2 = (table->emc_mrw2 & ~0xFFu) | static_cast<u32>(mrw2);
|
||||
table->emc_mrw = (table->emc_mrw & ~0x70u) | 0x40; /* nWR */
|
||||
table->emc_cfg_2 = 0x11083D;
|
||||
}
|
||||
|
||||
@@ -831,6 +815,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
s32 max0 = 1050;
|
||||
s32 max1 = 1025;
|
||||
s32 max2 = 1000;
|
||||
s32 voltAdd = 25 * C.emcDvbShift;
|
||||
|
||||
if (C.marikoSocVmax && C.marikoSocVmax > 1000) {
|
||||
max0 = C.marikoSocVmax;
|
||||
@@ -840,23 +825,15 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
|
||||
constexpr s32 MinVolt = 637;
|
||||
|
||||
auto ClampVolt = [&](s32 value, s32 max, s32 voltAdd) {
|
||||
auto ClampVolt = [&](s32 value, s32 max) {
|
||||
return std::clamp(value + voltAdd, MinVolt, max);
|
||||
};
|
||||
|
||||
auto DvbVolt = [&](s32 zero, s32 one, s32 two, u32 index) {
|
||||
const s32 overrideVoltage = C.marikoSocVoltArray[index];
|
||||
s32 voltAdd = 25 * C.emcDvbShift;
|
||||
|
||||
if (overrideVoltage) {
|
||||
zero = one = two = overrideVoltage;
|
||||
voltAdd = 0;
|
||||
}
|
||||
|
||||
auto DvbVolt = [&](s32 zero, s32 one, s32 two) {
|
||||
return std::array<s32, 3>{
|
||||
ClampVolt(zero, max0, voltAdd),
|
||||
ClampVolt(one, max1, voltAdd),
|
||||
ClampVolt(two, max2, voltAdd)
|
||||
ClampVolt(zero, max0),
|
||||
ClampVolt(one, max1),
|
||||
ClampVolt(two, max2)
|
||||
};
|
||||
};
|
||||
|
||||
@@ -864,47 +841,39 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
static_cast<u32>((v)[0]), \
|
||||
static_cast<u32>((v)[1]), \
|
||||
static_cast<u32>((v)[2])
|
||||
|
||||
#define DVB_OC(one, zero, two, idx) \
|
||||
DVB(DvbVolt(one, zero, two, idx))
|
||||
|
||||
DvbEntry emcDvbOcTableBrackets[] = {
|
||||
{ 204000, { 637, 637, 637, }, },
|
||||
{ 1331200, { 650, 637, 637, }, },
|
||||
{ 1600000, { 675, 650, 637, }, },
|
||||
{ 1866000, { DVB_OC( 700, 675, 650, 0) }, },
|
||||
{ 2000000, { DVB_OC( 712, 687, 662, 1) }, },
|
||||
{ 2133000, { DVB_OC( 725, 700, 675, 2) }, },
|
||||
{ 2200000, { DVB_OC( 737, 712, 687, 3) }, },
|
||||
{ 2266000, { DVB_OC( 750, 725, 700, 4) }, },
|
||||
{ 2333000, { DVB_OC( 762, 737, 712, 5) }, },
|
||||
{ 2400000, { DVB_OC( 775, 750, 725, 6) }, },
|
||||
{ 2433000, { DVB_OC( 787, 762, 737, 7) }, },
|
||||
{ 2466000, { DVB_OC( 800, 775, 750, 8) }, },
|
||||
{ 2533000, { DVB_OC( 812, 787, 762, 9) }, },
|
||||
{ 2566000, { DVB_OC( 825, 800, 775, 10) }, },
|
||||
{ 2600000, { DVB_OC( 837, 812, 787, 11) }, },
|
||||
{ 2666000, { DVB_OC( 850, 825, 800, 12) }, },
|
||||
{ 2700000, { DVB_OC( 875, 850, 825, 13) }, },
|
||||
{ 2733000, { DVB_OC( 887, 862, 837, 14) }, },
|
||||
{ 2766000, { DVB_OC( 912, 887, 862, 15) }, },
|
||||
{ 2800000, { DVB_OC( 925, 900, 875, 16) }, },
|
||||
{ 2833000, { DVB_OC( 937, 912, 887, 17) }, },
|
||||
{ 2900000, { DVB_OC( 950, 925, 900, 18) }, },
|
||||
{ 2933000, { DVB_OC( 962, 937, 912, 19) }, },
|
||||
{ 3000000, { DVB_OC( 975, 950, 925, 20) }, },
|
||||
{ 3033000, { DVB_OC( 987, 962, 937, 21) }, },
|
||||
{ 3100000, { DVB_OC(1000, 975, 950, 22) }, },
|
||||
{ 3133000, { DVB_OC(1025, 1000, 975, 23) }, },
|
||||
{ 3166000, { DVB_OC(1037, 1012, 987, 24) }, },
|
||||
{ 3200000, { DVB_OC(1050, 1025, 1000, 25) }, },
|
||||
{ 3266000, { DVB_OC(1075, 1050, 1025, 26) }, },
|
||||
{ 3333000, { DVB_OC(1100, 1075, 1050, 27) }, },
|
||||
{ ~0u, { }, },
|
||||
{ 204000, { 637, 637, 637, }, },
|
||||
{ 1331200, { 650, 637, 637, }, },
|
||||
{ 1600000, { 675, 650, 637, }, },
|
||||
{ 1866000, { DVB(DvbVolt( 700, 675, 650)) }, },
|
||||
{ 2000000, { DVB(DvbVolt( 712, 687, 662)) }, },
|
||||
{ 2133000, { DVB(DvbVolt( 725, 700, 675)) }, },
|
||||
{ 2200000, { DVB(DvbVolt( 737, 712, 687)) }, },
|
||||
{ 2266000, { DVB(DvbVolt( 750, 725, 700)) }, },
|
||||
{ 2333000, { DVB(DvbVolt( 762, 737, 712)) }, },
|
||||
{ 2400000, { DVB(DvbVolt( 775, 750, 725)) }, },
|
||||
{ 2433000, { DVB(DvbVolt( 787, 762, 737)) }, },
|
||||
{ 2466000, { DVB(DvbVolt( 800, 775, 750)) }, },
|
||||
{ 2533000, { DVB(DvbVolt( 812, 787, 762)) }, },
|
||||
{ 2566000, { DVB(DvbVolt( 825, 800, 775)) }, },
|
||||
{ 2600000, { DVB(DvbVolt( 837, 812, 787)) }, },
|
||||
{ 2666000, { DVB(DvbVolt( 850, 825, 800)) }, },
|
||||
{ 2700000, { DVB(DvbVolt( 875, 850, 825)) }, },
|
||||
{ 2733000, { DVB(DvbVolt( 887, 862, 837)) }, },
|
||||
{ 2766000, { DVB(DvbVolt( 912, 887, 862)) }, },
|
||||
{ 2800000, { DVB(DvbVolt( 925, 900, 875)) }, },
|
||||
{ 2833000, { DVB(DvbVolt( 937, 912, 887)) }, },
|
||||
{ 2900000, { DVB(DvbVolt( 950, 925, 900)) }, },
|
||||
{ 2933000, { DVB(DvbVolt( 962, 937, 912)) }, },
|
||||
{ 3000000, { DVB(DvbVolt( 975, 950, 925)) }, },
|
||||
{ 3033000, { DVB(DvbVolt( 987, 962, 937)) }, },
|
||||
{ 3100000, { DVB(DvbVolt(1000, 975, 950)) }, },
|
||||
{ 3133000, { DVB(DvbVolt(1025, 1000, 975)) }, },
|
||||
{ 3166000, { DVB(DvbVolt(1037, 1012, 987)) }, },
|
||||
{ 3200000, { DVB(DvbVolt(1050, 1025, 1000)) }, },
|
||||
{ ~0u, { }, },
|
||||
};
|
||||
#undef DVB
|
||||
#undef DVB_OC
|
||||
|
||||
DvbEntry emcDvbTableOc[newEmcList.size()];
|
||||
|
||||
u32 bracketIndex = 0;
|
||||
@@ -943,11 +912,14 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
} __attribute__((packed)) cmd;
|
||||
|
||||
I2cSession _session;
|
||||
R_TRY(i2cOpenSession(&_session, dev));
|
||||
Result res = i2cOpenSession(&_session, dev);
|
||||
if (R_FAILED(res)) {
|
||||
return res;
|
||||
}
|
||||
|
||||
cmd.reg = reg;
|
||||
cmd.val = val;
|
||||
Result res = i2csessionSendAuto(&_session, &cmd, sizeof(cmd), I2cTransactionOption_All);
|
||||
cmd.reg = reg;
|
||||
cmd.val = val;
|
||||
res = i2csessionSendAuto(&_session, &cmd, sizeof(cmd), I2cTransactionOption_All);
|
||||
i2csessionClose(&_session);
|
||||
return res;
|
||||
}
|
||||
@@ -984,6 +956,10 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
Result resultI2C = I2cSet_U8(I2cDevice_Max77812_2, 0x25, (emc_uv - uv_min) / uv_step);
|
||||
i2cExit();
|
||||
|
||||
if (R_SUCCEEDED(resultI2C)) {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
return resultI2C;
|
||||
}
|
||||
|
||||
@@ -1175,7 +1151,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
}
|
||||
|
||||
for (auto &entry : patches) {
|
||||
LOGGING("%s Count: %zu\n", entry.description, entry.patched_count);
|
||||
LOGGING("%s Count: %zu", entry.description, entry.patched_count);
|
||||
if (R_FAILED(entry.CheckResult())) {
|
||||
panic::SmcError(panic::Patch);
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace ams::ldr::hoc::pcv::mariko {
|
||||
|
||||
static const u32 cpuVoltThermalData[] = { 620, 1120, 20000, 620, 1120, 70000, 950, 1132, 0, 950, 1227, 0 };
|
||||
|
||||
static const u32 allowedCpuMaxFrequencies[] = { 1'963'500, 2'091'000, 2'193'000, 2'295'000, 2'397'000, 2'499'000, 2'601'000, 2'703'000, 2'805'000 };
|
||||
static const u32 allowedCpuMaxFrequencies[] = { 1'963'500, 2'091'000, 2'193'000, 2'295'000, 2'397'000, 2'499'000, 2'601'000, 2'703'000, };
|
||||
|
||||
constexpr cvb_entry_t GpuCvbTableDefault[] = {
|
||||
// GPUB01_NA_CVB_TABLE
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
namespace ams::ldr::hoc::ptm {
|
||||
|
||||
Result CpuPtmBoost(perf_conf_entry *entry) {
|
||||
Result CpuPtmBoost(perf_conf_entry* entry) {
|
||||
bool isMariko = (spl::GetSocType() == spl::SocType_Mariko);
|
||||
|
||||
if (!C.eristaCpuBoostClock || !C.marikoCpuBoostClock) {
|
||||
@@ -35,19 +35,19 @@ namespace ams::ldr::hoc::ptm {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result MemPtm(perf_conf_entry *entry) {
|
||||
Result MemPtm(perf_conf_entry* entry) {
|
||||
PATCH_OFFSET(&(entry->emc_freq_1), memPtmLimit);
|
||||
PATCH_OFFSET(&(entry->emc_freq_2), memPtmLimit);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
bool PtmEntryIsValid(perf_conf_entry *entry) {
|
||||
bool PtmEntryIsValid(perf_conf_entry* entry) {
|
||||
return (entry->cpu_freq_1 == entry->cpu_freq_2 && entry->gpu_freq_1 == entry->gpu_freq_2 && entry->emc_freq_1 == entry->emc_freq_2);
|
||||
}
|
||||
|
||||
bool PtmTablePatternFn(u32 *ptr) {
|
||||
perf_conf_entry *entry = reinterpret_cast<perf_conf_entry *>(ptr);
|
||||
bool PtmTablePatternFn(u32* ptr) {
|
||||
perf_conf_entry* entry = reinterpret_cast<perf_conf_entry *>(ptr);
|
||||
if (!PtmEntryIsValid(entry)) {
|
||||
return false;
|
||||
}
|
||||
@@ -56,9 +56,9 @@ namespace ams::ldr::hoc::ptm {
|
||||
}
|
||||
|
||||
void Patch(uintptr_t mapped_nso, size_t nso_size) {
|
||||
perf_conf_entry *confTable = nullptr;
|
||||
perf_conf_entry* confTable = nullptr;
|
||||
for (uintptr_t ptr = mapped_nso; ptr <= mapped_nso + nso_size - sizeof(perf_conf_entry) * entryCnt; ptr += sizeof(u32)) {
|
||||
u32 *ptr32 = reinterpret_cast<u32 *>(ptr);
|
||||
u32* ptr32 = reinterpret_cast<u32 *>(ptr);
|
||||
if (PtmTablePatternFn(ptr32)) {
|
||||
confTable = reinterpret_cast<perf_conf_entry *>(ptr);
|
||||
break;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
namespace ams::ldr::hoc::ptm {
|
||||
|
||||
struct perf_conf_entry {
|
||||
typedef struct {
|
||||
u32 conf_id;
|
||||
u32 cpu_freq_1; // min-max pair?
|
||||
u32 cpu_freq_2;
|
||||
@@ -31,7 +31,7 @@ namespace ams::ldr::hoc::ptm {
|
||||
u32 emc_freq_1;
|
||||
u32 emc_freq_2;
|
||||
u32 padding;
|
||||
};
|
||||
} perf_conf_entry;
|
||||
|
||||
constexpr u32 entryCnt = 16;
|
||||
constexpr u32 cpuPtmDefault = 1020'000'000;
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
# build artifacts
|
||||
build/
|
||||
*.nro
|
||||
*.elf
|
||||
*.nacp
|
||||
*.map
|
||||
|
||||
# generated nanovg shaders (regenerated by the build)
|
||||
resources/shaders/
|
||||
@@ -1,207 +0,0 @@
|
||||
#---------------------------------------------------------------------------------
|
||||
.SUFFIXES:
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
ifeq ($(strip $(DEVKITPRO)),)
|
||||
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
||||
endif
|
||||
|
||||
TOPDIR ?= $(CURDIR)
|
||||
include $(DEVKITPRO)/libnx/switch_rules
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
TARGET := Benchmark-Toolbox
|
||||
BUILD := build
|
||||
SOURCES := source source/furmark source/memtester source/cpustress
|
||||
DATA := data
|
||||
ICON := icon.jpg
|
||||
INCLUDES := source source/furmark source/memtester source/cpustress ../hoc-clk/common/include
|
||||
|
||||
APP_TITLE := Benchmark Toolbox
|
||||
APP_AUTHOR := Horizon-OC
|
||||
APP_VERSION := 2.0.0
|
||||
|
||||
ROMFS := resources
|
||||
BOREALIS_PATH := lib/borealis
|
||||
|
||||
# Output folder (in romfs) for borealis' autogenerated nanovg shaders
|
||||
OUT_SHADERS := shaders
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# options for code generation
|
||||
#---------------------------------------------------------------------------------
|
||||
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
|
||||
|
||||
CFLAGS := -g -Wall -O2 -ffunction-sections \
|
||||
$(ARCH) $(DEFINES)
|
||||
|
||||
CFLAGS += $(INCLUDE) -D__SWITCH__ -pthread
|
||||
|
||||
# -include optional: borealis' nanovg dk_renderer.hpp uses std::optional without
|
||||
# including <optional> (newer libstdc++ dropped the transitive include).
|
||||
CXXFLAGS := $(CFLAGS) -std=gnu++17 -O2 -Wno-volatile -fexceptions -include optional
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) -pthread
|
||||
|
||||
# borealis.mk prepends -ldeko3d -lm. gpu_bw.c uses EGL/GLES; the Furmark tests
|
||||
# use desktop GL via glad. Add the full GL stack.
|
||||
LIBS := -lglad -lGLESv2 -lEGL -lglapi -ldrm_nouveau -lnx
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
LIBDIRS := $(PORTLIBS) $(LIBNX)
|
||||
|
||||
# Pull in borealis: appends its SOURCES / INCLUDES / LIBS / CXXFLAGS.
|
||||
# Run `git submodule update --init --recursive` so lib/borealis is populated.
|
||||
include $(TOPDIR)/$(BOREALIS_PATH)/library/borealis.mk
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
ifneq ($(BUILD),$(notdir $(CURDIR)))
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OUTPUT := $(CURDIR)/$(TARGET)
|
||||
export TOPDIR := $(CURDIR)
|
||||
|
||||
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
|
||||
|
||||
export DEPSDIR := $(CURDIR)/$(BUILD)
|
||||
|
||||
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
|
||||
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
|
||||
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
|
||||
GLSLFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.glsl)))
|
||||
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
ifeq ($(strip $(CPPFILES)),)
|
||||
export LD := $(CC)
|
||||
else
|
||||
export LD := $(CXX)
|
||||
endif
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
|
||||
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
|
||||
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
|
||||
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
|
||||
|
||||
ifneq ($(strip $(ROMFS)),)
|
||||
ROMFS_TARGETS :=
|
||||
ROMFS_FOLDERS :=
|
||||
ifneq ($(strip $(OUT_SHADERS)),)
|
||||
ROMFS_SHADERS := $(ROMFS)/$(OUT_SHADERS)
|
||||
ROMFS_TARGETS += $(patsubst %.glsl, $(ROMFS_SHADERS)/%.dksh, $(GLSLFILES))
|
||||
ROMFS_FOLDERS += $(ROMFS_SHADERS)
|
||||
endif
|
||||
|
||||
export ROMFS_DEPS := $(foreach file,$(ROMFS_TARGETS),$(CURDIR)/$(file))
|
||||
endif
|
||||
|
||||
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
|
||||
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
|
||||
-I$(CURDIR)/$(BUILD)
|
||||
|
||||
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||
|
||||
export APP_ICON := $(TOPDIR)/$(ICON)
|
||||
|
||||
ifeq ($(strip $(NO_ICON)),)
|
||||
export NROFLAGS += --icon=$(APP_ICON)
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(NO_NACP)),)
|
||||
export NROFLAGS += --nacp=$(CURDIR)/$(TARGET).nacp
|
||||
endif
|
||||
|
||||
ifneq ($(APP_TITLEID),)
|
||||
export NACPFLAGS += --titleid=$(APP_TITLEID)
|
||||
endif
|
||||
|
||||
ifneq ($(ROMFS),)
|
||||
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
|
||||
endif
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all: $(ROMFS_TARGETS) | $(BUILD)
|
||||
@MSYS2_ARG_CONV_EXCL="-D;$(MSYS2_ARG_CONV_EXCL)" $(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||
|
||||
$(BUILD):
|
||||
@mkdir -p $@
|
||||
|
||||
ifneq ($(strip $(ROMFS_TARGETS)),)
|
||||
|
||||
$(ROMFS_TARGETS): | $(ROMFS_FOLDERS)
|
||||
|
||||
$(ROMFS_FOLDERS):
|
||||
@mkdir -p $@
|
||||
|
||||
$(ROMFS_SHADERS)/%_vsh.dksh: %_vsh.glsl
|
||||
@echo {vert} $(notdir $<)
|
||||
@uam -s vert -o $@ $<
|
||||
|
||||
$(ROMFS_SHADERS)/%_tcsh.dksh: %_tcsh.glsl
|
||||
@echo {tess_ctrl} $(notdir $<)
|
||||
@uam -s tess_ctrl -o $@ $<
|
||||
|
||||
$(ROMFS_SHADERS)/%_tesh.dksh: %_tesh.glsl
|
||||
@echo {tess_eval} $(notdir $<)
|
||||
@uam -s tess_eval -o $@ $<
|
||||
|
||||
$(ROMFS_SHADERS)/%_gsh.dksh: %_gsh.glsl
|
||||
@echo {geom} $(notdir $<)
|
||||
@uam -s geom -o $@ $<
|
||||
|
||||
$(ROMFS_SHADERS)/%_fsh.dksh: %_fsh.glsl
|
||||
@echo {frag} $(notdir $<)
|
||||
@uam -s frag -o $@ $<
|
||||
|
||||
$(ROMFS_SHADERS)/%.dksh: %.glsl
|
||||
@echo {comp} $(notdir $<)
|
||||
@uam -s comp -o $@ $<
|
||||
|
||||
endif
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
clean:
|
||||
@echo clean ...
|
||||
@rm -fr $(BUILD) $(ROMFS_FOLDERS) $(TARGET).nro $(TARGET).nacp $(TARGET).elf
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
else
|
||||
.PHONY: all
|
||||
|
||||
DEPENDS := $(OFILES:.o=.d)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
all : $(OUTPUT).nro
|
||||
|
||||
ifeq ($(strip $(NO_NACP)),)
|
||||
$(OUTPUT).nro : $(OUTPUT).elf $(OUTPUT).nacp $(ROMFS_DEPS)
|
||||
else
|
||||
$(OUTPUT).nro : $(OUTPUT).elf $(ROMFS_DEPS)
|
||||
endif
|
||||
|
||||
$(OUTPUT).elf : $(OFILES)
|
||||
|
||||
$(OFILES_SRC) : $(HFILES_BIN)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%.bin.o %_bin.h : %.bin
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
%.png.o %_png.h : %.png
|
||||
#---------------------------------------------------------------------------------
|
||||
@echo $(notdir $<)
|
||||
@$(bin2o)
|
||||
|
||||
-include $(DEPENDS)
|
||||
|
||||
#---------------------------------------------------------------------------------------
|
||||
endif
|
||||
#---------------------------------------------------------------------------------------
|
||||
|
Before Width: | Height: | Size: 413 B |
|
Before Width: | Height: | Size: 647 KiB |
|
Before Width: | Height: | Size: 403 KiB |
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 151 KiB |
|
Before Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 9.7 KiB |
@@ -1,21 +0,0 @@
|
||||
---
|
||||
AccessModifierOffset: -2
|
||||
AlignConsecutiveAssignments: 'true'
|
||||
BasedOnStyle: WebKit
|
||||
BreakBeforeBraces: Allman
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: '^<borealis/.*\.hpp>'
|
||||
Priority: 2
|
||||
- Regex: '^<.*\.h>'
|
||||
Priority: 1
|
||||
- Regex: '^<.*'
|
||||
Priority: 2
|
||||
- Regex: '.*'
|
||||
Priority: 3
|
||||
IndentCaseLabels: 'true'
|
||||
PointerAlignment: Left
|
||||
SortIncludes: 'true'
|
||||
Standard: Cpp11
|
||||
|
||||
...
|
||||
@@ -1,12 +0,0 @@
|
||||
# List of borealis's significant contributors
|
||||
#
|
||||
# This does not necessarily list everyone who has contributed code.
|
||||
# To see the full list of contributors, see the contributors page on GitHub
|
||||
# https://github.com/natinusala/borealis/graphs/contributors
|
||||
natinusala
|
||||
p-sam
|
||||
WerWolv
|
||||
bylaws
|
||||
H0neyBadger
|
||||
D3fau4
|
||||
Behemoth
|
||||
@@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -1,13 +0,0 @@
|
||||
Copyright 2019-2021 borealis contributors
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -1,79 +0,0 @@
|
||||

|
||||
# borealis
|
||||
|
||||
Controller and TV oriented UI library for PC and Nintendo Switch (libnx).
|
||||
|
||||
⚠️ Warning: the project is a WIP - See the Projects tab to follow the journey towards a stable version!
|
||||
|
||||
The code for the old version is available in the `legacy` branch.
|
||||
|
||||
⚠️ The wiki only contains the documentation for the old version of the library, it has yet to be updated!
|
||||
|
||||
- Mimicks the Nintendo Switch system UI, but can also be used to make anything else painlessly
|
||||
- Hardware acceleration and vector graphics with automatic scaling for TV usage (powered by nanovg)
|
||||
- Can be ported to new platforms and graphics APIs by providing a nanovg implementation
|
||||
- Powerful layout engine using flex box as a base for everything (powered by Yoga Layout)
|
||||
- Automated navigation paths for out-of-the-box controller navigation
|
||||
- Out of the box touch support
|
||||
- Define user interfaces using XML and only write code when it matters
|
||||
- Use and restyle built-in components or make your own from scratch
|
||||
- Display large amount of data efficiently using recycling lists
|
||||
- Integrated internationalization and storage systems
|
||||
- Integrated toolbox (logger, animations, timers, background tasks...)
|
||||
|
||||
## Building the demo for Switch
|
||||
|
||||
To build for Switch, a standard development environment must first be set up. In order to do so, [refer to the Getting Started guide](https://devkitpro.org/wiki/Getting_Started).
|
||||
|
||||
```bash
|
||||
(sudo) (dkp-)pacman -S switch-glfw switch-mesa switch-glm
|
||||
make -j
|
||||
nxlink -s borealis_demo.nro
|
||||
```
|
||||
|
||||
## Building the demo for PC
|
||||
|
||||
To build for PC, the following components are required:
|
||||
|
||||
- meson/ninja build system
|
||||
- A C++ compiler supporting the C++17 standard
|
||||
- GLFW version 3.3 or higher (as a static library)
|
||||
- GLM version 0.9.8 or higher
|
||||
|
||||
Please refer to the usual sources of information for your particular operating system. Usually the commands needed to build this project will look like this:
|
||||
|
||||
```bash
|
||||
meson build
|
||||
ninja -C build
|
||||
./build/borealis_demo
|
||||
```
|
||||
|
||||
Also, please note that the `resources` folder must be available in the working directory, otherwise the program will fail to find the shaders.
|
||||
|
||||
### Building the demo for Windows using msys2
|
||||
|
||||
msys2 provides all packages needed to build this project:
|
||||
|
||||
```bash
|
||||
pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-meson mingw-w64-x86_64-ninja mingw-w64-x86_64-pkg-config mingw-w64-x86_64-glfw mingw-w64-x86_64-glm
|
||||
meson build
|
||||
ninja -C build
|
||||
./build/borealis_demo
|
||||
```
|
||||
|
||||
### Including in your project (TL;DR: see the demo makefile in this repo)
|
||||
0. Your project must be built as C++17 (`-std=c++1z`). You also need to remove `-fno-rtti` and `-fno-exceptions` if you have them
|
||||
1. Use a submodule (or even better, a [subrepo](https://github.com/ingydotnet/git-subrepo)) to clone this repository in your project
|
||||
2. Copy the `resources` folder to the root of your project
|
||||
3. For PC (meson):
|
||||
1. take a standard meson file
|
||||
2. use `subdir` to import the library folder
|
||||
3. use the `borealis_files`, `borealis_dependencies`, `borealis_include` and `borealis_cpp_args` variables for respectively objects to build, dependencies (glfw...), includes directory and cpp args
|
||||
4. add a `BRLS_RESOURCES` define pointing to the resources folder at runtime (so `resources`)
|
||||
4. For Switch:
|
||||
1. take a standard deko3d homebrew makefile (from the switch-examples repo)
|
||||
2. add a `BOREALIS_PATH` variable containing the subfolder you put the library in
|
||||
3. set `ROMFS` to the resources folder - borealis resources path is set to `romfs:/` in borealis.mk
|
||||
4. use `include` to load `borealis.mk` (after `LIBDIRS` and `BOREALIS_PATH`)
|
||||
5. it's important for `OUT_SHADERS` to be set to `shaders` since nanovg will look for the shaders there
|
||||
6. if you have issues with the `BRLS_RESOURCES` define (missing quote terminator), change the `@$(MAKE)` line to `@MSYS2_ARG_CONV_EXCL="-D;$(MSYS2_ARG_CONV_EXCL)" $(MAKE)` in the Makefile (as in the demo Makefile)
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
Copyright 2020-2021 natinusala
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "captioned_image.hpp"
|
||||
|
||||
CaptionedImage::CaptionedImage()
|
||||
{
|
||||
// Load the XML file and inflate ourself with its content
|
||||
// The top-level Box in the XML corresponds to us, and every XML child
|
||||
// is added to our children (and the attributes are applied)
|
||||
// The CaptionedImage instance basically becomes what's written in the XML
|
||||
this->inflateFromXMLRes("xml/views/captioned_image.xml");
|
||||
|
||||
// The label stays hidden until focused, so hide it right away
|
||||
this->label->hide([] {});
|
||||
|
||||
// Forward Image and Label XML attributes
|
||||
this->forwardXMLAttribute("scalingType", this->image);
|
||||
this->forwardXMLAttribute("image", this->image);
|
||||
this->forwardXMLAttribute("focusUp", this->image);
|
||||
this->forwardXMLAttribute("focusRight", this->image);
|
||||
this->forwardXMLAttribute("focusDown", this->image);
|
||||
this->forwardXMLAttribute("focusLeft", this->image);
|
||||
this->forwardXMLAttribute("imageWidth", this->image, "width");
|
||||
this->forwardXMLAttribute("imageHeight", this->image, "height");
|
||||
|
||||
this->forwardXMLAttribute("caption", this->label, "text");
|
||||
}
|
||||
|
||||
void CaptionedImage::onChildFocusGained(brls::View* directChild, brls::View* focusedView)
|
||||
{
|
||||
// Called when a child of ours gets focused, in that case it's the Image
|
||||
|
||||
Box::onChildFocusGained(directChild, focusedView);
|
||||
|
||||
this->label->show([] {});
|
||||
}
|
||||
|
||||
void CaptionedImage::onChildFocusLost(brls::View* directChild, brls::View* focusedView)
|
||||
{
|
||||
// Called when a child of ours losts focused, in that case it's the Image
|
||||
|
||||
Box::onChildFocusLost(directChild, focusedView);
|
||||
|
||||
this->label->hide([] {});
|
||||
}
|
||||
|
||||
brls::View* CaptionedImage::create()
|
||||
{
|
||||
// Called by the XML engine to create a new CaptionedImage
|
||||
return new CaptionedImage();
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
Copyright 2020-2021 natinusala
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis.hpp>
|
||||
|
||||
class CaptionedImage : public brls::Box
|
||||
{
|
||||
public:
|
||||
CaptionedImage();
|
||||
|
||||
void onChildFocusGained(brls::View* directChild, brls::View* focusedView) override;
|
||||
void onChildFocusLost(brls::View* directChild, brls::View* focusedView) override;
|
||||
|
||||
static brls::View* create();
|
||||
|
||||
private:
|
||||
BRLS_BIND(brls::Image, image, "image");
|
||||
BRLS_BIND(brls::Label, label, "label");
|
||||
};
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
Copyright 2021 natinusala
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "components_tab.hpp"
|
||||
|
||||
ComponentsTab::ComponentsTab()
|
||||
{
|
||||
// Inflate the tab from the XML file
|
||||
this->inflateFromXMLRes("xml/tabs/components.xml");
|
||||
|
||||
// Bind the button click to a method using the macro (just for the sake of showcasing it, it's overkill in this situation)
|
||||
BRLS_REGISTER_CLICK_BY_ID("button_primary", this->onPrimaryButtonClicked);
|
||||
|
||||
// Get a handle to the button and register the action directly
|
||||
brls::Button* highlightButton = (brls::Button*)this->getView("button_highlight");
|
||||
highlightButton->registerAction(
|
||||
"Honk", brls::BUTTON_A, [](brls::View* view) { return true; }, false, brls::SOUND_HONK);
|
||||
}
|
||||
|
||||
bool ComponentsTab::onPrimaryButtonClicked(brls::View* view)
|
||||
{
|
||||
brls::Logger::info("Clicked");
|
||||
return true;
|
||||
}
|
||||
|
||||
brls::View* ComponentsTab::create()
|
||||
{
|
||||
// Called by the XML engine to create a new ComponentsTab
|
||||
return new ComponentsTab();
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
Copyright 2021 natinusala
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis.hpp>
|
||||
|
||||
class ComponentsTab : public brls::Box
|
||||
{
|
||||
public:
|
||||
ComponentsTab();
|
||||
|
||||
static brls::View* create();
|
||||
|
||||
private:
|
||||
bool onPrimaryButtonClicked(brls::View* view);
|
||||
};
|
||||
@@ -1,82 +0,0 @@
|
||||
/*
|
||||
Copyright 2020-2021 natinusala
|
||||
Copyright 2019 p-sam
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Switch include only necessary for demo videos recording
|
||||
#ifdef __SWITCH__
|
||||
#include <switch.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <borealis.hpp>
|
||||
#include <string>
|
||||
|
||||
#include "captioned_image.hpp"
|
||||
#include "components_tab.hpp"
|
||||
#include "main_activity.hpp"
|
||||
#include "recycling_list_tab.hpp"
|
||||
|
||||
using namespace brls::literals; // for _i18n
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
// Enable recording for Twitter memes
|
||||
#ifdef __SWITCH__
|
||||
appletInitializeGamePlayRecording();
|
||||
#endif
|
||||
|
||||
// Set log level
|
||||
// We recommend to use INFO for real apps
|
||||
brls::Logger::setLogLevel(brls::LogLevel::DEBUG);
|
||||
|
||||
// Init the app and i18n
|
||||
if (!brls::Application::init())
|
||||
{
|
||||
brls::Logger::error("Unable to init Borealis application");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
brls::Application::createWindow("demo/title"_i18n);
|
||||
|
||||
// Have the application register an action on every activity that will quit when you press BUTTON_START
|
||||
brls::Application::setGlobalQuit(true);
|
||||
|
||||
// Register custom views (including tabs, which are views)
|
||||
brls::Application::registerXMLView("CaptionedImage", CaptionedImage::create);
|
||||
brls::Application::registerXMLView("RecyclingListTab", RecyclingListTab::create);
|
||||
brls::Application::registerXMLView("ComponentsTab", ComponentsTab::create);
|
||||
|
||||
// Add custom values to the theme
|
||||
brls::getLightTheme().addColor("captioned_image/caption", nvgRGB(2, 176, 183));
|
||||
brls::getDarkTheme().addColor("captioned_image/caption", nvgRGB(51, 186, 227));
|
||||
|
||||
// Add custom values to the style
|
||||
brls::getStyle().addMetric("about/padding_top_bottom", 50);
|
||||
brls::getStyle().addMetric("about/padding_sides", 75);
|
||||
brls::getStyle().addMetric("about/description_margin", 50);
|
||||
|
||||
// Create and push the main activity to the stack
|
||||
brls::Application::pushActivity(new MainActivity());
|
||||
|
||||
// Run the app
|
||||
while (brls::Application::mainLoop())
|
||||
;
|
||||
|
||||
// Exit
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
/*
|
||||
Copyright 2020-2021 natinusala
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "main_activity.hpp"
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
Copyright 2020-2021 natinusala
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis.hpp>
|
||||
|
||||
class MainActivity : public brls::Activity
|
||||
{
|
||||
public:
|
||||
// Declare that the content of this activity is the given XML file
|
||||
CONTENT_FROM_XML_RES("activity/main.xml");
|
||||
};
|
||||
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
Copyright 2020-2021 natinusala
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#include "recycling_list_tab.hpp"
|
||||
|
||||
RecyclingListTab::RecyclingListTab()
|
||||
{
|
||||
// Inflate the tab from the XML file
|
||||
this->inflateFromXMLRes("xml/tabs/recycling_list.xml");
|
||||
}
|
||||
|
||||
brls::View* RecyclingListTab::create()
|
||||
{
|
||||
// Called by the XML engine to create a new RecyclingListTab
|
||||
return new RecyclingListTab();
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
/*
|
||||
Copyright 2020-2021 natinusala
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis.hpp>
|
||||
|
||||
class RecyclingListTab : public brls::Box
|
||||
{
|
||||
public:
|
||||
RecyclingListTab();
|
||||
|
||||
static brls::View* create();
|
||||
};
|
||||
@@ -1,35 +0,0 @@
|
||||
mkfile_path := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||
current_dir := $(BOREALIS_PATH)/$(notdir $(patsubst %/,%,$(dir $(mkfile_path))))
|
||||
|
||||
LIBS := -ldeko3d -lm $(LIBS)
|
||||
|
||||
include $(TOPDIR)/$(current_dir)/lib/extern/switch-libpulsar/deps.mk
|
||||
|
||||
SOURCES := $(SOURCES) \
|
||||
$(current_dir)/lib/core \
|
||||
$(current_dir)/lib/views \
|
||||
$(current_dir)/lib/platforms/switch \
|
||||
$(current_dir)/lib/extern/glad \
|
||||
$(current_dir)/lib/extern/nanovg-deko3d/source \
|
||||
$(current_dir)/lib/extern/nanovg-deko3d/source/framework \
|
||||
$(current_dir)/lib/extern/nanovg-deko3d/shaders \
|
||||
$(current_dir)/lib/extern/libretro-common/compat \
|
||||
$(current_dir)/lib/extern/libretro-common/encodings \
|
||||
$(current_dir)/lib/extern/libretro-common/features \
|
||||
$(current_dir)/lib/extern/nxfmtwrapper \
|
||||
$(current_dir)/lib/extern/yoga/src/yoga/event \
|
||||
$(current_dir)/lib/extern/yoga/src/yoga \
|
||||
$(current_dir)/lib/extern/tinyxml2/ \
|
||||
$(addprefix $(current_dir)/lib/extern/switch-libpulsar/, $(PLSR_SOURCES))
|
||||
|
||||
INCLUDES := $(INCLUDES) \
|
||||
$(current_dir)/include \
|
||||
$(current_dir)/lib/extern/fmt/include \
|
||||
$(current_dir)/lib/extern/yoga/src \
|
||||
$(current_dir)/lib/extern/nanovg-deko3d/include \
|
||||
$(current_dir)/lib/extern/tweeny/include \
|
||||
$(current_dir)/include/borealis/extern \
|
||||
$(current_dir)/include/borealis/extern/tinyxml2 \
|
||||
$(addprefix $(current_dir)/lib/extern/switch-libpulsar/, $(PLSR_INCLUDES))
|
||||
|
||||
CXXFLAGS := $(CXXFLAGS) -DYG_ENABLE_EVENTS -fdata-sections -DBRLS_RESOURCES="\"romfs:/\""
|
||||
@@ -1,53 +0,0 @@
|
||||
/*
|
||||
Copyright 2019-2021 natinusala
|
||||
Copyright 2019 p-sam
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
// Core
|
||||
#include <borealis/core/actions.hpp>
|
||||
#include <borealis/core/activity.hpp>
|
||||
#include <borealis/core/animation.hpp>
|
||||
#include <borealis/core/application.hpp>
|
||||
#include <borealis/core/assets.hpp>
|
||||
#include <borealis/core/audio.hpp>
|
||||
#include <borealis/core/bind.hpp>
|
||||
#include <borealis/core/box.hpp>
|
||||
#include <borealis/core/event.hpp>
|
||||
#include <borealis/core/font.hpp>
|
||||
#include <borealis/core/frame_context.hpp>
|
||||
#include <borealis/core/i18n.hpp>
|
||||
#include <borealis/core/input.hpp>
|
||||
#include <borealis/core/logger.hpp>
|
||||
#include <borealis/core/platform.hpp>
|
||||
#include <borealis/core/style.hpp>
|
||||
#include <borealis/core/task.hpp>
|
||||
#include <borealis/core/theme.hpp>
|
||||
#include <borealis/core/time.hpp>
|
||||
#include <borealis/core/timer.hpp>
|
||||
#include <borealis/core/video.hpp>
|
||||
#include <borealis/core/view.hpp>
|
||||
|
||||
//Views
|
||||
#include <borealis/views/applet_frame.hpp>
|
||||
#include <borealis/views/button.hpp>
|
||||
#include <borealis/views/header.hpp>
|
||||
#include <borealis/views/image.hpp>
|
||||
#include <borealis/views/label.hpp>
|
||||
#include <borealis/views/rectangle.hpp>
|
||||
#include <borealis/views/scrolling_frame.hpp>
|
||||
#include <borealis/views/sidebar.hpp>
|
||||
#include <borealis/views/tab_frame.hpp>
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 WerWolv
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/core/audio.hpp>
|
||||
#include <borealis/core/input.hpp>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
class View;
|
||||
|
||||
typedef std::function<bool(View*)> ActionListener;
|
||||
|
||||
typedef int ActionIdentifier;
|
||||
|
||||
#define ACTION_NONE -1
|
||||
|
||||
struct Action
|
||||
{
|
||||
enum ControllerButton button;
|
||||
|
||||
ActionIdentifier identifier;
|
||||
std::string hintText;
|
||||
bool available;
|
||||
bool hidden;
|
||||
enum Sound sound;
|
||||
ActionListener actionListener;
|
||||
|
||||
bool operator==(const enum ControllerButton other)
|
||||
{
|
||||
return this->button == other;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
@@ -1,162 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 natinusala
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/core/view.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
#define CONTENT_FROM_XML_RES(x) \
|
||||
brls::View* createContentView() override { return brls::View::createFromXMLResource(x); }
|
||||
#define CONTENT_FROM_XML_FILE(x) \
|
||||
brls::View* createContentView() override { return brls::View::createFromXMLFile(x); }
|
||||
#define CONTENT_FROM_XML_STR(x) \
|
||||
brls::View* createContentView() override { return brls::View::createFromXMLString(x); }
|
||||
|
||||
// An activity is a "screen" of your app in which the library adds
|
||||
// the UI components. The app is made of a stack of activities, each activity
|
||||
// containing a views tree.
|
||||
class Activity
|
||||
{
|
||||
public:
|
||||
Activity();
|
||||
virtual ~Activity();
|
||||
|
||||
/**
|
||||
* Sets the content view of this activity, aka
|
||||
* the root view of the tree.
|
||||
*
|
||||
* When the activity is pushed, setContentView() is
|
||||
* automatically called with the result of createContentView().
|
||||
* As such, you should override createContentView() if you want
|
||||
* to use XML in your activity.
|
||||
*/
|
||||
void setContentView(View* view);
|
||||
|
||||
/**
|
||||
* Called when the activity is created. Should return the activity content view, if any.
|
||||
*
|
||||
* Returning nullptr means the content is not known when the activity is created.
|
||||
*
|
||||
* You can use View::createFromXMLFile(), View::createFromXMLResource() and View::createFromXMLString() to load
|
||||
* a view from respectively an XML file path, an XML name in the resources/xml romfs directory and an XML string.
|
||||
*
|
||||
* The CONTENT_FROM_XML_FILE, CONTENT_FROM_XML_RES, CONTENT_FROM_XML_STR macros
|
||||
* are made to make this process simpler: just use them in the public block of your activity
|
||||
* header and it will override createContentView() with the right code for you.
|
||||
*
|
||||
* The onContentAvailable() method will be called once the content has been created, so that
|
||||
* you can get the references to the activity views (by id).
|
||||
*/
|
||||
virtual View* createContentView();
|
||||
|
||||
/**
|
||||
* Called when the content view is created, so that
|
||||
* you can get the references to the activity views (by id).
|
||||
*/
|
||||
virtual void onContentAvailable() {};
|
||||
|
||||
View* getContentView();
|
||||
|
||||
/**
|
||||
* Returns the view with the corresponding id, or nullptr
|
||||
* if it hasn't been found in the activity.
|
||||
*/
|
||||
View* getView(std::string id);
|
||||
|
||||
/**
|
||||
* Resizes the activity to fit the window. Called when the activity
|
||||
* is created and when the window is resized (Switch dock counts as window resize).
|
||||
*/
|
||||
void resizeToFitWindow();
|
||||
|
||||
/**
|
||||
* Returns the duration of the activity show / hide animation.
|
||||
*/
|
||||
virtual float getShowAnimationDuration(TransitionAnimation animation);
|
||||
|
||||
/**
|
||||
* Is this activity translucent, aka can we see the
|
||||
* activities under it in the stack?
|
||||
*/
|
||||
bool isTranslucent();
|
||||
|
||||
void willAppear(bool resetState = false);
|
||||
void willDisappear(bool resetState = false);
|
||||
|
||||
/**
|
||||
* If set to true, will force the activity to be translucent.
|
||||
*/
|
||||
void setInFadeAnimation(bool translucent);
|
||||
|
||||
/**
|
||||
* Shows the activity with a fade in animation, or no animation at all.
|
||||
*/
|
||||
void show(std::function<void(void)> cb, bool animate, float animationDuration);
|
||||
|
||||
/**
|
||||
* Hides the activity with a fade in animation, or no animation at all.
|
||||
*/
|
||||
void hide(std::function<void(void)> cb, bool animate, float animationDuration);
|
||||
|
||||
bool isHidden();
|
||||
|
||||
/**
|
||||
* Registers an action with the given parameters on the content view. The listener will be fired
|
||||
* when the user presses the key.
|
||||
*
|
||||
* The listener should return true if the action was consumed, false otherwise.
|
||||
* The sound will only be played if the listener returned true.
|
||||
*
|
||||
* A hidden action will not show up in the bottom-right hints.
|
||||
*
|
||||
* Must be called after the content view is set.
|
||||
*
|
||||
* Returns the identifier for the action, so it can be unregistered later on. Returns ACTION_NONE if the
|
||||
* action was not registered.
|
||||
*/
|
||||
ActionIdentifier registerAction(std::string hintText, enum ControllerButton button, ActionListener actionListener, bool hidden = false, enum Sound sound = SOUND_NONE);
|
||||
|
||||
/**
|
||||
* Unregisters an action with the given identifier on the content view.
|
||||
*
|
||||
* Must be called after the content view is set.
|
||||
*/
|
||||
void unregisterAction(ActionIdentifier identifier);
|
||||
|
||||
/**
|
||||
* Registers an action to exit the application with the default button BUTTON_START.
|
||||
*
|
||||
* Must be called after the content view is set.
|
||||
*
|
||||
* Returns the identifier for the action, so it can be unregistered later on. Returns ACTION_NONE if the
|
||||
* action was not registered.
|
||||
*/
|
||||
ActionIdentifier registerExitAction(enum ControllerButton button = brls::BUTTON_START);
|
||||
|
||||
void onWindowSizeChanged();
|
||||
|
||||
View* getDefaultFocus();
|
||||
|
||||
void setAlpha(float alpha);
|
||||
|
||||
private:
|
||||
View* contentView = nullptr;
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
Copyright 2021 natinusala
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <tweeny.h>
|
||||
|
||||
#include <borealis/core/time.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
using EasingFunction = tweeny::easing::enumerated;
|
||||
|
||||
// An animatable is a float which value can be animated from an initial value to a target value,
|
||||
// during a given amount of time. An easing function can also be specified.
|
||||
//
|
||||
// Declare the animatable and then use reset(initialValue) to reset the animation.
|
||||
// Add as many steps as you like by calling addStep(targetValue, duration, easing) one or multiple times.
|
||||
// Then, start and stop the animation with start() and stop().
|
||||
//
|
||||
// setEndCallback() and setTickCallback() allow you to execute code as long as the animation runs and / or once when it finishes.
|
||||
// Use .getValue() to get the current value at any time.
|
||||
//
|
||||
// An animatable has overloads for float conversion, comparison (==) and assignment operator (=) to allow
|
||||
// basic usage as a simple float. Assignment operator is a shortcut to the reset() method.
|
||||
class Animatable : public FiniteTicking
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Creates an animatable with the given initial value.
|
||||
*/
|
||||
Animatable(float value = 0.0f);
|
||||
|
||||
/**
|
||||
* Returns the current animatable value.
|
||||
*/
|
||||
float getValue();
|
||||
|
||||
/**
|
||||
* Stops and resets the animation, going back to the given initial value.
|
||||
* All steps are removed.
|
||||
* If an animation was already ongoing for that animatable, its end callback
|
||||
* will be called.
|
||||
*/
|
||||
void reset(float initialValue);
|
||||
|
||||
/**
|
||||
* Stops and resets the animation. The value will stay where it's at.
|
||||
* All steps are removed.
|
||||
* If an animation was already ongoing for that animatable, its end callback
|
||||
* will be called.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* Adds an animation step to the target value, lasting the specified duration in milliseconds.
|
||||
*
|
||||
* An animation can have multiple steps. Target value can be greater and lower than the previous step (it can go forwards or backwards).
|
||||
* Easing function is optional, default is EasingFunction::linear.
|
||||
*
|
||||
* Duration is int32_t due to internal limitations, so a step cannot last for longer than 2 147 483 647ms.
|
||||
* The sum of the duration of all steps cannot exceed 71582min.
|
||||
*/
|
||||
void addStep(float targetValue, int32_t duration, EasingFunction easing = EasingFunction::linear);
|
||||
|
||||
/**
|
||||
* Returns the progress of the animation between 0.0f and 1.0f.
|
||||
*/
|
||||
float getProgress();
|
||||
|
||||
operator float() const;
|
||||
operator float();
|
||||
void operator=(const float value);
|
||||
bool operator==(const float value);
|
||||
|
||||
protected:
|
||||
bool onUpdate(Time delta) override;
|
||||
|
||||
void onReset() override;
|
||||
void onRewind() override;
|
||||
|
||||
private:
|
||||
float currentValue = 0.0f;
|
||||
tweeny::tween<float> tween;
|
||||
};
|
||||
|
||||
void updateHighlightAnimation();
|
||||
void getHighlightAnimation(float* gradient_x, float* gradient_y, float* color);
|
||||
|
||||
} // namespace brls
|
||||
@@ -1,246 +0,0 @@
|
||||
/*
|
||||
Copyright 2019-2021 natinusala
|
||||
Copyright 2019 p-sam
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <nanovg.h>
|
||||
#include <tinyxml2.h>
|
||||
|
||||
#include <borealis/core/activity.hpp>
|
||||
#include <borealis/core/audio.hpp>
|
||||
#include <borealis/core/font.hpp>
|
||||
#include <borealis/core/frame_context.hpp>
|
||||
#include <borealis/core/logger.hpp>
|
||||
#include <borealis/core/platform.hpp>
|
||||
#include <borealis/core/style.hpp>
|
||||
#include <borealis/core/theme.hpp>
|
||||
#include <borealis/core/view.hpp>
|
||||
#include <borealis/views/label.hpp>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
typedef std::function<View*(void)> XMLViewCreator;
|
||||
|
||||
class Application
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Inits the borealis application.
|
||||
* Returns true if it succeeded, false otherwise.
|
||||
*/
|
||||
static bool init();
|
||||
|
||||
/**
|
||||
* Creates the application window with the given title.
|
||||
* Must be called after calling init().
|
||||
*/
|
||||
static void createWindow(std::string title);
|
||||
|
||||
/**
|
||||
* Application main loop iteration.
|
||||
* Must be called in an infinite loop until it returns false.
|
||||
*/
|
||||
static bool mainLoop();
|
||||
|
||||
static Platform* getPlatform();
|
||||
static AudioPlayer* getAudioPlayer();
|
||||
|
||||
static NVGcontext* getNVGContext();
|
||||
inline static float contentWidth, contentHeight;
|
||||
|
||||
/**
|
||||
* Called by the video context when the content window is resized
|
||||
* and when the context is ready (to setup the initial content scaling).
|
||||
*/
|
||||
static void onWindowResized(int width, int height);
|
||||
|
||||
/**
|
||||
* Pushes a view on this applications's view stack.
|
||||
*
|
||||
* The view will automatically be resized to take
|
||||
* the whole screen.
|
||||
*
|
||||
* The view will gain focus if applicable.
|
||||
*
|
||||
* The first activity to be pushed cannot be popped.
|
||||
*/
|
||||
static void pushActivity(Activity* view, TransitionAnimation animation = TransitionAnimation::FADE);
|
||||
|
||||
/**
|
||||
* Pops the last pushed activity from the stack
|
||||
* and gives focus back where it was before.
|
||||
*/
|
||||
static void popActivity(
|
||||
TransitionAnimation animation = TransitionAnimation::FADE, std::function<void(void)> cb = [] {});
|
||||
|
||||
/**
|
||||
* Gives the focus to the given view
|
||||
* or clears the focus if given nullptr.
|
||||
*/
|
||||
static void giveFocus(View* view);
|
||||
|
||||
inline static Style getStyle()
|
||||
{
|
||||
return brls::getStyle();
|
||||
}
|
||||
|
||||
static Theme getTheme();
|
||||
static ThemeVariant getThemeVariant();
|
||||
|
||||
/**
|
||||
* Loads a font from a given file and stores it in the font stash.
|
||||
* Returns true if the operation succeeded.
|
||||
*/
|
||||
static bool loadFontFromFile(std::string fontName, std::string filePath);
|
||||
|
||||
/**
|
||||
* Loads a font from a given memory buffer and stores it in the font stash.
|
||||
* Returns true if the operation succeeded.
|
||||
*/
|
||||
static bool loadFontFromMemory(std::string fontName, void* data, size_t size, bool freeData);
|
||||
|
||||
/**
|
||||
* Returns the nanovg handle to the given font name, or FONT_INVALID if
|
||||
* no such font is currently loaded.
|
||||
*/
|
||||
static int getFont(std::string fontName);
|
||||
|
||||
static void notify(std::string text);
|
||||
|
||||
static void onControllerButtonPressed(enum ControllerButton button, bool repeating);
|
||||
|
||||
/**
|
||||
* "Crashes" the app (displays a fullscreen CrashFrame)
|
||||
*/
|
||||
static void crash(std::string text);
|
||||
|
||||
static void quit();
|
||||
|
||||
/**
|
||||
* Blocks any and all user inputs
|
||||
*/
|
||||
static void blockInputs();
|
||||
|
||||
/**
|
||||
* Unblocks inputs after a call to
|
||||
* blockInputs()
|
||||
*/
|
||||
static void unblockInputs();
|
||||
|
||||
static void setCommonFooter(std::string footer);
|
||||
static std::string* getCommonFooter();
|
||||
|
||||
static void setDisplayFramerate(bool enabled);
|
||||
static void toggleFramerateDisplay();
|
||||
|
||||
static void setMaximumFPS(unsigned fps);
|
||||
|
||||
inline static float windowScale;
|
||||
|
||||
/**
|
||||
* Sets whether BUTTON_START will globally be used to close the application.
|
||||
*/
|
||||
static void setGlobalQuit(bool enabled);
|
||||
|
||||
/**
|
||||
* Sets whether BUTTON_BACK will globally be used to toggle an FPS display.
|
||||
*/
|
||||
static void setGlobalFPSToggle(bool enabled);
|
||||
|
||||
static GenericEvent* getGlobalFocusChangeEvent();
|
||||
static VoidEvent* getGlobalHintsUpdateEvent();
|
||||
|
||||
static View* getCurrentFocus();
|
||||
|
||||
static std::string getTitle();
|
||||
|
||||
/**
|
||||
* Registers a view to be created from XML. You must give the name of the XML node as well
|
||||
* as a function that creates the view.
|
||||
*
|
||||
* If you need attributes, register them with the given functions in the view
|
||||
* class constructor directly. They will be called one by one after the view is instantiated.
|
||||
*
|
||||
* You should not add any children in the function, it is already taken care of.
|
||||
*/
|
||||
static void registerXMLView(std::string name, XMLViewCreator creator);
|
||||
|
||||
static bool XMLViewsRegisterContains(std::string name);
|
||||
static XMLViewCreator getXMLViewCreator(std::string name);
|
||||
|
||||
/**
|
||||
* Returns the current system locale.
|
||||
*/
|
||||
static std::string getLocale();
|
||||
|
||||
private:
|
||||
inline static bool inited = false;
|
||||
inline static bool quitRequested = false;
|
||||
|
||||
inline static Platform* platform = nullptr;
|
||||
|
||||
inline static std::string title;
|
||||
|
||||
inline static FontStash fontStash;
|
||||
|
||||
inline static std::vector<Activity*> activitiesStack;
|
||||
inline static std::vector<View*> focusStack;
|
||||
|
||||
inline static unsigned windowWidth, windowHeight;
|
||||
|
||||
inline static View* currentFocus;
|
||||
|
||||
inline static unsigned blockInputsTokens = 0; // any value > 0 means inputs are blocked
|
||||
|
||||
inline static std::string commonFooter = "";
|
||||
|
||||
inline static bool globalQuitEnabled = false;
|
||||
inline static ActionIdentifier gloablQuitIdentifier = ACTION_NONE;
|
||||
inline static bool globalFPSToggleEnabled = false;
|
||||
inline static ActionIdentifier gloablFPSToggleIdentifier = ACTION_NONE;
|
||||
|
||||
inline static View* repetitionOldFocus = nullptr;
|
||||
|
||||
inline static GenericEvent globalFocusChangeEvent;
|
||||
inline static VoidEvent globalHintsUpdateEvent;
|
||||
|
||||
inline static std::unordered_map<std::string, XMLViewCreator> xmlViewsRegister;
|
||||
|
||||
static void navigate(FocusDirection direction);
|
||||
|
||||
static void onWindowSizeChanged();
|
||||
|
||||
static void frame();
|
||||
static void clear();
|
||||
static void exit();
|
||||
|
||||
/**
|
||||
* Handles actions for the currently focused view and
|
||||
* the given button
|
||||
* Returns true if at least one action has been fired
|
||||
*/
|
||||
static bool handleAction(char button);
|
||||
|
||||
static void registerBuiltInXMLViews();
|
||||
|
||||
static ActionIdentifier registerFPSToggleAction(Activity* activity);
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
@@ -1,23 +0,0 @@
|
||||
/*
|
||||
Copyright 2019-2021 natinusala
|
||||
Copyright 2019 p-sam
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef BRLS_RESOURCES
|
||||
#error BRLS_RESOURCES define missing
|
||||
#endif
|
||||
#define BRLS_ASSET(_str) BRLS_RESOURCES _str
|
||||
@@ -1,78 +0,0 @@
|
||||
/*
|
||||
Copyright 2021 natinusala
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
enum Sound
|
||||
{
|
||||
SOUND_NONE = 0, // no sound
|
||||
|
||||
SOUND_FOCUS_CHANGE, // played when the focus changes
|
||||
SOUND_FOCUS_ERROR, // played when the user wants to go somewhere impossible (while the highlight wiggles)
|
||||
SOUND_CLICK, // played when the click action runs
|
||||
SOUND_FOCUS_SIDEBAR, // played when the focus changes to a sidebar item
|
||||
SOUND_CLICK_ERROR, // played when the user clicks a disabled button / a view focused with no click action
|
||||
SOUND_HONK, // honk
|
||||
SOUND_CLICK_SIDEBAR, // played when a sidebar item is clicked
|
||||
|
||||
_SOUND_MAX, // not an actual sound, just used to count of many sounds there are
|
||||
};
|
||||
|
||||
// Platform agnostic Audio player
|
||||
// Each platform's AudioPlayer is responsible for managing the enum Sound -> internal representation map
|
||||
class AudioPlayer
|
||||
{
|
||||
public:
|
||||
virtual ~AudioPlayer() {};
|
||||
|
||||
/**
|
||||
* Preemptively loads the given sound so that it's ready to be played
|
||||
* when needed.
|
||||
*
|
||||
* Returns a boolean indicating if the sound has been loaded or not.
|
||||
*/
|
||||
virtual bool load(enum Sound sound) = 0;
|
||||
|
||||
/**
|
||||
* Plays the given sound.
|
||||
*
|
||||
* The AudioPlayer should not assume that the sound has been
|
||||
* loaded already, and must load it if needed.
|
||||
*
|
||||
* Returns a boolean indicating if the sound has been played or not.
|
||||
*/
|
||||
virtual bool play(enum Sound sound) = 0;
|
||||
};
|
||||
|
||||
// An AudioPlayer that does nothing
|
||||
class NullAudioPlayer : public AudioPlayer
|
||||
{
|
||||
public:
|
||||
bool load(enum Sound sound) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool play(enum Sound sound) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
Copyright 2021 natinusala
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/core/activity.hpp>
|
||||
#include <borealis/core/view.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// Exception thrown when using a BoundView with an unknown ID for
|
||||
// the given owner.
|
||||
class ViewNotFoundException : public std::exception
|
||||
{
|
||||
public:
|
||||
ViewNotFoundException(View* owner, std::string searchedId);
|
||||
ViewNotFoundException(Activity* owner, std::string searchedId);
|
||||
|
||||
const char* what() const noexcept;
|
||||
|
||||
private:
|
||||
std::string errorMessage;
|
||||
};
|
||||
|
||||
#define BRLS_BIND(type, name, id) brls::BoundView<type> name = brls::BoundView<type>(id, this)
|
||||
|
||||
// A BoundView represents a "child" view, bound to its "parent" view class.
|
||||
// Dereferencing operator has been overridden to directly resolve the view by ID and forward the call to the view pointer for you.
|
||||
// Allows easy access of child views inside the parent class when used with the BRLS_BIND macro.
|
||||
// Does NOT do any type check - it assumes the type you give it is the same as the view you are trying to get.
|
||||
template <typename T>
|
||||
class BoundView
|
||||
{
|
||||
public:
|
||||
BoundView(std::string id, View* owner)
|
||||
: id(id)
|
||||
, ownerView(owner)
|
||||
{
|
||||
}
|
||||
|
||||
BoundView(std::string id, Activity* owner)
|
||||
: id(id)
|
||||
, ownerActivity(owner)
|
||||
{
|
||||
}
|
||||
|
||||
T* getView()
|
||||
{
|
||||
this->resolve();
|
||||
return this->view;
|
||||
}
|
||||
|
||||
operator T*()
|
||||
{
|
||||
return this->getView();
|
||||
}
|
||||
|
||||
T* operator->()
|
||||
{
|
||||
return this->getView();
|
||||
}
|
||||
|
||||
bool operator==(const T* value)
|
||||
{
|
||||
return this->getView() == value;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string id = "";
|
||||
|
||||
T* view = nullptr;
|
||||
|
||||
View* ownerView = nullptr;
|
||||
Activity* ownerActivity = nullptr;
|
||||
|
||||
/**
|
||||
* Resolve the view pointer by id.
|
||||
*
|
||||
* Not called in the constructor
|
||||
* on purpose because the owner might now be ready when
|
||||
* the BoundView is constructed, so wait for the first
|
||||
* actual call before resolving the view.
|
||||
*/
|
||||
void resolve()
|
||||
{
|
||||
if (this->view)
|
||||
return;
|
||||
|
||||
// Resolve by owner activity first
|
||||
if (this->ownerView)
|
||||
{
|
||||
this->view = (T*)this->ownerView->getView(this->id);
|
||||
|
||||
if (!this->view)
|
||||
throw ViewNotFoundException(this->ownerView, this->id);
|
||||
}
|
||||
// Then resolve by owner view
|
||||
else if (this->ownerActivity)
|
||||
{
|
||||
this->view = (T*)this->ownerActivity->getView(this->id);
|
||||
|
||||
if (!this->view)
|
||||
throw ViewNotFoundException(this->ownerActivity, this->id);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::logic_error("No owner view or activity given to BoundView");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
@@ -1,280 +0,0 @@
|
||||
/*
|
||||
Copyright 2020-2021 natinusala
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/core/view.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
enum class JustifyContent
|
||||
{
|
||||
FLEX_START,
|
||||
CENTER,
|
||||
FLEX_END,
|
||||
SPACE_BETWEEN,
|
||||
SPACE_AROUND,
|
||||
SPACE_EVENLY,
|
||||
};
|
||||
|
||||
enum class AlignItems
|
||||
{
|
||||
AUTO,
|
||||
FLEX_START,
|
||||
CENTER,
|
||||
FLEX_END,
|
||||
STRETCH,
|
||||
BASELINE,
|
||||
SPACE_BETWEEN,
|
||||
SPACE_AROUND,
|
||||
};
|
||||
|
||||
enum class Axis
|
||||
{
|
||||
ROW,
|
||||
COLUMN,
|
||||
};
|
||||
|
||||
enum class Direction
|
||||
{
|
||||
INHERIT,
|
||||
LEFT_TO_RIGHT,
|
||||
RIGHT_TO_LEFT,
|
||||
};
|
||||
|
||||
// Generic FlexBox layout
|
||||
class Box : public View
|
||||
{
|
||||
public:
|
||||
Box(Axis flexDirection);
|
||||
Box();
|
||||
|
||||
void draw(NVGcontext* vg, float x, float y, float width, float height, Style style, FrameContext* ctx) override;
|
||||
View* getDefaultFocus() override;
|
||||
View* getNextFocus(FocusDirection direction, View* currentView) override;
|
||||
void willAppear(bool resetState) override;
|
||||
void willDisappear(bool resetState) override;
|
||||
void onWindowSizeChanged() override;
|
||||
void onFocusGained() override;
|
||||
void onFocusLost() override;
|
||||
void onParentFocusGained(View* focusedView) override;
|
||||
void onParentFocusLost(View* focusedView) override;
|
||||
bool applyXMLAttribute(std::string name, std::string value) override;
|
||||
|
||||
static View* create();
|
||||
|
||||
/**
|
||||
* Adds a view to this Box.
|
||||
* Returns the position the view was added at.
|
||||
*/
|
||||
virtual void addView(View* view);
|
||||
|
||||
/**
|
||||
* Adds a view to this Box at the given position.
|
||||
* Returns the position the view was added at.
|
||||
*/
|
||||
virtual void addView(View* view, size_t position);
|
||||
|
||||
/**
|
||||
* Removes the given view from the Box. It will be freed.
|
||||
*/
|
||||
virtual void removeView(View* view);
|
||||
|
||||
/**
|
||||
* Sets the padding of the view, aka the internal space to give
|
||||
* between this view boundaries and its children.
|
||||
*
|
||||
* Only does one layout pass instead of four when using the four methods separately.
|
||||
*/
|
||||
virtual void setPadding(float padding);
|
||||
|
||||
/**
|
||||
* Sets the padding of the view, aka the internal space to give
|
||||
* between this view boundaries and its children.
|
||||
*
|
||||
* Only does one layout pass instead of four when using the four methods separately.
|
||||
*/
|
||||
virtual void setPadding(float top, float right, float bottom, float left);
|
||||
|
||||
/**
|
||||
* Sets the padding of the view, aka the internal space to give
|
||||
* between this view boundaries and its children.
|
||||
*/
|
||||
virtual void setPaddingTop(float top);
|
||||
|
||||
/**
|
||||
* Sets the padding of the view, aka the internal space to give
|
||||
* between this view boundaries and its children.
|
||||
*/
|
||||
virtual void setPaddingRight(float right);
|
||||
|
||||
/**
|
||||
* Sets the padding of the view, aka the internal space to give
|
||||
* between this view boundaries and its children.
|
||||
*/
|
||||
virtual void setPaddingBottom(float bottom);
|
||||
|
||||
/**
|
||||
* Sets the padding of the view, aka the internal space to give
|
||||
* between this view boundaries and its children.
|
||||
*/
|
||||
virtual void setPaddingLeft(float left);
|
||||
|
||||
/**
|
||||
* Sets the children alignment along the Box axis.
|
||||
*
|
||||
* Default is FLEX_START.
|
||||
*/
|
||||
void setJustifyContent(JustifyContent justify);
|
||||
|
||||
/**
|
||||
* Sets the children alignment along the Box cross axis.
|
||||
*
|
||||
* Default is AUTO.
|
||||
*/
|
||||
void setAlignItems(AlignItems alignment);
|
||||
|
||||
/**
|
||||
* Sets the direction of the box, aka place the views
|
||||
* left to right or right to left (flips the children).
|
||||
*
|
||||
* Default is INHERIT.
|
||||
*/
|
||||
void setDirection(Direction direction);
|
||||
|
||||
void setAxis(Axis axis);
|
||||
|
||||
std::vector<View*>& getChildren();
|
||||
|
||||
/**
|
||||
* Returns the bounds used for culling children.
|
||||
*/
|
||||
virtual void getCullingBounds(float* top, float* right, float* bottom, float* left);
|
||||
|
||||
/**
|
||||
* Registers an XML attribute to be forwarded to the given view. Works regardless of the target attribute type.
|
||||
* Useful to expose attributes of children views in the parent box without copy pasting them individually.
|
||||
*
|
||||
* The forwarded attribute value will override the value of the regular attribute if it already exists in the target view.
|
||||
*/
|
||||
void forwardXMLAttribute(std::string attributeName, View* target);
|
||||
|
||||
/**
|
||||
* Registers an XML attribute to be forwarded to the given view, while changing the target attribute name.
|
||||
* Works regardless of the target attribute type.
|
||||
* Useful to expose attributes of children views in the parent box without copy pasting them individually, but with a different name.
|
||||
*
|
||||
* The forwarded attribute value will override the value of the regular attribute if it already exists in the target view.
|
||||
*/
|
||||
void forwardXMLAttribute(std::string attributeName, View* target, std::string targetAttributeName);
|
||||
|
||||
/**
|
||||
* Fired when focus is gained on one of this view's children, or one of the children
|
||||
* of the children...
|
||||
*
|
||||
* directChild is guaranteed to be one of your children. It may not be the view that has been
|
||||
* focused.
|
||||
*
|
||||
* If focusedView == directChild, then the child of yours has been focused.
|
||||
* Otherwise, focusedView is a child of directChild.
|
||||
*/
|
||||
virtual void onChildFocusGained(View* directChild, View* focusedView);
|
||||
|
||||
/**
|
||||
* Fired when focus is lost on one of this view's children. Works similarly to
|
||||
* onChildFocusGained().
|
||||
*/
|
||||
virtual void onChildFocusLost(View* directChild, View* focusedView);
|
||||
|
||||
View* getView(std::string id) override;
|
||||
|
||||
private:
|
||||
Axis axis;
|
||||
|
||||
std::vector<View*> children;
|
||||
|
||||
size_t defaultFocusedIndex = 0;
|
||||
|
||||
std::unordered_map<std::string, std::pair<std::string, View*>> forwardedAttributes;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Inflates the Box with the given XML string.
|
||||
*
|
||||
* The root element MUST be a brls::Box, corresponding to the inflated Box itself. Its
|
||||
* attributes will be applied to the Box.
|
||||
*
|
||||
* Each child node in the root brls::Box will be treated as a view and added
|
||||
* as a child of the Box.
|
||||
*/
|
||||
void inflateFromXMLString(std::string xml);
|
||||
|
||||
/**
|
||||
* Inflates the Box with the given XML element.
|
||||
*
|
||||
* The root element MUST be a brls::Box, corresponding to the inflated Box itself. Its
|
||||
* attributes will be applied to the Box.
|
||||
*
|
||||
* Each child node in the root brls::Box will be treated as a view and added
|
||||
* as a child of the Box.
|
||||
*/
|
||||
void inflateFromXMLElement(tinyxml2::XMLElement* element);
|
||||
|
||||
/**
|
||||
* Inflates the Box with the given XML resource.
|
||||
*
|
||||
* The root element MUST be a brls::Box, corresponding to the inflated Box itself. Its
|
||||
* attributes will be applied to the Box.
|
||||
*
|
||||
* Each child node in the root brls::Box will be treated as a view and added
|
||||
* as a child of the Box.
|
||||
*/
|
||||
void inflateFromXMLRes(std::string res);
|
||||
|
||||
/**
|
||||
* Inflates the Box with the given XML file path.
|
||||
*
|
||||
* The root element MUST be a brls::Box, corresponding to the inflated Box itself. Its
|
||||
* attributes will be applied to the Box.
|
||||
*
|
||||
* Each child node in the root brls::Box will be treated as a view and added
|
||||
* as a child of the Box.
|
||||
*/
|
||||
void inflateFromXMLFile(std::string path);
|
||||
|
||||
/**
|
||||
* Handles a child XML element.
|
||||
*
|
||||
* By default, calls createFromXMLElement() and adds the result
|
||||
* to the children of the Box.
|
||||
*/
|
||||
void handleXMLElement(tinyxml2::XMLElement* element) override;
|
||||
};
|
||||
|
||||
// An empty view that has auto x auto and grow=1.0 to push
|
||||
// all the next views in its box to the right (or to the bottom)
|
||||
class Padding : public View
|
||||
{
|
||||
public:
|
||||
Padding();
|
||||
|
||||
void draw(NVGcontext* vg, float x, float y, float width, float height, Style style, FrameContext* ctx) override;
|
||||
|
||||
static View* create();
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
Copyright 2020 natinusala
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <list>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// Simple observer pattern implementation
|
||||
//
|
||||
// Usage:
|
||||
// 1. typedef your event type
|
||||
// 2. create as many events as you want using that type
|
||||
// 3. call subscribe on the events with your observers
|
||||
// 4. call fire when you want to fire the events
|
||||
// it wil return true if at least one subscriber exists
|
||||
// for that event
|
||||
template <typename... Ts>
|
||||
class Event
|
||||
{
|
||||
public:
|
||||
typedef std::function<void(Ts...)> Callback;
|
||||
typedef std::list<Callback> CallbacksList;
|
||||
typedef typename CallbacksList::iterator Subscription;
|
||||
|
||||
Subscription subscribe(Callback cb);
|
||||
void unsubscribe(Subscription subscription);
|
||||
bool fire(Ts... args);
|
||||
|
||||
private:
|
||||
CallbacksList callbacks;
|
||||
};
|
||||
|
||||
template <typename... Ts>
|
||||
typename Event<Ts...>::Subscription Event<Ts...>::subscribe(Event<Ts...>::Callback cb)
|
||||
{
|
||||
this->callbacks.push_back(cb);
|
||||
return --this->callbacks.end();
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
void Event<Ts...>::unsubscribe(Event<Ts...>::Subscription subscription)
|
||||
{
|
||||
this->callbacks.erase(subscription);
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
bool Event<Ts...>::fire(Ts... args)
|
||||
{
|
||||
for (Callback cb : this->callbacks)
|
||||
cb(args...);
|
||||
|
||||
return !this->callbacks.empty();
|
||||
}
|
||||
|
||||
}; // namespace brls
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
Copyright 2021 natinusala
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
static constexpr const int FONT_INVALID = -1;
|
||||
|
||||
static const std::string FONT_REGULAR = "regular"; // regular Latin font
|
||||
static const std::string FONT_KOREAN_REGULAR = "korean"; // regular Korean font
|
||||
static const std::string FONT_MATERIAL_ICONS = "material"; // Material icons font
|
||||
static const std::string FONT_SWITCH_ICONS = "switch"; // Switch icons font (see the HOS shared symbols font for an example)
|
||||
|
||||
typedef std::unordered_map<std::string, int> FontStash;
|
||||
|
||||
// Platform interface to load fonts from disk or other sources (system / shared font...)
|
||||
class FontLoader
|
||||
{
|
||||
public:
|
||||
virtual ~FontLoader() {}
|
||||
/**
|
||||
* Called once on init to load every font in the font stash.
|
||||
*
|
||||
* The implementation must use the Application::loadFont and
|
||||
* Application::loadFontFromMemory methods to load as much as possible
|
||||
* of the "built-in" fonts defined in the FONT_* constants above.
|
||||
*/
|
||||
virtual void loadFonts() = 0;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Convenience method to load a font from a file path
|
||||
* with some more logging.
|
||||
*/
|
||||
bool loadFontFromFile(std::string fontName, std::string filePath);
|
||||
|
||||
/**
|
||||
* Can be called internally to load the Material icons font from resources.
|
||||
* Returns true if the operation succeeds.
|
||||
*/
|
||||
bool loadMaterialFromResources();
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 natinusala
|
||||
Copyright 2019 psam
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <nanovg.h>
|
||||
|
||||
#include <borealis/core/font.hpp>
|
||||
#include <borealis/core/style.hpp>
|
||||
#include <borealis/core/theme.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
class FrameContext
|
||||
{
|
||||
public:
|
||||
NVGcontext* vg = nullptr;
|
||||
float pixelRatio = 0.0;
|
||||
FontStash* fontStash = nullptr;
|
||||
Theme theme = nullptr;
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
Copyright 2020-2021 natinusala
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fmt/core.h>
|
||||
|
||||
#include <borealis/core/logger.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
const std::string LOCALE_JA = "ja";
|
||||
const std::string LOCALE_EN_US = "en-US";
|
||||
const std::string LOCALE_EN_GB = "en-GB";
|
||||
const std::string LOCALE_FR = "fr";
|
||||
const std::string LOCALE_FR_CA = "fr-CA";
|
||||
const std::string LOCALE_DE = "de";
|
||||
const std::string LOCALE_IT = "it";
|
||||
const std::string LOCALE_ES = "es";
|
||||
const std::string LOCALE_ZH_CN = "zh-CN";
|
||||
const std::string LOCALE_ZH_HANS = "zh-Hans";
|
||||
const std::string LOCALE_ZH_HANT = "zh-Hant";
|
||||
const std::string LOCALE_ZH_TW = "zh-TW";
|
||||
const std::string LOCALE_Ko = "ko";
|
||||
const std::string LOCALE_NL = "nl";
|
||||
const std::string LOCALE_PT = "pt";
|
||||
const std::string LOCALE_PT_BR = "pt-BR";
|
||||
const std::string LOCALE_RU = "ru";
|
||||
const std::string LOCALE_ES_419 = "es-419";
|
||||
|
||||
const std::string LOCALE_DEFAULT = LOCALE_EN_US;
|
||||
|
||||
namespace internal
|
||||
{
|
||||
std::string getRawStr(std::string stringName);
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* Returns the translation for the given string,
|
||||
* after injecting format parameters (if any)
|
||||
*/
|
||||
template <typename... Args>
|
||||
std::string getStr(std::string stringName, Args&&... args)
|
||||
{
|
||||
std::string rawStr = internal::getRawStr(stringName);
|
||||
|
||||
try
|
||||
{
|
||||
return fmt::format(rawStr, args...);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
Logger::error("Invalid format \"{}\" from string \"{}\": {}", rawStr, stringName, e.what());
|
||||
return stringName;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads all translations of the current system locale + default locale
|
||||
* Must be called before trying to get a translation!
|
||||
*/
|
||||
void loadTranslations();
|
||||
|
||||
inline namespace literals
|
||||
{
|
||||
/**
|
||||
* Returns the translation for the given string, without
|
||||
* injecting any parameters
|
||||
* Shortcut to brls::getStr(stringName)
|
||||
*/
|
||||
std::string operator"" _i18n(const char* str, size_t len);
|
||||
} // namespace literals
|
||||
} // namespace brls
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
Copyright 2021 natinusala
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// Abstract buttons enum - names correspond to a generic Xbox controller
|
||||
// LT and RT should not be buttons but for the sake of simplicity we'll assume they are.
|
||||
// Similarly, DPAD (also called HAT) is assumed to be buttons here.
|
||||
enum ControllerButton
|
||||
{
|
||||
BUTTON_LT = 0,
|
||||
BUTTON_LB,
|
||||
|
||||
BUTTON_LSB,
|
||||
|
||||
BUTTON_UP,
|
||||
BUTTON_RIGHT,
|
||||
BUTTON_DOWN,
|
||||
BUTTON_LEFT,
|
||||
|
||||
BUTTON_BACK,
|
||||
BUTTON_GUIDE,
|
||||
BUTTON_START,
|
||||
|
||||
BUTTON_RSB,
|
||||
|
||||
BUTTON_Y,
|
||||
BUTTON_B,
|
||||
BUTTON_A,
|
||||
BUTTON_X,
|
||||
|
||||
BUTTON_RB,
|
||||
BUTTON_RT,
|
||||
|
||||
_BUTTON_MAX,
|
||||
};
|
||||
|
||||
// Abstract axis enum - names correspond to a generic Xbox controller
|
||||
enum ControllerAxis
|
||||
{
|
||||
LEFT_X,
|
||||
LEFT_Y,
|
||||
|
||||
// No Z axis, LT and RT are in the buttons enum for the sake of simplicity
|
||||
|
||||
RIGHT_X, // also called 5th axis
|
||||
RIGHT_Y, // also called 4th axis
|
||||
|
||||
_AXES_MAX,
|
||||
};
|
||||
|
||||
// Represents the state of the controller (a gamepad or a keyboard) in the current frame
|
||||
typedef struct ControllerState
|
||||
{
|
||||
bool buttons[_BUTTON_MAX]; // true: pressed
|
||||
float axes[_AXES_MAX]; // from 0.0f to 1.0f
|
||||
} ControllerState;
|
||||
|
||||
// Interface responsible for reporting input state to the application - button presses,
|
||||
// axis position and touch screen state
|
||||
class InputManager
|
||||
{
|
||||
public:
|
||||
virtual ~InputManager() {}
|
||||
|
||||
/**
|
||||
* Called once every frame to fill the given ControllerState struct with the controller state.
|
||||
*/
|
||||
virtual void updateControllerState(ControllerState* state) = 0;
|
||||
};
|
||||
|
||||
}; // namespace brls
|
||||
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
Copyright 2019 natinusala
|
||||
Copyright 2019 p-sam
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fmt/core.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
enum class LogLevel
|
||||
{
|
||||
ERROR = 0,
|
||||
WARNING,
|
||||
INFO,
|
||||
DEBUG
|
||||
};
|
||||
|
||||
class Logger
|
||||
{
|
||||
public:
|
||||
static void setLogLevel(LogLevel logLevel);
|
||||
|
||||
template <typename... Args>
|
||||
inline static void log(LogLevel logLevel, std::string prefix, std::string color, std::string format, Args&&... args)
|
||||
{
|
||||
if (Logger::logLevel < logLevel)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
fmt::print("\033{}[{}]\033[0m ", color, prefix);
|
||||
fmt::print(format, args...);
|
||||
fmt::print("\n");
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
// will be printed after the first fmt::print (so after the log tag)
|
||||
printf("! Invalid log format string: \"%s\": %s\n", format.c_str(), e.what());
|
||||
}
|
||||
|
||||
#ifdef __MINGW32__
|
||||
fflush(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline static void error(std::string format, Args&&... args)
|
||||
{
|
||||
Logger::log(LogLevel::ERROR, "ERROR", "[0;31m", format, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline static void warning(std::string format, Args&&... args)
|
||||
{
|
||||
Logger::log(LogLevel::WARNING, "WARNING", "[0;33m", format, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline static void info(std::string format, Args&&... args)
|
||||
{
|
||||
Logger::log(LogLevel::INFO, "INFO", "[0;34m", format, args...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
inline static void debug(std::string format, Args&&... args)
|
||||
{
|
||||
Logger::log(LogLevel::DEBUG, "DEBUG", "[0;32m", format, args...);
|
||||
}
|
||||
|
||||
private:
|
||||
inline static LogLevel logLevel = LogLevel::INFO;
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
@@ -1,106 +0,0 @@
|
||||
/*
|
||||
Copyright 2021 natinusala
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/core/audio.hpp>
|
||||
#include <borealis/core/font.hpp>
|
||||
#include <borealis/core/input.hpp>
|
||||
#include <borealis/core/theme.hpp>
|
||||
#include <borealis/core/video.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// Interface to provide everything platform specific required to run borealis: graphics context, inputs, audio...
|
||||
// The best platform is automatically selected when the application starts, and cannot be changed by the user at the moment
|
||||
class Platform
|
||||
{
|
||||
public:
|
||||
virtual ~Platform() {};
|
||||
|
||||
/**
|
||||
* Called on startup, right after instanciation, to create and open a window
|
||||
* with the given title and size.
|
||||
*/
|
||||
virtual void createWindow(std::string title, uint32_t width, uint32_t height) = 0;
|
||||
|
||||
/**
|
||||
* Returns the human-readable name of the platform.
|
||||
*/
|
||||
virtual std::string getName() = 0;
|
||||
|
||||
/**
|
||||
* Called at every iteration of the main loop.
|
||||
* Must return false if the app should continue running
|
||||
* (for example, return false if the X button was pressed on the window).
|
||||
*/
|
||||
virtual bool mainLoopIteration() = 0;
|
||||
|
||||
/**
|
||||
* Can be called at anytime to get the current system theme variant.
|
||||
*
|
||||
* For now, the variant is assumed to stay the same during the whole time
|
||||
* the app is running (no variant hot swap).
|
||||
*
|
||||
* As such, the result should be cached by the platform code.
|
||||
*/
|
||||
virtual ThemeVariant getThemeVariant() = 0;
|
||||
|
||||
/**
|
||||
* Can be called at anytime to get the current locale
|
||||
*
|
||||
* For now, the locale is assumed to stay the same during the whole time
|
||||
* the app is running (no locale hot swap)
|
||||
*
|
||||
* As such, the result should be cached by the platform code.
|
||||
* The method should return one of the locale constants
|
||||
* defined in the i18n header file.
|
||||
*/
|
||||
virtual std::string getLocale() = 0;
|
||||
|
||||
/**
|
||||
* Returns the AudioPlayer for the platform.
|
||||
* Cannot return nullptr.
|
||||
*/
|
||||
virtual AudioPlayer* getAudioPlayer() = 0;
|
||||
|
||||
/**
|
||||
* Returns the VideoContext for the platform.
|
||||
* Cannot return nullptr.
|
||||
*/
|
||||
virtual VideoContext* getVideoContext() = 0;
|
||||
|
||||
/**
|
||||
* Returns the InputManager for the platform.
|
||||
* Cannot return nullptr.
|
||||
*/
|
||||
virtual InputManager* getInputManager() = 0;
|
||||
|
||||
/**
|
||||
* Returns the FontLoader for the platform.
|
||||
* Cannot return nullptr.
|
||||
*/
|
||||
virtual FontLoader* getFontLoader() = 0;
|
||||
|
||||
/**
|
||||
* Selects and returns the best platform.
|
||||
*/
|
||||
static Platform* createPlatform();
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
Copyright 2019-2020 natinusala
|
||||
Copyright 2019 WerWolv
|
||||
Copyright 2019 p-sam
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <initializer_list>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
class StyleValues
|
||||
{
|
||||
public:
|
||||
StyleValues(std::initializer_list<std::pair<std::string, float>> list);
|
||||
|
||||
void addMetric(std::string name, float value);
|
||||
float getMetric(std::string name);
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, float> values;
|
||||
};
|
||||
|
||||
// Simple wrapper around StyleValues for the array operator
|
||||
class Style
|
||||
{
|
||||
public:
|
||||
Style(StyleValues* values);
|
||||
float operator[](std::string name);
|
||||
|
||||
void addMetric(std::string name, float value);
|
||||
float getMetric(std::string name);
|
||||
|
||||
private:
|
||||
StyleValues* values;
|
||||
};
|
||||
|
||||
Style getStyle();
|
||||
|
||||
} // namespace brls
|
||||
@@ -1,51 +0,0 @@
|
||||
/*
|
||||
Copyright 2021 natinusala
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/core/timer.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// A RepeatingTask is a task executed repeatedly on the main thread at a given period in ms
|
||||
class RepeatingTask : private RepeatingTimer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Create a RepeatingTask with the given period in ms.
|
||||
*
|
||||
* The task is guaranteed to wait for at least the given period of time between
|
||||
* handler runs, but it can wait for slightly longer (usually less than a ms late)
|
||||
*/
|
||||
RepeatingTask(Time period);
|
||||
|
||||
/**
|
||||
* Task handler executed repeatedly on the main thread at the given period.
|
||||
*/
|
||||
virtual void run() = 0;
|
||||
|
||||
/**
|
||||
* Starts the task.
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* Stops the task.
|
||||
*/
|
||||
void stop();
|
||||
};
|
||||
} // namespace brls
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
Copyright 2019-2020 natinusala
|
||||
Copyright 2019 p-sam
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <nanovg.h>
|
||||
|
||||
#include <initializer_list>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
enum class ThemeVariant
|
||||
{
|
||||
LIGHT,
|
||||
DARK
|
||||
};
|
||||
|
||||
class ThemeValues
|
||||
{
|
||||
public:
|
||||
ThemeValues(std::initializer_list<std::pair<std::string, NVGcolor>> list);
|
||||
|
||||
void addColor(std::string name, NVGcolor color);
|
||||
NVGcolor getColor(std::string name);
|
||||
|
||||
private:
|
||||
std::unordered_map<std::string, NVGcolor> values;
|
||||
};
|
||||
|
||||
// Simple wrapper around ThemeValues for the array operator
|
||||
class Theme
|
||||
{
|
||||
public:
|
||||
Theme(ThemeValues* values);
|
||||
NVGcolor operator[](std::string name);
|
||||
|
||||
void addColor(std::string name, NVGcolor color);
|
||||
NVGcolor getColor(std::string name);
|
||||
|
||||
private:
|
||||
ThemeValues* values;
|
||||
};
|
||||
|
||||
Theme getLightTheme();
|
||||
Theme getDarkTheme();
|
||||
|
||||
} // namespace brls
|
||||
@@ -1,157 +0,0 @@
|
||||
/*
|
||||
Copyright 2021 natinusala
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libretro-common/features/features_cpu.h>
|
||||
#include <libretro-common/libretro.h>
|
||||
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
typedef retro_time_t Time;
|
||||
|
||||
/**
|
||||
* Returns the current CPU time in microseconds.
|
||||
*/
|
||||
inline Time getCPUTimeUsec()
|
||||
{
|
||||
return cpu_features_get_time_usec();
|
||||
}
|
||||
|
||||
typedef std::function<void()> TickingGenericCallback;
|
||||
|
||||
typedef std::function<void(bool)> TickingEndCallback;
|
||||
typedef TickingGenericCallback TickingTickCallback;
|
||||
|
||||
// Interface representing something that "ticks" every frame for a certain amount of frames,
|
||||
// like a timer, an animation, a background task...
|
||||
// The library manages a list of running tickings. Each ticking is reponsible for managing its own
|
||||
// lifetime by returning true or false in onUpdate.
|
||||
class Ticking
|
||||
{
|
||||
public:
|
||||
virtual ~Ticking();
|
||||
|
||||
/**
|
||||
* Starts the ticking, pushing it to the list of running tickings.
|
||||
* If the ticking is finished, it will be restarted.
|
||||
* If the ticking is already running, this method will have no effect.
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* Stops the ticking if it was running, and executes the end callback.
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* Sets a callback to be executed when the
|
||||
* ticking finishes.
|
||||
* The callback argument will be set to true if the ticking stopped
|
||||
* on its own, false if it was stopped early by the user.
|
||||
*/
|
||||
void setEndCallback(TickingEndCallback endCallback);
|
||||
|
||||
/**
|
||||
* Sets a callback to be executed at every tick
|
||||
* until the ticking finishes.
|
||||
*
|
||||
* The last animation tick will execute the tick callback
|
||||
* then the end callback.
|
||||
*/
|
||||
void setTickCallback(TickingTickCallback tickCallback);
|
||||
|
||||
/**
|
||||
* Returns true if the ticking is currently running.
|
||||
*/
|
||||
bool isRunning();
|
||||
|
||||
/**
|
||||
* Called internally by the main loop. Takes all running tickings
|
||||
* and updates them.
|
||||
*/
|
||||
static void updateTickings();
|
||||
|
||||
inline static std::vector<Ticking*> runningTickings;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Executed every frame while the ticking lives.
|
||||
* Delta is the time difference in ms between the last frame
|
||||
* and the current one.
|
||||
* Must return false if the ticking is finished and should be
|
||||
* removed from the list of active tickings.
|
||||
* The end callback will automatically be called then.
|
||||
*/
|
||||
virtual bool onUpdate(Time delta) = 0;
|
||||
|
||||
/**
|
||||
* Called when the ticking becomes active.
|
||||
*/
|
||||
virtual void onStart() {};
|
||||
|
||||
/**
|
||||
* Called when the ticking is stopped, either by the user
|
||||
* or because it finished.
|
||||
*/
|
||||
virtual void onStop() {};
|
||||
|
||||
private:
|
||||
void stop(bool finished);
|
||||
|
||||
bool running = false;
|
||||
|
||||
TickingEndCallback endCallback = [](bool finished) {};
|
||||
TickingTickCallback tickCallback = [] {};
|
||||
};
|
||||
|
||||
// Represents a "finite" ticking that runs for a known amount of time
|
||||
// and can be seek / reset / rewound.
|
||||
class FiniteTicking : public Ticking
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Rewinds the ticking to go back to the beginning
|
||||
* without losing its state (as opposed to reset() that clears
|
||||
* everything in the ticking).
|
||||
* Does not start or stop it.
|
||||
*/
|
||||
void rewind();
|
||||
|
||||
/**
|
||||
* Stops and resets the ticking, clearing its state
|
||||
* in the process (as opposed to rewind() that just restarts
|
||||
* the ticking from the beginning without losing the state).
|
||||
*/
|
||||
void reset();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Called when the ticking gets rewound.
|
||||
*/
|
||||
virtual void onRewind() {};
|
||||
|
||||
/**
|
||||
* Called when the ticking gets reset.
|
||||
*/
|
||||
virtual void onReset() {};
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
@@ -1,93 +0,0 @@
|
||||
/*
|
||||
Copyright 2021 natinusala
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/core/time.hpp>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
// A Timer allows to run a callback once after a given period of time, in ms
|
||||
// Add the callback with setEndCallback(), set the duration with setDuration() then start the timer
|
||||
class Timer : public FiniteTicking
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Starts the timer directly with a given duration, in ms.
|
||||
*/
|
||||
void start(Time duration);
|
||||
|
||||
/**
|
||||
* Starts the timer with the already set duration.
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* Sets the duration of the timer, in ms.
|
||||
* Does not stop or reset it.
|
||||
*/
|
||||
void setDuration(Time duration);
|
||||
|
||||
void onStart() override;
|
||||
bool onUpdate(Time delta) override;
|
||||
void onReset() override;
|
||||
void onRewind() override;
|
||||
|
||||
protected:
|
||||
Time duration = 0;
|
||||
Time progress = 0;
|
||||
};
|
||||
|
||||
// A RepeatingTimer allows to run a callback repeatedly at a given time interval, in ms
|
||||
// Add the callback with setCallback(), set the period with setPeriod() then start the timer
|
||||
class RepeatingTimer : public Ticking
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Starts the timer directly with a given period, in ms.
|
||||
*/
|
||||
void start(Time period);
|
||||
|
||||
/**
|
||||
* Starts the timer with the already set period.
|
||||
*/
|
||||
void start();
|
||||
|
||||
/**
|
||||
* Sets the period of the timer, in ms.
|
||||
* Does not stop or reset it.
|
||||
*/
|
||||
void setPeriod(Time period);
|
||||
|
||||
/**
|
||||
* Sets the callback of the timer.
|
||||
* Tick callback is still executed every tick.
|
||||
* End callback is executed when the timer is stopped.
|
||||
*/
|
||||
void setCallback(TickingGenericCallback callback);
|
||||
|
||||
void onStart() override;
|
||||
bool onUpdate(Time delta) override;
|
||||
|
||||
protected:
|
||||
Time period = 0;
|
||||
Time progress = 0;
|
||||
|
||||
TickingGenericCallback callback = [] {};
|
||||
};
|
||||
|
||||
} // namespace brls
|
||||
@@ -1,30 +0,0 @@
|
||||
/*
|
||||
Copyright 2021 natinusala
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <borealis/core/logger.hpp>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace brls
|
||||
{
|
||||
|
||||
/**
|
||||
* Prints the given error message message and throws a std::logic_error.
|
||||
*/
|
||||
[[noreturn]] void fatal(std::string message);
|
||||
|
||||
} // namespace brls
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
Copyright 2021 natinusala
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <nanovg.h>
|
||||
|
||||
// A VideoContext is responsible for providing a nanovg context for the app
|
||||
// (so by extension it manages all the graphics state as well as the window / context).
|
||||
// The VideoContext implementation must also provide the nanovg implementation. As such, there
|
||||
// can only be one VideoContext linked at any time in the binary.
|
||||
// Context creation and teardown can be done in the constructor and destructor.
|
||||
class VideoContext
|
||||
{
|
||||
public:
|
||||
virtual ~VideoContext() {};
|
||||
|
||||
/**
|
||||
* Called at the beginning of every frame to clear the window
|
||||
*/
|
||||
virtual void clear(NVGcolor color) = 0;
|
||||
|
||||
/**
|
||||
* Called at the beginning of every frame to begin it.
|
||||
*/
|
||||
virtual void beginFrame() = 0;
|
||||
|
||||
/**
|
||||
* Called at the end of every frame to end it (swap buffers...).
|
||||
*/
|
||||
virtual void endFrame() = 0;
|
||||
|
||||
/**
|
||||
* Can be called by the application to reset the graphics
|
||||
* state, in case there is a need to use the graphics API
|
||||
* directly (for instance direct OpenGL calls).
|
||||
*/
|
||||
virtual void resetState() = 0;
|
||||
|
||||
virtual NVGcontext* getNVGContext() = 0;
|
||||
};
|
||||
@@ -1,39 +0,0 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (boolean.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_BOOLEAN_H
|
||||
#define __LIBRETRO_SDK_BOOLEAN_H
|
||||
|
||||
#ifndef __cplusplus
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1800 && !defined(SN_TARGET_PS3)
|
||||
/* Hack applied for MSVC when compiling in C89 mode as it isn't C99 compliant. */
|
||||
#define bool unsigned char
|
||||
#define true 1
|
||||
#define false 0
|
||||
#else
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,59 +0,0 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (strl.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_COMPAT_STRL_H
|
||||
#define __LIBRETRO_SDK_COMPAT_STRL_H
|
||||
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(RARCH_INTERNAL) && defined(HAVE_CONFIG_H)
|
||||
#include "../../../config.h"
|
||||
#endif
|
||||
|
||||
#include <libretro-common/retro_common_api.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
#ifdef __MACH__
|
||||
#ifndef HAVE_STRL
|
||||
#define HAVE_STRL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_STRL
|
||||
/* Avoid possible naming collisions during link since
|
||||
* we prefer to use the actual name. */
|
||||
#define strlcpy(dst, src, size) strlcpy_retro__(dst, src, size)
|
||||
|
||||
#define strlcat(dst, src, size) strlcat_retro__(dst, src, size)
|
||||
|
||||
size_t strlcpy(char *dest, const char *source, size_t size);
|
||||
size_t strlcat(char *dest, const char *source, size_t size);
|
||||
|
||||
#endif
|
||||
|
||||
char *strldup(const char *s, size_t n);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -1,67 +0,0 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (utf.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _LIBRETRO_ENCODINGS_UTF_H
|
||||
#define _LIBRETRO_ENCODINGS_UTF_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <libretro-common/boolean.h>
|
||||
|
||||
#include <libretro-common/retro_common_api.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
enum CodePage
|
||||
{
|
||||
CODEPAGE_LOCAL = 0, /* CP_ACP */
|
||||
CODEPAGE_UTF8 = 65001 /* CP_UTF8 */
|
||||
};
|
||||
|
||||
size_t utf8_conv_utf32(uint32_t *out, size_t out_chars,
|
||||
const char *in, size_t in_size);
|
||||
|
||||
bool utf16_conv_utf8(uint8_t *out, size_t *out_chars,
|
||||
const uint16_t *in, size_t in_size);
|
||||
|
||||
size_t utf8len(const char *string);
|
||||
|
||||
size_t utf8cpy(char *d, size_t d_len, const char *s, size_t chars);
|
||||
|
||||
const char *utf8skip(const char *str, size_t chars);
|
||||
|
||||
uint32_t utf8_walk(const char **string);
|
||||
|
||||
bool utf16_to_char_string(const uint16_t *in, char *s, size_t len);
|
||||
|
||||
char* utf8_to_local_string_alloc(const char *str);
|
||||
|
||||
char* local_to_utf8_string_alloc(const char *str);
|
||||
|
||||
wchar_t* utf8_to_utf16_string_alloc(const char *str);
|
||||
|
||||
char* utf16_to_utf8_string_alloc(const wchar_t *str);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -1,75 +0,0 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (features_cpu.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _LIBRETRO_SDK_CPU_INFO_H
|
||||
#define _LIBRETRO_SDK_CPU_INFO_H
|
||||
|
||||
#include <libretro-common/retro_common_api.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <libretro-common/libretro.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
/**
|
||||
* cpu_features_get_perf_counter:
|
||||
*
|
||||
* Gets performance counter.
|
||||
*
|
||||
* Returns: performance counter.
|
||||
**/
|
||||
retro_perf_tick_t cpu_features_get_perf_counter(void);
|
||||
|
||||
/**
|
||||
* cpu_features_get_time_usec:
|
||||
*
|
||||
* Gets time in microseconds, from an undefined epoch.
|
||||
* The epoch may change between computers or across reboots.
|
||||
*
|
||||
* Returns: time in microseconds
|
||||
**/
|
||||
retro_time_t cpu_features_get_time_usec(void);
|
||||
|
||||
/**
|
||||
* cpu_features_get:
|
||||
*
|
||||
* Gets CPU features.
|
||||
*
|
||||
* Returns: bitmask of all CPU features available.
|
||||
**/
|
||||
uint64_t cpu_features_get(void);
|
||||
|
||||
/**
|
||||
* cpu_features_get_core_amount:
|
||||
*
|
||||
* Gets the amount of available CPU cores.
|
||||
*
|
||||
* Returns: amount of CPU cores available.
|
||||
**/
|
||||
unsigned cpu_features_get_core_amount(void);
|
||||
|
||||
void cpu_features_get_model_name(char *name, int len);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -1,37 +0,0 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_assert.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __RETRO_ASSERT_H
|
||||
#define __RETRO_ASSERT_H
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef RARCH_INTERNAL
|
||||
#include <stdio.h>
|
||||
#define retro_assert(cond) do { \
|
||||
if (!(cond)) { printf("Assertion failed at %s:%d.\n", __FILE__, __LINE__); abort(); } \
|
||||
} while(0)
|
||||
#else
|
||||
#define retro_assert(cond) assert(cond)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,117 +0,0 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_common_api.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _LIBRETRO_COMMON_RETRO_COMMON_API_H
|
||||
#define _LIBRETRO_COMMON_RETRO_COMMON_API_H
|
||||
|
||||
/*
|
||||
This file is designed to normalize the libretro-common compiling environment
|
||||
for public API headers. This should be leaner than a normal compiling environment,
|
||||
since it gets #included into other project's sources.
|
||||
*/
|
||||
|
||||
/* ------------------------------------ */
|
||||
|
||||
/*
|
||||
Ordinarily we want to put #ifdef __cplusplus extern "C" in C library
|
||||
headers to enable them to get used by c++ sources.
|
||||
However, we want to support building this library as C++ as well, so a
|
||||
special technique is called for.
|
||||
*/
|
||||
|
||||
#define RETRO_BEGIN_DECLS
|
||||
#define RETRO_END_DECLS
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#ifdef CXX_BUILD
|
||||
/* build wants everything to be built as c++, so no extern "C" */
|
||||
#else
|
||||
#undef RETRO_BEGIN_DECLS
|
||||
#undef RETRO_END_DECLS
|
||||
#define RETRO_BEGIN_DECLS extern "C" {
|
||||
#define RETRO_END_DECLS }
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
/* header is included by a C source file, so no extern "C" */
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
IMO, this non-standard ssize_t should not be used.
|
||||
However, it's a good example of how to handle something like this.
|
||||
*/
|
||||
#ifdef _MSC_VER
|
||||
#ifndef HAVE_SSIZE_T
|
||||
#define HAVE_SSIZE_T
|
||||
#if defined(_WIN64)
|
||||
typedef __int64 ssize_t;
|
||||
#elif defined(_WIN32)
|
||||
typedef int ssize_t;
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(__MACH__)
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#if _MSC_VER >= 1800
|
||||
#include <inttypes.h>
|
||||
#else
|
||||
#ifndef PRId64
|
||||
#define PRId64 "I64d"
|
||||
#define PRIu64 "I64u"
|
||||
#define PRIuPTR "Iu"
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
/* C++11 says this one isn't needed, but apparently (some versions of) mingw require it anyways */
|
||||
/* https://stackoverflow.com/questions/8132399/how-to-printf-uint64-t-fails-with-spurious-trailing-in-format */
|
||||
/* https://github.com/libretro/RetroArch/issues/6009 */
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#include <inttypes.h>
|
||||
#endif
|
||||
#ifndef PRId64
|
||||
#error "inttypes.h is being screwy"
|
||||
#endif
|
||||
#define STRING_REP_INT64 "%" PRId64
|
||||
#define STRING_REP_UINT64 "%" PRIu64
|
||||
#define STRING_REP_USIZE "%" PRIuPTR
|
||||
|
||||
/*
|
||||
I would like to see retro_inline.h moved in here; possibly boolean too.
|
||||
|
||||
rationale: these are used in public APIs, and it is easier to find problems
|
||||
and write code that works the first time portably when theyre included uniformly
|
||||
than to do the analysis from scratch each time you think you need it, for each feature.
|
||||
|
||||
Moreover it helps force you to make hard decisions: if you EVER bring in boolean.h,
|
||||
then you should pay the price everywhere, so you can see how much grief it will cause.
|
||||
|
||||
Of course, another school of thought is that you should do as little damage as possible
|
||||
in as few places as possible...
|
||||
*/
|
||||
|
||||
/* _LIBRETRO_COMMON_RETRO_COMMON_API_H */
|
||||
#endif
|
||||
@@ -1,39 +0,0 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_inline.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_INLINE_H
|
||||
#define __LIBRETRO_SDK_INLINE_H
|
||||
|
||||
#ifndef INLINE
|
||||
|
||||
#if defined(_WIN32) || defined(__INTEL_COMPILER)
|
||||
#define INLINE __inline
|
||||
#elif defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L
|
||||
#define INLINE inline
|
||||
#elif defined(__GNUC__)
|
||||
#define INLINE __inline__
|
||||
#else
|
||||
#define INLINE
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -1,94 +0,0 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_math.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _LIBRETRO_COMMON_MATH_H
|
||||
#define _LIBRETRO_COMMON_MATH_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#elif defined(_WIN32) && defined(_XBOX)
|
||||
#include <Xtl.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <libretro-common/compat/msvc.h>
|
||||
#endif
|
||||
#include <libretro-common/retro_inline.h>
|
||||
|
||||
#ifndef M_PI
|
||||
#if !defined(USE_MATH_DEFINES)
|
||||
#define M_PI 3.14159265358979323846264338327
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* next_pow2:
|
||||
* @v : initial value
|
||||
*
|
||||
* Get next power of 2 value based on initial value.
|
||||
*
|
||||
* Returns: next power of 2 value (derived from @v).
|
||||
**/
|
||||
static INLINE uint32_t next_pow2(uint32_t v)
|
||||
{
|
||||
v--;
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
v++;
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* prev_pow2:
|
||||
* @v : initial value
|
||||
*
|
||||
* Get previous power of 2 value based on initial value.
|
||||
*
|
||||
* Returns: previous power of 2 value (derived from @v).
|
||||
**/
|
||||
static INLINE uint32_t prev_pow2(uint32_t v)
|
||||
{
|
||||
v |= v >> 1;
|
||||
v |= v >> 2;
|
||||
v |= v >> 4;
|
||||
v |= v >> 8;
|
||||
v |= v >> 16;
|
||||
return v - (v >> 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,182 +0,0 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_miscellaneous.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __RARCH_MISCELLANEOUS_H
|
||||
#define __RARCH_MISCELLANEOUS_H
|
||||
|
||||
#define RARCH_MAX_SUBSYSTEMS 10
|
||||
#define RARCH_MAX_SUBSYSTEM_ROMS 10
|
||||
|
||||
#include <stdint.h>
|
||||
#include <libretro-common/boolean.h>
|
||||
#include <libretro-common/retro_inline.h>
|
||||
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#elif defined(_WIN32) && defined(_XBOX)
|
||||
#include <Xtl.h>
|
||||
#endif
|
||||
|
||||
#if defined(__CELLOS_LV2__)
|
||||
#include <sys/fs_external.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <libretro-common/compat/msvc.h>
|
||||
#endif
|
||||
|
||||
static INLINE void bits_or_bits(uint32_t *a, uint32_t *b, uint32_t count)
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < count;i++)
|
||||
a[i] |= b[i];
|
||||
}
|
||||
|
||||
static INLINE void bits_clear_bits(uint32_t *a, uint32_t *b, uint32_t count)
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < count;i++)
|
||||
a[i] &= ~b[i];
|
||||
}
|
||||
|
||||
static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
if (ptr[i] != 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef PATH_MAX_LENGTH
|
||||
#if defined(__CELLOS_LV2__)
|
||||
#define PATH_MAX_LENGTH CELL_FS_MAX_FS_PATH_LENGTH
|
||||
#elif defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(PS2) || defined(GEKKO)|| defined(WIIU) || defined(ORBIS)
|
||||
#define PATH_MAX_LENGTH 512
|
||||
#else
|
||||
#define PATH_MAX_LENGTH 4096
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
#define BITS_GET_ELEM(a, i) ((a).data[i])
|
||||
#define BITS_GET_ELEM_PTR(a, i) ((a)->data[i])
|
||||
|
||||
#define BIT_SET(a, bit) ((a)[(bit) >> 3] |= (1 << ((bit) & 7)))
|
||||
#define BIT_CLEAR(a, bit) ((a)[(bit) >> 3] &= ~(1 << ((bit) & 7)))
|
||||
#define BIT_GET(a, bit) (((a)[(bit) >> 3] >> ((bit) & 7)) & 1)
|
||||
|
||||
#define BIT16_SET(a, bit) ((a) |= (1 << ((bit) & 15)))
|
||||
#define BIT16_CLEAR(a, bit) ((a) &= ~(1 << ((bit) & 15)))
|
||||
#define BIT16_GET(a, bit) (((a) >> ((bit) & 15)) & 1)
|
||||
#define BIT16_CLEAR_ALL(a) ((a) = 0)
|
||||
|
||||
#define BIT32_SET(a, bit) ((a) |= (1 << ((bit) & 31)))
|
||||
#define BIT32_CLEAR(a, bit) ((a) &= ~(1 << ((bit) & 31)))
|
||||
#define BIT32_GET(a, bit) (((a) >> ((bit) & 31)) & 1)
|
||||
#define BIT32_CLEAR_ALL(a) ((a) = 0)
|
||||
|
||||
#define BIT64_SET(a, bit) ((a) |= (UINT64_C(1) << ((bit) & 63)))
|
||||
#define BIT64_CLEAR(a, bit) ((a) &= ~(UINT64_C(1) << ((bit) & 63)))
|
||||
#define BIT64_GET(a, bit) (((a) >> ((bit) & 63)) & 1)
|
||||
#define BIT64_CLEAR_ALL(a) ((a) = 0)
|
||||
|
||||
#define BIT128_SET(a, bit) ((a).data[(bit) >> 5] |= (1 << ((bit) & 31)))
|
||||
#define BIT128_CLEAR(a, bit) ((a).data[(bit) >> 5] &= ~(1 << ((bit) & 31)))
|
||||
#define BIT128_GET(a, bit) (((a).data[(bit) >> 5] >> ((bit) & 31)) & 1)
|
||||
#define BIT128_CLEAR_ALL(a) memset(&(a), 0, sizeof(a))
|
||||
|
||||
#define BIT128_SET_PTR(a, bit) BIT128_SET(*a, bit)
|
||||
#define BIT128_CLEAR_PTR(a, bit) BIT128_CLEAR(*a, bit)
|
||||
#define BIT128_GET_PTR(a, bit) BIT128_GET(*a, bit)
|
||||
#define BIT128_CLEAR_ALL_PTR(a) BIT128_CLEAR_ALL(*a)
|
||||
|
||||
#define BIT256_SET(a, bit) BIT128_SET(a, bit)
|
||||
#define BIT256_CLEAR(a, bit) BIT128_CLEAR(a, bit)
|
||||
#define BIT256_GET(a, bit) BIT128_GET(a, bit)
|
||||
#define BIT256_CLEAR_ALL(a) BIT128_CLEAR_ALL(a)
|
||||
|
||||
#define BIT256_SET_PTR(a, bit) BIT256_SET(*a, bit)
|
||||
#define BIT256_CLEAR_PTR(a, bit) BIT256_CLEAR(*a, bit)
|
||||
#define BIT256_GET_PTR(a, bit) BIT256_GET(*a, bit)
|
||||
#define BIT256_CLEAR_ALL_PTR(a) BIT256_CLEAR_ALL(*a)
|
||||
|
||||
#define BITS_COPY16_PTR(a,bits) \
|
||||
{ \
|
||||
BIT128_CLEAR_ALL_PTR(a); \
|
||||
BITS_GET_ELEM_PTR(a, 0) = (bits) & 0xffff; \
|
||||
}
|
||||
|
||||
#define BITS_COPY32_PTR(a,bits) \
|
||||
{ \
|
||||
BIT128_CLEAR_ALL_PTR(a); \
|
||||
BITS_GET_ELEM_PTR(a, 0) = (bits); \
|
||||
}
|
||||
|
||||
/* Helper macros and struct to keep track of many booleans. */
|
||||
/* This struct has 256 bits. */
|
||||
typedef struct
|
||||
{
|
||||
uint32_t data[8];
|
||||
} retro_bits_t;
|
||||
|
||||
#ifdef _WIN32
|
||||
# ifdef _WIN64
|
||||
# define PRI_SIZET PRIu64
|
||||
# else
|
||||
# if _MSC_VER == 1800
|
||||
# define PRI_SIZET PRIu32
|
||||
# else
|
||||
# define PRI_SIZET "u"
|
||||
# endif
|
||||
# endif
|
||||
#elif PS2
|
||||
# define PRI_SIZET "u"
|
||||
#else
|
||||
# if (SIZE_MAX == 0xFFFF)
|
||||
# define PRI_SIZET "hu"
|
||||
# elif (SIZE_MAX == 0xFFFFFFFF)
|
||||
# define PRI_SIZET "u"
|
||||
# elif (SIZE_MAX == 0xFFFFFFFFFFFFFFFF)
|
||||
# define PRI_SIZET "lu"
|
||||
# else
|
||||
# error PRI_SIZET: unknown SIZE_MAX
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -1,116 +0,0 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (retro_timers.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_COMMON_TIMERS_H
|
||||
#define __LIBRETRO_COMMON_TIMERS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
|
||||
#include <sys/timer.h>
|
||||
#elif defined(XENON)
|
||||
#include <time/time.h>
|
||||
#elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)
|
||||
#include <unistd.h>
|
||||
#elif defined(WIIU)
|
||||
#include <wiiu/os/thread.h>
|
||||
#elif defined(PSP)
|
||||
#include <pspthreadman.h>
|
||||
#elif defined(VITA)
|
||||
#include <psp2/kernel/threadmgr.h>
|
||||
#elif defined(PS2)
|
||||
#include <SDL/SDL_timer.h>
|
||||
#elif defined(_3DS)
|
||||
#include <3ds.h>
|
||||
#else
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#elif defined(_WIN32) && defined(_XBOX)
|
||||
#include <Xtl.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <libretro-common/compat/msvc.h>
|
||||
#endif
|
||||
#include <libretro-common/retro_inline.h>
|
||||
|
||||
#ifdef DJGPP
|
||||
#define timespec timeval
|
||||
#define tv_nsec tv_usec
|
||||
#include <unistd.h>
|
||||
|
||||
extern int nanosleep(const struct timespec *rqtp, struct timespec *rmtp);
|
||||
|
||||
static int nanosleepDOS(const struct timespec *rqtp, struct timespec *rmtp)
|
||||
{
|
||||
usleep(1000000 * rqtp->tv_sec + rqtp->tv_nsec / 1000);
|
||||
|
||||
if (rmtp)
|
||||
rmtp->tv_sec = rmtp->tv_nsec=0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define nanosleep nanosleepDOS
|
||||
#endif
|
||||
|
||||
/**
|
||||
* retro_sleep:
|
||||
* @msec : amount in milliseconds to sleep
|
||||
*
|
||||
* Sleeps for a specified amount of milliseconds (@msec).
|
||||
**/
|
||||
static INLINE void retro_sleep(unsigned msec)
|
||||
{
|
||||
#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
|
||||
sys_timer_usleep(1000 * msec);
|
||||
#elif defined(PSP) || defined(VITA)
|
||||
sceKernelDelayThread(1000 * msec);
|
||||
#elif defined(PS2)
|
||||
SDL_Delay(msec);
|
||||
#elif defined(_3DS)
|
||||
svcSleepThread(1000000 * (s64)msec);
|
||||
#elif defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
|
||||
SleepEx(msec, FALSE);
|
||||
#elif defined(_WIN32)
|
||||
Sleep(msec);
|
||||
#elif defined(XENON)
|
||||
udelay(1000 * msec);
|
||||
#elif defined(GEKKO) || defined(__PSL1GHT__) || defined(__QNX__)
|
||||
usleep(1000 * msec);
|
||||
#elif defined(WIIU)
|
||||
OSSleepTicks(ms_to_ticks(msec));
|
||||
#else
|
||||
struct timespec tv = {0};
|
||||
tv.tv_sec = msec / 1000;
|
||||
tv.tv_nsec = (msec % 1000) * 1000000;
|
||||
nanosleep(&tv, NULL);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,111 +0,0 @@
|
||||
/* Copyright (C) 2010-2018 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (file_stream.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_FILE_STREAM_H
|
||||
#define __LIBRETRO_SDK_FILE_STREAM_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <libretro-common/libretro.h>
|
||||
#include <libretro-common/retro_common_api.h>
|
||||
#include <libretro-common/retro_inline.h>
|
||||
#include <libretro-common/boolean.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#define FILESTREAM_REQUIRED_VFS_VERSION 2
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
typedef struct RFILE RFILE;
|
||||
|
||||
#define FILESTREAM_REQUIRED_VFS_VERSION 2
|
||||
|
||||
void filestream_vfs_init(const struct retro_vfs_interface_info* vfs_info);
|
||||
|
||||
int64_t filestream_get_size(RFILE *stream);
|
||||
|
||||
int64_t filestream_truncate(RFILE *stream, int64_t length);
|
||||
|
||||
/**
|
||||
* filestream_open:
|
||||
* @path : path to file
|
||||
* @mode : file mode to use when opening (read/write)
|
||||
* @bufsize : optional buffer size (-1 or 0 to use default)
|
||||
*
|
||||
* Opens a file for reading or writing, depending on the requested mode.
|
||||
* Returns a pointer to an RFILE if opened successfully, otherwise NULL.
|
||||
**/
|
||||
RFILE *filestream_open(const char *path, unsigned mode, unsigned hints);
|
||||
|
||||
int64_t filestream_seek(RFILE *stream, int64_t offset, int seek_position);
|
||||
|
||||
int64_t filestream_read(RFILE *stream, void *data, int64_t len);
|
||||
|
||||
int64_t filestream_write(RFILE *stream, const void *data, int64_t len);
|
||||
|
||||
int64_t filestream_tell(RFILE *stream);
|
||||
|
||||
void filestream_rewind(RFILE *stream);
|
||||
|
||||
int filestream_close(RFILE *stream);
|
||||
|
||||
int64_t filestream_read_file(const char *path, void **buf, int64_t *len);
|
||||
|
||||
char *filestream_gets(RFILE *stream, char *s, size_t len);
|
||||
|
||||
int filestream_getc(RFILE *stream);
|
||||
|
||||
int filestream_scanf(RFILE *stream, const char* format, ...);
|
||||
|
||||
int filestream_eof(RFILE *stream);
|
||||
|
||||
bool filestream_write_file(const char *path, const void *data, int64_t size);
|
||||
|
||||
int filestream_putc(RFILE *stream, int c);
|
||||
|
||||
int filestream_vprintf(RFILE *stream, const char* format, va_list args);
|
||||
|
||||
int filestream_printf(RFILE *stream, const char* format, ...);
|
||||
|
||||
int filestream_error(RFILE *stream);
|
||||
|
||||
int filestream_flush(RFILE *stream);
|
||||
|
||||
int filestream_delete(const char *path);
|
||||
|
||||
int filestream_rename(const char *old_path, const char *new_path);
|
||||
|
||||
const char *filestream_get_path(RFILE *stream);
|
||||
|
||||
bool filestream_exists(const char *path);
|
||||
|
||||
char *filestream_getline(RFILE *stream);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -1,134 +0,0 @@
|
||||
/* Copyright (C) 2010-2019 The RetroArch team
|
||||
*
|
||||
* ---------------------------------------------------------------------------------------
|
||||
* The following license statement only applies to this file (stdstring.h).
|
||||
* ---------------------------------------------------------------------------------------
|
||||
*
|
||||
* Permission is hereby granted, free of charge,
|
||||
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __LIBRETRO_SDK_STDSTRING_H
|
||||
#define __LIBRETRO_SDK_STDSTRING_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <libretro-common/boolean.h>
|
||||
|
||||
#include <libretro-common/retro_common_api.h>
|
||||
#include <libretro-common/retro_inline.h>
|
||||
#include <libretro-common/compat/strl.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
static INLINE bool string_is_empty(const char *data)
|
||||
{
|
||||
return !data || (*data == '\0');
|
||||
}
|
||||
|
||||
static INLINE bool string_is_equal(const char *a, const char *b)
|
||||
{
|
||||
return (a && b) ? !strcmp(a, b) : false;
|
||||
}
|
||||
|
||||
#define STRLEN_CONST(x) ((sizeof((x))-1))
|
||||
|
||||
#define string_is_not_equal(a, b) !string_is_equal((a), (b))
|
||||
|
||||
#define string_add_pair_open(s, size) strlcat((s), " (", (size))
|
||||
#define string_add_pair_close(s, size) strlcat((s), ")", (size))
|
||||
#define string_add_bracket_open(s, size) strlcat((s), "{", (size))
|
||||
#define string_add_bracket_close(s, size) strlcat((s), "}", (size))
|
||||
#define string_add_single_quote(s, size) strlcat((s), "'", (size))
|
||||
#define string_add_quote(s, size) strlcat((s), "\"", (size))
|
||||
#define string_add_colon(s, size) strlcat((s), ":", (size))
|
||||
#define string_add_glob_open(s, size) strlcat((s), "glob('*", (size))
|
||||
#define string_add_glob_close(s, size) strlcat((s), "*')", (size))
|
||||
|
||||
#define string_is_not_equal_fast(a, b, size) (memcmp(a, b, size) != 0)
|
||||
#define string_is_equal_fast(a, b, size) (memcmp(a, b, size) == 0)
|
||||
|
||||
static INLINE void string_add_between_pairs(char *s, const char *str,
|
||||
size_t size)
|
||||
{
|
||||
string_add_pair_open(s, size);
|
||||
strlcat(s, str, size);
|
||||
string_add_pair_close(s, size);
|
||||
}
|
||||
|
||||
static INLINE bool string_is_equal_case_insensitive(const char *a,
|
||||
const char *b)
|
||||
{
|
||||
int result = 0;
|
||||
const unsigned char *p1 = (const unsigned char*)a;
|
||||
const unsigned char *p2 = (const unsigned char*)b;
|
||||
|
||||
if (!a || !b)
|
||||
return false;
|
||||
if (p1 == p2)
|
||||
return true;
|
||||
|
||||
while ((result = tolower (*p1) - tolower (*p2++)) == 0)
|
||||
if (*p1++ == '\0')
|
||||
break;
|
||||
|
||||
return (result == 0);
|
||||
}
|
||||
|
||||
static INLINE bool string_is_equal_noncase(const char *a, const char *b)
|
||||
{
|
||||
int result = 0;
|
||||
const unsigned char *p1 = (const unsigned char*)a;
|
||||
const unsigned char *p2 = (const unsigned char*)b;
|
||||
|
||||
if (!a || !b)
|
||||
return false;
|
||||
if (p1 == p2)
|
||||
return false;
|
||||
|
||||
while ((result = tolower (*p1) - tolower (*p2++)) == 0)
|
||||
if (*p1++ == '\0')
|
||||
break;
|
||||
|
||||
return (result == 0);
|
||||
}
|
||||
|
||||
char *string_to_upper(char *s);
|
||||
|
||||
char *string_to_lower(char *s);
|
||||
|
||||
char *string_ucwords(char *s);
|
||||
|
||||
char *string_replace_substring(const char *in, const char *pattern,
|
||||
const char *by);
|
||||
|
||||
/* Remove leading whitespaces */
|
||||
char *string_trim_whitespace_left(char *const s);
|
||||
|
||||
/* Remove trailing whitespaces */
|
||||
char *string_trim_whitespace_right(char *const s);
|
||||
|
||||
/* Remove leading and trailing whitespaces */
|
||||
char *string_trim_whitespace(char *const s);
|
||||
|
||||
/* max_lines == 0 means no limit */
|
||||
char *word_wrap(char *buffer, const char *string,
|
||||
int line_width, bool unicode, unsigned max_lines);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
||||
@@ -1,18 +0,0 @@
|
||||
Copyright (c) 2013 Mikko Mononen memon@inside.org
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
|
||||