Mario Kart Live: Home Circuit
This page documents the Mario Kart Live: Home Circuit game.
Communication with the kart is done directly over local-WLAN via an access point that the game sets up using lp2p:app, making it the first title on retail to use lp2p. The underlying device management uses RCD. The RCD implementation is in the main-codebin itself, without symbols - however there are strings for this.
This is also the first known title on retail which uses stack cookies. This is used by main-codebin, the ssp functionality in sdknso is still not used other than being called from an initialization func. This is implemented in the main-codebin as follows:
- The global u64 __stack_chk_guard is loaded then saved immediately before {first saved register} on stack, during func entry. During func exit, the global u64 is compared with the cookie on stack, it will call __stack_chk_fail on mismatch. __stack_chk_fail just executes an undefined instruction to trigger a crash.
- There is no initialization func for __stack_chk_guard, it's just a hard-coded constant: 0xDEADBEEFDEADBEEF. Since it's constant, this renders the stack cookie useless.
RomFs contains only two files:
- "data.zip"
- "update.pua": This is the firmware update data for the Kart. This is a tar archive. The extracted archive contains "update.pui" and "pui.hash". The latter is a binary 0x100-byte file. The former is another tar archive, the content of that archive is the following:
- "config.txt": Contains config which includes fields for efuse_key, efuse_fw, secure_boot, etc. Also references the data under generic/. Seems to be configuration for firmware installation, not uboot.
- "audiofw_sha": 0x20-byte binary SHA256 hash for the "bluecore.audio.aes" file.
- "dtb_sha": 0x20-byte binary SHA256 hash for the .dtb file.
- "rootfs_sha": 0x20-byte binary SHA256 hash for the "root.nand.cpio.gz_pad.img.aes" file.
- "tee_sha": 0x20-byte binary SHA256 hash for the tee file.
- "uImage_sha": 0x20-byte binary SHA256 hash for the "nand.uImage.aes" file.
- "generic/": This contains:
- "android.nand.dtb": Plaintext "kernelDT".
- "bluecore.audio.aes": Encrypted "audioKernel".
- "nand.uImage.aes": Encrypted "linuxKernel".
- "root.nand.cpio.gz_pad.img.aes": Encrypted "InitrdRootFS".
- "tee.bin.aes": Encrypted "tee".
Note that the only firmware archive files accessed by the game are "update.pui", "pui.hash", and "config.txt". The content of "config.txt" is only used with sscanf() to extract the version fields. "update.pui"/"pui.hash" are probably sent over the network connection to the kart - it's unknown whether the game does anything with the content of "pui.hash" other than this.
Kart
The kart is likely codenamed "Fuji" as this is both what the game calls it internally, and how it identifies itself during RCD handshake. Various strings in the kart OSS refer to it as "DHC".
OSS is available for the kart itself.
This uses Linux. The 1.1.0_3 archive contains the following:
busybox-1.22.1.tar.bz2 eudev-1.5.3.tar.gz kmod-17.tar.xz libnl-3.2.24.tar.gz linux-kernel_5c3cb2e0be2243f6d4553ccad2047c9d72e25ea2.tar.gz lrzsz-0.12.20.tar.gz PsdDriver_5a8d821.zip rtl8188eu_074cc66fece232b0d5f1e1f7de57e72022ec12b1.tar.gz uboot_53a0fa98b176329e340b0a2fca6edb7117209751.tar.gz util-linux-2.24.2.tar.xz
PsdDriver is Nintendo's custom kernel module, the GPL license header used in the source starts with the following:
* Sensors and Motors driver * Copyright (C) 2020 Nintendo Co, Ltd
The only changes in the OSS for 1.0.0_1 -> 1.1.0_3 are the following (note that there are more versions between these):
- The following archives were updated: linux-kernel, PsdDriver, rtl8188eu, uboot.
- In the PsdDriver source, the line-ending at the start of various source files was updated.
- In sources/psd_util.c,
initialize_table();
is now called by a dedicatedpsd_util_init_crc8
function instead ofpsd_util_get_crc8
, which is now called bydevice_init
in sources/psd.c.
- In sources/psd_util.c,
The above git-commit-hashes (?) from the filenames doesn't seem to match commits in the upstream repos.
On October 28, 2020, the existing OSS archives were updated without adding a new version. With 1.1.0_3, the uboot archive (which has the same filename) had the "/examples" directory removed.
Pairing process
The kart communicates with the Switch via standard 802.11 frames on channel 1/6/11, with standard CCMP encryption, but the authentication and key exchange protocol is Nintendo-proprietary. See LDN services for more information.
On first startup, Home Circuit generates a random SSID (beginning with 'G') and 0x20-byte PSK (for use in the aforementioned key exchange; it is not standard WPA). These are saved and reused on every subsequent startup, so that any kart(s) with this information stored can reconnect without needing to be paired again.
When pairing, Home Circuit creates a temporary network (random SSID beginning with 'P', randomized PSK, neither stored) and shows the details for this "pairing network" in a QR code for the kart to scan. Once the kart connects, it fetches the main "game" network SSID+PSK and stores them, and both it and Home Circuit exit pairing mode. The pairing network is only active while the QR code is displayed, otherwise the main "game" network runs.
The QR code is a "version 4" (33x33) code with level-M error correction. It uses byte encoding, and stores 0x3E bytes:
Offset | Size | Description |
---|---|---|
0x0 | 0x10 | Pairing seed. LP2P PSK is SHA256(seed) |
0x10 | 0x20 | Pairing SSID. Remaining space is filled with zeros. |
0x30 | 0x2 | Pairing channel. Encoded little-endian. Usually 0. |
0x32 | 0xC | Padding bytes; zero. |
Network protocols
Once the kart connects to the "game" network hosted by Home Circuit, it requests an IP address via DHCP, then connects to the Switch via standard TCP/IP to announce its presence. A series of TCP and UDP connections are established to exchange information, stream video, transmit control signals, monitor kart telemetry, etc.
Protocol | Endpoint | Port | Description | RCD service ID |
---|---|---|---|---|
Management | ||||
TCP | Switch | 5201 | RCD handshake service (pairing only) | 0x0001 |
5202 | RCD handshake service (non-pairing only) | 0x0001 | ||
Kart | 5103 | "Fuji Control" RCD service | 0x0100 | |
5106 | "Fuji Pairing" RCD service (pairing only) | 0x0102 | ||
5107 | "Fuji Update" RCD service | 0x0103 | ||
UDP | Kart | 5004 | Time synchronization | N/A |
Video | ||||
UDP | Switch | 5016+kartid | "LSP" video streaming | N/A |
TCP | 5032+kartid | "LSP" control channel | N/A (non-RCD) | |
Control | ||||
UDP | Kart | 5102 | Teleoperation (throttle, steering, tail light control) | N/A |
Switch | 5116+kartid | Telemetry | N/A |
Note: The ports determined by the kart ID are actually assigned by the Switch and configured via the "Fuji Control" service. The kart itself will actually use any port it is told to use; shown above are how Home Circuit calculates the port numbers.
Versions
This section documents the changes for game-updates.
v1.0.1
This only updated the Kart firmware.
ExeFs:
- Nothing changed besides the usual NPDM update.
RomFs:
- Only update.pua was updated, the following was changed in the extracted update.pui (pui.hash in update.pua was also updated):
- "config.txt": system_minor_version was changed from "3" to "4".
- "audiofw_sha"
- "rootfs_sha"
- "uImage_sha"
- "generic/bluecore.audio.aes": Starts differing at offset 0x1D0.
- "generic/nand.uImage.aes": Starts differing at offset 0x0.
- "generic/root.nand.cpio.gz_pad.img.aes": Starts differing at offset 0x0.