Linux cryptographic layer development
 help / color / mirror / Atom feed
From: Saravanakrishnan Krishnamoorthy <skrishnamoorthy@rambus.com>
To: Albert Ou <aou@eecs.berkeley.edu>,
	Alex Ousherovitch <aousherovitch@rambus.com>,
	Conor Dooley <conor+dt@kernel.org>,
	"David S. Miller" <davem@davemloft.net>,
	Herbert Xu <herbert@gondor.apana.org.au>,
	Jonathan Corbet <corbet@lwn.net>,
	Krzysztof Kozlowski <krzk+dt@kernel.org>,
	Palmer Dabbelt <palmer@dabbelt.com>,
	Paul Walmsley <pjw@kernel.org>, Rob Herring <robh@kernel.org>,
	Saravanakrishnan Krishnamoorthy <skrishnamoorthy@rambus.com>,
	Shuah Khan <shuah@kernel.org>
Cc: Alexandre Ghiti <alex@ghiti.fr>,
	devicetree@vger.kernel.org,
	Joel Wittenauer <Joel.Wittenauer@cryptography.com>,
	linux-api@vger.kernel.org, linux-crypto@vger.kernel.org,
	linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-kselftest@vger.kernel.org, linux-riscv@lists.infradead.org,
	Shuah Khan <skhan@linuxfoundation.org>,
	Thi Nguyen <thin@rambus.com>
Subject: [PATCH v3 17/19] Documentation: ioctl: add CMH ioctl documentation and register 'J'
Date: Thu,  6 Aug 2026 12:55:16 -0700	[thread overview]
Message-ID: <20260806195519.2703224-18-skrishnamoorthy@rambus.com> (raw)
In-Reply-To: <20260806195519.2703224-1-skrishnamoorthy@rambus.com>

From: Alex Ousherovitch <aousherovitch@rambus.com>

Add Documentation/userspace-api/ioctl/cmh_mgmt.rst documenting the
ioctl commands on the /dev/cmh_mgmt misc device for the Rambus
CryptoManager Hub (CMH) hardware crypto accelerator driver.  Covers
key management, KIC key derivation, PKE (RSA, ECDSA, ECDH, EdDSA),
PQC (ML-KEM, ML-DSA, SLH-DSA), SM2, EAC, and DRBG.  Link the page
into the userspace-api/ioctl index toctree.

Register ioctl magic number 'J' (0x4A) in ioctl-number.rst.  The
driver uses ioctls 0x01-0x40.

Co-developed-by: Saravanakrishnan Krishnamoorthy <skrishnamoorthy@rambus.com>
Signed-off-by: Saravanakrishnan Krishnamoorthy <skrishnamoorthy@rambus.com>
Signed-off-by: Alex Ousherovitch <aousherovitch@rambus.com>
Reviewed-by: Joel Wittenauer <Joel.Wittenauer@cryptography.com>
Reviewed-by: Thi Nguyen <thin@rambus.com>
---
 .../userspace-api/ioctl/cmh_mgmt.rst          | 1295 +++++++++++++++++
 Documentation/userspace-api/ioctl/index.rst   |    1 +
 .../userspace-api/ioctl/ioctl-number.rst      |    1 +
 3 files changed, 1297 insertions(+)
 create mode 100644 Documentation/userspace-api/ioctl/cmh_mgmt.rst

