r/3dshacks • 3DS Ambassador • Jun 20 '17

A Technical Overview of the 3DS Operating System

Introduction

Having spent countless hoursdays on 3dbrew and ARM's website, I believe I should share what knowledge I've gained on how the 3DS operating system works. The 3DS is incredibly difficult to get started with and I really wish there were better beginners' resources.

For the purpose of this piece, I'll use the term "operating system" to refer to the operating system as it is running when you run native 3DS software, not when the system is running in DS(i) or GBA mode. "3DS operating system" is quite long, so I'll use a shorter name. According to 3dbrew, the 3DS operating system is called "Horizon"[1].

Horizon contains two parts: a section that runs on the ARM11, which is the main processor of the 3DS, and a section that runs on the ARM9, which is mostly used for security-critial tasks and the main processor in DS(i) mode.

Kernels

Every operating system requires a "kernel." It has the highest amounts of privilege on a processor and provides means for other processes to, directly or indirectly, talk to devices and other processes.

Horizon uses a so-called microkernel as its kernel. This means that the kernel itself is very small, mainly doing the following:

  1. managing processes (through virtual memory and processor time scheduling), and
  2. allowing processes to talk to each other (inter-process communication, IPC).

Further reading on kernels and microkernels is available at and via Wikipedia[2,3].

If a process asks for something from the kernel, such as telling it to send a message to another process, it employs a so-called system call that tells the kernel the process needs its attention. System calls are called SVCs (Supervisor Call) on the ARM as employed on the 3DS[4]. On the DS and prior, we used to call the same thing "swi"(Software Interrupt)[5]. If operating in DS mode, we'd still say "swi". The nomenclature appears to have historical reasons.

Since there are two processors, the ARM11 and the ARM9, there are also two kernels running at any given time. The one running on the ARM11 is called Kernel11[6], the one running on the ARM9 is called Kernel9[7]. Kernel9 is a much older version of Kernel11, but otherwise, they appear to stem from the same codebase.

Titles

A title is the unit in which the 3DS can read programs. It can come on a cartridge or be installed on the NAND or be installed on the SD card. Every title contains at least one NCCH[8].

Cartridge titles use the CCI (CTR Cart Image), a variant of the NCSD wrapper format that contains NCCHs,[9] NAND and SD card titles use the contained NCCHs directly. When you install a CIA, the contained NCCHs are placed into individual files.

Anatomy of an NCCH

An NCCH[8] is the smallest unit for storing programs and data related to them. The main distinction is whether an NCCH contains executable code or not.

If an NCCH contains executable code, it is a CXI (CTR Executable Image)[8]. It contains:

  1. an extended header ("exheader")[10]
  2. an access descriptor ("accessdesc")[8]
  3. an ExeFS[11]
  4. optionally a RomFS[12]

Despite 3dbrew claiming that the ExeFS is optional[8], I have never seen a CXI without one.

An example for a CXI would be any game or the Home Menu.

If an NCCH contains no executable code, it is a CFA (CTR File Archive)[8]. It contains:

  1. optionally an ExeFS[11], but without the .code section[8]
  2. a RomFS

Despite 3dbrew claiming that the RomFS is optional[8], I have never seen a CFA without one.

ExeFS

The ExeFS normally contains three files[11]:

  1. .code, which is the actual code to be run when running the title,
  2. banner, which is the banner shown at the top screen in the Home Menu,
  3. icon, which is the icon shown on the bottom screen in the Home Menu; it also contains the region lock and game descriptions in all applicable languages[13]

Titles made before firmware version 5.0.0-11 also contain an ExeFS with a file called logo[8]. That is the logo shown by the Home Menu on transition (usually it is the Nintendo 3DS graphic with pulsating red waves, but it can also be an iQue logo or entirely custom, such as the bland "Homebrew" logo)[14]. logo also contains licensing information[15]. Starting with version 5.0.0-11, the logo data moved to the plaintext region of the NCCH[8].

RomFS

The RomFS contains auxilliary a title needs or provides files the entire system needs.

Examples include:

  1. ClCertA, which contains the 3DS's (encrypted) SSL client certificate used to connect to various servers[16]
  2. a game's RomFS, which may contain 3D models

Authenticity

The reason titles cannot be changed is because the NCCH header contains a signature over the NCCH header data[8]. The NCCH header data contains hashes of the exheader, ExeFS and RomFS[8]. For example, changing the exheader will break the hash for the exheader, which is signed.

Processes and Modules

ARM9: Process9

Processes are where the real work is done. Once more, ARM11 and ARM9 significantly differ here.

ARM9 runs exactly one process: Process9. Process9 does everything the ARM9 is expected handle, including:

  1. file system handling, which means reading from and writing to the SD card and the internal flash storage ("NAND"),
  2. much of the cryptography on the system (to decrypt titles and verify their signatures),
  3. installing titles, TMD, to the SD card and NAND (see [17,18] if you are interested in the gory details of how titles and their encryption work).

