From d2bf10733b4e87a06acb086e6a5f5114f466699a Mon Sep 17 00:00:00 2001 From: TuxSH <1922548+TuxSH@users.noreply.github.com> Date: Mon, 30 Sep 2024 20:30:29 +0200 Subject: [PATCH] Rewrite README, add screenshots --- README.md | 114 ++++++++++++++++++++++++++++++------- img/boot_menu_v132.png | Bin 0 -> 6009 bytes img/rosalina_menu_v132.png | Bin 0 -> 1762 bytes 3 files changed, 93 insertions(+), 21 deletions(-) create mode 100644 img/boot_menu_v132.png create mode 100644 img/rosalina_menu_v132.png diff --git a/README.md b/README.md index 04cebe2b..c0ac3f44 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,112 @@ # Luma3DS +![GitHub Downloads (all assets, all releases)](https://img.shields.io/github/downloads/LumaTeam/Luma3DS/total) +![License](https://img.shields.io/badge/License-GPLv3-blue.svg) + *Nintendo 3DS "Custom Firmware"* -## What it is -**Luma3DS** is a program patching and reimplementing significant parts of the software running on all models of the Nintendo 3DS family of consoles. +![Boot menu screenshot](img/boot_menu_v132.png) +![Rosalina menu screenshot](img/rosalina_menu_v132.png) -It aims at greatly improving the user experience and at supporting the 3DS far beyond its end-of-life. Features include: +## Description +**Luma3DS** patches and reimplements significant parts of the system software running on all models of the Nintendo 3DS family of consoles. It aims to greatly improve the user experience and support the 3DS far beyond its end-of-life. Features include: -* First class support of 3DSX homebrew -* An overlay menu called "Rosalina" (triggerable by L+Down+Select by default), allowing amongst many thing to take screenshots while in-game -* Removal of restrictions such as the region lock -* Per-game language settings, asset content path redirection (LayeredFS), game plugins... -* A fully-fledged GDB stub allowing to debug software (homebrew and system software alike) +* **First-class support for homebrew applications** +* **Rosalina**, an overlay menu (triggered by L+Down+Select by default), allowing things like: + * Taking screenshots while in game + * Blue light filters and other screen filters + * Input redirection to play with external devices, such as controllers + * Using cheat codes + * Setting time and date accurately from the network (NTP) + * ... and much more! +* **Many game modding features**, such as, but not limited to: + * Game plugins (in 3GX format) + * Per-game language overrides ("locale emulation") + * Asset content path redirection ("LayeredFS") +* **Support for user-provided patches and/or full "system modules" replacements**, an essential feature for Nintendo Network replacements (amongst other projects) +* A **fully-fledged GDB stub**, allowing homebrew developers and reverse-engineers alike to work much more efficiently +* Ability to chainload other firmware files, including other versions of itself * ... and much more! -Luma3DS requires a full-system persisent exploit such as [boot9strap](https://github.com/SciresM/boot9strap) to run. +## Installation and upgrade +Luma3DS requires [boot9strap](https://github.com/SciresM/boot9strap) to run. -## Compiling +Once boot9strap has been installed, simply download the [latest release archive](https://github.com/LumaTeam/Luma3DS/releases/latest) and extract the archive onto the root of your SD card to "install" or to upgrade Luma3DS alongside the [homebrew menu and certs bundle](https://github.com/devkitPro/3ds-hbmenu) shipped with it. Replace existing files and merge existing folders if necessary. + +## Basic usage +**The main Luma3DS configuration menu** can be accessed by pressing Select at boot. The configuration file is stored in `/luma/config.ini` on the SD card (or `/rw/luma/config.ini` on the CTRNAND partition if Luma3DS has been launched from the CTRNAND partition, which happens when SD card is missing). + +**The chainloader menu** is accessed by pressing Start at boot, or from the configuration menu. Payloads are expected to be located in `/luma/payloads` with the `.firm` extension; if there is only one such payload, the aforementionned selection menu will be skipped. Hotkeys can be assigned to payload, for example `x_test.firm` will be chainloaded when X is pressed at boot. + +**The overlay menu, Rosalina**, has a default button combination: L+Down+Select. For greater flexbility, most Rosalina menu settings aren't saved automatically, hence the "Save settings" option. + +**GDB ports**, when enabled, are `4000-4002` for the normal ports. Use of `attach` in "extended-remote" mode, alongside `info os processes` is supported and encouraged (for reverse-engineering, also check out `monitor getmemregions`). The port for the break-on-start feature is `4003` without "extended-remote". Both devkitARM-patched GDB and IDA Pro (without "stepping support" enabled) are actively supported. + +We have a wiki, however it is currently very outdated. + +## Components + +Luma3DS consists of multiple components. While the code style within each component is mostly consistent, these components have been written over many years and may not reflect how maintainers would write new code in new components/projects: + +* **arm9**, **arm11**: baremetal main settings menu, chainloader and firmware loader. Aside from showing settings and chainloading to other homebrew firmware files on demand, it is responsible for patching the official firmware to modify `Process9` code and to inject all other custom components. This was the first component ever written for this project, in 2015 +* **k11_extension**: code extending the Arm11 `NATIVE_FIRM` kernel (`Kernel11`). It is injected by the above mentioned baremetal loader into the kernel by hooking its startup code, then hooks itself into the rest of the kernel. Its features include hooking system calls (SVCs), introducing new SVCs and hooking into interprocess communications, to bypass limitations in Nintendo's system design. This is the component that allows Rosalina to pause other processes on overlay menu entry, for example. This was written at a time when we didn't fully reverse-engineer the kernel, and originally released in 2017 alongside Rosalina. Further hooks for "game plugin" support have been merged in 2023 +* **sysmodules**: reimplementation of "system modules" (processes) of the 3DS's OS (except for Rosalina being custom), currently only initial processes loaded directly in-memory by the kernel ("kernel initial process", or KIP in short) + * **loader**: process that loads non-KIP processes from storage. Because this is the perfect place to patch/replace executable code, this is where all process patches are done, enabling in particular "game modding" features. This is also the sysmodule handling 3DSX homebrew loading. Introduced in 2016 + * _**rosalina**_: the most important component of Luma3DS and custom KIP: overlay menu, GDB server, `err:f` (fatal error screen) reimplementation, and much more. Introduced in mid-2017, and has continuously undergone changes and received many external contributions ever since + * **pxi**: Arm11<>Arm9 communication KIP, reimplemented just for the sake of it. Introduced late 2017 + * **sm**: service manager KIP, reimplemented to remove service access control restrictions. Introduced late 2017 + * **pm**: process manager KIP reponsible of starting/terminating processes and instructing `loader` to load them. The reimplemention allows for break-on-start GDB feature in Rosalina, as well as lifting FS access control restrictions the proper way. Introduced in 2019 + +## Maintainers + +* **[@TuxSH](https://github.com/TuxSH)**: lead developer, created and maintains most features of the project. Joined in 2016 +* **[@AuroraWright](https://github.com/AuroraWright)**: author of the project, implemented the core features (most of the baremetal boot settings menu and firmware loading code) with successful design decisions that made the project popular. Created the project in 2015, currently inactive +* **[@PabloMK7](https://github.com/PabloMK7)**: maintainer of the plugin loader feature merged for the v13.0 release. Joined in 2023 + +## Roadmap + +There are still a lot more features and consolidation planned for Luma3DS! Here is a list of what is currently in store: + +* Full reimplementation of `TwlBg` and `AgbBg`. This will allow much better, and more configurable, upscaling for top screen in DS and GBA games (except on Old 2DS). This is currently being developed privately in C++23 (no ETA). While this is quite a difficult endeavor as this requires rewriting the entire driver stack in semi-bare-metal (limited kernel with no IPC), this is the most critical feature for Luma3DS to have and will make driver sysmodule reimpelementation trivial +* Reimplementation of `Process9` for `TWL_FIRM` and `AGB_FIRM` to allow for more features in DS and GBA compatibility mode (ones that require file access) +* Eventually, a full `Kernel11` reimplementation + +## Known issues + +* **Cheat engine crashes with some applications, in particular Pokémon games**: there is a race condition in Nintendo's `Kernel11` pertaining to attaching a new `KDebugThread` to a `KThread` on thread creation, and another thread null-dereferencing `thread->debugThread`. This causes the cheat engine to crashes games that create and destroy many threads all the time (like Pokémon). + * For these games, having a **dedicated "game plugin"** is the only alternative until `Kernel11` is reimplemented. +* **Applications reacting to Rosalina menu button combo**: Rosalina merely polls button input at an interval to know when to show the menu. This means that the Rosalina menu combo can sometimes be processed by the game/process that is going to be paused. + * You can **change the menu combo** in the "Miscellaneous options" submenu (then save it with "Save settings" in the main menu) to work around this. + +## Building from source To build Luma3DS, the following is needed: * git -* up-to-date devkitARM and libctru -* [makerom](https://github.com/jakcron/Project_CTR) in PATH +* [makerom](https://github.com/jakcron/Project_CTR) in `$PATH` * [firmtool](https://github.com/TuxSH/firmtool) installed +* up-to-date devkitARM and libctru: + * install `dkp-pacman` (or, for distributions that already provide pacman, add repositories): https://devkitpro.org/wiki/devkitPro_pacman + * install packages from `3ds-dev` metapackage: `sudo dkp-pacman -S 3ds-dev --needed` + * while libctru and Luma3DS releases are kept in sync, you may have to build libctru from source for non-release Luma3DS commits -The produced `boot.firm` is meant to be copied to the root of your SD card for usage with Boot9Strap. - -## Setup / Usage / Features -See https://github.com/LumaTeam/Luma3DS/wiki (needs rework) - -## Credits -See https://github.com/LumaTeam/Luma3DS/wiki/Credits (needs rework) +While Luma3DS releases are bundled with `3ds-hbmenu`, Luma3DS actually compiles into one single file: `boot.firm`. Just copy it over to the root of your SD card ([ftpd](https://github.com/mtheall/ftpd) is the easiest way to do so), and you're done. ## Licensing This software is licensed under the terms of the GPLv3. You can find a copy of the license in the LICENSE.txt file. -Files in the GDB stub are instead triple-licensed as MIT or "GPLv2 or any later version", in which case it's specified in the file header. +Files in the GDB stub are instead triple-licensed as MIT or "GPLv2 or any later version", in which case it's specified in the file header. PM, SM, PXI reimplementations are also licensed under MIT. -By contributing to this repository, you agree to license your changes to the project's owners. +## Credits + +Luma3DS would not be what it is without the contributions and constructive feedback of many. We would like to thanks in particular: + +* **[@devkitPro](https://github.com/devkitPro)** (especially **[@fincs](https://github.com/fincs)**, **[@WinterMute](https://github.com/WinterMute)** and **[@mtheall](https://github.com/mtheall)**) for providing quality and easy-to-use toolchains with bleeding-edge GCC, and for their continued technical advice +* **[@Nanquitas](https://github.com/Nanquitas)** for the initial version of the game plugin loader code as well as very useful contributions to the GDB stub +* **[@piepie62](https://github.com/piepie62)** for the current implementation of the Rosalina cheat engine, **Duckbill** for its original implementation +* **[@panicbit](https://github.com/panicbit)** for the original implementation of screen filters in Rosalina +* **[@jasondellaluce](https://github.com/jasondellaluce)** for LayeredFS +* **[@LiquidFenrir](https://github.com/LiquidFenrir)** for the memory viewer inside Rosalina's "Process List" +* **ChaN** for [FatFs](http://elm-chan.org/fsw/ff/00index_e.html) +* Everyone who has contributed to the Luma3DS repository +* Everyone who has assisted with troubleshooting end-users +* Everyone who has provided constructive feedback to Luma3DS diff --git a/img/boot_menu_v132.png b/img/boot_menu_v132.png new file mode 100644 index 0000000000000000000000000000000000000000..75f37aaed055e4cd955cfebbd2badaecb4fe5d04 GIT binary patch literal 6009 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 O)5OripiIy8)qer2QSuD{ literal 0 HcmV?d00001 diff --git a/img/rosalina_menu_v132.png b/img/rosalina_menu_v132.png new file mode 100644 index 0000000000000000000000000000000000000000..703a245af35064795b67650eeab3732fd1efe34a GIT binary patch literal 1762 zcmZ`(dpy$%8~@FvnOl)^JMQ8ooSC@|ot4StGIy$37&Dj6J#B82D3U_jIVf>lcAR)e zZX0Tmq*^5~roqS?_=EAMf+|JkR(0T)v;@zi*bSi@lV%k~jbWQVwX8I{<)? z0=^?8EU1#UUVH(Fgq(Fg3jp1^u{)LSKvp014S22^yJ8 z`6?KK;~bpr!0QmzlLqQ}3oB*-Ao{`qb=LFR>n*G^c?ls|m30K#7(=^?AqMm1AW$$m zZSTx=ADhgD!Ud0KckdTeZNVc0d1VxpXz@w1@fE$IQhvxy20Bmktro`0hRo;_ola1~qUmu=ov!)dqVB&OY!^5Q{TWBCs?rKTc1D)EiU1@oeW=kQo)7!`lpzZ|H$ND) z4M~yu1^gu+1%V}K%}_xWwrdrqY;A-QpiZ&DvK8im5$1Zw0Q{w8TC#N|aIz2Ckpl5z zp_0hRcjHQ{t4TD23#~ayG3J9M=UXsiqnwi4DpRCm?}!F*14dg`R&RHIX@eR#EqGKk zMEV_TQ-U9|3^yKjzDeXSG?=UpFt#iXT>qJHDQv=6La_^o9=mP=yf;t$WwA@>#|J9o^1i|-`fmZOz9J~ITvc4HBA*eI@Z)vX4gDjoq0M+ ziuM!LU^={(F1fzO(7?{7Cny5-8{L^WM>o1cEmLDGfHk1no({Rd|3c<RNnx+hA)jS;6~kGs?$wpeXt4EGBXcz}>*0gfnkvuOZcjsv zktB^eaK*%C_CBEmKGyZxHTdERHmg_wNa8NxXumGr2P7666S@hpAgR||DiL#usR)yb&v#Jb)rMfJIL zd?>+!e>~Ru;w0gfEdBS)BMdn9p3hD<5A~NNkzpp1`ygfb-jOz}E%F-{Q`NU;HS~45 z2?w8^KXd77rQXcKr&qD2`|V90^E2&EiX2pfVyXL()M>yjFrwTd*q{5fDbsVKPhXj> z3aMV_4{EB$va?qVq-^awpI~O--xG(aTNoX7bEbOFmhx z9H(Nx5nWCmbG!^Y$GkIE-!08to64}#?VC%mDqzJ#OO&|CF6Zb|81f?^T~bU~sy}G& zMduY?N&@>)Q~e(fArU!`nGHKF&BbZ+%cRHt*yc6LRLyg3Btm$C(622OT9Y28Kw{8> zOfsAfPqM6@e@h*wHW1`K{@jGig&ufsN||*#;&xdRw!H;2=8-L@=UySOsQ;4Xwf=oo626D~t#z7rBKPX9=_SUNso&Q5=v&-j z_Gng0Dr5@&0soV<1@1dvG|&6p=Sbu@Vp2DG_U-D5guj=~cCHArBvScM*azf*o8z63 zDHG#|#bzByGSn8CGx$p9QO`C$_5I|?WPM^^8hcn@eX?SJF2Ru}qS?OVI|pDgbZCw4 zyJsgOTEZ1s5NVwz|4Hn+siLl?Rwp#U?`c;Ujje^6di=SBDX8u;f#)Q!YH((4J=I;N z95Mr+J}#P!ox1OZoTS_P-In`oxqI~SeSd|7e5}CUfm3mIzHvbTalr_DOt1g|7!(FK zgjyP!Ks{kF1l$+_Gd&H3BB0RY!!f7-M?i`U3MEkfzaa2VKmErG2Rj#3-8uj3{{ZO; BAE*ET literal 0 HcmV?d00001