diff --git a/Documentation/userspace-api/ioctl/cmh_mgmt.rst b/Documentation/userspace-api/ioctl/cmh_mgmt.rst
new file mode 100644
index 000000000000..d17a77975df6
--- /dev/null
+++ b/Documentation/userspace-api/ioctl/cmh_mgmt.rst
@@ -0,0 +1,1295 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=============================================
+CMH Key Management ioctl Interface (cmh_mgmt)
+=============================================
+
+:Author: Cryptography Research, Inc. (CRI)
+:Maintainer: linux-crypto@vger.kernel.org
+
+Introduction
+============
+
+The ``/dev/cmh_mgmt`` character device provides user-space access to key
+management, key derivation, public-key, and post-quantum cryptographic
+operations on the CryptoManager Hub (CMH) hardware accelerator.
+
+The device is created by the ``cmh`` kernel module as a ``misc_device``.
+All operations are synchronous -- the ioctl blocks until the hardware
+completes.  Opening the device requires ``CAP_SYS_ADMIN``.
+
+All ioctl argument structures are versioned: user space sets the
+``version`` field to ``CMH_MGMT_V1`` (currently 1).  This allows the
+driver to extend structures in the future without breaking the ABI.
+
+Data types and ioctl numbers are defined in
+``<uapi/linux/cmh_mgmt_ioctl.h>``.  The ioctl type letter is ``'J'``
+(0x4A).
+
+Error Handling
+==============
+
+Unless otherwise noted, all ioctls return 0 on success and a negative
+errno on failure.  Common error codes:
+
+========== =============================================================
+``EINVAL`` Invalid ``version`` field, unsupported parameter, or
+           out-of-range length.
+``EFAULT`` Failed to copy data to/from user space.
+``ENOMEM`` Kernel memory allocation failed.
+``EIO``    Hardware returned an error (eSW command failure).
+``ENOENT`` Key not found (``KEY_FIND``, ``KEY_LIST``).
+========== =============================================================
+
+Datastore Concepts
+==================
+
+The CMH hardware maintains an embedded datastore managed by the eSW
+firmware.  Objects in the datastore are identified by a 64-bit reference
+(``ref``) and optionally by a 64-bit Content ID (``cid``).
+
+Two storage classes exist:
+
+**Temporary (SYS_REF_TEMP)**
+  Lifetime is scoped to a single mailbox slot.  The eSW firmware
+  reclaims the object when the slot is reused.  Used for raw-key
+  provisioning via ``KEY_NEW`` + ``KEY_WRITE``.
+
+**Persistent (SYS_REF_PERSIST)**
+  Survives across mailbox slots.  Requires explicit deletion via
+  ``KEY_DELETE``.  Identified by CID; resolved to a per-mailbox ref
+  via ``KEY_FIND``.
+
+Mailbox Dispatch
+================
+
+All ``/dev/cmh_mgmt`` ioctls are submitted on a single management
+mailbox.  This is a structural requirement of the eSW datastore model,
+not a tunable:
+
+* Datastore access control is **per-mailbox**.  ``KEY_NEW`` grants the
+  creating mailbox read/write/execute access; other mailboxes have none
+  until granted.  The returned 64-bit ``ref`` encodes a randomised
+  offset and does **not** carry the owning mailbox, so an operation that
+  receives only a ``ref`` (``KEY_GRANT``, ``KEY_READ``, ``KEY_DELETE``,
+  ``DS_EXPORT``) cannot itself determine which mailbox owns the object.
+  Using one fixed management mailbox guarantees that a key's create,
+  modify, grant, read and hardware-held-key compute steps all share the
+  mailbox that holds its access rights, without exposing mailbox
+  identity in the UABI.  User space may still widen a key's access to
+  additional mailboxes via ``KEY_GRANT``.
+
+* The eSW ``SYS_REF_TEMP`` scratch store is per-mailbox and persists
+  across ioctl calls, so a multi-step flow that derives into
+  ``SYS_REF_TEMP`` (for example a ``KIC_*`` derivation) and later
+  consumes it (``DS_EXPORT`` with ``wrap_key = SYS_REF_TEMP``) requires
+  both calls to use the same mailbox.
+
+Per-mailbox ``rambus,cores`` device-tree affinity applies to the *stateless*
+in-kernel crypto API path, which carries no datastore state between
+requests and is balanced across mailboxes by the driver.
+
+Key Types
+=========
+
+The ``ds_type`` field in ``KEY_NEW`` and ``KEY_WRITE`` selects the
+datastore object type.  Values are defined as ``CMH_DS_*`` constants:
+
+=================================  =====  ==============================
+Constant                           Value  Description
+=================================  =====  ==============================
+``CMH_DS_RAW_VALUE``               1      Raw byte array
+``CMH_DS_AES_KEY``                 2      AES key (128/192/256-bit)
+``CMH_DS_AES_XTS_KEY``             3      AES-XTS key (256/512-bit)
+``CMH_DS_HMAC_KEY``                4      HMAC key
+``CMH_DS_KMAC_KEY``                5      KMAC key
+``CMH_DS_SM4_KEY``                 6      SM4 key (128-bit)
+``CMH_DS_CHACHA20_KEY``            7      ChaCha20 key (256-bit)
+``CMH_DS_RSA_PRIV_KEY``            10     RSA private key
+``CMH_DS_RSA_PUB_KEY``             11     RSA public key
+``CMH_DS_RSA_CRT_KEY``             12     RSA CRT private key
+``CMH_DS_ECDSA_PRIV_KEY``          13     ECDSA private key
+``CMH_DS_ECDSA_PUB_KEY``           14     ECDSA public key
+``CMH_DS_ECDH_PRIV_KEY``           15     ECDH private key
+``CMH_DS_EDDSA_PRIV_KEY``          16     EdDSA private key
+``CMH_DS_SHARED_SECRET``           17     Shared secret
+``CMH_DS_SM2_PRIV_KEY``            18     SM2 private key
+``CMH_DS_ML_KEM_DK``               20     ML-KEM decapsulation key
+``CMH_DS_ML_DSA_SK``               21     ML-DSA secret key
+``CMH_DS_SLHDSA_SK``               25     SLH-DSA secret key
+=================================  =====  ==============================
+
+Key Flags
+=========
+
+The ``flags`` field in ``KEY_NEW`` and ``KEY_WRITE`` is a bitmask:
+
+==================  ===========  ========================================
+Flag                Bit          Description
+==================  ===========  ========================================
+``CMH_FLAG_PT``     16           Key can be read as plaintext
+``CMH_FLAG_XC``     17           Key can be exported over XC bus
+``CMH_FLAG_SCA``    18           SCA key stored in 2 shares
+==================  ===========  ========================================
+
+Elliptic Curve IDs
+==================
+
+Curve identifiers for PKE operations (``curve`` field):
+
+==========================  =====
+Constant                    Value
+==========================  =====
+``CMH_CURVE_P192``          0x01
+``CMH_CURVE_P224``          0x02
+``CMH_CURVE_P256``          0x03
+``CMH_CURVE_P384``          0x04
+``CMH_CURVE_P521``          0x05
+``CMH_CURVE_SECP256K1``     0x07
+``CMH_CURVE_BP192R1``       0x11
+``CMH_CURVE_BP224R1``       0x12
+``CMH_CURVE_BP256R1``       0x13
+``CMH_CURVE_BP320R1``       0x14
+``CMH_CURVE_BP384R1``       0x15
+``CMH_CURVE_BP512R1``       0x16
+``CMH_CURVE_SM2``           0x18
+``CMH_CURVE_25519``         0x21
+``CMH_CURVE_448``           0x22
+==========================  =====
+
+Key Management ioctls
+=====================
+
+CMH_IOCTL_KEY_NEW
+-----------------
+
+Create a new empty datastore object.
+
+:Direction: ``_IOWR``
+:Number: 0x01
+:Argument: ``struct cmh_ioctl_key_new``
+
+::
+
+  struct cmh_ioctl_key_new {
+      __u32 version;     /* must be CMH_MGMT_V1 */
+      __u32 ds_type;     /* CMH_DS_* key type */
+      __u32 len;         /* key length in bytes */
+      __u32 flags;       /* CMH_FLAG_* */
+      __u64 cid;         /* caller ID (name) for the key */
+      __u64 ref;         /* [out] key reference */
+  };
+
+The returned ``ref`` is used in subsequent ``KEY_WRITE``, ``KEY_READ``,
+and crypto operation ioctls.
+
+CMH_IOCTL_KEY_NEW_RANDOM
+------------------------
+
+Create a new datastore object filled with hardware-generated random data.
+
+:Direction: ``_IOWR``
+:Number: 0x0B
+:Argument: ``struct cmh_ioctl_key_new``
+
+Same structure as ``KEY_NEW``.  The hardware DRBG fills the object with
+``len`` random bytes.
+
+CMH_IOCTL_KEY_WRITE
+-------------------
+
+Write key material into a previously created datastore object.
+
+:Direction: ``_IOW``
+:Number: 0x02
+:Argument: ``struct cmh_ioctl_key_write``
+
+::
+
+  struct cmh_ioctl_key_write {
+      __u32 version;
+      __u32 len;         /* key data length */
+      __u32 ds_type;     /* CMH_DS_* key type */
+      __u32 flags;       /* CMH_FLAG_* */
+      __u64 ref;         /* key reference from KEY_NEW */
+      __u64 wrap_key;    /* wrapping key ref (CMH_REF_NONE = plaintext) */
+      __u64 data;        /* user-space pointer to key material */
+  };
+
+If ``wrap_key`` is ``CMH_REF_NONE`` (0), key material is written in
+plaintext.  Otherwise, the data is unwrapped using the specified
+wrapping key.
+
+CMH_IOCTL_KEY_READ
+------------------
+
+Read key material from a datastore object.
+
+:Direction: ``_IOWR``
+:Number: 0x03
+:Argument: ``struct cmh_ioctl_key_read``
+
+::
+
+  struct cmh_ioctl_key_read {
+      __u32 version;
+      __u32 len;         /* buffer length */
+      __u64 ref;         /* key reference */
+      __u64 wrap_key;    /* wrapping key ref (CMH_REF_NONE = plaintext) */
+      __u64 data;        /* user-space pointer to output buffer */
+      __u32 out_len;     /* [out] actual bytes written */
+      __u32 __reserved;
+  };
+
+Plaintext reads require the ``CMH_FLAG_PT`` attribute on the key.
+The eSW prepends a 16-byte header (``CMH_SYS_WRAP_HDR_SIZE``) even
+for plaintext reads; the output buffer must accommodate this.  The
+output overhead is ``CMH_DS_EXPORT_OVERHEAD_PLAIN`` (16 bytes) for
+plaintext reads and ``CMH_DS_EXPORT_OVERHEAD_WRAPPED`` (48 bytes:
+16-byte header + 16-byte nonce + 16-byte tag) for wrapped reads.
+
+CMH_IOCTL_KEY_FIND
+------------------
+
+Resolve a Content ID to a datastore reference.
+
+:Direction: ``_IOWR``
+:Number: 0x04
+:Argument: ``struct cmh_ioctl_key_find``
+
+::
+
+  struct cmh_ioctl_key_find {
+      __u32 version;
+      __u32 __reserved;
+      __u64 cid;         /* caller ID to search for */
+      __u64 ref;         /* [out] resolved key reference */
+      __u32 len;         /* [out] key length */
+      __u32 type;        /* [out] key type */
+  };
+
+Returns ``-ENOENT`` if no object with the given CID exists.
+
+CMH_IOCTL_KEY_LIST
+------------------
+
+Iterate datastore objects.
+
+:Direction: ``_IOWR``
+:Number: 0x0E
+:Argument: ``struct cmh_ioctl_key_list``
+
+::
+
+  struct cmh_ioctl_key_list {
+      __u32 version;
+      __u32 __reserved;
+      __u64 start_ref;   /* starting DS reference (0 = first) */
+      __u64 ref;         /* [out] object reference */
+      __u64 cid;         /* [out] caller ID */
+      __u32 len;         /* [out] object length */
+      __u32 type;        /* [out] object type */
+  };
+
+Pass ``start_ref=0`` to begin from the first object.  On return, pass
+the returned ``ref`` as ``start_ref`` in the next call.  Iteration ends
+when ``ref == 0``.
+
+CMH_IOCTL_KEY_GRANT
+-------------------
+
+Set per-mailbox access permissions on a datastore object.
+
+:Direction: ``_IOW``
+:Number: 0x05
+:Argument: ``struct cmh_ioctl_key_grant``
+
+::
+
+  struct cmh_ioctl_key_grant {
+      __u32 version;
+      __u32 __reserved;
+      __u64 ref;         /* key reference */
+      __u64 read;        /* per-MBX read permission bitfield */
+      __u64 write;       /* per-MBX write permission bitfield */
+      __u64 execute;     /* per-MBX execute permission bitfield */
+  };
+
+CMH_IOCTL_KEY_DELETE
+--------------------
+
+Delete a datastore object (persistent keys only).
+
+:Direction: ``_IOW``
+:Number: 0x06
+:Argument: ``struct cmh_ioctl_key_grant``
+
+Uses the same structure as ``KEY_GRANT``; only the ``ref`` field is
+used.
+
+Datastore Export/Import ioctls
+==============================
+
+CMH_IOCTL_DS_EXPORT
+-------------------
+
+Export the entire datastore as an encrypted blob.
+
+:Direction: ``_IOWR``
+:Number: 0x07
+:Argument: ``struct cmh_ioctl_ds_export``
+
+::
+
+  struct cmh_ioctl_ds_export {
+      __u32 version;
+      __u32 len;         /* buffer length */
+      __u64 cid;         /* caller ID for response tagging */
+      __u64 wrap_key;    /* wrapping key ref (CMH_REF_NONE = plaintext) */
+      __u64 data;        /* user-space pointer to output buffer */
+      __u32 out_len;     /* [out] actual bytes written */
+      __u32 __reserved;
+  };
+
+CMH_IOCTL_DS_IMPORT
+-------------------
+
+Import a previously exported datastore blob.
+
+:Direction: ``_IOW``
+:Number: 0x08
+:Argument: ``struct cmh_ioctl_ds_import``
+
+::
+
+  struct cmh_ioctl_ds_import {
+      __u32 version;
+      __u32 len;         /* blob length */
+      __u64 wrap_key;    /* wrapping key ref (CMH_REF_NONE = plaintext) */
+      __u64 data;        /* user-space pointer to import blob */
+  };
+
+Key Derivation ioctls (KIC)
+===========================
+
+The Key Initialization Core (KIC) provides hardware key derivation from
+OTP-provisioned base keys.  Up to 8 base keys are available
+(``CMH_KIC_KEY1`` through ``CMH_KIC_KEY8``).
+
+CMH_IOCTL_KIC_HKDF1
+--------------------
+
+HKDF-based key derivation (single-step, label only).
+
+:Direction: ``_IOWR``
+:Number: 0x09
+:Argument: ``struct cmh_ioctl_kic_hkdf1``
+
+::
+
+  struct cmh_ioctl_kic_hkdf1 {
+      __u32 version;
+      __u32 key_len;     /* output key length */
+      __u64 base_key;    /* KIC base key reference */
+      __u64 cid;         /* CID for the new DS entry */
+      __u64 label;       /* user-space pointer to label data */
+      __u32 label_len;   /* label length in bytes */
+      __u32 flags;       /* CMH_KIC_FLAG_* */
+      __u64 ref;         /* [out] derived key reference */
+  };
+
+If ``CMH_KIC_FLAG_TEMP`` is set, the result is stored in the temporary
+datastore (not persistent).
+
+CMH_IOCTL_KIC_HKDF2
+--------------------
+
+HKDF-based key derivation (two-step, with salt key).
+
+:Direction: ``_IOWR``
+:Number: 0x0A
+:Argument: ``struct cmh_ioctl_kic_hkdf2``
+
+::
+
+  struct cmh_ioctl_kic_hkdf2 {
+      __u32 version;
+      __u32 key_len;
+      __u64 base_key;
+      __u64 salt_key;    /* salt key reference (CMH_REF_NONE = no salt) */
+      __u64 cid;
+      __u64 label;
+      __u32 label_len;
+      __u32 flags;
+      __u64 ref;         /* [out] derived key reference */
+  };
+
+CMH_IOCTL_KIC_AES_CMAC_KDF
+---------------------------
+
+AES-CMAC-based key derivation (NIST SP 800-108).
+
+:Direction: ``_IOWR``
+:Number: 0x0C
+:Argument: ``struct cmh_ioctl_kic_aes_cmac_kdf``
+
+::
+
+  struct cmh_ioctl_kic_aes_cmac_kdf {
+      __u32 version;
+      __u32 key_len;     /* base & output key length (must be 32) */
+      __u64 base_key;
+      __u64 cid;
+      __u64 label;
+      __u32 label_len;
+      __u32 flags;
+      __u64 ref;         /* [out] derived key reference */
+  };
+
+CMH_IOCTL_KIC_DKEK_DERIVE
+--------------------------
+
+Derive a Device Key Encryption Key (DKEK) for secure key export.
+
+:Direction: ``_IOWR``
+:Number: 0x0D
+:Argument: ``struct cmh_ioctl_kic_dkek_derive``
+
+::
+
+  struct cmh_ioctl_kic_dkek_derive {
+      __u32 version;
+      __u32 host_id;     /* target host ID (0 = caller's own) */
+      __u64 base_key;
+      __u64 cid;
+      __u64 metadata;    /* user-space pointer to metadata */
+      __u32 metadata_len;
+      __u32 flags;
+      __u64 ref;         /* [out] derived KEK reference */
+  };
+
+PKE (Public Key Engine) ioctls
+==============================
+
+RSA Operations
+--------------
+
+CMH_IOCTL_PKE_RSA_ENC
+~~~~~~~~~~~~~~~~~~~~~~
+
+RSA public-key encryption.
+
+:Direction: ``_IOWR``
+:Number: 0x10
+:Argument: ``struct cmh_ioctl_pke_rsa_enc``
+
+::
+
+  struct cmh_ioctl_pke_rsa_enc {
+      __u32 version;
+      __u32 bits;        /* RSA key size in bits (512-4096) */
+      __u64 e;           /* user-space pointer to public exponent */
+      __u32 e_len;       /* exponent length in bytes */
+      __u32 __reserved;
+      __u64 n;           /* user-space pointer to modulus */
+      __u64 input;       /* user-space pointer to input data */
+      __u64 output;      /* user-space pointer to output buffer */
+  };
+
+The public key (e, n) is passed as raw user-space buffers.
+
+CMH_IOCTL_PKE_RSA_DEC
+~~~~~~~~~~~~~~~~~~~~~~
+
+RSA private-key decryption using a datastore key reference.
+
+:Direction: ``_IOWR``
+:Number: 0x11
+:Argument: ``struct cmh_ioctl_pke_rsa_dec``
+
+::
+
+  struct cmh_ioctl_pke_rsa_dec {
+      __u32 version;
+      __u32 bits;
+      __u64 e;           /* public exponent */
+      __u32 e_len;
+      __u32 __reserved;
+      __u64 n;           /* modulus */
+      __u64 input;       /* ciphertext */
+      __u64 output;      /* plaintext output */
+      __u64 key_ref;     /* private key DS reference */
+  };
+
+CMH_IOCTL_PKE_RSA_CRT_DEC
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+RSA CRT private-key decryption (faster, uses CRT key format).
+
+:Direction: ``_IOWR``
+:Number: 0x12
+:Argument: ``struct cmh_ioctl_pke_rsa_crt_dec``
+
+::
+
+  struct cmh_ioctl_pke_rsa_crt_dec {
+      __u32 version;
+      __u32 bits;
+      __u64 e;
+      __u32 e_len;
+      __u32 __reserved;
+      __u64 n;
+      __u64 input;
+      __u64 output;
+      __u64 crt_ref;     /* CRT key DS reference */
+  };
+
+CMH_IOCTL_PKE_RSA_KEYGEN
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Generate an RSA key pair in hardware.
+
+:Direction: ``_IOWR``
+:Number: 0x13
+:Argument: ``struct cmh_ioctl_pke_rsa_keygen``
+
+::
+
+  struct cmh_ioctl_pke_rsa_keygen {
+      __u32 version;
+      __u32 bits;        /* key size in bits */
+      __u64 e;           /* user-space pointer to public exponent */
+      __u32 e_len;
+      __u32 flags;       /* CMH_FLAG_* */
+      __u64 n;           /* [out] user-space pointer to modulus buffer */
+      __u64 d_cid;       /* CID for private key DS entry */
+      __u64 d_ref;       /* [out] private key reference */
+      __u64 crt_cid;     /* CID for CRT key DS entry (0 = skip CRT) */
+      __u64 crt_ref;     /* [out] CRT key reference */
+  };
+
+Returns private key and optional CRT key as datastore references.
+The modulus is written back to user space.
+
+ECDSA Operations
+----------------
+
+CMH_IOCTL_PKE_ECDSA_SIGN
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ECDSA signature generation using a datastore private key.
+
+:Direction: ``_IOWR``
+:Number: 0x14
+:Argument: ``struct cmh_ioctl_pke_ecdsa_sign``
+
+::
+
+  struct cmh_ioctl_pke_ecdsa_sign {
+      __u32 version;
+      __u32 curve;       /* ABI curve ID (e.g. 0x03 = P-256) */
+      __u64 digest;      /* user-space pointer to hash digest */
+      __u32 digest_len;  /* digest length in bytes */
+      __u32 __reserved;
+      __u64 signature;   /* [out] user-space pointer to (r,s) */
+      __u64 key_ref;     /* private key DS reference */
+  };
+
+CMH_IOCTL_PKE_ECDH
+~~~~~~~~~~~~~~~~~~~
+
+Compute ECDH shared secret from a peer public key and a datastore
+private key.
+
+:Direction: ``_IOWR``
+:Number: 0x16
+:Argument: ``struct cmh_ioctl_pke_ecdh``
+
+::
+
+  struct cmh_ioctl_pke_ecdh {
+      __u32 version;
+      __u32 curve;
+      __u64 peer_key_x;  /* user-space pointer to peer public key X */
+      __u64 key_ref;     /* private key DS reference */
+      __u32 flags;       /* CMH_PKE_FLAG_DS_RESULT */
+      __u32 __reserved;
+      __u64 result_cid;  /* CID for DS result (if FLAG_DS_RESULT) */
+      __u64 output;      /* [out] raw shared secret or DS ref */
+  };
+
+If ``CMH_PKE_FLAG_DS_RESULT`` is set, the shared secret is stored in
+the datastore and a reference is returned instead of raw bytes.
+
+CMH_IOCTL_PKE_ECDH_KEYGEN
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Derive a public key from a datastore private key.
+
+:Direction: ``_IOWR``
+:Number: 0x17
+:Argument: ``struct cmh_ioctl_pke_ecdh_keygen``
+
+::
+
+  struct cmh_ioctl_pke_ecdh_keygen {
+      __u32 version;
+      __u32 curve;
+      __u64 key_ref;       /* private key DS reference */
+      __u64 public_key_x;  /* [out] user-space pointer to public key X */
+  };
+
+EdDSA Operations
+----------------
+
+CMH_IOCTL_PKE_EDDSA_SIGN
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+EdDSA (Ed25519/Ed448) signature generation.
+
+:Direction: ``_IOWR``
+:Number: 0x18
+:Argument: ``struct cmh_ioctl_pke_eddsa_sign``
+
+::
+
+  struct cmh_ioctl_pke_eddsa_sign {
+      __u32 version;
+      __u32 curve;       /* CURVE_25519 or CURVE_448 */
+      __u64 digest;      /* user-space ptr to message (not digest) */
+      __u32 digest_len;
+      __u32 __reserved;
+      __u64 signature;   /* [out] user-space pointer to signature */
+      __u64 key_ref;     /* private key DS reference */
+  };
+
+Note: the ``digest`` field is the full message (pure EdDSA), not a
+pre-computed hash.
+
+CMH_IOCTL_PKE_EDDSA_VERIFY
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+EdDSA signature verification.
+
+:Direction: ``_IOW``
+:Number: 0x19
+:Argument: ``struct cmh_ioctl_pke_eddsa_verify``
+
+::
+
+  struct cmh_ioctl_pke_eddsa_verify {
+      __u32 version;
+      __u32 curve;
+      __u64 digest;
+      __u32 digest_len;
+      __u32 __reserved;
+      __u64 signature;
+      __u64 public_key_y;  /* user-space pointer to public key Y */
+  };
+
+EC Key Management
+-----------------
+
+CMH_IOCTL_PKE_EC_KEYGEN
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Generate an EC private key in the hardware datastore.
+
+:Direction: ``_IOWR``
+:Number: 0x1A
+:Argument: ``struct cmh_ioctl_pke_ec_keygen``
+
+::
+
+  struct cmh_ioctl_pke_ec_keygen {
+      __u32 version;
+      __u32 curve;
+      __u32 flags;       /* CMH_FLAG_* */
+      __u32 __reserved;
+      __u64 cid;         /* CID for the new key DS entry */
+      __u64 ref;         /* [out] private key reference */
+  };
+
+CMH_IOCTL_PKE_EC_PUBGEN
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Derive the public key from a datastore private key.
+
+:Direction: ``_IOWR``
+:Number: 0x1B
+:Argument: ``struct cmh_ioctl_pke_ec_pubgen``
+
+::
+
+  struct cmh_ioctl_pke_ec_pubgen {
+      __u32 version;
+      __u32 curve;
+      __u64 key_ref;     /* private key DS reference */
+      __u64 public_key;  /* [out] user-space pointer to public key */
+  };
+
+CMH_IOCTL_PKE_EDDSA_KEYGEN_SCA
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Generate a 2-share SCA-protected Ed448 private key.
+
+:Direction: ``_IOWR``
+:Number: 0x1C
+:Argument: ``struct cmh_ioctl_pke_eddsa_keygen_sca``
+
+::
+
+  struct cmh_ioctl_pke_eddsa_keygen_sca {
+      __u32 version;
+      __u32 curve;       /* must be CURVE_448 */
+      __u64 key_ref;     /* input: normal Ed448 private key DS ref */
+      __u64 cid;         /* CID for the new SCA key DS entry */
+      __u64 sca_ref;     /* [out] SCA private key reference */
+  };
+
+Post-Quantum Cryptography (PQC) ioctls
+=======================================
+
+PQC operations support the following flags in the ``flags`` field:
+
+============================  ====  ====================================
+Flag                          Bit   Description
+============================  ====  ====================================
+``CMH_QSE_FLAG_MASKED``       0     Use masked (SCA-resistant) HW path
+``CMH_QSE_FLAG_DS_REF``       1     Store key output in DS, return ref
+``CMH_QSE_FLAG_HW_RNG``       2     Use HW RNG for seed/randomness
+============================  ====  ====================================
+
+ML-KEM (FIPS 203)
+-----------------
+
+CMH_IOCTL_ML_KEM_KEYGEN
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Generate an ML-KEM key pair.
+
+:Direction: ``_IOWR``
+:Number: 0x20
+:Argument: ``struct cmh_ioctl_ml_kem_keygen``
+
+::
+
+  struct cmh_ioctl_ml_kem_keygen {
+      __u32 version;
+      __u32 k;           /* security parameter: 2/3/4 */
+      __u32 flags;       /* CMH_QSE_FLAG_* */
+      __u32 __reserved;
+      __u64 seed;        /* user-space pointer to seed (or 0 for HW RNG) */
+      __u64 z;           /* user-space pointer to z (or 0 for HW RNG) */
+      __u64 ek;          /* [out] user-space pointer to encapsulation key */
+      __u64 dk;          /* [out] user-space pointer to decapsulation key,
+                          *       or [out] DS ref if CMH_QSE_FLAG_DS_REF */
+      __u64 dk_cid;      /* CID for DS entry (if DS_REF) */
+      __u64 dk_ref;      /* [out] dk DS reference (if DS_REF) */
+  };
+
+Security parameter ``k`` selects the strength: 2 (ML-KEM-512),
+3 (ML-KEM-768), or 4 (ML-KEM-1024).
+
+CMH_IOCTL_ML_KEM_ENC
+~~~~~~~~~~~~~~~~~~~~~
+
+ML-KEM encapsulation.  Produces ciphertext and shared secret.
+
+:Direction: ``_IOWR``
+:Number: 0x21
+:Argument: ``struct cmh_ioctl_ml_kem_enc``
+
+::
+
+  struct cmh_ioctl_ml_kem_enc {
+      __u32 version;
+      __u32 k;
+      __u32 flags;       /* CMH_QSE_FLAG_* */
+      __u32 __reserved;
+      __u64 coin;        /* user-space pointer to random coin (or 0) */
+      __u64 ek;          /* user-space pointer to encapsulation key */
+      __u64 ct;          /* [out] user-space pointer to ciphertext */
+      __u64 ss;          /* [out] user-space pointer to shared secret */
+      __u64 __reserved2[2];  /* reserved for future use */
+  };
+
+CMH_IOCTL_ML_KEM_DEC
+~~~~~~~~~~~~~~~~~~~~~
+
+ML-KEM decapsulation.  Recovers shared secret from ciphertext.
+
+:Direction: ``_IOWR``
+:Number: 0x22
+:Argument: ``struct cmh_ioctl_ml_kem_dec``
+
+::
+
+  struct cmh_ioctl_ml_kem_dec {
+      __u32 version;
+      __u32 k;
+      __u32 flags;       /* CMH_QSE_FLAG_* */
+      __u32 __reserved;
+      __u64 ct;          /* user-space pointer to ciphertext */
+      __u64 dk;          /* user-space pointer to dk or DS ref */
+      __u64 ss;          /* [out] user-space pointer to shared secret */
+      __u64 __reserved2[2];  /* reserved for future use */
+  };
+
+ML-DSA (FIPS 204)
+-----------------
+
+CMH_IOCTL_ML_DSA_KEYGEN
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Generate an ML-DSA key pair.
+
+:Direction: ``_IOWR``
+:Number: 0x23
+:Argument: ``struct cmh_ioctl_ml_dsa_keygen``
+
+::
+
+  struct cmh_ioctl_ml_dsa_keygen {
+      __u32 version;
+      __u32 mode;        /* security parameter: 2/3/5 */
+      __u32 flags;       /* CMH_QSE_FLAG_* */
+      __u32 __reserved;
+      __u64 seed;        /* user-space pointer to seed (or 0 for HW RNG) */
+      __u64 pk;          /* [out] user-space pointer to public key */
+      __u64 sk;          /* [out] user-space pointer to secret key,
+                          *       or [out] DS ref if CMH_QSE_FLAG_DS_REF */
+      __u64 sk_cid;      /* CID for DS entry (if DS_REF) */
+      __u64 sk_ref;      /* [out] sk DS reference (if DS_REF) */
+  };
+
+Security parameter ``mode`` selects the strength: 2 (ML-DSA-44),
+3 (ML-DSA-65), or 5 (ML-DSA-87).
+
+.. note::
+
+   When ``CMH_QSE_FLAG_DS_REF`` keeps the secret key in the datastore,
+   the public key returned in ``pk`` is the only copy: there is no
+   operation to derive the public key from the secret-key reference
+   for ML-DSA.  User space must persist ``pk`` at keygen time.
+
+CMH_IOCTL_ML_DSA_SIGN
+~~~~~~~~~~~~~~~~~~~~~~
+
+ML-DSA signature generation.
+
+:Direction: ``_IOWR``
+:Number: 0x24
+:Argument: ``struct cmh_ioctl_ml_dsa_sign``
+
+::
+
+  struct cmh_ioctl_ml_dsa_sign {
+      __u32 version;
+      __u32 mode;
+      __u32 flags;       /* CMH_QSE_FLAG_* */
+      __u32 mlen;        /* message length in bytes */
+      __u64 m;           /* user-space pointer to message */
+      __u64 sk;          /* user-space pointer to sk or DS ref */
+      __u64 sig;         /* [out] user-space pointer to signature */
+      __u64 rnd;         /* user-space pointer to randomness (or 0) */
+  };
+
+If ``mlen`` is set to ``CMH_ML_DSA_MLEN_EXTERNAL_MU`` (0xFFFFFFFF),
+the ``m`` pointer is interpreted as a 64-byte pre-hashed mu value
+(ExternalMu mode).
+
+CMH_IOCTL_SLHDSA_KEYGEN
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Generate an SLH-DSA key pair.
+
+:Direction: ``_IOWR``
+:Number: 0x28
+:Argument: ``struct cmh_ioctl_slhdsa_keygen``
+
+::
+
+  struct cmh_ioctl_slhdsa_keygen {
+      __u32 version;
+      __u32 parameter_set;  /* HCQ_SLHDSA_SHAKE_128S .. SHA2_256F */
+      __u32 flags;          /* CMH_QSE_FLAG_DS_REF */
+      __u32 __reserved;
+      __u64 seed;           /* user-space pointer to seed */
+      __u64 pk;             /* [out] user-space pointer to public key */
+      __u64 sk;             /* [out] user-space pointer to secret key,
+                             *       or [out] DS ref if CMH_QSE_FLAG_DS_REF */
+      __u64 sk_cid;         /* CID for DS entry (if DS_REF) */
+      __u64 sk_ref;         /* [out] sk DS reference (if DS_REF) */
+  };
+
+.. note::
+
+   When ``CMH_QSE_FLAG_DS_REF`` keeps the secret key in the datastore,
+   the public key returned in ``pk`` is the only copy: there is no
+   operation to derive the public key from the secret-key reference
+   for SLH-DSA.  User space must persist ``pk`` at keygen time.
+
+CMH_IOCTL_SLHDSA_SIGN
+~~~~~~~~~~~~~~~~~~~~~~
+
+SLH-DSA signature generation (pure mode).
+
+:Direction: ``_IOWR``
+:Number: 0x29
+:Argument: ``struct cmh_ioctl_slhdsa_sign``
+
+::
+
+  struct cmh_ioctl_slhdsa_sign {
+      __u32 version;
+      __u32 parameter_set;
+      __u32 msg_len;
+      __u32 ctx_len;
+      __u64 msg;         /* user-space pointer to message */
+      __u64 ctx;         /* user-space pointer to context (or 0) */
+      __u64 sk;          /* DS ref for secret key */
+      __u64 sig;         /* [out] user-space pointer to signature */
+      __u64 add_random;  /* user-space pointer to addl. randomness (or 0) */
+  };
+
+CMH_IOCTL_SLHDSA_SIGN_PREHASH
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+SLH-DSA pre-hash signature generation.
+
+:Direction: ``_IOWR``
+:Number: 0x2D
+:Argument: ``struct cmh_ioctl_slhdsa_sign_prehash``
+
+::
+
+  struct cmh_ioctl_slhdsa_sign_prehash {
+      __u32 version;
+      __u32 parameter_set;
+      __u32 prehash_algo;  /* CMH_SLHDSA_PREHASH_* */
+      __u32 digest;        /* 0 = raw msg (eSW hashes), 1 = pre-computed */
+      __u32 msg_len;
+      __u32 ctx_len;
+      __u64 msg;           /* user-space pointer to message/digest */
+      __u64 ctx;           /* user-space pointer to context (or 0) */
+      __u64 sk;            /* DS ref for secret key */
+      __u64 sig;           /* [out] user-space pointer to signature */
+      __u64 add_random;    /* user-space pointer to addl. randomness (or 0) */
+  };
+
+The ``prehash_algo`` field selects the hash algorithm
+(``CMH_SLHDSA_PREHASH_SHA256``, etc.).
+
+CMH_IOCTL_SM2_ENC_POINT
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+:Direction: ``_IOWR``
+:Number: 0x33
+:Argument: ``struct cmh_ioctl_sm2_enc_point``
+
+::
+
+  struct cmh_ioctl_sm2_enc_point {
+      __u32 version;
+      __u32 nonce_len;   /* 0 = HW generates, 32 = caller provides */
+      __u64 nonce;       /* user-space pointer to nonce (or 0) */
+      __u64 public_key;  /* user-space pointer to public key (64B) */
+      __u64 ciphertext;  /* [out] user-space pointer to C1 (64B) */
+      __u64 enc_point;   /* [out] user-space pointer to enc point (64B) */
+  };
+
+CMH_IOCTL_SM2_ENC_HASH
+~~~~~~~~~~~~~~~~~~~~~~~
+
+:Direction: ``_IOWR``
+:Number: 0x37
+:Argument: ``struct cmh_ioctl_sm2_enc_hash``
+
+::
+
+  struct cmh_ioctl_sm2_enc_hash {
+      __u32 version;
+      __u32 message_len;  /* message length (1..32) */
+      __u64 message;      /* user-space pointer to plaintext */
+      __u64 enc_point;    /* user-space pointer to enc point (64B) */
+      __u64 ciphertext;   /* [out] user-space pointer to ciphertext */
+  };
+
+CMH_IOCTL_SM2_DEC_POINT
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+:Direction: ``_IOWR``
+:Number: 0x32
+:Argument: ``struct cmh_ioctl_sm2_dec_point``
+
+::
+
+  struct cmh_ioctl_sm2_dec_point {
+      __u32 version;
+      __u32 ciphertext_len;  /* total ciphertext length (97..128) */
+      __u64 ciphertext;      /* user-space pointer to ciphertext (64B: C1) */
+      __u64 dec_point;       /* [out] user-space pointer to dec point (64B) */
+      __u64 key_ref;         /* private key DS reference */
+  };
+
+CMH_IOCTL_SM2_DEC_HASH
+~~~~~~~~~~~~~~~~~~~~~~~
+
+:Direction: ``_IOWR``
+:Number: 0x36
+:Argument: ``struct cmh_ioctl_sm2_dec_hash``
+
+::
+
+  struct cmh_ioctl_sm2_dec_hash {
+      __u32 version;
+      __u32 ciphertext_len;  /* ciphertext length (97..128) */
+      __u64 ciphertext;      /* user-space pointer to full ciphertext */
+      __u64 dec_point;       /* user-space pointer to dec point (64B) */
+      __u64 plaintext;       /* [out] user-space pointer to plaintext */
+  };
+
+SM2 Key Exchange (GM/T 0003.3)
+------------------------------
+
+The key exchange protocol is a multi-step flow:
+
+1. ``EC_KEYGEN(CMH_CURVE_SM2)`` -- generate a long-lived private key.
+2. ``EC_PUBGEN`` -- derive the public key.
+3. ``SM2_ID_DIGEST`` -- compute the SM3 identity digest (ZA).
+4. ``SM2_ECDH_KEYGEN`` -- generate an ephemeral session key.
+5. Exchange session keys with the peer.
+6. ``SM2_ECDH`` -- compute the shared point.
+7. ``SM2_ECDH_HASH`` -- derive the shared key from the shared point
+   and both parties' ZA digests.
+
+CMH_IOCTL_SM2_ECDH_KEYGEN
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+:Direction: ``_IOWR``
+:Number: 0x30
+:Argument: ``struct cmh_ioctl_sm2_ecdh_keygen``
+
+::
+
+  struct cmh_ioctl_sm2_ecdh_keygen {
+      __u32 version;
+      __u32 nonce_len;    /* 0 = HW generates r (written back), 32 = caller */
+      __u64 nonce;        /* [in/out] user-space pointer to nonce buffer (32B) */
+      __u64 session_key;  /* [out] user-space pointer to R=r*G (64B) */
+  };
+
+``nonce_len`` must be 0 or 32.  If ``nonce_len=0``, the hardware
+generates the ephemeral scalar and writes it back to the ``nonce``
+buffer.
+
+CMH_IOCTL_SM2_ECDH
+~~~~~~~~~~~~~~~~~~~
+
+:Direction: ``_IOWR``
+:Number: 0x31
+:Argument: ``struct cmh_ioctl_sm2_ecdh``
+
+::
+
+  struct cmh_ioctl_sm2_ecdh {
+      __u32 version;
+      __u32 nonce_len;         /* 0 = HW generates, 32 = caller provides */
+      __u64 nonce;             /* [in/out] user-space pointer to nonce r (32B) */
+      __u64 peer_public_key;   /* user-space pointer to peer pub key (64B) */
+      __u64 peer_session_key;  /* user-space pointer to peer session key (64B) */
+      __u64 key_ref;           /* private key DS reference */
+      __u64 shared_point;      /* [out] user-space pointer to shared point (64B) */
+      __u64 shared_point_ref;  /* [in/out] 0 = read-back; &ref = keep DS */
+  };
+
+If ``shared_point_ref`` points to a non-zero value, the shared point
+is kept in the datastore for use by ``SM2_ECDH_HASH``.
+
+CMH_IOCTL_SM2_ID_DIGEST
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Compute the SM3 identity digest (ZA) for a public key and identity
+string.
+
+:Direction: ``_IOWR``
+:Number: 0x34
+:Argument: ``struct cmh_ioctl_sm2_id_digest``
+
+::
+
+  struct cmh_ioctl_sm2_id_digest {
+      __u32 version;
+      __u32 id_len;      /* identity length in bytes (<=32) */
+      __u64 id;          /* user-space pointer to identity string */
+      __u64 public_key;  /* user-space pointer to public key (64B) */
+      __u64 digest;      /* [out] user-space pointer to ZA digest (32B) */
+  };
+
+CMH_IOCTL_SM2_ECDH_HASH
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Derive the shared key from the shared point and ZA digests.
+
+:Direction: ``_IOWR``
+:Number: 0x35
+:Argument: ``struct cmh_ioctl_sm2_ecdh_hash``
+
+::
+
+  struct cmh_ioctl_sm2_ecdh_hash {
+      __u32 version;
+      __u32 __reserved;
+      __u64 peer_id_digest;    /* ptr to Z_A -- initiator's digest (32B) */
+      __u64 id_digest;         /* ptr to Z_B -- responder's digest (32B) */
+      __u64 shared_point_ref;  /* DS reference from SM2_ECDH */
+      __u64 shared_key;        /* [out] ptr to shared key (16B) */
+  };
+
+.. important::
+
+   The digest fields use **absolute** ordering per GM/T 0003.3, not
+   relative own/peer ordering.  Both parties must pass:
+
+   - ``peer_id_digest`` = Z_A (initiator's digest) -- hashed first
+   - ``id_digest`` = Z_B (responder's digest) -- hashed second
+
+Hardware Management ioctls
+==========================
+
+CMH_IOCTL_EAC_READ
+-------------------
+
+Read and clear the hardware Error and Alarm Controller registers.
+
+:Direction: ``_IOWR``
+:Number: 0x0F
+:Argument: ``struct cmh_ioctl_eac_read``
+
+::
+
+  struct cmh_ioctl_eac_read {
+      __u32 version;
+      __u32 __reserved;
+      __u64 mailbox_notification;
+      __u32 hw_error;
+      __u32 hw_nmi;
+      __u32 hw_panic;
+      __u32 safety_fatal;
+      __u32 safety_notification;
+      __u32 sw_info0;
+      __u32 sw_info1;
+      __u32 sram_bank_errors[4];
+      __u32 __pad;
+  };
+
+The eSW atomically reads and clears the registers on each call.
+Successive reads show only new events since the last read.
+
+CMH_IOCTL_DRBG_CONFIG
+----------------------
+
+Configure the hardware DRBG before first use.
+
+:Direction: ``_IOW``
+:Number: 0x40
+:Argument: ``struct cmh_ioctl_drbg_config``
+
+::
+
+  struct cmh_ioctl_drbg_config {
+      __u32 version;
+      __u32 entropy_ratio;       /* CMH_DRBG_RATIO_* */
+      __u32 security_strength;   /* CMH_DRBG_STRENGTH_* */
+      __u32 __reserved;
+  };
+
+This is a management operation normally performed once at system
+startup.  Must be called before any ``hwrng`` reads or DRBG generate
+operations.
+
+ioctl Number Summary
+====================
+
+======================================  ====  ====  =========================================
+ioctl                                   Dir   Seq   Argument
+======================================  ====  ====  =========================================
+``CMH_IOCTL_KEY_NEW``                   IOWR  0x01  ``cmh_ioctl_key_new``
+``CMH_IOCTL_KEY_WRITE``                 IOW   0x02  ``cmh_ioctl_key_write``
+``CMH_IOCTL_KEY_READ``                  IOWR  0x03  ``cmh_ioctl_key_read``
+``CMH_IOCTL_KEY_FIND``                  IOWR  0x04  ``cmh_ioctl_key_find``
+``CMH_IOCTL_KEY_GRANT``                 IOW   0x05  ``cmh_ioctl_key_grant``
+``CMH_IOCTL_KEY_DELETE``                IOW   0x06  ``cmh_ioctl_key_grant``
+``CMH_IOCTL_DS_EXPORT``                 IOWR  0x07  ``cmh_ioctl_ds_export``
+``CMH_IOCTL_DS_IMPORT``                 IOW   0x08  ``cmh_ioctl_ds_import``
+``CMH_IOCTL_KIC_HKDF1``                 IOWR  0x09  ``cmh_ioctl_kic_hkdf1``
+``CMH_IOCTL_KIC_HKDF2``                 IOWR  0x0A  ``cmh_ioctl_kic_hkdf2``
+``CMH_IOCTL_KEY_NEW_RANDOM``            IOWR  0x0B  ``cmh_ioctl_key_new``
+``CMH_IOCTL_KIC_AES_CMAC_KDF``          IOWR  0x0C  ``cmh_ioctl_kic_aes_cmac_kdf``
+``CMH_IOCTL_KIC_DKEK_DERIVE``           IOWR  0x0D  ``cmh_ioctl_kic_dkek_derive``
+``CMH_IOCTL_KEY_LIST``                  IOWR  0x0E  ``cmh_ioctl_key_list``
+``CMH_IOCTL_EAC_READ``                  IOWR  0x0F  ``cmh_ioctl_eac_read``
+``CMH_IOCTL_PKE_RSA_ENC``               IOWR  0x10  ``cmh_ioctl_pke_rsa_enc``
+``CMH_IOCTL_PKE_RSA_DEC``               IOWR  0x11  ``cmh_ioctl_pke_rsa_dec``
+``CMH_IOCTL_PKE_RSA_CRT_DEC``           IOWR  0x12  ``cmh_ioctl_pke_rsa_crt_dec``
+``CMH_IOCTL_PKE_RSA_KEYGEN``            IOWR  0x13  ``cmh_ioctl_pke_rsa_keygen``
+``CMH_IOCTL_PKE_ECDSA_SIGN``            IOWR  0x14  ``cmh_ioctl_pke_ecdsa_sign``
+``CMH_IOCTL_PKE_ECDH``                  IOWR  0x16  ``cmh_ioctl_pke_ecdh``
+``CMH_IOCTL_PKE_ECDH_KEYGEN``           IOWR  0x17  ``cmh_ioctl_pke_ecdh_keygen``
+``CMH_IOCTL_PKE_EDDSA_SIGN``            IOWR  0x18  ``cmh_ioctl_pke_eddsa_sign``
+``CMH_IOCTL_PKE_EDDSA_VERIFY``          IOW   0x19  ``cmh_ioctl_pke_eddsa_verify``
+``CMH_IOCTL_PKE_EC_KEYGEN``             IOWR  0x1A  ``cmh_ioctl_pke_ec_keygen``
+``CMH_IOCTL_PKE_EC_PUBGEN``             IOWR  0x1B  ``cmh_ioctl_pke_ec_pubgen``
+``CMH_IOCTL_PKE_EDDSA_KEYGEN_SCA``      IOWR  0x1C  ``cmh_ioctl_pke_eddsa_keygen_sca``
+``CMH_IOCTL_ML_KEM_KEYGEN``             IOWR  0x20  ``cmh_ioctl_ml_kem_keygen``
+``CMH_IOCTL_ML_KEM_ENC``                IOWR  0x21  ``cmh_ioctl_ml_kem_enc``
+``CMH_IOCTL_ML_KEM_DEC``                IOWR  0x22  ``cmh_ioctl_ml_kem_dec``
+``CMH_IOCTL_ML_DSA_KEYGEN``             IOWR  0x23  ``cmh_ioctl_ml_dsa_keygen``
+``CMH_IOCTL_ML_DSA_SIGN``               IOWR  0x24  ``cmh_ioctl_ml_dsa_sign``
+``CMH_IOCTL_SLHDSA_KEYGEN``             IOWR  0x28  ``cmh_ioctl_slhdsa_keygen``
+``CMH_IOCTL_SLHDSA_SIGN``               IOWR  0x29  ``cmh_ioctl_slhdsa_sign``
+``CMH_IOCTL_SLHDSA_SIGN_PREHASH``       IOWR  0x2D  ``cmh_ioctl_slhdsa_sign_prehash``
+``CMH_IOCTL_SM2_ECDH_KEYGEN``           IOWR  0x30  ``cmh_ioctl_sm2_ecdh_keygen``
+``CMH_IOCTL_SM2_ECDH``                  IOWR  0x31  ``cmh_ioctl_sm2_ecdh``
+``CMH_IOCTL_SM2_DEC_POINT``             IOWR  0x32  ``cmh_ioctl_sm2_dec_point``
+``CMH_IOCTL_SM2_ENC_POINT``             IOWR  0x33  ``cmh_ioctl_sm2_enc_point``
+``CMH_IOCTL_SM2_ID_DIGEST``             IOWR  0x34  ``cmh_ioctl_sm2_id_digest``
+``CMH_IOCTL_SM2_ECDH_HASH``             IOWR  0x35  ``cmh_ioctl_sm2_ecdh_hash``
+``CMH_IOCTL_SM2_DEC_HASH``              IOWR  0x36  ``cmh_ioctl_sm2_dec_hash``
+``CMH_IOCTL_SM2_ENC_HASH``              IOWR  0x37  ``cmh_ioctl_sm2_enc_hash``
+``CMH_IOCTL_DRBG_CONFIG``               IOW   0x40  ``cmh_ioctl_drbg_config``
+======================================  ====  ====  =========================================
+
+Relationship to the in-kernel crypto API
+=========================================
+
+The main reason these operations are exposed as ioctls, rather than
+through the standard in-kernel crypto API, is the CMH datastore key
+model: an ioctl can operate on a *datastore-referenced* (hardware-held)
+key, identified only by a ``ref`` or CID, whose raw bytes the CPU never
+sees.  The standard crypto API cannot express this -- every
+``.setkey()`` takes raw key material -- so hardware key lifecycle
+(create, import, derive, grant, destroy) and compute-on-hardware-held-key
+operations have no crypto API equivalent and are only reachable here.
+
+These ioctls remain supported.  Where an operation can *also* be
+expressed through a standard kernel abstraction, additional in-kernel
+crypto API bindings may be added over time; when such a binding lands the
+driver registers through it, and the ioctl continues to be maintained for
+backward compatibility:
+
+- **EdDSA** (``CMH_IOCTL_PKE_EDDSA_*``): a kernel ``sig`` binding may be
+  added once ed25519/ed448 algorithm types are accepted upstream.
+
+- **ML-KEM** (``CMH_IOCTL_ML_KEM_*``): a kernel KEM binding may be added
+  once the in-flight KEM subsystem series lands.
+
+- **Key lifecycle** (``CMH_IOCTL_KEY_*``): integration with the kernel
+  KEYS subsystem (trusted-keys / encrypted-keys) may be evaluated as a
+  follow-up series.
+
+Operations that are inherently vendor-specific (EAC Chip Authentication,
+KIC key derivation, SM2 key exchange, DRBG configuration, datastore
+export/import) have no corresponding kernel abstraction and are expected
+to remain ioctl-only.
diff --git a/Documentation/userspace-api/ioctl/index.rst b/Documentation/userspace-api/ioctl/index.rst
index 475675eae086..bf88bb6b9a6f 100644
--- a/Documentation/userspace-api/ioctl/index.rst
+++ b/Documentation/userspace-api/ioctl/index.rst
@@ -12,4 +12,5 @@ IOCTLs
    ioctl-decoding
 
    cdrom
+   cmh_mgmt
    hdio
diff --git a/Documentation/userspace-api/ioctl/ioctl-number.rst b/Documentation/userspace-api/ioctl/ioctl-number.rst
index 3f0ef1e27eb0..83fd74b6f396 100644
--- a/Documentation/userspace-api/ioctl/ioctl-number.rst
+++ b/Documentation/userspace-api/ioctl/ioctl-number.rst
@@ -170,6 +170,7 @@ Code  Seq#    Include File                                             Comments
 'I'   all    linux/isdn.h                                              conflict!
 'I'   00-0F  drivers/isdn/divert/isdn_divert.h                         conflict!
 'I'   40-4F  linux/mISDNif.h                                           conflict!
+'J'   01-40  uapi/linux/cmh_mgmt_ioctl.h                               Rambus CryptoManager Hub (CMH)
 'K'   all    linux/kd.h
 'L'   00-1F  linux/loop.h                                              conflict!
 'L'   10-1F  drivers/scsi/mpt3sas/mpt3sas_ctl.h                        conflict!
-- 
2.43.7


  parent reply	other threads:[~2026-08-06 19:55 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-06 19:54 [PATCH v3 00/19] crypto: cmh - add Rambus CryptoManager Hub driver Saravanakrishnan Krishnamoorthy
2026-08-06 19:55 ` [PATCH v3 01/19] dt-bindings: crypto: add Rambus CryptoManager Hub Saravanakrishnan Krishnamoorthy
2026-08-06 19:55 ` [PATCH v3 02/19] crypto: cmh - add core platform driver Saravanakrishnan Krishnamoorthy
2026-08-06 19:55 ` [PATCH v3 03/19] crypto: cmh - add key provisioning and management Saravanakrishnan Krishnamoorthy
2026-08-06 19:55 ` [PATCH v3 04/19] crypto: cmh - add SHA-2/SHA-3/SHAKE ahash Saravanakrishnan Krishnamoorthy
2026-08-06 19:55 ` [PATCH v3 05/19] crypto: cmh - add HMAC ahash Saravanakrishnan Krishnamoorthy
2026-08-06 19:55 ` [PATCH v3 06/19] crypto: cmh - add CSHAKE/KMAC ahash Saravanakrishnan Krishnamoorthy
2026-08-06 19:55 ` [PATCH v3 07/19] crypto: cmh - add SM3 ahash Saravanakrishnan Krishnamoorthy
2026-08-06 19:55 ` [PATCH v3 08/19] crypto: cmh - add AES skcipher/aead/cmac Saravanakrishnan Krishnamoorthy
2026-08-06 19:55 ` [PATCH v3 09/19] crypto: cmh - add SM4 skcipher/aead/cmac/xcbc Saravanakrishnan Krishnamoorthy
2026-08-06 19:55 ` [PATCH v3 10/19] crypto: cmh - add ChaCha20-Poly1305 Saravanakrishnan Krishnamoorthy
2026-08-06 19:55 ` [PATCH v3 11/19] crypto: cmh - add DRBG hwrng Saravanakrishnan Krishnamoorthy
2026-08-06 19:55 ` [PATCH v3 12/19] crypto: cmh - add RSA akcipher Saravanakrishnan Krishnamoorthy
2026-08-06 19:55 ` [PATCH v3 13/19] crypto: cmh - add ECDSA/SM2 sig Saravanakrishnan Krishnamoorthy
2026-08-06 19:55 ` [PATCH v3 14/19] crypto: cmh - add ECDH/X25519 kpp Saravanakrishnan Krishnamoorthy
2026-08-06 19:55 ` [PATCH v3 15/19] crypto: cmh - add ML-KEM/ML-DSA (QSE) Saravanakrishnan Krishnamoorthy
2026-08-06 19:55 ` [PATCH v3 16/19] crypto: cmh - add SLH-DSA/LMS/XMSS (HCQ) Saravanakrishnan Krishnamoorthy
2026-08-06 19:55 ` Saravanakrishnan Krishnamoorthy [this message]
2026-08-06 19:55 ` [PATCH v3 18/19] selftests: crypto: cmh - add kselftest for management ioctl Saravanakrishnan Krishnamoorthy
2026-08-06 19:55 ` [PATCH v3 19/19] MAINTAINERS: add Rambus CryptoManager Hub (CMH) Saravanakrishnan Krishnamoorthy

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260806195519.2703224-18-skrishnamoorthy@rambus.com \
    --to=skrishnamoorthy@rambus.com \
    --cc=Joel.Wittenauer@cryptography.com \
    --cc=alex@ghiti.fr \
    --cc=aou@eecs.berkeley.edu \
    --cc=aousherovitch@rambus.com \
    --cc=conor+dt@kernel.org \
    --cc=corbet@lwn.net \
    --cc=davem@davemloft.net \
    --cc=devicetree@vger.kernel.org \
    --cc=herbert@gondor.apana.org.au \
    --cc=krzk+dt@kernel.org \
    --cc=linux-api@vger.kernel.org \
    --cc=linux-crypto@vger.kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=linux-riscv@lists.infradead.org \
    --cc=palmer@dabbelt.com \
    --cc=pjw@kernel.org \
    --cc=robh@kernel.org \
    --cc=shuah@kernel.org \
    --cc=skhan@linuxfoundation.org \
    --cc=thin@rambus.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox