Manu services
Manu ("Manufacturing") services are provided by the 010000000000B14A sysmodule, which is installed at the factory but not on normal retail systems.
manu
This is "nn::manu::IManu".
Cmd | Name |
---|---|
0 | InitializeForUfio |
1 | GetFileSize |
2 | ReadFromHost |
3 | WriteToHost |
4 | InitializeForUsbTransfer |
5 | UsbRead |
6 | UsbWrite |
7 | [7.0.0+] |
8 | [14.0.0+] |
All commands are wrappers for usb:ds requests with USB configured as:
VID: 0x057E (Nintendo Co., Ltd) PID: 0x3000 bcdDevice: 0x0100 (1.00) Manufacturer: "Nintendo" Product: "NintendoSdkDebugger" SerialNumber: "SerialNumber"
[7.0.0+] USB is now configured as:
VID: 0x057E (Nintendo Co., Ltd) PID: 0x3003 bcdDevice: 0x0100 (1.00) Manufacturer: "Nintendo" Product: "NintendoSdkManufacturing" SerialNumber: "SerialNumber"
InitializeForUfio
Takes an input u32. No output.
Configures a transfer pipe over usb:ds for file access mode.
GetFileSize
Takes a type-0x9 input buffer containing a path string. Returns an output u64.
Checks whether the specified file exists.
ReadFromHost
Takes a type-0x6 output buffer, a type-0x9 input buffer containing a path string and three u64s OutSize, Offset and InSize. No output.
Reads data from the specified file.
WriteToHost
Takes a type-0x5 input buffer, a type-0x9 input buffer containing a path string and three u64s OutSize, Offset and InSize. No output.
Writes data to the specified file.
InitializeForUsbTransfer
Takes an input u32. No output.
Configures a transfer pipe over usb:ds for raw access mode.
UsbRead
Takes a type-0x6 output buffer and two u64s Offset and Size. No output.
Reads raw data from the device.
UsbWrite
Takes a type-0x5 input buffer and two u64s Offset and Size. No output.
Writes raw data to the device.
Cmd7
Takes a type-0x9 input buffer containing a path string. No output.
Cmd8
Takes a type-0x9 input buffer containing a path string. No output.
Protocol
CommandId
Value | Name |
---|---|
1 | GetFileSize |
2 | ReadFromHost |
3 | WriteToHost |
4 | #Cmd7 |
5 | #Cmd8 |
ServerCommandId
Value | Name |
---|---|
1 | LaunchProgram |
2 | Shutdown |
3 | Reboot |
5 | GetReports |
Unofficial names.
Unrecognized commands are handled by just returning 0.
Shutdown/Reboot were added at some point after LaunchProgram, these are present in [9.1.0] (exact version which added these is unknown). These call the SystemApplet Main() func (also used by qlaunch) with a funcptr to call the relevant am IGlobalStateController StartShutdownSequence/StartRebootSequence cmd.
LaunchProgram
This essentially supports launching a specified program (ns:dev, pgl in newer versions) with the input arguments passed to ldr:shel, etc.
The u64 at payload+0 is the ProgramId, while the rest of the data is passed as the ldr:shel arguments buffer (size is determined from the payload size).
This first terminates the previously launched process, if the PID field is still set (TerminateProcess). Then the arguments are passed to ldr:shel (SetProgramArgument), if required FlushArguments is used then SetProgramArgument is used again. Then LaunchProgram is used with the input ProgramId and BuiltInSystem, launch_flags=0x1, and pgl_launch_flags=0x0. Then SetProgramArgument is used to clear the program arguments (empty string is passed).
Then pgl IEventObserver is used to wait on process events. When events Exited/DebugRunning occur for the launched program, TerminateProcess is used with that PID with the stored PID being cleared, then the wait loop exits. Other events result in the wait loop continuing. Event-wait timeout will result in breaking from the loop, without process-termination. The timeout in nanoseconds is 10 days.
Lastly cleanup is done, then the func returns.
GetReports
This was added at some point after Shutdown/Reboot, this is present in [14.0.0] (exact version which added this is unknown). The command payload data contains a s32 path_size, followed by a NUL-terminated string with that size. After loading the input string, a handler func is called with this string.
This essentially loads the error reports from erpt:r (GetReportList and reads each report). Once finished it calls the IPC vfunc for WriteFile with the data buffer, and with the path from: nn::util::SNPrintf(out, 0x100, "%s/%s", inarg_path, tmpstr);
Where tmpstr is from the following earlier: nn::util::SNPrintf(tmpstr, 0x20, "%s%02d.txt", "_report", cur_report_index);
Command
Offset | Size | Description |
---|---|---|
0x0 | 0x8 | Magicnum (0xDEADCAFEDEADCAFE) |
0x8 | 0x4 | CommandId when sent to the remote device, ServerCommandId for received commands. |
0xC | 0x4 | Padding |
0x10 | 0x8 | Payload size |
The payload data with the above size follows.
After WriteFile sends the file-data, it reads an additional Response.
Response
Offset | Size | Description |
---|---|---|
0x0 | 0x8 | Ignored by manu. |
0x8 | 0x4 | Status, non-zero indicates error. |
0xC | 0x4 | Padding |
0x10 | 0x8 | Output value if any. May be returned by the service commands. |
ReadFile additionally returns the requested file-data, followed by another Response.
CommandServerStatus
Offset | Size | Description |
---|---|---|
0x0 | 0x4 | Status, non-zero indicates error. |
CommandServerResponse
Offset | Size | Description |
---|---|---|
0x0 | 0x4 | Status, non-zero indicates error. |
0x4 | 0x4 | Padding |
0x8 | 0x4 | Result from handling the ServerCommandId. |
Notes
There's a total of 3 threads: 2 for the IPC handler threads (which send commands to the remote device and gets the response). And there's the separate nn::manu::CommandServer::RunThread, which receives commands from the remote device and sends replies. This latter thread runs regardless of any service commands being used.