├── .gitignore ├── README.md ├── linux-macos-boot.sh ├── payloads ├── cbfs.bin ├── cbfs.elf └── coreboot.rom ├── sd └── boot │ ├── Image.gz │ ├── boot.scr │ └── tegra210-nintendo-switch.dtb ├── shofel2 └── shofel2.py ├── src ├── boot.txt └── make.sh ├── tegrarcmsmash ├── TegraRcmSmash_win32.exe └── TegraRcmSmash_x64.exe ├── windows-boot.bat └── windows-win32-boot.bat /.gitignore: -------------------------------------------------------------------------------- 1 | src/boot.scr 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Painless Linux 2 | 3 | Boot Linux on the Switch without imx_usb_loader - Windows, Linux, Mac OS & Android 4 | 5 | ## Disclaimer 6 | 7 | I am not reponsible in case you brick or blow up your Switch, its LCD screen or its battery. Use this at your own risks, as Linux is known to cause **battery calibration** and **RTC** desync as well as potential **damage to the LCD display**. 8 | 9 | **You have been warned.** 10 | 11 | ## What am I booting ? 12 | 13 | ### The system 14 | 15 | It's Arch Linux ARM (ALARM) with the GNOME desktop manager and some utilities : 16 | * `sudo` 17 | * chromium browser 18 | * scripts to manage GPU clock profiles 19 | * SSH server enabled by default 20 | * automatic root filesystem expand to fit your SD card 21 | 22 | The default user is `alarm`, its password is `alarm`. The root password is `root`. 23 | 24 | ### How to see and select the current GPU clock profile 25 | 26 | The system comes with two scripts to see and select the current GPU clock profile. There are currently three profiles which can be enabled : 27 | 28 | * `low` (`03`) : normal undockedspeed 29 | * **(default)** `normal` (`0a`) : normal docked speed 30 | * `high` (`0d`) : (not recommended) maximum speed, will cause power failures 31 | 32 | The system will reset to the normal profile at each reboot. 33 | 34 | To see the current clock profile, run the `get-gpu-clock-profile` command as root. It will list all the available profiles, with a star next to the one currently activated. 35 | 36 | To set the current clock profile, use the `set-gpu-clock-profile` command. 37 | 38 | ### First boot 39 | 40 | When booting for the first time, the system will expand the root partition to fill your entire SD card, and then reboot (like a Raspberry Pi). You will need to run the exploit again once the screen turns black to finalize the reboot process, like when enabling Wi-Fi. 41 | 42 | ### Good practices 43 | 44 | When shutting down the Switch from Linux, **it doesn't actually power it off**. Press the power button for 10 seconds and reboot into Horizon before shutting down from there. 45 | 46 | ## How to use it 47 | 48 | ### Step 0 : what you'll need 49 | 50 | * A first-gen Switch 51 | * A way to run the exploit (the host machine) : 52 | * A PC on Windows or Linux 53 |  * A Mac 54 |  * An Android device with Android 4.3 or newer, USB OTG support and a XHCI controller (you can't really know that before trying) 55 | * A way to plug your Switch in the host machine : 56 | * If using a computer, an USB A-to-C or C-to-C cable 57 | * If using an Android device with a Micro USB port, find a Micro USB cable (often labelled "OTG") and chain it to a Type-C cable 58 | * If using an Android device with a Type-C port, find a C-to-C cable or a C-to-A chained to a A-to-C cable 59 | * A SD card for you Switch (of at least 8Gb) 60 | * 128Gb cards are currently not supported by the Switch, a Linux kernel patch is required 61 | * A way to put your Switch in RCM mode (a jig, a paperclip, a wire, a Joy-Con mod, a screwdriver, a soldering iron...) 62 | 63 | ### Step 1 : downloading things 64 | 65 | 1. Clone or download this repository ([here](https://github.com/natinusala/switch-linux/archive/master.zip)) 66 | 2. Download the latest image file : 67 | * [from mega.co.gz](https://mega.nz/#!CPBEFARA!eZ2Ylhjz6kkSt14H_tPi2xZPJ0G0-a-6fLdMR7u0qNQ) 68 | * [from Google Drive (thanks to kevandkkim)](https://drive.google.com/file/d/1rO8XmusLBG6UnB2FfRp13_cL6t_0CsOM/view?usp=sharing) 69 | 70 | ### Step 2 : SD card preparation 71 | 72 | Follow [this guide](https://www.raspberrypi.org/documentation/installation/installing-images/) with your SD card and the image file you downloaded. 73 | 74 | TL;DR : on Windows use Etcher, on Linux & Mac OS use `dd` 75 | 76 | ### Step 3 : booting Linux 77 | 78 | #### From a Windows PC 79 | 80 | On Windows, you will first need to install the required driver : 81 | 82 | 1. Get your Switch in RCM mode and plug it into your PC 83 | * It should appear as "APX" in Windows 84 | 2. Download and run the Zadig Driver Installer from here : https://zadig.akeo.ie/ 85 | 3. In the list, choose the device "APX" 86 | * If it's not showing up, check "List all devices" in the options 87 | 4. At the right end of the green arrow, choose "libusbK (v3.0.7.0)" 88 | 5. Click on the big "Install driver" button 89 | 90 | Then, make sure that your Switch is plugged in your PC and in RCM mode. Open the folder of this repository (the one you downloaded and extracted) and run `windows-boot.bat` (or `windows-win32-boot.bat` on a 32bit machine). Voilà ! 91 | 92 | _Having a Win32 error 31 is normal._ 93 | 94 | #### From a Linux PC or a Mac 95 | 96 | Install Python 3 (usually already installed). Open a terminal to install the required package : `pip3 install pyusb==1.0.0`. I let you deal with permissions issues (hint : `sudo` works on Linux). 97 | 98 | Then, plug your switch in your PC and put it in RCM mode. You should use a blue "SS" port as these have a greater chance of success (EHCI controller doesn't work, XHCI controller works, blue ports have a greater chance of using XHCI). 99 | 100 | Once ready, run the `linux-macos-boot.sh` script from this repository's folder. Again, I let you deal with permissions issues (if it cannot find the module `usb` it means that you have insufficient permissions). Voilà ! 101 | 102 | #### From an Android device 103 | 104 | 1. Download and install the latest release of this app : https://github.com/natinusala/switch_linux_launcher/releases/latest 105 | 2. Run it - it will tell you that some files are missing, remember the folder in the dialog, it should look like one of these : 106 | * `/storage/emulated/0/Android/data/io.mrarm.switchlinuxlauncher.noimx/files/shofel2` 107 | * `/sdcard/Android/data/io.mrarm.switchlinuxlauncher.noimx/files/shofel2` 108 | 4. Exit the app (if you can close the task using the multitask button it's better) 109 | 5. From the `payloads` folder of the repository, copy the `cbfs.bin` and `coreboot.rom` files to the `shofel2` folder on your Android device (the folder of the previous step) 110 | 6. Run the app again - if the dialog doesn't show up then you can go on, otherwise you did something wrong 111 | 7. (Optional) Depending on your device, you might need to enable "OTG" or "OTG Storage" in the Android settings 112 | 8. Plug your Switch in your Android device 113 | * If the Switch is charging from your phone, you can go on 114 | * If your phone is charging from the Switch, try to reverse the cabling so that your phone charges the Switch instead 115 | * If nothing happens, I'm afraid your phone doesn't have OTG (or it's not enabled) - the exploit might now work 116 | 9. Put your Switch in RCM mode 117 | 10. Voilà ! 118 | 119 | ## Troubleshooting 120 | 121 | * Having a black screen despite the fact that the exploit worked ? Just shut down the Switch (10 seconds power button press) and try again, it happens sometimes. 122 | * Wi-Fi doesn't work ? Make sure you reboot properly : 123 | 1. Plug your Switch back into your host machine 124 | 2. Using the touchscreen, open the top-right menu and click on the power button 125 | 3. Click on the `Restart` button 126 | 4. Wait for the full reboot of the console 127 | 5. Launch the exploit again so that Linux boots 128 | 129 | ## What works / what doesn't work 130 | 131 | * **Wi-Fi** : works after a reboot 132 | * After each cold boot, you should reboot (it will reboot to RCM) and run the exploit again to enable Wi-Fi 133 | * **Bluetooth** : works partially 134 | * Keyboards and mice work 135 | * Joy-Cons, speakers and headphones don't 136 | * **Touch screen** : works 137 | * **Audio** : not working, even through Bluetooth headphones or speakers 138 | * **Hardware graphics acceleration** : works 139 | * You have to select a power profile manually at each reboot using the `switchpower` script 140 | * **Wired Joy-Cons** : to be implemented 141 | * **Volume buttons** : recognized but don't do anything since there is no audio device 142 | * **Power button** : only works to halt the system with a long-press 143 | * no graceful shutdown 144 | * no sleep mode 145 | * **USB** : not working 146 | * **Dock** : to be implemented 147 | * **Power management** : works partially 148 | * No graceful shutdown 149 | * No reboot to Linux, only reboot to RCM 150 | * GPU profile has to be selected by hand 151 | * Battery level correctly recognized 152 | * Be careful as staying for a long time in Linux desyncs the battery calibration on Horizon and _can_ cause the console to shutdown unexpectedly (at 50%) 153 | 154 | * **Gnome-terminal** : Tofix ! It crash use xterm instead . 155 | ## How to build it yourself 156 | 157 | Follow the steps on fail0verflow's repository, but instead of using their fork of u-boot, use [mine](https://github.com/natinusala/switch-u-boot). If you already built everything, you will need to rebuild u-boot using my fork and _then_ rebuild coreboot. 158 | 159 | Then, make sure that the first partition of the console's SD card is FAT32 and create a `boot` folder. Inside, put : 160 | * `Image.gz` : the zipped Linux kernel 161 | * `tegra210-nintendo-switch.dtb` : the DTB 162 | * `boot.scr` : you can generate it by using the `make.sh` script in the `src` folder of this repository 163 | 164 | Put the SD card in the console. 165 | 166 | Then, use shofel2 to run the coreboot you recompiled, like usual. Linux should boot immediately without the need to run `imx_usb` ! 167 | 168 | _You should probably put a rootfs in mmcblk0p2._ 169 | 170 | ## Credits 171 | * kombos for the pre-built kernel and DTB 172 | * rajkosto for TegraRcmSmash 173 | * MCMrARM for the Switch Linux Launcher app 174 | * Gigaa for the GPU clock speed service 175 | * 00cancer for the initial GNOME image 176 | * ctyler for the rootfs-resize script 177 | * fail0verflow for shofel2 and their coreboot, u-boot & Linux port 178 | * Everyone else who participated ! 179 | -------------------------------------------------------------------------------- /linux-macos-boot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "Put your Switch in RCM mode now" 3 | ./shofel2/shofel2.py payloads/cbfs.bin payloads/coreboot.rom 4 | -------------------------------------------------------------------------------- /payloads/cbfs.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natinusala/painless-linux/f1609b0a3872b4bbc6c0df4bb99c886551981cbe/payloads/cbfs.bin -------------------------------------------------------------------------------- /payloads/cbfs.elf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natinusala/painless-linux/f1609b0a3872b4bbc6c0df4bb99c886551981cbe/payloads/cbfs.elf -------------------------------------------------------------------------------- /payloads/coreboot.rom: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natinusala/painless-linux/f1609b0a3872b4bbc6c0df4bb99c886551981cbe/payloads/coreboot.rom -------------------------------------------------------------------------------- /sd/boot/Image.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natinusala/painless-linux/f1609b0a3872b4bbc6c0df4bb99c886551981cbe/sd/boot/Image.gz -------------------------------------------------------------------------------- /sd/boot/boot.scr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natinusala/painless-linux/f1609b0a3872b4bbc6c0df4bb99c886551981cbe/sd/boot/boot.scr -------------------------------------------------------------------------------- /sd/boot/tegra210-nintendo-switch.dtb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natinusala/painless-linux/f1609b0a3872b4bbc6c0df4bb99c886551981cbe/sd/boot/tegra210-nintendo-switch.dtb -------------------------------------------------------------------------------- /shofel2/shofel2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # shofEL2 nintendo switch (and related) cold boot exploit 4 | #------------------------------------------------------------------------------ 5 | # Switch will enter RCM if (PMC_SCRATCH0 & 2) is set, or if coldboot path 6 | # fails to find something to boot. So just disconnect/corrupt emmc during 7 | # early boot. 8 | import usb.core 9 | import usb.util 10 | import errno 11 | import time 12 | import binascii 13 | import struct 14 | import sys 15 | import os 16 | import hashlib 17 | import ctypes 18 | import fcntl 19 | import platform 20 | 21 | IS_OSX = platform.system() == "Darwin" 22 | USBDEVFS_URB_TYPE_CONTROL = 2 23 | USBDEVFS_SUBMITURB = 0x8038550a 24 | USBDEVFS_REAPURB = 0x4008550c 25 | USBDEVFS_DISCARDURB = 0x0000550b 26 | 27 | def parse32(buf, offset): 28 | return struct.unpack('II', addr, len(data))) 115 | while len(data) > 0: 116 | chunk = data[:32*1024] 117 | s.ep1_write(chunk) 118 | data = data[32*1024:] 119 | def cmd(s): 120 | uboot = s.binload(2) 121 | bl31 = s.binload(3) 122 | fdt = s.binload(4) 123 | kernel = s.binload(5) 124 | ep = None 125 | if len(uboot) > 0: 126 | s.send('u-boot', s.uboot_addr, uboot) 127 | ep = s.uboot_addr 128 | if len(bl31) > 0: 129 | s.send('bl31', s.bl31_addr, bl31) 130 | ep = s.bl31_addr 131 | if len(fdt) > 0: 132 | s.send('fdt', s.fdt_addr, fdt) 133 | if len(kernel) > 0: 134 | s.send('kernel', s.kernel_addr, kernel) 135 | print('bootstrapping ccplex @0x%x' % ep) 136 | s.ep1_write('BOOT') 137 | s.ep1_write(struct.pack('>I', ep)) 138 | sys.exit(0) 139 | else: 140 | print('exiting') 141 | s.ep1_write('EXIT') 142 | def cbfs(s): 143 | data = s.binload(2) 144 | if len(data) < 20 * 1024: 145 | print('invalid coreboot.rom') 146 | return 147 | while True: 148 | (offset, length) = struct.unpack('>II', s.ep1_read(8)) 149 | if offset + length == 0: 150 | print('you have been served') 151 | sys.exit(0) 152 | print('sending 0x%x bytes @0x%x' % (length, offset)) 153 | while length > 0: 154 | l = length 155 | if l > 32 * 1024: 156 | l = 32 * 1024 157 | s.ep1_write(data[offset:offset + l]) 158 | offset = offset + l 159 | length = length - l 160 | def pwn(s): 161 | # this is sp+0xc 162 | src_base = 0x4000fc84 163 | # memcpy pushes r4,lr 164 | # memcpy_wrapper pushes r0,lr 165 | target = src_base - 0xc - 2 * 4 - 2 * 4 166 | dst_base = 0x40009000 167 | overwrite_len = target - dst_base 168 | payload_base = 0x40010000 169 | 170 | # rom is in rcm_send_chip_id_and_version 171 | # unblock it 172 | init_msg = s.read_init_msg() 173 | print(binascii.hexlify(init_msg)) 174 | 175 | # now in rcm_recv_buf 176 | s.sanity_check(src_base, dst_base) 177 | 178 | # need to build payload buffer 179 | # write header 180 | s.ep1_write(struct.pack('>> Switching to dumping mode...') 224 | else: 225 | #data = data.decode('utf-8') 226 | print(repr(data)) 227 | if data.split(b'\n')[0] == b'READY.': 228 | print('>>> Switching to cmd mode...') 229 | s.cmd() 230 | elif data.split(b'\n')[0] == b'CBFS': 231 | print('>>> Switching to cbfs mode...') 232 | s.cbfs() 233 | except usb.core.USBError as e: 234 | if e.errno == errno.ENODEV: 235 | print('usb device lost, reconnecting...') 236 | s.dev = wait_for_device(s.DEV_ID_SWITCH) 237 | else: 238 | time.sleep(0.1) 239 | h = hashlib.sha1() 240 | fp = open('../dump.bin', 'wb') 241 | recvd_size = 0 242 | while True: 243 | data = s.ep1_read(4096).tostring() 244 | if len(data) == 20: 245 | # Last block, SHA1 246 | print('>>> Done! Expected sha1:', data.encode('hex'), 247 | 'received:', h.hexdigest()) 248 | break 249 | else: 250 | h.update(data) 251 | fp.write(data) 252 | recvd_size += len(data) 253 | if recvd_size % 2**20 == 0: 254 | print(recvd_size / 2**20, 'MiB received') 255 | 256 | rcm = RCM() 257 | rcm.pwn() 258 | -------------------------------------------------------------------------------- /src/boot.txt: -------------------------------------------------------------------------------- 1 | mmc dev 1 2 | load mmc 1:1 0x83000000 /boot/Image.gz 3 | load mmc 1:1 0x8d000000 /boot/tegra210-nintendo-switch.dtb 4 | unzip 0x83000000 0x85000000 5 | setenv bootargs 'root=/dev/mmcblk0p2 rw fbcon=rotate:3 rootwait' 6 | usb reset 7 | booti 0x85000000 - 0x8d000000 8 | -------------------------------------------------------------------------------- /src/make.sh: -------------------------------------------------------------------------------- 1 | mkimage -A arm -T script -O linux -d boot.txt boot.scr 2 | -------------------------------------------------------------------------------- /tegrarcmsmash/TegraRcmSmash_win32.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natinusala/painless-linux/f1609b0a3872b4bbc6c0df4bb99c886551981cbe/tegrarcmsmash/TegraRcmSmash_win32.exe -------------------------------------------------------------------------------- /tegrarcmsmash/TegraRcmSmash_x64.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/natinusala/painless-linux/f1609b0a3872b4bbc6c0df4bb99c886551981cbe/tegrarcmsmash/TegraRcmSmash_x64.exe -------------------------------------------------------------------------------- /windows-boot.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo Put your Switch in RCM mode now 3 | tegrarcmsmash\TegraRcmSmash_x64.exe -w --relocator= "payloads/cbfs.bin" "CBFS:payloads/coreboot.rom" 4 | echo Done 5 | pause -------------------------------------------------------------------------------- /windows-win32-boot.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | echo Put your Switch in RCM mode now 3 | tegrarcmsmash\TegraRcmSmash_win32.exe -w --relocator= "payloads/cbfs.bin" "CBFS:payloads/coreboot.rom" 4 | echo Done 5 | pause --------------------------------------------------------------------------------