Mario Kart Live: Home Circuit

From Nintendo Switch Brew
Jump to navigation Jump to search

This page documents the Mario Kart Live: Home Circuit game.

Communication with the kart is done directly over local-WLAN via lp2p:app. The service implementation is in the main-codebin itself, without symbols - however there are strings for this. This is the first title on retail which uses lp2p.

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:

  • ""
  • "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 "" 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".
      • "": 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.


The kart is internally referred to by the game as "RCD" and "Fuji". 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:


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 dedicated psd_util_init_crc8 function instead of psd_util_get_crc8, which is now called by device_init in sources/psd.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.


This section documents the changes for game-updates.


This only updated the Kart firmware.


  • Nothing changed besides the usual NPDM update.


  • 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/": 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.