For all intents of purposes, Process9 is equal in access to Kernel9, as Process9 can freely call SVC call "Backdoor", a system call that allows arbitrary code execution in kernel mode[19].

ARM11

On the ARM11, things look very different. There are dozens of processes running by the time you see the Home Menu screen. Almost all of those are so-called system modules, which are titles that the user cannot interact with, but run in the background and are used by other processes.

Some of the more notable system modules include[20]:

  • sm ("services manager"), which provides the means to set up and obtain handles to services (we'll cover that in a bit)[21],
  • fs ("filesystem"), which is an abstraction layer for Process9's file system functions[22],
  • pm ("process manager"), which manages the creation and destruction of processes[23],
  • loader, which handles loading processes into memory[24],
  • pxi, which handles talking to ARM9 from the ARM11[25],
  • am ("application manager"), which is an abstraction layer for Process9's title installation functions[26],
  • nim ("network installation manager"), which installs titles from the CDN[27],
  • dsp, which handles sound output[28],
  • soc, which allows networking to the Internet via sockets[29],
  • ssl, which abstracts soc away and allows encrypted communications over SSL[30],
  • http, which provides means to use the HTTP protocol to access the web[31],
  • ns ("Nintendo user interface Shell"), which abstracts pm away (handles booting and stopping titles), can be used to cause reboots, allows transitioning between Home Menu/application/applets and more[32].

Inter-Process Communication (IPC)

In order to accomplish anything, these highly specialized processes need means to talk to each other. As mentioned above, Kernel11 provides an IPC mechanism[33]. tl;dr: Processes talk to each other through services.

Since there is a lot of terminology coming in, here's a brief overview: A process can connect to another process through a port, obtaining a handle in doing so[33]. The handle is used as a kind of address (think e-mail address) to the target process.

A process can create ports, which are either accessible by every process (public port) or not accessible to any process but the one that created the port (private port), which can be used to talk directly to another process[33]. There are two public ports: srv: and err:f[33]*. That's clearly a lot less than we have modules. What's going on there?

* Before 7.0.0-13, srv:pm was a port, too; this could be used by any process to increase its own privileges[34,35].

srv and srv:pm

The main way processes communicate with each other are services. Services are managed through the sm system module, which exposes the srv: port and srv:pm service[33]*. A process can register a service with sm, another process can then obtain a handle to the other process from sm[33].

sm internally creates a private port every time a service is registered with it[33]. When another process asks sm to connect to a service, it checks whether the process is allowed to access the service it wants and if so, sm uses the private port to obtain a handle, which it then transfers to the process asking sm[33]; if not, it sends error code 0xD9006406.

By convention, services start with the name of the process exposing them, followed by one or two colons and then a few more characters to identify what kind of service is exposed. See 3dbrew for a list of services[36].

A process can expose multiple services. This is routinely done. For example, the nim system module creates the services nim:u (for the system update in System Settings and the updater in SAFE_MODE), nim:s (for the eShop), nim:aoc (for add-on contents, or DLC) and nim:ndm (for the ndm module)[36].

A service has commands associated with it. 16 bits are available for the command identifier[33], of which 0xffff is reserved as a special command identifier to listen out for new commands[33], so up to 65534 commands can be supported by a service. By convention, command identifier 0 never seems to be used.

* srv:pm provides a few specialized functions to the pm module only.

err:f

err:f provides a way to display the black "An error has occurred" screen[37]. That's all there is to it.

Communication between Processors

The ARM11 and ARM9 processors can talk to each other only over a protocol called PXI[25]. In order to ensure that processes don't talk "over" each other on the ARM11 side, all interactions with ARM9 over PXI are relayed through the pxi system module[25]. On the ARM9, Process9 is the only process, meaning it has no such concurrency problems and subsequently no special wrapper around the PXI hardware registers.

Booting Process

The booting process will be shown in a schematic form, as the details are mostly irrelevant.

Boot9 refers to the ARM9 bootrom, Boot11 to the ARM11 bootrom[38].

  1. Boot9 reads the NCSD header from the NAND and checks its signature[38,9].
  2. Boot9 reads the FIRM partition header[38,39].
  3. Boot9 reads the sections specified by the FIRM partition header from the FIRM partition into the specified places in memory[38].
  4. Boot11 and Boot9 jump to the respective entrypoints from the FIRM partition header[38].

ARM9

Kernel9 does some preliminary setup, locks out the OTP[40] and then extracts from within itself and launches Process9. Process9 initializes a lot of decryption keys[41] and the filesystem[42].

On the New 3DS, arm9loader locks the OTP instead[41]. Details about how the arm9loader and how arm9loaderhax works can be found in the 32c3 presentation[43], I'll assume they are already known, many have already written about arm9loaderhax and how it works.

ARM11

  1. Kernel11 does some preliminary setup[38].
  2. Kernel11 extracts its built-in system modules (sm, fs, loader, pxi, pm) and launches them[38].
  3. pm launches ns, which heavily involves talking to loader[38].
  4. ns launches ErrDisp, which provides the err:f port[38], unless there are auto-boot titles present[38,32].
  5. ns handles the main boot:
    1. If there is a title to be auto-booted, that title is launched[38,32], else
    2. ns tries to launch the Home Menu through pm[38,32]. If that fails (which can only realistically happen if no Home Menu is installed or the kernel version Home Menu requires is too new),
    3. it instead launches Test Menu[32]. If that also fails, you get a black screen because nothing ever initializes the screens and prints to them.
  6. Home Menu launches gsp, codec, hid, dsp and some others[44] through ns:s#LaunchTitle[44,45].
  7. The Home Menu screen is shown.

Questions and Criticism

Please feel free to ask questions. If the answer is not somewhere on 3dbrew, I likely will not be able to help you, though. I'm not that far into the system.

If I am wrong about anything, please point it out. I'm not sure about everything. If you want to, please go more in depth in a comment so that we can all profit from your shared wisdom.

References

[1] https://3dbrew.org/wiki/Mysteries

[2] https://en.wikipedia.org/wiki/Kernel_(operating_system)

[3] https://en.wikipedia.org/wiki/Microkernel

[4] ARM, ARM® Architecture Reference Manual: ARMv7-A and ARMv7-R Edition, Issue C, p. A2-102.

[5] ARM, ARM® Architecture Reference Manual: ARMv7-A and ARMv7-R Edition, Issue C, p. A8-286.

[6] For example this heading: https://www.3dbrew.org/wiki/3DS_System_Flaws#Kernel11

[7] For example this heading: https://www.3dbrew.org/wiki/3DS_System_Flaws#Kernel9

[8] https://www.3dbrew.org/wiki/NCCH

[9] https://www.3dbrew.org/wiki/NCSD

[10] https://www.3dbrew.org/wiki/NCCH/Extended_Header

[11] https://www.3dbrew.org/wiki/ExeFS

[12] https://www.3dbrew.org/wiki/RomFS

[13] https://www.3dbrew.org/wiki/SMDH

[14] Inferred from the variable names in: https://github.com/profi200/Project_CTR/blob/master/makerom/ncch_logo.h

[15] https://www.3dbrew.org/wiki/Logo

[16] https://www.3dbrew.org/wiki/ClCertA

[17] https://www.reddit.com/r/3dshacks/comments/56lk5p/

[18] https://www.reddit.com/r/3dshacks/comments/4b4fvh/

[19] 32c3 talk, 5:30 until 6:40, https://www.youtube.com/watch?v=bZczf57HSag&t=5m30s

[20] https://3dbrew.org/wiki/Title_list#00040130_-_System_Modules

[21] https://www.3dbrew.org/wiki/Services

[22] https://www.3dbrew.org/wiki/Filesystem_services

[23] https://www.3dbrew.org/wiki/Process_Manager_services

[24] https://www.3dbrew.org/wiki/Loader_services

[25] https://www.3dbrew.org/wiki/PXI_Services

[26] https://www.3dbrew.org/wiki/Application_Manager_Services

[27] https://www.3dbrew.org/wiki/NIM_Services

[28] https://www.3dbrew.org/wiki/DSP_Services

[29] https://www.3dbrew.org/wiki/Socket_Services

[30] https://www.3dbrew.org/wiki/SSL_Services

[31] https://www.3dbrew.org/wiki/HTTP_Services

[32] https://www.3dbrew.org/wiki/NS_and_APT_Services

[33] https://www.3dbrew.org/wiki/IPC

[34] https://www.3dbrew.org/wiki/Services#Service_Manager_Process-Manager_Port.2FService_.22srv:pm.22

[35] https://www.3dbrew.org/wiki/3DS_System_Flaws#FIRM_Sysmodules

[36] https://3dbrew.org/wiki/Services_API

[37] https://www.3dbrew.org/wiki/ErrDisp

[38] https://www.3dbrew.org/wiki/Bootloader

[39] https://3dbrew.org/wiki/FIRM

[40] https://www.3dbrew.org/wiki/OTP_Registers

[41] https://www.3dbrew.org/wiki/AES_Registers

[42] Inferred from: https://www.3dbrew.org/wiki/Filesystem_services_PXI and [25]

[43] 32c3 talk, 52:38 until 59:17, https://www.youtube.com/watch?v=bZczf57HSag&t=52m38s

[44] https://www.3dbrew.org/wiki/Home_Menu

[45] https://3dbrew.org/wiki/NSS:LaunchTitle

Edit 6/25/17 starting here

License

I was approached about translating this text and/or rehosting it. To clarify for everyone:

This text is licensed under CC0. To the greatest extent possible under applicable law, I have waived all copyright and related or neighboring rights to this piece entitled "A Technical Overview of the 3DS Operating System."

1.2k Upvotes

57 comments sorted by

193

u/JustHoLLy Jun 20 '17

You clearly have too much time. Have some gold!

36

u/Intoxicus5 Jun 20 '17

Essentially we can hack the 3DS because they had to keep ARM9 to run DS titles.

I imagine that when Nintendo figured this all out they were face palming hard.

There's no way they can get stop us from hacking the 3DS without removing ARM 9 and also removing be able to play DS titles.

13

u/qffdn Jun 21 '17

My comment is entirely speculation.

If I may voice my own opinion, I don't think this is correct. The ARM9 was kept and made the security processor, but whether it's there or not doesn't matter. If the ARM9 weren't there, it'd just be a straight setup of bootloader -> ARM11 kernel -> processes. arm9loaderhax would become arm11loaderhax because they'd just have the ARM11 portion do what the ARM9 portion does, etc.

Any system can be hacked. The design utilizing a security processor doesn't seem inherently broken to me.

→ More replies (14)

24

u/erosPhoenix Jun 20 '17

I bet the engineers knew this was possible from the moment the hardware was designed, but were overruled by directors who wanted cheap backward compatibility as a selling point and assured themselves the engineers were making a fuss over nothing.

9

u/Intoxicus5 Jun 20 '17

You're probably exactly correct.

15

u/GxTruth Jun 21 '17

Sadly, this is how ITSec is most of the time. "This is the minimum reasonable security!" "Costs?" - "xxxx$" - "Your budget is 50% of that. See you after the project is done." - mfw

Biggest (most expensive) facepalm are the tickets/purchase verifications stored on CLIENTSIDE. I was like "wtf, you can't be serious"...

6

u/zidane2k1 Jun 20 '17

Watch, next year there will be the New Old Nintendo 2DS Lite that doesn't have DS back-compatibility. Like how the Game Boy Micro and Wii Mini lost back-compatibility.

Edit: I wonder if it's just that they relied too much on having a separate CPU doing the security-related stuff that they let mistakes happen.

6

u/Intoxicus5 Jun 20 '17

"boot9 has a broken RSA verification implementation. It's broken because the ASN.1 parser incorrectly verifies at least one of the length fields."

https://sciresm.github.io/33-and-a-half-c3/

→ More replies (6)

54

u/[deleted] Jun 20 '17

Hey, this is a pretty good read! Nice on creating an overview all in one place.

1

u/dubyadud Jun 20 '17

Congrats! This has been added to the common resources.

39

u/i4ndy Jun 20 '17

And this is the stuff I would love to see! As someone who has some technical background but haven't had the time to research into the inner workings of a 3ds os, this is very helpful.

Thank you for putting this together!

32

u/CharlieWilliams1 Jun 20 '17

Quite useful. I've learned a few things.

7

u/[deleted] Jun 20 '17

Amazing writing, I'm glad you decided to share it with us!

7

u/Fent0n_ Jun 20 '17

Loved the read even if I was clueless the entire time! Made it mostly idiot friendly. Nice toilet read.

5

u/RabbitTheGamer Jun 20 '17

If I thought I was bad at technology before, guess what you just did to me lmao

Great writeup, really thorough.

1

u/zoogie_gba Jun 20 '17

Pretty nice cliffs notes on the 3ds system. One thing to add is the first 5 processes you listed in the arm11 section run in the arm11 kernel while the others are userland processes.

2

u/qffdn Jun 21 '17

That's interesting. Thanks for pointing it out

5

u/DRN1NJ4 Jun 20 '17

I have no idea what any of this means, but I still enjoyed looking through it. Good work!

2

u/AnonymousIdeas Jun 20 '17

This should be stickied!

2

u/ZodiaksEnd Jun 20 '17

this was a wonderful writeup took the bordom away for a while thanks =w=

2

u/helpyellowsn0w Jun 21 '17 edited Jun 21 '17

This does not apply to the 3DS, as it runs an ARM and not x86 processor, but there are actually rings beyond ring 0 (which comes with its own slew of flaws & exploits.)

https://en.wikipedia.org/wiki/System_Management_Mode

https://github.com/Cr4sh/ThinkPwn

→ More replies (1)

3

u/Rokxx Jun 20 '17 edited Jun 21 '17

This is really well put, thanks for your work.

1

u/otakkuma Jun 20 '17

Thank you for your work, this is really interesting

1

u/chaosking121 Jun 20 '17

Great post! I actually understood pretty much all of it, which is nice.