Skip to content

Instantly share code, notes, and snippets.

@xerpi
Last active March 27, 2024 12:02
Show Gist options
  • Star 23 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save xerpi/3c720d345820691a2985502fcd80268f to your computer and use it in GitHub Desktop.
Save xerpi/3c720d345820691a2985502fcd80268f to your computer and use it in GitHub Desktop.
3DS Linux build instructions

Step 1: Compiling or Downloading the toolchain

Step 1.a: If you choose to download a pre-compiled toolchain (only for Linux x86-64)

  • Go to https://toolchains.bootlin.com
  • Select arch: armv6-eabihf
  • Select libc: glibc
  • Download bleeding-edge
  • Uncompress it (for example to /opt)
  • Add the bin/directory of the toolchain to $PATH
    • In my case: export PATH=$PATH:/opt/armv6-eabihf--glibc--bleeding-edge-2020.08-1

Step 1.b: If you choose to compile the toolchain yourself:

  • git clone https://github.com/crosstool-ng/crosstool-ng.git
  • Run: autoconf && ./configure --enable-local && make install
  • Run ./ct-ng ct-ng menuconfig
  • Go to Target options
  • Target Architecture -> Select arm
  • Floating point -> Select Hardware (FPU)
  • Emit assembly for CPU -> Write mpcore
  • Exit -> Exit -> Save? -> Yes
  • Run ./ct-ng build

Step 2: Build buildroot (to generate a rootfs)

  • git clone https://github.com/buildroot/buildroot.git
  • Download Buildroot .config to buildroot/.config
  • (You can add your custom scripts to output/target/)
    • Acutally, this is deprecated. Better to use the "filesystem overlay" option of Buildroot to add custom files to the rootfs.
  • Set toolchain path (in my case /opt/armv6-eabihf--glibc--bleeding-edge-2020.02-2/):
    • make menuconfig
    • Navigate to Toolchain --->
    • Properly set the Toolchain path, save and exit
  • Run make (-j N)

Step 3: Build Linux

  • git clone https://github.com/xerpi/linux_3ds.git
  • Copy buildroot/output/images/rootfs.cpio.gz to linux_3ds/
  • Run ./make_3ds.sh
  • Copy arch/arm/boot/zImage to sd:/linux/
  • Copy arch/arm/boot/dts/nintendo3ds_ctr.dtb to sd:/linux/

Step 4: Build arm9linuxfw (optional, but needed for SD card support)

  • git clone https://github.com/xerpi/arm9linuxfw
  • Run make
  • Copy arm9linuxfw.bin to sd:/linux/

Step 5: Build FIRM Linux Loader

  • git clone https://github.com/xerpi/firm_linux_loader
  • Run make
  • Copy firm_linux_loader.firm to sd:/luma/payloads/ (the payload folder Luma3DS will look for)

Step 6: Run Linux!

  • Power on the 3DS pressing START (or the button you have assocciated with the FIRM Linux Loader Luma3DS payload)
@ParzivalWolfram
Copy link

ParzivalWolfram commented Nov 13, 2018

You need to drop the Linux kernel version to 4.9.x and set the path and prefix to be "arm-buildroot-linux-gnueabihf" in the config and use this precompiled toolchain hardlink: https://toolchains.bootlin.com/downloads/releases/toolchains/armv6-eabihf/tarballs/armv6-eabihf--glibc--bleeding-edge-2018.02-1.tar.bz2

It's closest to what you had set in the config, but there was no toolchain that matched perfectly.

@ParzivalWolfram
Copy link

ParzivalWolfram commented Nov 27, 2018

Turns out, with crosstool-ng, the problems I had compiling my OWN toolchain, it was because you're supposed to run the "bootstrap" executable included with it instead of autoconf.

@marcotw2
Copy link

I made an upgraded version with additional customization tutorials.

https://gist.github.com/marcotw2/e3cf66bc2a69c499a5b36cf659674a14

@nickdesaulniers
Copy link

It looks like

Copy firm_linux_loader.firm to the payloads/ folder of 3DS

Should be

Copy firm_linux_loader.firm to luma/payloads/ (the payload folder Luma3DS will look for).

Also, hold start when booting to launch Luma3DS (I forgot and had to look this up).

@nickdesaulniers
Copy link

Neat! I was able to boot this on my new 3DS XL. Here's what I did differently.

PXL_20210329_015027866

Skip step 1, use clang to cross compile (but did need binutils; I couldn't get LLD to link a working arm9linuxfw). sudo apt install binutils-arm-linux-gnueabi.

Skip step 2, use prebuilt images from https://github.com/ClangBuiltLinux/boot-utils/blob/main/images/arm/rootfs.cpio.zst. Clone, decompress zstd -d rootfs.cpio.zstd, recompress as gzip gzip -9 rootfs.cpio.

Step 3: build kernel with clang ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- make LLVM=1 LLVM_IAS=1 -j72. Needed to modify the DTS since using a custom initrd:

diff --git a/arch/arm/boot/dts/nintendo3ds_ctr.dts b/arch/arm/boot/dts/nintendo3ds_ctr.dts
index cc45f8f8e0b0..7357541df526 100644
--- a/arch/arm/boot/dts/nintendo3ds_ctr.dts
+++ b/arch/arm/boot/dts/nintendo3ds_ctr.dts
@@ -9,7 +9,7 @@ / {
        #size-cells = <1>;
 
        chosen {
-               bootargs = "nr_cpus=2 keep_bootcon fbcon=rotate:1";
+               bootargs = "nr_cpus=2 keep_bootcon fbcon=rotate:1 rdinit=/bin/sh";
 
                #address-cells = <1>;
                #size-cells = <1>;

Step 4:
modify arm9linuxfw to build with clang and llvm-objcopy, still use GNU BFD linker rather than LLD (todo: see why LLD won't put .text.start at 0x08080000 llvm-objdump -dr -j .text.start arm9linuxfw.elf | less).

diff --git a/Makefile b/Makefile
index 268d936..6d273b7 100644
--- a/Makefile
+++ b/Makefile
@@ -1,15 +1,10 @@
-ifeq ($(strip $(DEVKITARM)),)
-$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
-endif
-
-include $(DEVKITARM)/base_tools
-
 TARGET = $(notdir $(CURDIR))
 OBJS   = source/start.o source/main.o source/tmio.o source/delay.o \
        source/draw.o source/i2c.o source/utils.o source/pxi.o source/tiny-printf.o source/libc.o
-ARCH   = -mcpu=arm946e-s -march=armv5te -mlittle-endian -mthumb-interwork
-ASFLAGS        = $(ARCH) -x assembler-with-cpp
-CFLAGS         = -Wall -O0 -fno-builtin -nostartfiles -nostdlib -fomit-frame-pointer $(ARCH) -Iinclude
+ARCH   = -mcpu=arm946e-s -march=armv5t -mlittle-endian
+ASFLAGS        = $(ARCH) -x assembler-with-cpp --target=arm-linux-gnueabi
+CFLAGS         = -Wall -O0 -fno-builtin -nostartfiles -nostdlib -fomit-frame-pointer $(ARCH) -Iinclude --target=arm-linux-gnueabi-
 DEPS   = $(OBJS:.o=.d)
 
 all: $(TARGET).bin
@@ -19,7 +14,8 @@ debug: ASFLAGS += -DDEBUG
 debug: $(TARGET).bin
 
 $(TARGET).elf: $(OBJS)
-       $(CC) -T linker.ld $(CFLAGS) $^ -o $@
+       $(LD) -T linker.ld $^ -o $@ 
 %.bin: %.elf
        $(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@
$ LD=arm-linux-gnueabi-ld OBJCOPY=~/llvm-project/llvm/build/bin/llvm-objcopy CC=~/llvm-project/llvm/build/bin/clang make

step 5: just use latest release

@xerpi
Copy link
Author

xerpi commented Mar 29, 2021

Thanks @nickdesaulniers for the corrections to the build instructions, and also for providing the instructions to build the kernel with Clang!

@dumbnerd08
Copy link

What can you do with this installation?

@BBGS11
Copy link

BBGS11 commented May 20, 2023

Will installing Linux delete my files already saved like digital games, save data ect. or will I be able to switch between linux and "normal" 3ds

@ParzivalWolfram
Copy link

ParzivalWolfram commented May 20, 2023 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment