Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

IOCTL Catalog

All file:line citations on this page are into the GPL-2.0 source of aws-neuronx-dkms 2.27.4.0, shipped under /usr/src/aws-neuronx-2.27.4.0/. The command macros are read verbatim from neuron_ioctl.h (876 lines); the handlers from neuron_cdev.c (4043 lines). The source is read directly, not reverse-engineered; every _IOC number is anchored to its #define line and every handler to its function line. Other driver versions renumber lines and add/remove commands. Part — Kernel Driver · back to index

Abstract

This page is the authoritative cross-map of the Neuron driver's ioctl command set: the complete table of every command under magic char 'N' (NEURON_IOCTL_BASE, 0x4E, neuron_ioctl.h:656), its _IOC number and direction, its argument struct and size, the kernel handler it dispatches to, the libnrt/NDL ndl_* caller that issues it, and the gate tier that admits it. It is the reference a reimplementer drives the device from: pick a command, read its row, learn exactly which struct to pack, which fd lane to use, which line in neuron_cdev.c consumes it, and whether DEVICE_INIT ownership is required. The dispatch mechanism — the three-tier gate model, the _IOC_NR/_IOC_SIZE/_IOC_DIR overload-resolution discipline, the *64 sub-gate slip — is owned by the dispatch page and is not re-derived here; this page links to it and tabulates the result.

The command space is 96 distinct macros over a sparse _IOC_NR set {1..135}, grouped into five families: mem (allocation, copy, memset, info, zerocopy — handlers traced by the mem page), dma (engine/queue lifecycle, descriptor I/O, H2T queue management — the dma page), nq (notification-queue init, plus semaphore/event/hw-counter — the nq page), pod (UltraServer membership query/control — the pod/misc page), and misc (device info, version, BDF, topology, PRINTK, the deprecated/stub set). Eleven _IOC_NR values are size-overloaded: two or three differently-sized structs share one nr and direction, demultiplexed kernel-side by exact cmd == or _IOC_SIZE(cmd). The gate tier is one of three: PID (the command is in the npid_is_attached attach allow-list, :3210-3219, so it requires the DEVICE_INIT owner on a non-free-access fd), FA (free-access: reachable on the O_WRONLY misc lane through ncdev_misc_ioctl, :3147, with no attach gate), or none (a non-free-access fd, no attach sub-gate). Every command present kernel-side has a libnrt caller except the deprecated/stub set (DEVICE_INIT/RELEASE/RESET, DMA_ENG_INIT, NOTIFICATIONS_DESTROY_V1/QUEUE_INFO, DMA_QUIESCE_QUEUES).

For this reference, the contract is:

  • The exact command constantnr, direction, and the 32-bit cmd the caller passes (strace-visible), recomputed from the _IOC macro and verified against the #define line.
  • The arg struct and its byte size — what libnrt packs and the handler copy_from_users; for size-overloaded families, every variant.
  • The handler and the caller — the ncdev_* function (file:line) that consumes the command, and the ndl_* userspace caller (@addr, libnrt.so) that issues it.
  • The gate tier and variants — PID / FA / none, plus the V1/V2/*64 sibling set per nr, so a reimplementer knows which fd lane and which struct width each command demands.
Command base'N' = 0x4E (neuron_ioctl.h:656)
Macro spanneuron_ioctl.h:659-874; _IOC_NR set {1..135} sparse, 96 macros
Dispatcherncdev_ioctl (neuron_cdev.c:3188) · misc lane ncdev_misc_ioctl (:3147)
Encodingdir<<30 | size<<16 | 'N'<<8 | nr; ptr-form macros ⇒ _IOC_SIZE = 8 (LP64)
Gate tiersPID (attach allow-list :3210-3219) · FA (free-access misc lane) · none
Size-overloaded nr11 (23, 24, 28, 38, 102, 105, 106, 108, 110, 111, 122, 123)
Userspace caller bandlibnrt.so ndl_* .text 0xc1940..0xc5a30 (NDL)
ConfidenceHIGH — every _IOC macro line and every handler line read verbatim from the shipped source

At a Glance — The Five Families and Their Lanes

The catalogue partitions by family; each family's gate profile is distinctive, and that profile is the first thing a reimplementer needs.

Familynr spanHandler file regionDominant gateNotes
mem21-29, 102, 105, 107-112, 116, 124, 129neuron_cdev.c:416-1426, :2299, :2390PID (alloc/free/copy) + nonesize-overloaded 23/24/28/102/105/108/111; *64 slips the attach gate
dma30-40, 125-126, 133, 135:103-414, :2920-3144PID (control) + none (queries)38 *64 slips the attach gate; DMA_QUIESCE (40) removed
nq / sem / event41-46, 51-54, 58, 61:1428-1476, :1694, :1996-2074PID (NQ init only) + nonesem/event/hw-counter ungated; DESTROY_V1/QUEUE_INFO stubs
pod121-123:2804-2918FA (all three)V1/V2 size-overloaded 122/123; state-changing POD_CTRL on the ungated lane
misc / info1-13, 71-72, 81-93, 100-101, 103-104, 106-107, 110, 113-115, 117-120, 127-128, 130-132, 134scatteredmixed (FA info + none + PID)deprecated stubs at 1/4/5/30/52/58; PRINTK/CRWL/DRIVER_INFO_GET on the FA lane

The dispatch cell (ncdev_ioctl, :3188) routes by exact cmd == for single-variant commands and by _IOC_NR(cmd) == for the size-overloaded families; the dispatch page §3 owns that logic. The columns below name the dispatch line so a row can be cross-checked, but the resolution rule itself is not repeated per row.

Reading a row

  • cmd name — the NEURON_IOCTL_* macro suffix.
  • _IOC nr — the _IOC_NR, exactly as the #define assigns it (header line in the citation).
  • dir_IO (NONE) · _IOR (R) · _IOW (W) · _IOWR (RW), from the macro. Note the driver ignores _IOC_DIR for dispatch except in ncdev_driver_info; several read-back handlers are encoded _IOR yet copy_to_user results — see the dispatch page.
  • arg struct / size — the struct neuron_ioctl_* packed by the caller; size is the C sizeof (LP64, natural packing). Pointer-form macros encode _IOC_SIZE = 8 regardless of the pointed-to struct; struct-form macros encode the struct's sizeof (which is what makes a *64 sibling's cmd differ).
  • kernel handler (file:line) — the ncdev_* function in neuron_cdev.c, plus the dispatch line in parentheses.
  • ndl_* caller — the libnrt NDL function (@addr in libnrt.so) that issues this command, from the DWARF-attributed NDL disassembly.
  • gatePID (attach allow-list :3210-3219) · FA (free-access misc lane) · none.
  • variants — sibling commands sharing the nr (/64, /V2, /V2MT*, _EXT0).

QUIRK — the byte size and the encoded _IOC_SIZE are not always equal. A pointer-form macro — _IOR('N', 21, struct neuron_ioctl_mem_alloc *) — encodes _IOC_SIZE = sizeof(void*) = 8, so its cmd is 0x80084E15 even though the struct it points at is 32 bytes. A struct-form macro — _IOR('N', 23, struct neuron_ioctl_mem_copy64) (no *) — encodes _IOC_SIZE = sizeof(struct) = 40, giving 0x80284E17. This is exactly how the two siblings of an overloaded nr get distinct cmd constants: MEM_COPY is pointer-form (8) and MEM_COPY64 is struct-form (40). The size column below reports the struct size; the cmd-hex in prose reports the encoded value.


Family: mem

Allocation, copy, memset, info queries, and the zero-copy fast path. Handlers traced in the memory page; the security boundary for every copy/memset is mc_access_is_within_bounds (neuron_mempool.h:225). The npid_is_attached attach gate covers MEM_ALLOC, MEM_FREE, MEM_COPY (base), MEM_GET_PA, MEM_COPY_ASYNC (base), MEM_COPY_ASYNC_WAIT, MEM_GET_INFO (:3213-3216); the *64 siblings and the buf-copy/zerocopy/memset families are not in the attach list (they still require a non-free-access fd).

cmd name_IOC nrdirarg struct / sizekernel handler (file:line)ndl_* callergatevariantsConf
MEM_ALLOC21 (:681)Rmem_alloc * / 32ncdev_mem_alloc :416 (:3282)ndl_memory_alloc_cm2 @0xc1a00 (legacy)PIDHIGH
MEM_FREE22 (:684)Rmem_free * / 8ncdev_mem_free :691 (:3292)ndl_memory_free @0xc2ba0PIDHIGH
MEM_COPY23 (:686)Rmem_copy * / 28ncdev_mem_copy :761 (_IOC_NR :3294)ndl_memory_copy_cm @0xc1c30PIDMEM_COPY64HIGH
MEM_COPY6423 (:687)Rmem_copy64 / 40ncdev_mem_copy :761 (_IOC_NR :3294)ndl_memory_copy @0xc2dc0none ×MEM_COPYHIGH
MEM_BUF_COPY24 (:690)RWmem_buf_copy * / 8ncdev_mem_buf_copy :1045 (_IOC_NR :3300)ndl_memory_buf_copy_cm @0xc1b50noneMEM_BUF_COPY64HIGH
MEM_BUF_COPY6424 (:691)RWmem_buf_copy64 / 40ncdev_mem_buf_copy :1045 (_IOC_NR :3300)ndl_memory_buf_copy @0xc24d0noneMEM_BUF_COPYHIGH
MEM_GET_PA25 (:694)Rmem_get_pa * / 8ncdev_mem_get_pa_deprecated :551 (:3290)ndl_memory_get_pa @0xc2a00PIDHIGH
MEM_GET_INFO26 (:696)Rmem_get_info * / 8ncdev_mem_get_info_deprecated :568 (:3288)ndl_memory_map @0xc2a40; ndl_memory_map_contiguous_scratchpad @0xc54d0PIDHIGH
PROGRAM_ENGINE27 (:697)RWprogram_engine * / 8ncdev_program_engine :949 (:3306)ndl_program_engine_cm @0xc2040noneHIGH
MEMSET28 (:699)Rmemset * / 8ncdev_memset :709 (_IOC_NR :3310)ndl_memset_cm @0xc1bc0noneMEMSET64HIGH
MEMSET6428 (:700)Rmemset64 / 32ncdev_memset :709 (_IOC_NR :3310)ndl_memset @0xc2d00noneMEMSETHIGH
MEM_GET_EXTENDED_INFO29 (:705)Rmem_get_extended_info * / 8ncdev_mem_get_extended_info :594 (:3286)(mem layer)noneHIGH
MEM_ALLOC_V2102 (:785)Rmem_alloc_v2 * / 8ncdev_mem_alloc_libnrt :456 (_IOC_NR :3284)ndl_memory_alloc_cm2 @0xc1a00PIDV2MT, V2MT64HIGH
MEM_ALLOC_V2MT102 (:786)Rmem_alloc_v2_mem_type / 48ncdev_mem_alloc_libnrt :456 (_IOC_NR :3284)ndl_memory_alloc @0xc2820PIDV2, V2MT64HIGH
MEM_ALLOC_V2MT64102 (:787)Rmem_alloc_v2_mem_type64 / 56ncdev_mem_alloc_libnrt :456 (_IOC_NR :3284)ndl_alloc_contiguous_scratchpad @0xc53c0PIDV2, V2MTHIGH
PROGRAM_ENGINE_NC105 (:796)RWprogram_engine_nc * / 8ncdev_program_engine_nc :984 (_IOC_NR :3308)ndl_program_engine @0xc2c00nonePROGRAM_ENGINE_NC64HIGH
PROGRAM_ENGINE_NC64105 (:797)RWprogram_engine_nc64 / 40ncdev_program_engine_nc :984 (_IOC_NR :3308)ndl_program_engine @0xc2c00 (size-selected)nonePROGRAM_ENGINE_NCHIGH
DMABUF_FD107 (:806)Rdmabuf_fd * / 24ncdev_get_dmabuf_fd :674 (misc :3158)ndl_get_dmabuf_fd @0xc4ad0FAHIGH
MEM_COPY_ASYNC108 (:809)RWmem_copy_async / 48ncdev_mem_copy_async :823 (_IOC_NR :3296)ndl_memory_copy_as_cm2 @0xc2e90PIDMEM_COPY_ASYNC64HIGH
MEM_COPY_ASYNC64108 (:810)RWmem_copy_async64 / 56ncdev_mem_copy_async :823 (_IOC_NR :3296)ndl_memory_copy_as @0xc2ee0none ×MEM_COPY_ASYNCHIGH
MEM_COPY_ASYNC_WAIT109 (:813)Wmem_copy_async_wait / 24ncdev_mem_copy_async_wait :903 (:3298)ndl_memory_copy_as_wait @0xc3020PIDHIGH
MEM_MC_GET_INFO111 (:820)RWmem_get_mc_mmap_info / 24ncdev_mem_get_mc_mmap_info :628 (_IOC_NR :3358)ndl_mem_get_mc_mmap_info_v1 @0xc1fe0noneMEM_MC_GET_INFO_V2HIGH
MEM_MC_GET_INFO_V2111 (:821)RWmem_get_mc_mmap_info_v2 / 32ncdev_mem_get_mc_mmap_info :628 (_IOC_SIZE :3358)ndl_mem_get_mc_mmap_info @0xc4b70noneMEM_MC_GET_INFOHIGH
RESOURCE_MMAP_INFO112 (:824)RWresource_mmap_info / 32ncdev_resource_mmap_info :2299 (:3360)ndl_mmap_bar_region_ @0xc1df0noneHIGH
DUMP_MEM_CHUNKS116 (:835)Rdump_mem_chunks * / 24ncdev_dump_mem_chunks :2390 (:3364)ndl_dump_device_allocation_info @0xc4e00noneHIGH
MEM_BUF_ZEROCOPY64124 (:852)RWmem_buf_copy64zc / 48ncdev_mem_buf_zerocopy64 :1150 (_IOC_NR :3302)ndl_memory_buf_zerocopy @0xc47c0noneHIGH
MEM_BUF_ZEROCOPY64_BATCHES129 (:861)RWmem_buf_copy64zc_batches / 32ncdev_mem_buf_zerocopy64_batch :1242 (:3304)ndl_memory_buf_batch_copy @0xc5a30noneHIGH

GOTCHA — the rows marked × (MEM_COPY64, MEM_COPY_ASYNC64) carry gate none while their 32-bit base siblings carry PID. This is the *64 sub-gate slip: the attach allow-list tests exact cmd values (cmd == NEURON_IOCTL_MEM_COPY, :3214; cmd == NEURON_IOCTL_MEM_COPY_ASYNC, :3215) but the dispatcher reaches the family by _IOC_NR (:3294, :3296), which is true for both widths. The *64 cmd differs in _IOC_SIZE, so the exact compare is false and npid_is_attached is skipped — a non-DEVICE_INIT opener of a non-free-access fd can issue them. Blast radius is bounded by handle ownership and bounds-checking; full analysis is finding S3 on the attack-surface page. DMA_COPY_DESCRIPTORS64 (dma family) shares the slip.

QUIRK — the V2MT64 allocation struct (mem_alloc_v2_mem_type64, 56 B) is byte-identical to V2MT (48 B) plus a trailing __u32 pad (neuron_ioctl.h:52-62). The pad is never read by ncdev_mem_alloc_libnrt; it exists solely to bump _IOC_SIZE so libnrt can feature-probe whether the driver accepts the wider command — i.e. whether it has >=4GB allocation/copy support. The size column reflects this manufactured difference (8 → 48 → 56 across V2/V2MT/V2MT64). The same idea drives the DRIVER_INFO feature_flags1 capability bitmap (misc family).


Family: dma

Engine and queue lifecycle, descriptor staging, and H2T (host-to-tensor) queue management. Handlers traced in the dma page; they are thin marshalling wrappers that delegate to the ring layer (ndmar_*) and the DMA layer (ndma_*). The attach gate covers DMA_ENG_INIT, DMA_ENG_SET_STATE, DMA_QUEUE_INIT, DMA_ACK_COMPLETED, DMA_QUEUE_RELEASE, DMA_COPY_DESCRIPTORS (base) (:3211-3212); state queries and the H2T family are ungated (still non-free-access).

cmd name_IOC nrdirarg struct / sizekernel handler (file:line)ndl_* callergatevariantsConf
DMA_ENG_INIT30 (:709)Rdma_eng_init * / 8inline return 0 (:3257, deprecated)(none — deprecated)PIDHIGH
DMA_ENG_SET_STATE31 (:712)Rdma_eng_set_state * / 8ncdev_dma_engine_set_state :103 (:3259)ndl_dma_eng_set_state @0xc3670PIDHIGH
DMA_ENG_GET_STATE32 (:714)RWdma_eng_get_state * / 8ncdev_dma_engine_get_state :113 (:3273)ndl_dma_eng_get_state @0xc3690noneHIGH
DMA_QUEUE_INIT33 (:716)Rdma_queue_init * / 8ncdev_dma_queue_init :127 (:3261)ndl_dma_queue_init @0xc3860; ndl_dma_queue_init_batch_cm @0xc1ea0PIDHIGH
DMA_QUEUE_RELEASE34 (:719)Rdma_queue_release * / 8ncdev_dma_queue_release :321 (:3269)ndl_dma_queue_release @0xc3960PIDHIGH
DMA_QUEUE_COPY_START35 (:721)Rdma_queue_copy_start * / 8ncdev_dma_copy_start :281 (:3265)ndl_dma_queue_copy_start @0xc3930noneHIGH
DMA_ACK_COMPLETED36 (:723)Rdma_ack_completed * / 8ncdev_dma_ack_completed :293 (:3267)ndl_dma_ack_completed_desc @0xc3900PIDHIGH
DMA_QUEUE_GET_STATE37 (:725)RWdma_queue_get_state * / 8ncdev_dma_queue_get_state :304 (:3275)ndl_dma_queue_get_state @0xc36c0noneHIGH
DMA_COPY_DESCRIPTORS38 (:727)Rdma_copy_descriptors * / 8ncdev_dma_copy_descriptors :211 (_IOC_NR :3271)ndl_dma_copy_descriptors_cm @0xc1cb0PIDDMA_COPY_DESCRIPTORS64HIGH
DMA_COPY_DESCRIPTORS6438 (:728)Rdma_copy_descriptors64 / 40ncdev_dma_copy_descriptors :211 (_IOC_NR :3271)ndl_dma_copy_descriptors @0xc3980none ×DMA_COPY_DESCRIPTORSHIGH
DMA_DESCRIPTOR_COPYOUT39 (:731)RWdma_descriptor_copyout * / 8ncdev_dma_descriptor_copyout :331 (:3277)ndl_dma_descriptor_copyout @0xc36f0noneHIGH
DMA_QUIESCE_QUEUES40 (:733)Rdma_quiesce_all * / 8removed → -ENOIOCTLCMD (:3279)(none)PIDHIGH
H2T_DMA_ALLOC_QUEUES125 (:854)RWh2t_dma_alloc_queues / 24ncdev_h2t_dma_alloc_queues :2920 (:3370)ndl_h2t_dma_queue_alloc @0xc5600noneHIGH
H2T_DMA_FREE_QUEUES126 (:855)RWh2t_dma_free_queues / 8ncdev_h2t_dma_free_queues :2978 (:3372)ndl_h2t_dma_queue_free @0xc5680noneHIGH
DMA_QUEUE_INIT_BATCH133 (:870)Rdma_queue_init_batch / 12296ncdev_dma_queue_init_batch :180 (:3263)ndl_dma_queue_init_batch @0xc3740noneMED †
GET_ASYNC_H2T_DMA_COMPL_QUEUES135 (:874)RWget_async_h2t_dma_compl_queues / 264ncdev_get_async_h2d_dma_compl_queues :3096 (:3382)ndl_get_async_h2t_dma_compl_queues @0xc5770noneHIGH

GOTCHA — DMA_QUIESCE_QUEUES (nr 40) is listed in the attach allow-list region but the handler is gone: :3279 returns -ENOIOCTLCMD with a "no longer supported" log. A reimplementer hunting for the queue-quiesce semantics will not find a handler — it was removed. DMA_ENG_INIT (nr 30) is likewise a deprecated inline return 0 (:3257) yet stays in the gate list; both are dead arms preserved for ABI stability.

CORRECTION (XMAP-batch) — DMA_QUEUE_INIT_BATCH's real struct is 8 + 256×48 = 12296 bytes (MAX_DMA_QUEUE_INIT_BATCH = 256, neuron_ioctl.h:271), which exceeds the 14-bit _IOC_SIZE field (max 0x3FFF); the encoded size therefore wraps. NDL was observed issuing 0xB0084E85 and falling back to the _cm path on -EINVAL (P1-L-NDL-03). The kernel dispatch matches this command by exact cmd == (:3263), so userspace and kernel agree on the same wrapped constant — the wrap self-cancels. The 12296-byte figure is the true sizeof; the encoded _IOC_SIZE is the wrapped value, hence Conf MED on the exact 32-bit hex (HIGH on the US↔K pairing).


Family: nq / semaphore / event / hw-counter

Notification-queue init (V1 deprecated, V2, V2-with-realloc) plus the multiplexed semaphore, event, and hardware-counter handlers. Traced in the nq page. Only the three NQ-init commands are in the attach gate (:3217-3219); semaphore, event, and READ_HW_COUNTERS are reachable on any non-free-access fd with no attach check.

cmd name_IOC nrdirarg struct / sizekernel handler (file:line)ndl_* callergatevariantsConf
SEMAPHORE_INCREMENT41 (:738)Rsemaphore * / 12ncdev_semaphore_ioctl :1428 (:3316)ndl_nc_semaphore_increment @0xc3ba0noneshares handlerHIGH
SEMAPHORE_DECREMENT42 (:739)Rsemaphore * / 12ncdev_semaphore_ioctl :1428 (:3318)ndl_nc_semaphore_decrement @0xc3bd0noneshares handlerHIGH
SEMAPHORE_READ43 (:740)RWsemaphore * / 12ncdev_semaphore_ioctl :1428 (:3312)ndl_nc_semaphore_read @0xc3c00noneshares handlerHIGH
SEMAPHORE_WRITE44 (:741)Rsemaphore * / 12ncdev_semaphore_ioctl :1428 (:3314)ndl_nc_semaphore_write @0xc3c40noneshares handlerHIGH
EVENT_SET45 (:742)Revent * / 12ncdev_events_ioctl :1457 (:3322)ndl_nc_event_set @0xc3cb0noneshares handlerHIGH
EVENT_GET46 (:743)RWevent * / 12ncdev_events_ioctl :1457 (:3320)ndl_nc_event_get @0xc3c70noneshares handlerHIGH
NOTIFICATIONS_INIT_V151 (:747)Rnotifications_init_v1 * / 24ncdev_nc_nq_init_deprecated :1996 (:3332)(legacy)PID_V2, _REALLOC_V2HIGH
NOTIFICATIONS_DESTROY_V152 (:748)Rnotifications_destroy * / 8inline return 0 (:3338)ndl_notification_destroy @0xc40d0 (munmap)noneHIGH
NOTIFICATIONS_INIT_V253 (:749)Rnotifications_init_v2 * / 48ncdev_nc_nq_init_libnrt :2014 (:3334)ndl_notification_init @0xc3ce0PID_V1, _REALLOC_V2HIGH
NOTIFICATIONS_INIT_WITH_REALLOC_V254 (:750)Rnotifications_init_with_realloc_v2 * / 56ncdev_nc_nq_init_with_realloc_libnrt :2045 (:3336)ndl_notification_init_with_realloc @0xc3ea0PID_V1, _V2HIGH
NOTIFICATIONS_QUEUE_INFO58 (:752)Rnotifications_queue_info * / 12inline return -1 (:3340, stub)(none)noneHIGH
READ_HW_COUNTERS61 (:755)Rread_hw_counters * / 24ncdev_read_hw_counters :1694 (:3342)ndl_read_hw_counters @0xc3630noneHIGH

NOTE — the EVENT_SET/EVENT_GET macros are encoded against struct neuron_ioctl_semaphore * (:742-743) but the handler copy_from_users into struct neuron_ioctl_event (:1462). The two are layout-identical (3 × __u32), so the wire form matches; the handler simply uses a clearer struct name. SEMAPHORE_READ/EVENT_GET are _IOWR (they read a value back); INCREMENT/DECREMENT/WRITE/SET and the NQ-init + READ_HW_COUNTERS are encoded _IOR despite writing back via explicit copy_to_user — the driver dispatches on the full cmd, not _IOC_DIR.

GOTCHA — NOTIFICATIONS_QUEUE_INFO (nr 58) returns a raw -1 (:3340), which surfaces to userspace as -EPERM, not -ENOSYS — a reimplementer probing for "unsupported" on this command sees a permission error, not an unimplemented one. NOTIFICATIONS_DESTROY_V1 (nr 52) is an inline return 0: NQ teardown is implicit on reset/flush, and libnrt's ndl_notification_destroy does the userspace munmap of the ring rather than relying on a kernel destroy.

CORRECTION (nq/counter sizeof) — the size column for NOTIFICATIONS_INIT_WITH_REALLOC_V2 and READ_HW_COUNTERS previously read 52 and 20; those were the unpadded field sums. The true sizeof on LP64 is 56 and 24 (verified gcc -m64): the realloc struct is 9 × __u32 (36) + 4 pad + 2 × __u64 (16) = 56 (neuron_ioctl.h:366-378), where the trailing __u64 mmap_offset forces 8-byte alignment after the odd ninth __u32 force_alloc_mem; read_hw_counters is __u64 * + __u32 * + __u32 count + 4 pad = 24 (:405-409). The handler copy_from_users sizeof(arg) (the padded value), so the kernel reads 56/24. See ioctl-nq §correction, which already documented this and flagged the catalog.


Family: pod

UltraServer / pod membership query and control. All three commands dispatch on the free-access misc lane (:3173-3178), so they are reachable on an O_WRONLY fd with no attach gate. Handlers traced in the pod/misc page; they thunk to the pod-election engine ndhal->ndhal_npe.npe_*. POD_STATUS and POD_CTRL are V1/V2 size-overloaded.

cmd name_IOC nrdirarg struct / sizekernel handler (file:line)ndl_* callergatevariantsConf
POD_INFO121 (:844)RWpod_info / 260ncdev_pod_info :2804 (_IOC_NR misc :3173)ndl_pod_info @0xc4f50FAHIGH
POD_STATUS122 (:846)RWpod_status / 268ncdev_pod_status :2832 (_IOC_NR misc :3175)ndl_pod_mapping_info @0xc5080FAPOD_STATUS_V2HIGH
POD_STATUS_V2122 (:847)RWpod_status_v2 / 276ncdev_pod_status :2832 (cmd == misc :3175)ndl_pod_election_state @0xc4ff0; ndl_pod_status @0xc51b0FAPOD_STATUSHIGH
POD_CTRL123 (:849)RWpod_ctrl / 16ncdev_pod_ctrl :2873 (_IOC_NR misc :3177)ndl_pod_ctrl @0xc5110 (v1)FAPOD_CTRL_V2HIGH
POD_CTRL_V2123 (:850)RWpod_ctrl_v2 / 20ncdev_pod_ctrl :2873 (cmd == misc :3177)ndl_pod_ctrl @0xc5110 (v2)FAPOD_CTRLHIGH

GOTCHA — POD_CTRL is state-changing on the ungated free-access lane. It thunks to npe_pod_ctrl (:2902), which can trigger a pod-election state transition (ctrl ∈ {REQ_POD, REQ_SINGLE_NODE, REQ_KILL, SET_MODE}, neuron_driver_shared.h:38). An O_WRONLY opener that never attached can drive pod control. The V1 path forces mode = NEURON_ULTRASERVER_MODE_UNSET (:2886); V2 carries an explicit mode. This is finding S5/S8-adjacent on the attack-surface page. The V1/V2 split is resolved by _IOC_SIZE (static_assert(POD_CTRL != POD_CTRL_V2), :2875), and the handlers memset the arg after copy_from_user then only honour .sz — all other [in] fields of POD_INFO/POD_STATUS are discarded by design.


Family: misc / info / lifecycle

Device info, version negotiation, BDF, topology discovery, CRWL core reservation, PRINTK, datastore acquire/release, the metric/power/HBM commands, and the deprecated/stub set. This is the largest and most heterogeneous family; gate tier varies per command. The free-access (FA) members are the topology/discovery/diagnostic subset the misc lane was built for; the rest run on the main path (none), with a handful PID-gated.

cmd name_IOC nrdirarg struct / sizekernel handler (file:line)ndl_* callergatevariantsConf
DEVICE_RESET1 (:659)NONEncdev_device_reset_deprecated :1744 (:3227)(none — deprecated)noneHIGH
DEVICE_READY2 (:660)R__u8 / 1ncdev_device_ready_deprecated :1772 (:3229)(legacy)noneorder vs RESET_STATUSHIGH
DEVICE_INFO3 (:663)Rdevice_info * / 80ncdev_device_info :1845 (:3247)ndl_get_board_info fallback @0xc4980noneHIGH
DEVICE_INIT4 (:666)Rdevice_init * / 8inline return 0 (:3249, deprecated)(none)noneHIGH
DEVICE_RELEASE5 (:667)NONEinline return 0 (:3251, deprecated)(none)noneHIGH
DEVICE_APP_PID6 (:670)R__s32 / 4ncdev_app_pid_deprecated :1926 (:3253)(none observed)noneHIGH
DEVICE_GET_ALL_APPS_INFO7 (:671)Rget_apps_info * / 8ncdev_get_all_apps_info :1931 (:3255)ndl_get_all_apps_info @0xc3ad0noneHIGH
BAR_READ11 (:674)Rbar_rw * / 32ncdev_bar_rw(.., true) :1622 (:3324)ndl_bar_read @0xc3590noneHIGH
BAR_WRITE12 (:676)Wbar_rw * / 32ncdev_bar_rw(.., false) (:3326)ndl_bar_write @0xc35e0PIDHIGH
POST_METRIC13 (:678)Wpost_metric * / 8ncdev_post_metric :1657 (:3328)(metrics layer)PIDHIGH
ACQUIRE_NEURON_DS71 (:758)Rneuron_ds_info * / 8ncdev_acquire_neuron_ds :2076 (:3344)ndl_nds_open @0xc4110noneHIGH
RELEASE_NEURON_DS72 (:759)Rneuron_ds_info * / 8ncdev_release_neuron_ds :2098 (:3346)ndl_nds_close @0xc41b0noneHIGH
CRWL_READER_ENTER81 (:762)Wcrwl * / 36ncdev_crwl_reader_enter :2109 (:3348)ndl_crwl_reader_enter @0xc4200noneHIGH
CRWL_READER_EXIT82 (:763)Wcrwl * / 36ncdev_crwl_reader_exit :2121 (:3350)ndl_crwl_reader_exit @0xc4240noneHIGH
CRWL_WRITER_ENTER83 (:764)Wcrwl * / 36ncdev_crwl_writer_enter :2133 (:3352)ndl_crwl_writer_enter @0xc4280noneHIGH
CRWL_WRITER_DOWNGRADE84 (:765)Wcrwl * / 36ncdev_crwl_writer_downgrade :2145 (:3354)ndl_crwl_writer_downgrade @0xc42c0noneHIGH
CRWL_NC_RANGE_MARK85 (:766)Wcrwl_nc_map * / 24ncdev_crwl_nc_range_mark :2163 (misc :3148)ndl_crwl_nc_range_mark @0xc4300FA_EXT0HIGH
CRWL_NC_RANGE_MARK_EXT085 (:767)RWcrwl_nc_map_ext / 80ncdev_crwl_nc_range_mark :2163 (misc :3148)ndl_crwl_nc_range_mark @0xc4300FAMARKHIGH
CRWL_NC_RANGE_UNMARK86 (:768)Wcrwl_nc_map * / 24ncdev_crwl_nc_range_unmark :2220 (misc :3150)ndl_crwl_nc_range_unmark @0xc4420FA_EXT0HIGH
CRWL_NC_RANGE_UNMARK_EXT086 (:769)Wcrwl_nc_map_ext / 80ncdev_crwl_nc_range_unmark :2220 (misc :3150)ndl_crwl_nc_range_unmark @0xc4420FAUNMARKHIGH
CINIT_SET_STATE91 (:772)Wcinit_set * / 8ncdev_cinit_set_state :2256 (:3243)ndl_nc_init_set_state @0xc4900noneHIGH
NC_MODEL_STARTED_COUNT92 (:773)Wnc_model_started_count * / 8ncdev_nc_model_started_count :2273 (:3245)ndl_nc_model_started_count @0xc4940noneHIGH
COMPATIBLE_VERSION93 (:776)Wcompatible_version * / 8ncdev_compatible_version :2321 (misc :3152)ndl_get_compatible_version @0xc2770FAHIGH
DEVICE_BASIC_INFO100 (:779)Wdevice_basic_info * / 8ncdev_device_basic_info :1790 (misc :3154)ndl_get_board_info @0xc4980FAHIGH
DEVICE_BDF101 (:782)Rdevice_bdf * / 8ncdev_device_bdf :1797 (:3356)ndl_get_device_bdf @0xc4a80noneHIGH
NC_RESET103 (:790)Rdevice_reset * / 8ncdev_nc_reset :1726 (:3241)ndl_reset_ncs @0xc3a50noneHIGH
NC_RESET_READY104 (:793)Rdevice_ready * / 8ncdev_nc_reset_ready :1757 (:3237)ndl_ready_ncs @0xc3a90noneHIGH
DEVICE_RESET_STATUS106 (:800)R__u8 / 1ncdev_reset_status_deprecated :1751 (:3239)(none — deprecated)noneBDF_EXT (NR-collision)HIGH
DEVICE_BDF_EXT106 (:803)Rdevice_bdf_ext * / 8ncdev_device_bdf_ext :1806 (misc :3156)ndl_get_device_bdf_ext @0xc4b00FARESET_STATUS (NR-collision)HIGH
DRIVER_INFO_GET110 (:816)Rdevice_driver_info / 24ncdev_driver_info :1896 (_IOC_NR misc :3163)ndl_feature_supported @0xc22d0FASET (_IOC_DIR)HIGH
DRIVER_INFO_SET110 (:817)Wdevice_driver_info / 24ncdev_driver_info :1896 (→ -ENOTSUPP)(none observed)PID †GET (_IOC_DIR)HIGH
PRINTK113 (:827)Wprintk / 16ncdev_printk :2333 (misc :3165)ndl_printk @0xc4ca0; ndl_printk_cm @0xc1960FAHIGH
HOST_DEVICE_ID114 (:830)Rhost_device_id / 4ncdev_get_host_device_id :2362 (:3362)ndl_get_host_device_id @0xc4d20noneHIGH
HOST_DEVICE_ID_TO_RID_MAP115 (:833)RWhost_device_id_to_rid_map / 260ncdev_host_device_id_to_rid_map :2376 (_IOC_NR misc :3167)ndl_get_host_device_id_to_rid_map @0xc4d50FAHIGH
NC_PID_STATE_DUMP117 (:837)RWnc_pid_state_dump / 16ncdev_nc_pid_state_dump :2454 (misc :3169)ndl_dump_nc_pid_info @0xc4e50FAHIGH
HBM_SCRUB_START118 (:839)RWhbm_scrub_start / 16ncdev_hbm_scrub_start :2498 (:3366)ndl_hbm_scrub_start @0xc4e90noneHIGH
HBM_SCRUB_WAIT119 (:840)RWhbm_scrub_wait / 8ncdev_hbm_scrub_wait_for_cmpl :2681 (:3368)ndl_hbm_scrub_wait @0xc4f10noneHIGH
GET_LOGICAL_TO_PHYSICAL_NC_MAP120 (:842)RWget_logical_to_physical_nc_map / 16ncdev_logical_to_physical_nc_map :2753 (misc :3171)ndl_get_logical_to_physical_nc_map @0xc27b0FAHIGH
POWER_PROFILE127 (:857)Wpower_profile / 8ncdev_power_profile_set :3005 (:3374)ndl_set_performance_profile @0xc58c0noneHIGH
METRICS_CTRL128 (:859)Wmetrics_ctrl / 4ncdev_metric_ctrl :1682 (:3330)ndl_metrics_ctrl @0xc5a00noneHIGH
THROTTLING_NOTIFICATIONS130 (:863)Wthrottling_notifications / 4ncdev_throttling_notifications_set :3063 (:3378)ndl_enable_throttling_notifications @0xc5950noneHIGH
GET_VA_PLACEMENT131 (:865)Wget_va_placement / 16ncdev_get_va_placement :3075 (misc :3179)ndl_get_va_placement @0xc5af0FAHIGH
GET_PERFORMANCE_PROFILE132 (:867)RWpower_profile / 8ncdev_power_profile_get :3023 (:3376)ndl_get_performance_profile @0xc5900noneHIGH
AVAILABLE_PERF_PROFILES134 (:872)RWavailable_perf_profiles / 36ncdev_available_perf_profiles :3046 (:3380)ndl_get_supported_profiles @0xc5980noneHIGH

QUIRK — nr 106 is a genuine _IOC_NR collision: DEVICE_RESET_STATUS (__u8, size 1, :800) and DEVICE_BDF_EXT (ptr, size 8, :803) share it. They are disambiguated by both _IOC_SIZE (different cmd constants) and access-mode lane: RESET_STATUS is matched by exact cmd on the main path (:3239), BDF_EXT by exact cmd on the misc lane (:3156). Separately, DEVICE_READY (nr 2) must be tested before RESET_STATUS (:3229 ahead of :3239) because older drivers assigned both to ioctl 2; the dispatch order preserves the legacy contract. Neither collision is ambiguous as shipped — see dispatch §3.

NOTE — DRIVER_INFO (nr 110) is the lone command keyed on _IOC_DIR. GET (_IOR, :816) is dispatched in the misc lane by _IOC_NR (:3163) and so is reachable free-access; SET (_IOW, :817) is in the attach allow-list (:3218) on the main path, but ncdev_driver_info returns -ENOTSUPP for the write direction (:1902-1903) — so SET is effectively unimplemented regardless of lane. The on the gate marks this dir-demux: a SET-form cmd arriving on a free-access fd reaches ncdev_driver_info by _IOC_NR and is rejected by _IOC_DIR. The GET response advertises feature_flags1 = 0x1FF (all nine capability bits, :1912-1916) with version = 0.

GOTCHA — the FA rows in this family are the free-access lane's full membership: CRWL_NC_RANGE_MARK/UNMARK (+_EXT0), COMPATIBLE_VERSION, DEVICE_BASIC_INFO, DEVICE_BDF_EXT, DMABUF_FD (mem family), DRIVER_INFO_GET, PRINTK, HOST_DEVICE_ID_TO_RID_MAP, NC_PID_STATE_DUMP, GET_LOGICAL_TO_PHYSICAL_NC_MAP, POD_INFO/STATUS/CTRL (pod family), GET_VA_PLACEMENT. Most are read-only topology/info, but CRWL_NC_RANGE_MARK/UNMARK mutate the device-spanning core-reservation map and PRINTK carries the size-0 OOB stack-read bug (finding S1). A reimplementation that treats "O_WRONLY ⇒ harmless query" is wrong — see attack-surface §1.

CORRECTION (crwl sizeof) — the size column for the four CRWL_{READER,WRITER}_* rows and the two CRWL_NC_RANGE_{MARK,UNMARK} rows previously read 8 (the pointer-form encoded _IOC_SIZE), which violates this page's convention (§"Reading a row": the size column reports the struct sizeof). The pointed-to structs are 36 and 24 (verified gcc -m64): struct neuron_ioctl_crwl { __u32 nc_id; struct neuron_uuid uuid; } = 4 + 32 = 36 (neuron_ioctl.h:411-414, neuron_uuid = __u8[32] at share/neuron_driver_shared.h:150-152); struct neuron_ioctl_crwl_nc_map = 4 × __u32 (16) + volatile long unsigned int bitmap (8) = 24 (:416-422). The _EXT0 row's 80 (= 4 × __u32 + long unsigned int bitmap[8], :424-430) was already struct-form and is unchanged.


Cross-References

  • IOCTL Dispatch and the Privilege-Gate Model — the dispatch mechanism this catalogue tabulates: the three-tier gate model, _IOC_NR/_IOC_SIZE/_IOC_DIR overload resolution, and the *64 sub-gate slip (not re-derived here)
  • Memory IOCTL Handlers — per-handler detail for the mem family: mem_chunk lifecycle, the 2-level handle table, mc_access_is_within_bounds, and the BAR4 zero-copy path
  • DMA IOCTL Handlers — per-handler detail for the dma family: ring/queue lifecycle, descriptor staging, and the H2T queue-management commands
  • NQ and Semaphore IOCTL Handlers — per-handler detail for NQ init (V1/V2/realloc), the multiplexed semaphore/event handlers, and READ_HW_COUNTERS
  • Pod and Misc IOCTL Handlers — per-handler detail for the pod family and the misc info/version/BDF/topology commands
  • The IOCTL Attack Surface (14 Findings) — the security projection of this catalogue: which gate tier admits each finding (the *64 slip S3, the ungated free-access state-changers S5/S8, the PRINTK OOB read S1)