{"id":2234746,"url":"http://patchwork.ozlabs.org/api/1.2/patches/2234746/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-pci/patch/20260508031710.514574-12-alistair.francis@wdc.com/","project":{"id":28,"url":"http://patchwork.ozlabs.org/api/1.2/projects/28/?format=json","name":"Linux PCI development","link_name":"linux-pci","list_id":"linux-pci.vger.kernel.org","list_email":"linux-pci@vger.kernel.org","web_url":null,"scm_url":null,"webscm_url":null,"list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<20260508031710.514574-12-alistair.francis@wdc.com>","list_archive_url":null,"date":"2026-05-08T03:17:03","name":"[11/18] lib: rspdm: Support SPDM get_version","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"19a9e94c45f5d5e58bba2f6497f147bad394ef80","submitter":{"id":64571,"url":"http://patchwork.ozlabs.org/api/1.2/people/64571/?format=json","name":"Alistair Francis","email":"alistair23@gmail.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/linux-pci/patch/20260508031710.514574-12-alistair.francis@wdc.com/mbox/","series":[{"id":503312,"url":"http://patchwork.ozlabs.org/api/1.2/series/503312/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-pci/list/?series=503312","date":"2026-05-08T03:16:52","name":"lib: Rust implementation of SPDM","version":1,"mbox":"http://patchwork.ozlabs.org/series/503312/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2234746/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2234746/checks/","tags":{},"related":[],"headers":{"Return-Path":"\n <linux-pci+bounces-54166-incoming=patchwork.ozlabs.org@vger.kernel.org>","X-Original-To":["incoming@patchwork.ozlabs.org","linux-pci@vger.kernel.org"],"Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=a+a6o51L;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=104.64.211.4; helo=sin.lore.kernel.org;\n envelope-from=linux-pci+bounces-54166-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)","smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com\n header.b=\"a+a6o51L\"","smtp.subspace.kernel.org;\n arc=none smtp.client-ip=209.85.214.178","smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com","smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=gmail.com"],"Received":["from sin.lore.kernel.org (sin.lore.kernel.org [104.64.211.4])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4gBZDC5q7Zz1yK7\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 08 May 2026 13:22:03 +1000 (AEST)","from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sin.lore.kernel.org (Postfix) with ESMTP id F05E1301D4A0\n\tfor <incoming@patchwork.ozlabs.org>; Fri,  8 May 2026 03:19:19 +0000 (UTC)","from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id 184132F7AB0;\n\tFri,  8 May 2026 03:18:54 +0000 (UTC)","from mail-pl1-f178.google.com (mail-pl1-f178.google.com\n [209.85.214.178])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id C278D2F260F\n\tfor <linux-pci@vger.kernel.org>; Fri,  8 May 2026 03:18:48 +0000 (UTC)","by mail-pl1-f178.google.com with SMTP id\n d9443c01a7336-2baca78cfaaso8654405ad.1\n        for <linux-pci@vger.kernel.org>; Thu, 07 May 2026 20:18:48 -0700 (PDT)","from toolbx.alistair23.me ([2403:581e:fdf9:0:6209:4521:6813:45b7])\n        by smtp.gmail.com with ESMTPSA id\n d9443c01a7336-2baf1eafa62sm3220685ad.74.2026.05.07.20.18.40\n        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n        Thu, 07 May 2026 20:18:46 -0700 (PDT)"],"ARC-Seal":"i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1778210332; cv=none;\n b=kYzxbzsvRAjCYycFLNivxC3/SlgPbHp6KXEQ//LMdTsfThWc9hQ/j6XVBwSfx5XCmC4LJgGpxOJGcJcEh8gBgDsmmpfCQIt2RZy4eRBmCDEzgB+X3w7OQ9OOYFZWbdmuPM1PHbG2+nZZRq2xoSVXHHSD0zO4YioCvAzppvlhxwM=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1778210332; c=relaxed/simple;\n\tbh=oxNrGjcZCazizcSxSSIR96HPVNGWilr6D9NtWMsT9rw=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=gHP1TCb0kogIWy8WJX5Jq52Mv62GCGi7Vl3XR9W0GZmP7OiaihAWg+Dz8EDiRjlwGqmCZHuJ1j3exQYwUma5jtC2rPyvUfB7Z+AZJ8eYoZ0lMFqZx4rZX3zRFZRLGvu+dQt7KO2cW0TV7DZf6wO3KYQqb7wWn2YRwhxYbu3bMx4=","ARC-Authentication-Results":"i=1; smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com;\n spf=pass smtp.mailfrom=gmail.com;\n dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com\n header.b=a+a6o51L; arc=none smtp.client-ip=209.85.214.178","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n        d=gmail.com; s=20251104; t=1778210327; x=1778815127;\n darn=vger.kernel.org;\n        h=content-transfer-encoding:mime-version:references:in-reply-to\n         :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n         :message-id:reply-to;\n        bh=sdaY8XVDz6HV3abuC4HHO5UewMGlDvcsArdslgC4GX0=;\n        b=a+a6o51LnORkrj8YRpE5Xy8JhOmLgr/EPwjAL1nxVAAUF7J/76zW8cfLLpMBpc+jns\n         XcNxlEblsg+g11U2adOV+fhOn2uS9A6CY3/bNdrFONHCmqaIAsgl0q/hr5WfpCg8bM5b\n         6vf/vijWohGSxuTGnjTDAbGb0ACVYYMjaGSu0RObcl2b5X+i20WV80p62/qFMKtB6821\n         RRr5M3CCWanHzG5v+6a+O1729SgJnff7wzrEFHwSxKZetRdHfXOAhzH2ojVYlwoIoJ2a\n         0QMvd14MRAivzBwj11Ad1oHAyb9kYXAvUf8hmH9dkE1ixQNdqyt0N1XL+SmuK+9NffPp\n         NNlQ==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n        d=1e100.net; s=20251104; t=1778210327; x=1778815127;\n        h=content-transfer-encoding:mime-version:references:in-reply-to\n         :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n         :to:cc:subject:date:message-id:reply-to;\n        bh=sdaY8XVDz6HV3abuC4HHO5UewMGlDvcsArdslgC4GX0=;\n        b=gH3yiqP8bUhzTzz/PlBVTnytDHXbt8oNETXk6WqSIlsxk7IAZbT0FMOg4sjPCWdzgt\n         Wby3L8ANBUauyLUbYBu+XUJmnNi8g2VJ9XMtbYle2tir5lTucqZmbPpYX0UKzszmHe90\n         6X1IYaw5oNWQP22ewA0YfOnHS09gu7l2VY22JA4TAMXoEOQUu+GCPZkwHp9mhvArF2+2\n         nDv2f8MaGtgJzJ5KvOg8h2qLYkWy7Mv8HedxAsq6frYr9ebGfcSnDF/Y696AjIhdDt5H\n         OnVTtdrK8xoh2RFak7/DYbwW7OpInGs/B85ATxGIsMMP9F5seNuFUWdwFgJbM3y03IV4\n         hINA==","X-Forwarded-Encrypted":"i=1;\n AFNElJ+/OnLlVvv65IV0Yyql99VI0yGfvTuIiaTW9DzoCj7/0VWHs3IIWeAOuWJ+WAngIZHp37NX72N3zhw=@vger.kernel.org","X-Gm-Message-State":"AOJu0Yx7P/iHwSYl1bpdzKhx2xUiQPL1b92xeQXNVojnk0J/AFue+Cwx\n\tKVownEdsEZkw1zGb7Iw+SMxBMrJkWUkNozDhXREXTUbTWTyAfmEiwkJx","X-Gm-Gg":"Acq92OGlDslE4wmuLKwaKaKxe3jiSkcs+JZdU41t08M5G6f8Erg/huNW8mtVtBpVVps\n\tbnh/+2y6GIt6po3JGuDzVBSR9Htn1GVrIKu4beA+tKi8xO9Lo1gnjkiMgoe/fCRgm+Im6F/AgKw\n\t7rH70bTz7JiJzGqIW7ZLd+A/foUq9En6L2bCKu1FtuhSFGqD+o5XMTN3F3C+XU19cqG+Xame+Lk\n\tmi8mX7/94C0N98QgYdpBQnug3DXERt2Zr8V59dMHT3JJ/jmejNcbyQJC/gmUwqUt0MKb0KV19Te\n\tmt0KUF7od3+wtDtJHxtjhbTnoDNjJqb5608OPnB4FRgQd8dmnYSQ7rKTzEnNQBAZeP9IWuhBhAD\n\tYfo9v9ekbotsu5zeGlMnxSyq4M4ZrSZfhhwwiMjTv8vyHj9ulzjYnmwBFpvrxIuQNOCdCtgTMsf\n\tIiR5SzQ8NZmT4sk9Stm3QGLOK34hfjI4qDdJ9zAswk","X-Received":"by 2002:a17:903:1af0:b0:2ad:bd4c:a5 with SMTP id\n d9443c01a7336-2ba78f63c82mr112714875ad.1.1778210327123;\n        Thu, 07 May 2026 20:18:47 -0700 (PDT)","From":"alistair23@gmail.com","X-Google-Original-From":"alistair.francis@wdc.com","To":"alistair@alistair23.me,\n\tlinux-kernel@vger.kernel.org,\n\tlukas@wunner.de,\n\tJonathan.Cameron@huawei.com,\n\tbhelgaas@google.com,\n\trust-for-linux@vger.kernel.org,\n\takpm@linux-foundation.org,\n\tlinux-cxl@vger.kernel.org,\n\tdjbw@kernel.org,\n\tlinux-pci@vger.kernel.org","Cc":"alex.gaynor@gmail.com,\n\twilfred.mallawa@wdc.com,\n\tgary@garyguo.net,\n\tbjorn3_gh@protonmail.com,\n\tbenno.lossin@proton.me,\n\taliceryhl@google.com,\n\tboqun.feng@gmail.com,\n\ta.hindborg@kernel.org,\n\ttmgross@umich.edu,\n\tojeda@kernel.org,\n\talistair23@gmail.com","Subject":"[PATCH 11/18] lib: rspdm: Support SPDM get_version","Date":"Fri,  8 May 2026 13:17:03 +1000","Message-ID":"<20260508031710.514574-12-alistair.francis@wdc.com>","X-Mailer":"git-send-email 2.52.0","In-Reply-To":"<20260508031710.514574-1-alistair.francis@wdc.com>","References":"<20260508031710.514574-1-alistair.francis@wdc.com>","Precedence":"bulk","X-Mailing-List":"linux-pci@vger.kernel.org","List-Id":"<linux-pci.vger.kernel.org>","List-Subscribe":"<mailto:linux-pci+subscribe@vger.kernel.org>","List-Unsubscribe":"<mailto:linux-pci+unsubscribe@vger.kernel.org>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit"},"content":"From: Alistair Francis <alistair@alistair23.me>\n\nSupport the GET_VERSION SPDM command.\n\nSigned-off-by: Alistair Francis <alistair@alistair23.me>\n---\n lib/rspdm/consts.rs    | 14 +++++++++\n lib/rspdm/lib.rs       |  8 ++++-\n lib/rspdm/state.rs     | 61 ++++++++++++++++++++++++++++++++++++\n lib/rspdm/validator.rs | 70 ++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 152 insertions(+), 1 deletion(-)","diff":"diff --git a/lib/rspdm/consts.rs b/lib/rspdm/consts.rs\nindex 2feddde67885..5482a0f6cee0 100644\n--- a/lib/rspdm/consts.rs\n+++ b/lib/rspdm/consts.rs\n@@ -7,10 +7,21 @@\n //! Rust implementation of the DMTF Security Protocol and Data Model (SPDM)\n //! <https://www.dmtf.org/dsp/DSP0274>\n \n+use crate::validator::SpdmHeader;\n+use core::mem;\n+\n /* SPDM versions supported by this implementation */\n pub(crate) const SPDM_VER_10: u8 = 0x10;\n+#[allow(dead_code)]\n+pub(crate) const SPDM_VER_11: u8 = 0x11;\n+#[allow(dead_code)]\n+pub(crate) const SPDM_VER_12: u8 = 0x12;\n+#[allow(dead_code)]\n+pub(crate) const SPDM_VER_13: u8 = 0x13;\n+pub(crate) const SPDM_VER_14: u8 = 0x14;\n \n pub(crate) const SPDM_MIN_VER: u8 = SPDM_VER_10;\n+pub(crate) const SPDM_MAX_VER: u8 = SPDM_VER_14;\n \n pub(crate) const SPDM_REQ: u8 = 0x80;\n pub(crate) const SPDM_ERROR: u8 = 0x7f;\n@@ -54,3 +65,6 @@ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n         Ok(())\n     }\n }\n+\n+pub(crate) const SPDM_GET_VERSION: u8 = 0x84;\n+pub(crate) const SPDM_GET_VERSION_LEN: usize = mem::size_of::<SpdmHeader>() + u8::MAX as usize;\ndiff --git a/lib/rspdm/lib.rs b/lib/rspdm/lib.rs\nindex 758d43fba5cb..1cc6c33516fb 100644\n--- a/lib/rspdm/lib.rs\n+++ b/lib/rspdm/lib.rs\n@@ -105,7 +105,13 @@\n /// Return 0 on success or a negative errno.  In particular, -EPROTONOSUPPORT\n /// indicates authentication is not supported by the device.\n #[export]\n-pub unsafe extern \"C\" fn spdm_authenticate(_state_ptr: *mut spdm_state) -> c_int {\n+pub unsafe extern \"C\" fn spdm_authenticate(state_ptr: *mut spdm_state) -> c_int {\n+    let state: &mut SpdmState = unsafe { &mut (*(state_ptr as *mut SpdmState)) };\n+\n+    if let Err(e) = state.get_version() {\n+        return e.to_errno() as c_int;\n+    }\n+\n     0\n }\n \ndiff --git a/lib/rspdm/state.rs b/lib/rspdm/state.rs\nindex 18e81f24c724..26b90942b298 100644\n--- a/lib/rspdm/state.rs\n+++ b/lib/rspdm/state.rs\n@@ -8,6 +8,7 @@\n //! <https://www.dmtf.org/dsp/DSP0274>\n \n use core::ffi::c_void;\n+use core::slice::from_raw_parts_mut;\n use kernel::prelude::*;\n use kernel::{\n     bindings,\n@@ -22,10 +23,14 @@\n use crate::consts::{\n     SpdmErrorCode,\n     SPDM_ERROR,\n+    SPDM_GET_VERSION_LEN,\n+    SPDM_MAX_VER,\n     SPDM_MIN_VER,\n     SPDM_REQ, //\n };\n use crate::validator::{\n+    GetVersionReq,\n+    GetVersionRsp,\n     SpdmErrorRsp,\n     SpdmHeader, //\n };\n@@ -232,4 +237,60 @@ pub(crate) fn spdm_exchange(\n \n         Ok(length)\n     }\n+\n+    /// Negotiate a supported SPDM version and store the information\n+    /// in the `SpdmState`.\n+    pub(crate) fn get_version(&mut self) -> Result<(), Error> {\n+        let mut request = GetVersionReq::default();\n+        request.version = self.version;\n+\n+        // SAFETY: `request` is repr(C) and packed, so we can convert it to a slice\n+        let request_buf = unsafe {\n+            from_raw_parts_mut(\n+                &mut request as *mut _ as *mut u8,\n+                core::mem::size_of::<GetVersionReq>(),\n+            )\n+        };\n+\n+        let mut response_vec: KVec<u8> = KVec::with_capacity(SPDM_GET_VERSION_LEN, GFP_KERNEL)?;\n+        // SAFETY: `response_vec` is SPDM_GET_VERSION_LEN length, initialised, aligned\n+        // and won't be mutated\n+        let response_buf =\n+            unsafe { from_raw_parts_mut(response_vec.as_mut_ptr(), SPDM_GET_VERSION_LEN) };\n+\n+        let rc = self.spdm_exchange(request_buf, response_buf)?;\n+\n+        // SAFETY: `rc` is the length of data read, which will be smaller\n+        // than the capacity of the vector\n+        unsafe { response_vec.inc_len(rc as usize) };\n+\n+        let response: &mut GetVersionRsp = Untrusted::new_mut(&mut response_vec).validate_mut()?;\n+\n+        let mut foundver = false;\n+        let unaligned = core::ptr::addr_of_mut!(response.version_number_entries) as *mut u16;\n+\n+        for i in 0..response.version_number_entry_count {\n+            // Creating a reference on a packed struct will result in\n+            // undefined behaviour, so we operate on the raw data directly\n+            let addr = unaligned.wrapping_add(i as usize);\n+            let alpha_version = (unsafe { core::ptr::read_unaligned::<u16>(addr) } & 0xF) as u8;\n+            let version = (unsafe { core::ptr::read_unaligned::<u16>(addr) } >> 8) as u8;\n+\n+            if alpha_version > 0 {\n+                pr_warn!(\"Alpha version {alpha_version} is unsupported\\n\");\n+            }\n+\n+            if version >= self.version && version <= SPDM_MAX_VER {\n+                self.version = version;\n+                foundver = true;\n+            }\n+        }\n+\n+        if !foundver {\n+            pr_err!(\"No common supported version\\n\");\n+            to_result(-(bindings::EPROTO as i32))?;\n+        }\n+\n+        Ok(())\n+    }\n }\ndiff --git a/lib/rspdm/validator.rs b/lib/rspdm/validator.rs\nindex 58039f532b7d..8f45bafd4d69 100644\n--- a/lib/rspdm/validator.rs\n+++ b/lib/rspdm/validator.rs\n@@ -7,6 +7,10 @@\n //! Rust implementation of the DMTF Security Protocol and Data Model (SPDM)\n //! <https://www.dmtf.org/dsp/DSP0274>\n \n+use crate::bindings::{\n+    __IncompleteArrayField,\n+    __le16, //\n+};\n use crate::consts::SpdmErrorCode;\n use core::mem;\n use kernel::prelude::*;\n@@ -21,6 +25,11 @@\n     },\n };\n \n+use crate::consts::{\n+    SPDM_GET_VERSION,\n+    SPDM_MIN_VER, //\n+};\n+\n #[repr(C, packed)]\n pub(crate) struct SpdmHeader {\n     pub(crate) version: u8,\n@@ -71,3 +80,64 @@ pub(crate) struct SpdmErrorRsp {\n     pub(crate) error_code: SpdmErrorCode,\n     pub(crate) error_data: u8,\n }\n+\n+#[repr(C, packed)]\n+pub(crate) struct GetVersionReq {\n+    pub(crate) version: u8,\n+    pub(crate) code: u8,\n+    pub(crate) param1: u8,\n+    pub(crate) param2: u8,\n+}\n+\n+impl Default for GetVersionReq {\n+    fn default() -> Self {\n+        GetVersionReq {\n+            version: 0,\n+            code: SPDM_GET_VERSION,\n+            param1: 0,\n+            param2: 0,\n+        }\n+    }\n+}\n+\n+#[repr(C, packed)]\n+pub(crate) struct GetVersionRsp {\n+    pub(crate) version: u8,\n+    pub(crate) code: u8,\n+    param1: u8,\n+    param2: u8,\n+    reserved: u8,\n+    pub(crate) version_number_entry_count: u8,\n+    pub(crate) version_number_entries: __IncompleteArrayField<__le16>,\n+}\n+\n+impl Validate<&mut Unvalidated<KVec<u8>>> for &mut GetVersionRsp {\n+    type Err = Error;\n+\n+    fn validate(unvalidated: &mut Unvalidated<KVec<u8>>) -> Result<Self, Self::Err> {\n+        let raw = unvalidated.raw_mut();\n+        if raw.len() < mem::size_of::<GetVersionRsp>() {\n+            return Err(EINVAL);\n+        }\n+\n+        let version = *(raw.get(0).ok_or(ENOMEM))? as usize;\n+        if version != SPDM_MIN_VER.into() {\n+            return Err(EINVAL);\n+        }\n+\n+        let version_number_entries = *(raw.get(5).ok_or(ENOMEM))? as usize;\n+        let total_expected_size =\n+            version_number_entries * mem::size_of::<__le16>() + mem::size_of::<GetVersionRsp>();\n+        if raw.len() < total_expected_size {\n+            return Err(EINVAL);\n+        }\n+\n+        let ptr = raw.as_mut_ptr();\n+        // CAST: `GetVersionRsp` only contains integers and has `repr(C)`.\n+        let ptr = ptr.cast::<GetVersionRsp>();\n+        // SAFETY: `ptr` came from a reference and the cast above is valid.\n+        let rsp: &mut GetVersionRsp = unsafe { &mut *ptr };\n+\n+        Ok(rsp)\n+    }\n+}\n","prefixes":["11/18"]}