The Switch makes use of a customized NVIDIA driver.

nvdrv:a

Main NVIDIA driver service.

Cmd Name
0 #Open
1 #Ioctl
2 #Close
3 #Initialize
4 QueryEvent
5 MapSharedMem
6 ?
7 ?
8 BindDisplayService
9 ?

Open

Word Value
0 0x00100004
1 0x00000008
2-4 Type 5 descriptor: Device path
0-1 "SFCI"
2-3 Cmd id (0)

Ioctl

Word Value
0 0x11100004
1 0x00000C0B
? Type 0x21 descriptor: Input buffer
? Type 0x22 descriptor: Output buffer
0-1 "SFCI"
2-3 Cmd id (1)
4 Device fd
5 Ioctl Cmd

Close

Word Value
0 0x00000004
1 0x00000009
0-1 "SFCI"
2-3 Cmd id (2)
4 Device fd

Initialize

Word Value
0 0x00000004
1 0x80000009
? Handle descriptor: Current process
? Handle descriptor: Shared memory mirror
0-1 "SFCI"
2-3 Cmd id (3)
4 Shared memory size

Webkit applet creates the shared memory with perm = 0 and size 0x300000.

Ioctls

The ioctl number is generated with the following primitive (see Linux kernel):

#define _IOC(inout, group, num, len) \
   (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num))

The following table contains known ioctls.

/dev/nvhost-ctrl

Value Direction Size Description Notes
0xC0080014 Inout 8 NVHOST_IOCTL_CTRL_SYNCPT_READ
0x40040015 In 4 NVHOST_IOCTL_CTRL_SYNCPT_INCR
0xC00C0016 Inout 12 NVHOST_IOCTL_CTRL_SYNCPT_WAIT
0x40080017 In 8 NVHOST_IOCTL_CTRL_MODULE_MUTEX
0xC0180018 Inout 24 NVHOST32_IOCTL_CTRL_MODULE_REGRDWR
0xC0100019 Inout 16 NVHOST_IOCTL_CTRL_SYNCPT_WAITEX
0xC008001A Inout 8 NVHOST_IOCTL_CTRL_SYNCPT_READ_MAX
0xC004001C Inout 4
0xC010001D Inout 16 NvRmSyncWaitEvent (wait on event?)
0xC010001E Inout 16 NvRmSyncWaitEvent (wait on event?)
0xC004001F Inout 4 NvRmSyncWaitEvent (signal event?)
0xC0040020 Inout 4 NvRmSyncWaitEvent (signal event?)
0x40080021 In 8 cancel_wait_event Cancels all events

/dev/nvhost-as-gpu

Each fd opened to this device creates an address space. An address space is then later bound with a channel.

Once a nvgpu channel has been bound to an address space it cannot be unbound. There is no support for allowing an nvgpu channel to change from one address space to another (or from one to none).

Device Direction Size Value Description Notes
/dev/nvhost-as-gpu In 4 0x40044101 #NVGPU_AS_IOCTL_BIND_CHANNEL
/dev/nvhost-as-gpu Inout 24 0xC0184102 #NVGPU_AS_IOCTL_ALLOC_SPACE
/dev/nvhost-as-gpu Inout 16 0xC0104103 #NVGPU_AS_IOCTL_FREE_SPACE
/dev/nvhost-as-gpu Inout 24 0xC0184104 #NVGPU_AS_IOCTL_MAP_BUFFER
/dev/nvhost-as-gpu Inout 8 0xC0084105 #NVGPU_AS_IOCTL_UNMAP_BUFFER
/dev/nvhost-as-gpu Inout 40 0xC0284106 NVGPU_AS_IOCTL_MAP_BUFFER_EX
/dev/nvhost-as-gpu In 16 0x40104107 #NVGPU_AS_IOCTL_INITIALIZE
/dev/nvhost-as-gpu Inout 64 0xC0404108 #NVGPU_AS_IOCTL_GET_VA_REGIONS
/dev/nvhost-as-gpu In 40 0x40284109 #NVGPU_AS_IOCTL_INITIALIZE_EX
/dev/nvhost-as-gpu Inout 20 0xC0144114

NVGPU_AS_IOCTL_BIND_CHANNEL

Identical to Linux driver.

 struct {
   u32 __fd; // in
 };

NVGPU_AS_IOCTL_ALLOC_SPACE

This one reserves pages in the device address space.

 struct {
   u32 __pages;     // in
   u32 __page_size; // in
   u32 __flags;     // in
   u32 __pad;
   union {
     u64 __offset;  // out
     u64 __align;   // in
   };
 };

NVGPU_AS_IOCTL_FREE_SPACE

 struct {
   u64 __offset;    // in
   u32 __pages;     // in
   u32 __page_size; // in
 };

NVGPU_AS_IOCTL_MAP_BUFFER

Map a memory region in the device address space. Identical to Linux driver pretty much.

On success, the mapped memory region is locked by having SVC#MemoryState bit34 set.

 struct {
   u32 __flags;        // in, 4 works
   u32 __reserved;
   u32 __nvmap_handle; // in
   u32 __page_size;    // inout, 0 means don't care
   union {
     u64 __offset;     // out
     u64 __align;      // in
   };
 };

NVGPU_AS_IOCTL_UNMAP_BUFFER

Doesn't do shit.

NVGPU_AS_IOCTL_INITIALIZE

Nintendo custom.

 struct {
   u32 __size;       // in (must be aligned to 0x10000; 0=default)
   u32 __zeroes[3];  // in
 };

NVGPU_AS_IOCTL_GET_VA_REGIONS

Nintendo modified heavily.

 struct va_region {
   u64 __offset;
   u32 __page_size;
   u32 __reserved;
   u64 __pages;
 };
 
 struct {
   u64              __not_used;
   u32              __bufsize;    // inout, forced to 2*sizeof(struct va_region)
   u32              __reserved;
   struct va_region __regions[2]; // out
 };

NVGPU_AS_IOCTL_INITIALIZE_EX

Nintendo custom.

 struct {
   u32 __size; // in (must be aligned to 0x10000; 0=default)
   u32 __pad0;
   u32 __unk0; // in
   u32 __pad1;
   u64 __unk1; // in
   u64 __unk2; // in
   u64 __unk3; // in
 };

/dev/nvmap

Value Direction Size Description Notes
0xC0080101 Inout 8 #NVMAP_IOC_CREATE
0x00000102 - 0 NVMAP_IOC_CLAIM Returns NotSupported
0xC0080103 Inout 8 #NVMAP_IOC_FROM_ID
0xC0200104 Inout 32 #NVMAP_IOC_ALLOC
0xC0180105 Inout 24 #NVMAP_IOC_FREE
0xC0280106 Inout 40 NVMAP_IOC_MMAP Returns NotSupported
0xC0280107 Inout 40 NVMAP_IOC_WRITE Returns NotSupported
0xC0280108 Inout 40 NVMAP_IOC_READ Returns NotSupported
0xC00C0109 Inout 12 #NVMAP_IOC_PARAM
0xC010010A Inout 16 NVMAP_IOC_PIN_MULT Returns NotSupported
0xC010010B Inout 16 NVMAP_IOC_UNPIN_MULT Returns NotSupported
0xC008010C Inout 8 NVMAP_IOC_CACHE Returns NotSupported
0xC004010D Inout 4 Returns NotSupported
0xC008010E Inout 8 #NVMAP_IOC_GET_ID
0xC004010F Inout 4 Returns NotSupported
0x40040110 In 4 Returns NotSupported
0x00000111 - 0 Returns NotSupported

NVMAP_IOC_CREATE

Creates an nvmap object. Identical to Linux driver.

 struct {
   u32 __size;   // in
   u32 __handle; // out
 };

NVMAP_IOC_FROM_ID

Get handle to an existing nvmap object. Identical to Linux driver.

 struct {
   u32 __id;     // in
   u32 __handle; // out
 };

NVMAP_IOC_ALLOC

Allocate memory for the nvmap object. Nintendo extended this one with 16 bytes, and changed it from in to inout.

 struct {
   u32 __handle;   // in
   u32 __heapmask; // in
   u32 __flags;    // in (0=read-only, 1=read-write)
   u32 __align;    // in
   u8  __unk0;     // in
   u8  __pad[7];
   u64 __addr;     // in
 };

NVMAP_IOC_FREE

This one is completely custom. Partly because the Linux driver passed the handle as the ioctl "arg-ptr", and HIPC can't handle that voodoo.

 struct {
   u32 __handle;   // in
   u32 __pad;
   u64 __refcount; // out
   u32 __size;     // out
   u32 __flags;    // out, 1=NOT_FREED_YET
 };

NVMAP_IOC_PARAM

Returns info about a nvmap object. Identical to Linux driver, but extended with further params.

 struct {
   u32 __handle; // in
   u32 __param;  // in, 1=SIZE, 2=ALIGNMENT, 3=BASE (returns error), 4=HEAP (always 0x40000000), 5=KIND, 6=COMPR (unused)
   u32 __result; // out
 };

NVMAP_IOC_GET_ID

Returns an id for a nvmap object. Identical to Linux driver.

 struct {
   u32 __id;     // out
   u32 __handle; // in
 };

/dev/nvhost-ctrl-gpu

This device is for global (context independent) operations on the gpu.

Value Direction Size Description Notes
0x80044701 Out 4 NVGPU_GPU_IOCTL_ZCULL_GET_CTX_SIZE
0x80284702 Out 40 NVGPU_GPU_IOCTL_ZCULL_GET_INFO
0x402C4703 In 44 NVGPU_GPU_IOCTL_ZBC_SET_TABLE
0xC0344704 Inout 52 NVGPU_GPU_IOCTL_ZBC_QUERY_TABLE
0xC0B04705 Inout 176 NVGPU_GPU_IOCTL_GET_CHARACTERISTICS
0xC0184706 Inout 24 NVGPU_GPU_IOCTL_GET_TPC_MASKS
0x40084707 In 8 NVGPU_GPU_IOCTL_OPEN_CHANNEL
0x4008470E In 8
0x4010470F In 16
0xC0084710 Inout 8
0x80084711 Out 8
0x80084712 Out 8
0xC0044713 Inout 4
0x80084714 Out 8
0x80044715 Out 4
0x8018471A Out 24
0xC008471B Inout 8
0xC010471C Inout 16

Channels

Channels are a concept for NVIDIA hardware blocks that share a common interface.

Path Name
/dev/nvhost-gpu
/dev/nvhost-vic
/dev/nvhost-nvdec
/dev/nvhost-nvjpg

Channel Ioctls

Value Size Description Notes
0xC0??0001 Variable NVHOST_IOCTL_CHANNEL_SUBMIT
0xC0080002 8 NVHOST_IOCTL_CHANNEL_GET_SYNCPOINT
0xC0080003 8 NVHOST_IOCTL_CHANNEL_GET_WAITBASE
0xC0080004 8 NVHOST_IOCTL_CHANNEL_SET_TIMEOUT_EX
0x40040007 4
0xC0??0009 Variable NVHOST_IOCTL_CHANNEL_MAP_BUFFER
0xC0??000A Variable NVHOST_IOCTL_CHANNEL_UNMAP_BUFFER
0x00000013 0
0x40044801 4 #NVGPU_IOCTL_CHANNEL_SET_NVMAP_FD
0x40044803 4 NVGPU_IOCTL_CHANNEL_SET_PRIORITY
0x40084805 8 #NVGPU_IOCTL_CHANNEL_ALLOC_GPFIFO
0xC0044807 4 NVGPU_IOCTL_CHANNEL_CYCLE_STATS
0xC0??4808 Variable #NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO
0xC0104809 16 #NVGPU_IOCTL_CHANNEL_ALLOC_OBJ_CTX
0xC010480B 16 NVGPU_IOCTL_CHANNEL_ZCULL_BIND
0xC018480C 24 #NVGPU_IOCTL_CHANNEL_SET_ERROR_NOTIFIER
0x4004480D 4 #NVGPU_IOCTL_CHANNEL_OPEN
0x0000480E 0 #NVGPU_IOCTL_CHANNEL_ENABLE
0x0000480F 0 #NVGPU_IOCTL_CHANNEL_DISABLE
0x00004810 0 #NVGPU_IOCTL_CHANNEL_PREEMPT
0x00004811 0 #NVGPU_IOCTL_CHANNEL_FORCE_RESET
0x40084812 8 #NVGPU_IOCTL_CHANNEL_EVENTS_CTRL
0xC0104813 16 NVGPU_IOCTL_CHANNEL_CYCLE_STATS_SNAPSHOT
0x80804816 128 Only works when the channel is busy
0xC0104817 16 #NVGPU_IOCTL_CHANNEL_GET_ERROR
0x40204818 32 #NVGPU_IOCTL_CHANNEL_ALLOC_GPFIFO_EX
0xC0??4819 Variable #NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO_EX
0xC020481A 32 #NVGPU_IOCTL_CHANNEL_ALLOC_GPFIFO_EX2
0x40084714 8 set_user_address Sets an unknown user context address
0x80084715 8 get_user_address Gets an unknown user context address

NVGPU_IOCTL_CHANNEL_SET_NVMAP_FD

Binds a nvmap object to this channel. Identical to Linux driver.

 struct {
   u32 __nvmap_fd;     // in
 };

NVGPU_IOCTL_CHANNEL_ALLOC_GPFIFO

Allocates gpfifo entries. Identical to Linux driver.

 struct {
   u32 __num_entries;     // in
   u32 __flags;           // in
 };

NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO

Submits a gpfifo object. Modified to take inline fence objects instead of a pointer.

 struct fence {
   u32 __id;
   u32 __value;
 };

 struct {
   u64 __gpfifo;              // in (pointer to gpfifo fence structs; ignored)
   u32 __num_entries;         // in (number of fence objects being submitted)
   u32 __flags;               // in
   struct fence __fence_out;  // out (returned new fence object for others to wait on)
   struct fence __fence[];    // in (fence objects; depends on __num_entries)
 };

NVGPU_IOCTL_CHANNEL_ALLOC_OBJ_CTX

Allocates a graphics context object. Modified to ignore object's ID.

 struct {
   u32 __class_num;    // in (0xB197=2d, 0xB1C0=compute, 0xA140=kepler, 0xB0B5=DMA, 0xB06F=channel_gpfifo)
   u32 __flags;        // in
   u64 __obj_id;       // out (ignored; used for FREE_OBJ_CTX ioctl, which is not supported)
 };

NVGPU_IOCTL_CHANNEL_SET_ERROR_NOTIFIER

Initializes the error notifier for this channel. Identical to Linux driver.

 struct {
   u64 __offset;    // in
   u64 __size;      // in
   u32 __mem;       // in (nvmap object handle)
   u32 __padding;   // in
 };

NVGPU_IOCTL_CHANNEL_OPEN

Opens the current channel. Unused and takes an unknown argument.

 struct {
   u32 __unk;    // in (only accepts 0x32, 0x64 or 0x96)
 };

NVGPU_IOCTL_CHANNEL_ENABLE

Enables the current channel. Identical to Linux driver.

NVGPU_IOCTL_CHANNEL_DISABLE

Disables the current channel. Identical to Linux driver.

NVGPU_IOCTL_CHANNEL_PREEMPT

Clears the FIFO pipe for this channel. Identical to Linux driver.

NVGPU_IOCTL_CHANNEL_FORCE_RESET

Forces the channel to reset. Identical to Linux driver.

NVGPU_IOCTL_CHANNEL_EVENTS_CTRL

Controls event notifications. Modified to take an additional argument.

 struct {
   u32 __cmd;    // in (0=disable, 1=enable, 2=clear)
   u32 __unk;    // in (accepts 1 or 2)
 };

NVGPU_IOCTL_CHANNEL_GET_ERROR

Returns the current error notification caught by the error notifier. Exclusive to the Switch.

 struct {
   u64 __timestamp;    // out (nanoseconds since Jan. 1, 1970)
   u32 __info32;       // out (error code)
   u16 __info16;       // out (additional error info)
   u16 __status;       // out (always 0xFFFF)
 };

NVGPU_IOCTL_CHANNEL_ALLOC_GPFIFO_EX

Allocates gpfifo entries with additional parameters. Exclusive to the Switch.

 struct {
   u32 __num_entries;     // in
   u32 __flags;           // in
   u32 __unk0;            // in (1 works)
   u32 __unk1;            // in
   u32 __unk2;            // in
   u32 __unk3;            // in
   u32 __unk4;            // in
   u32 __unk5;            // in
 };

NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO_EX

Submits a gpfifo object (async version). Exclusive to the Switch.

 struct fence {
   u32 __id;
   u32 __value;
 };

 struct {
   u64 __gpfifo;              // in (pointer to gpfifo fence structs; ignored)
   u32 __num_entries;         // in (number of fence objects being submitted)
   u32 __flags;               // in
   struct fence __fence_out;  // out (returned new fence object for others to wait on)
   struct fence __fence;      // in (fence objects; depends on __num_entries)
   ...
 };

NVGPU_IOCTL_CHANNEL_ALLOC_GPFIFO_EX2

Allocates gpfifo entries with additional parameters and returns a fence. Exclusive to the Switch.

 struct fence {
   u32 __id;
   u32 __value;
 };

 struct {
   u32 __num_entries;         // in
   u32 __flags;               // in
   u32 __unk0;                // in (1 works)
   struct fence __fence_out;  // out
   u32 __unk1;                // in
   u32 __unk2;                // in
   u32 __unk3;                // in
 };

Remaining Ioctls

Value Size Description Notes
/dev/nvhost-dbg-gpu 0x40084401 NVGPU_DBG_GPU_IOCTL_BIND_CHANNEL
/dev/nvhost-dbg-gpu 0xC0??4402 NVGPU_DBG_GPU_IOCTL_REG_OPS ?? == size is unknown
/dev/nvhost-dbg-gpu 0x40084403 NVGPU_DBG_GPU_IOCTL_EVENTS_CTRL
/dev/nvhost-dbg-gpu 0x40044404 NVGPU_DBG_GPU_IOCTL_POWERGATE
/dev/nvhost-dbg-gpu 0x40044405 NVGPU_DBG_GPU_IOCTL_SMPC_CTXSW_MODE
/dev/nvhost-dbg-gpu 0xC0184407 NVGPU_DBG_GPU_IOCTL_PERFBUF_MAP
/dev/nvhost-dbg-gpu 0x40084408 NVGPU_DBG_GPU_IOCTL_PERFBUF_UNMAP
/dev/nvhost-dbg-gpu 0x40084409 NVGPU_DBG_GPU_IOCTL_PC_SAMPLING

nvmemp

NVIDIA memory profiler (this service is not available on retail units).

mm:u

NVIDIA multimedia (NvMM) platform service.

Cmd Name
0 ?
1 ?
2 ?
3 ?
4 module_init_clk
5 module_deinit_clk
6 module_set_clk_rate
7 module_get_clk_rate

Errors

Most nvidia driver commands return an error code apart from the normal return code.

Cmd Name
0 Success
1 NotImplemented
2 NotSupported
3 NotInitialized
4 BadParameter
5 Timeout
6 InsufficientMemory
7 ReadOnlyAttribute
8 InvalidState
9 InvalidAddress
0xA InvalidSize
0xB BadValue
0xD AlreadyAllocated
0xE Busy
0xF ResourceError
0x10 CountMismatch
0x1000 SharedMemoryTooSmall
0x30003 FileOperationFailed
0x3000F IoctlFailed