Your one-stop-shop for Nintendo Switch IPC definitions. This repo contains our best info on the state of IPC interfaces as of version 3.0, along with a parser in Python and scripts to generate and manipulate these files.
ipcdefs
-- The actual IPC definitions, in the various.id
files.scripts
-- Various scripts. Some notable ones:genallipc.py
-- This is what generatesauto.id
. That should be up to date in the repo, so you only need to run this when you're actively modifying the data in this script.
idparser.py
-- This is our module for parsing interface definitions from Python.
These are the types that are permitted in SwIPC:
u8, u16, u32, u64
- Unsigned integersi8, i16, i32, i64
- Signed integersb8
- Booleanf32
- Floating pointbytes<size[, alignment]>
- BLOBunknown
- No semantic information nor any size information is availableunknown<size>
- No semantic information is available, but the size is known. This is equivalent tobytes<size>
data
- Untyped data, for use inbuffer<>
expressionsstruct { type name; ... }
- Structured data A type may be followed by a number in square brackets to represent that it is an array of that type with the given length.
Type definitions, interface definitions, and command definitions can all be decorated to provide additional information. They are placed before the definition, typically on their own line.
Currently, the only specified decorator is the version decorator, which provides information about which versions the following definition applies to.
@version(2.0.0)
type nn::hid::debug::FirmwareVersion = i32;
Inside the parentheses is a version range, which can take the form of a single version (1.0.0
, 2.0.0
, etc.), an inclusive range of versions (1.0.0-3.0.0
), or a beginning version with no end (2.0.0+
).
Multiple conflicting definitions can be made if they are decorated with different version ranges.
@version(1.0.0-3.0.0)
[200] OpenLibraryAppletProxy(u64, pid, KHandle<copy>) -> object<nn::am::service::ILibraryAppletProxy>;
@version(3.0.0+)
[200] OpenLibraryAppletProxyOld(u64, pid, KHandle<copy>) -> object<nn::am::service::ILibraryAppletProxy>;
You can define a type using a type
statement. Type statements can be decorated with @version
decorators, and can conflict with each other as long as their versions do not overlap.
type nn::ApplicationId = i32;
type nn::account::CallbackUri = bytes<0x100>;
type nn::socket::timeout = struct {
u64 sec;
u64 usec;
u64 off;
}; // note that there is a semicolon after the closing curly brace
type
type nn::socket::sockaddr = unknown; // size is unknown
An interface
block defines the list of commands on a given class. A @version
decorator applied to an interface
block means that the entire interface only exists on those versions.
interface nn::am::service::IAudioController {
[0] SetExpectedMasterVolume(f32, f32);
[1] GetMainAppletExpectedMasterVolume() -> f32;
[2] GetLibraryAppletExpectedMasterVolume() -> f32;
[3] ChangeMainAppletMasterVolume(f32, u64);
[4] SetTransparentVolumeRate(f32);
}
If the interface represents a service registered with sm:
, its registration can also be represented with an is
clause.
interface nn::apm::IManager is apm {
[0] OpenSession() -> object<nn::apm::ISession>;
[1] GetPerformanceMode() -> nn::apm::PerformanceMode;
}
Multiple registrations for the same interface can also be represented.
interface nn::bcat::detail::ipc::IServiceCreator is bcat:a, bcat:m, bcat:u, bcat:s {
[0] CreateBcatService(u64, pid) -> object<nn::bcat::detail::ipc::IBcatService>;
[1] CreateDeliveryCacheStorageService(u64, pid) -> object<nn::bcat::detail::ipc::IDeliveryCacheStorageService>;
[2] CreateDeliveryCacheStorageServiceWithApplicationId(nn::ApplicationId) -> object<nn::bcat::detail::ipc::IDeliveryCacheStorageService>;
}
Inside the interface
block are command definitions. They should be indented with one tab character.
A command definition takes the following format.
[command id] Name(parameters) -> values;
If there are no values, everything between the closing paren and the semicolon can be omitted. If there is more than one, they need to be wrapped in a pair of parentheses and separated by commas.
Command definitions can be decorated with the @version
decorator, and definitions can conflict as long as their versions do not overlap.
The parameters represent the fields and descriptors that need to be included in a request destined for this endpoint. Note that the request will also need to include any buffers or arrays defined in the values
section.
The values, aside from any buffers or arrays, represent the values that will be included in a well-formed response from this endpoint.
In addition to any types built in or elsewhere defined, the parameters and values of a command can also include the following.
pid
- The message must include a handle descriptor with the "send PID" flag sethandle<move/copy/unknown>
- A handle included in the handle descriptor.handle<move/copy/unknown, type>
- A handle representing the given type of kernel object.buffer<data_type, transfer_type, size>
- A buffer that needs to be included in the request.transfer_type
is the only field that is required to not beunknown
.size
may be a positive integer (matching the size ofdata_type
if it is specified),unknown
if the size is unknown, orvariable
if the size is known not to be checked. Translation between buffers of a giventransfer_type
and a set of A/B/C/X descriptors is described on SwitchBrew.buffer<data, transfer_type>
- A buffer transferring untyped data with variable size.array<data_type, transfer_type>
- Equivalent to a buffer of the givendata_type
andtransfer_type
with a variablesize
.object<interface_name/unknown>
- An object of the given type.
genallipc.py is auto-generated from SDK symbols, which will in turn generate the auto.id
. This will miss some symbols, because the SDK symbols are not necessarily complete.
From a conversation with @hthh :
What's with serverInfo and clientInfo ?
I have two scripts, one for "server" and one for "client". "Server" does dynamic analysis of server code (using unicorn), which can reliably extract data from server dispatch functions. The fields available are inbytes, outbytes, ininterfaces, outinterfaces, inhandles, outhandles, buffers and sends_pid. But back when we did this we hadn't found a way to dump the builtin code, so we got docs with lots of information, but no information for FS or LDR or NCM which was annoying.
So "client" just works by extracting the command ID and sometimes the interface name from client code vtables. In the SDK it extracts the mangled symbols which sometimes includes the full method name and parameter types, and usually includes full parameter serialization information. So this is 2 mangled function names associated with a command ID. Unfortunately these are mostly fixed limitations. Much of the data has been compiled out and can't be recovered, particularly names and types. Serialization data can be recovered by hand, but I couldn't find a way to automate it.
2.0 was the first version to include the 2nd mangled function name, so we get 1.0 types/names but not serialization data. Interface names were removed from the serverside data available on 4.1, so I wrote a dynamic client script which can figure out the input buffer types and (rough) input data size using unicorn and used that to match things. This is also interesting for things like TMA services where we only have client code and no server code.
I should really write this all up in a better format sometime. Basically I've done my best to extract this data, but I haven't addressed the huge problem of turning it into something coherent and useful.