get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/2190211/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2190211,
    "url": "http://patchwork.ozlabs.org/api/patches/2190211/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/fwts/patch/20260129035557.61443-1-ivan.hu@canonical.com/",
    "project": {
        "id": 24,
        "url": "http://patchwork.ozlabs.org/api/projects/24/?format=api",
        "name": "Firmware Test Suite development",
        "link_name": "fwts",
        "list_id": "fwts-devel.lists.ubuntu.com",
        "list_email": "fwts-devel@lists.ubuntu.com",
        "web_url": null,
        "scm_url": null,
        "webscm_url": null,
        "list_archive_url": "",
        "list_archive_url_format": "",
        "commit_url_format": ""
    },
    "msgid": "<20260129035557.61443-1-ivan.hu@canonical.com>",
    "list_archive_url": null,
    "date": "2026-01-29T03:55:57",
    "name": "[V2] New tests for Arm PSCI functions",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": false,
    "hash": "6e50833be66a845d95ac802492209bdfe701be6d",
    "submitter": {
        "id": 14061,
        "url": "http://patchwork.ozlabs.org/api/people/14061/?format=api",
        "name": "Ivan Hu",
        "email": "ivan.hu@canonical.com"
    },
    "delegate": null,
    "mbox": "http://patchwork.ozlabs.org/project/fwts/patch/20260129035557.61443-1-ivan.hu@canonical.com/mbox/",
    "series": [
        {
            "id": 490165,
            "url": "http://patchwork.ozlabs.org/api/series/490165/?format=api",
            "web_url": "http://patchwork.ozlabs.org/project/fwts/list/?series=490165",
            "date": "2026-01-29T03:55:57",
            "name": "[V2] New tests for Arm PSCI functions",
            "version": 2,
            "mbox": "http://patchwork.ozlabs.org/series/490165/mbox/"
        }
    ],
    "comments": "http://patchwork.ozlabs.org/api/patches/2190211/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2190211/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<fwts-devel-bounces@lists.ubuntu.com>",
        "X-Original-To": "incoming@patchwork.ozlabs.org",
        "Delivered-To": "patchwork-incoming@legolas.ozlabs.org",
        "Authentication-Results": [
            "legolas.ozlabs.org;\n\tdkim=fail reason=\"signature verification failed\" (4096-bit key;\n unprotected) header.d=canonical.com header.i=@canonical.com\n header.a=rsa-sha256 header.s=20251003 header.b=VZQHmVvt;\n\tdkim-atps=neutral",
            "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=lists.ubuntu.com\n (client-ip=185.125.189.65; helo=lists.ubuntu.com;\n envelope-from=fwts-devel-bounces@lists.ubuntu.com;\n receiver=patchwork.ozlabs.org)"
        ],
        "Received": [
            "from lists.ubuntu.com (lists.ubuntu.com [185.125.189.65])\n\t(using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4f1lgF5xP8z1xqf\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 29 Jan 2026 14:56:09 +1100 (AEDT)",
            "from localhost ([127.0.0.1] helo=lists.ubuntu.com)\n\tby lists.ubuntu.com with esmtp (Exim 4.86_2)\n\t(envelope-from <fwts-devel-bounces@lists.ubuntu.com>)\n\tid 1vlJ8X-0001F6-9C; Thu, 29 Jan 2026 03:56:05 +0000",
            "from smtp-relay-internal-0.internal ([10.131.114.225]\n helo=smtp-relay-internal-0.canonical.com)\n by lists.ubuntu.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128)\n (Exim 4.86_2) (envelope-from <ivan.hu@canonical.com>)\n id 1vlJ8V-0001Ei-En\n for fwts-devel@lists.ubuntu.com; Thu, 29 Jan 2026 03:56:03 +0000",
            "from mail-pl1-f199.google.com (mail-pl1-f199.google.com\n [209.85.214.199])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest\n SHA256)\n (No client certificate requested)\n by smtp-relay-internal-0.canonical.com (Postfix) with ESMTPS id 0BBAD3FAE8\n for <fwts-devel@lists.ubuntu.com>; Thu, 29 Jan 2026 03:56:03 +0000 (UTC)",
            "by mail-pl1-f199.google.com with SMTP id\n d9443c01a7336-2a07fa318fdso4951145ad.0\n for <fwts-devel@lists.ubuntu.com>; Wed, 28 Jan 2026 19:56:02 -0800 (PST)",
            "from canonical.com (118-163-61-247.hinet-ip.hinet.net.\n [118.163.61.247]) by smtp.gmail.com with ESMTPSA id\n d9443c01a7336-2a88b4c3db4sm36334515ad.50.2026.01.28.19.55.59\n for <fwts-devel@lists.ubuntu.com>\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Wed, 28 Jan 2026 19:55:59 -0800 (PST)"
        ],
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com;\n s=20251003; t=1769658963;\n bh=B3RatcEG92oHztfT+FkE5agDmuqf42mLMWp1DRK6bcs=;\n h=From:To:Subject:Date:Message-ID:MIME-Version:Content-Type;\n b=VZQHmVvtRhAg9yUwlb/tU8lFceS8Ojk7EJFgBPab3gSTtnhxLaLcY/aGguYCiQeHZ\n nJ/KtXiRqOfOVDdbdNv03JQWdAxznjMUeesBNsqr9mNE+oiCNwv5gE1iUW3ePlIrNr\n IcX+J1xFnVNsp1qYBnyl+cCz8ey2NEEshL84qug9ahbV1nfL4qZ+hi7gqqbFqih1Gn\n jPQ7cDLrhuZfqzDdXBfBt9n5vt79IIe/JlRWl6qjZV+g4aJyKW6vNk90ua73YliR//\n 4cR2WX8ziatXw+eW3KhXqfTR172f5nUgU3VCnENxkj5Qf4aKWfddYOWSU0ezrua8sk\n xuVoSEqEBz1lBuUFpZzKHwvCIMt0Fwng0T+JKlmzxoiwVFZcUY/EvH5tWUmZb6IWXw\n BkAw1gfPt+i+LDtmrp5sy0oFlNdg+kKxus88dDdk2P3XmN3a96hkSUgOn+kFUka+mB\n LJGlMo8z6Bm/46d0CTvCXFCypSJiR9UC9Hm5YTuVoCIcQi8UhaDzNddZsvrUvnbT02\n WENcGawEnt6CWMFw59a+CAgk52POQgPMLn0mI8clAwRX8ZFLqo8qbMZDIZhkVP6ODM\n wvErKVzeImHYnISHZ0qqa4ySCEalVSt5Yqb+zsafrH8W74pqITgBjDPvVXFdu4v3FE\n CABfxRSvBtBjGfzZB86/2tl4=",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20230601; t=1769658961; x=1770263761;\n h=content-transfer-encoding:mime-version:message-id:date:subject:to\n :from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date:message-id\n :reply-to;\n bh=B3RatcEG92oHztfT+FkE5agDmuqf42mLMWp1DRK6bcs=;\n b=g/61Df6fzfqYcyyizXW2LXJ5Q52fznFH5ZV4zdGG2Bc4qEHrDL3kOdDosRX8y2bw6S\n +ENvf6TmE092ZPS38EaPW7v+MtJr6bhHCws1jSLfKNFTIAIBCftd0oJ65fIYMoM/MPOp\n p9jBoD37EG8GqQwASP45w2AmPrL5HFXKFh4DCfj6rCaUj7QllRvmnhVfvyIaaxECalZf\n 8jCuSXpuPyNYcCy5YE+pOsqLZbYtBdAjQ/wvitiBdbiO4+oOUpPDavAOYU+TjSfcSurF\n DUrp3G4mWtPDKg5Xd1dyl8+sxV+J/OxLEAVx3t7TZMJXJVcAJgfSLPYrnDPc5znMchN8\n 4ZYg==",
        "X-Gm-Message-State": "AOJu0YwCsfNYTYU0BHZfLiCnzi/pyqkO3lllv/of1umji7aD9RM806pK\n rryGKbrytHjs6jQdhDKQPdV+ypr7Sg6E1EwmOzQ91g6imEqbdCMa8eIqs0LSTkMcr2ONrICQ0Lk\n xHfTnZI1LJzdY+bjRH9xYqE7G+DLaC40izlDmnNcS4e7QxHKHGqUh2QztC7gZWb0wVLuFcLKbH/\n 1NUb6glzN53Ywx",
        "X-Gm-Gg": "AZuq6aIvUuQwmUBArmjGVRuGLKzIi0U6LWV6bbdAX6VNTapJ9Z/0O3lAXib52oYDFEC\n T5V5s9Jb8zxGq24/+8/RPxDtzHVbS73mKQWz0W3w4/V/PCAFQ4vS1+jqXNcqUCXpG1wLrrksneA\n SDip+0Q+lT5YGGhW992Azc0IT03uRGbdbhBBaXOe0/tcEjP8qjCvrMsdtGnp2CPY5ykkJWsenHj\n HqJofmKKyRkkBBTMrEyzSuI5dQGz5Elbd/rYVxHiPzubRr7miYxzlrCEwilGTpRwPsyU4hJJS+m\n te/tYIzoL7x2ZfPV5yh7hrbt7BSr4SvbqO/PMflFvROq1z7gmSwA8PnvKoJlQXNCRJhkOMDTBuT\n NRJ+dAR9TAHCMk1jidoIFKj53x+sRQnc2abneBI08Y4smJguaDQ==",
        "X-Received": [
            "by 2002:a17:902:ceca:b0:295:fc0:5a32 with SMTP id\n d9443c01a7336-2a870d47e9amr79304255ad.3.1769658961113;\n Wed, 28 Jan 2026 19:56:01 -0800 (PST)",
            "by 2002:a17:902:ceca:b0:295:fc0:5a32 with SMTP id\n d9443c01a7336-2a870d47e9amr79304105ad.3.1769658960483;\n Wed, 28 Jan 2026 19:56:00 -0800 (PST)"
        ],
        "From": "Ivan Hu <ivan.hu@canonical.com>",
        "To": "fwts-devel@lists.ubuntu.com",
        "Subject": "[V2][PATCH] New tests for Arm PSCI functions",
        "Date": "Thu, 29 Jan 2026 11:55:57 +0800",
        "Message-ID": "<20260129035557.61443-1-ivan.hu@canonical.com>",
        "X-Mailer": "git-send-email 2.43.0",
        "MIME-Version": "1.0",
        "X-BeenThere": "fwts-devel@lists.ubuntu.com",
        "X-Mailman-Version": "2.1.20",
        "Precedence": "list",
        "List-Id": "Firmware Test Suite Development <fwts-devel.lists.ubuntu.com>",
        "List-Unsubscribe": "<https://lists.ubuntu.com/mailman/options/fwts-devel>,\n <mailto:fwts-devel-request@lists.ubuntu.com?subject=unsubscribe>",
        "List-Archive": "<https://lists.ubuntu.com/archives/fwts-devel>",
        "List-Post": "<mailto:fwts-devel@lists.ubuntu.com>",
        "List-Help": "<mailto:fwts-devel-request@lists.ubuntu.com?subject=help>",
        "List-Subscribe": "<https://lists.ubuntu.com/mailman/listinfo/fwts-devel>,\n <mailto:fwts-devel-request@lists.ubuntu.com?subject=subscribe>",
        "Content-Type": "text/plain; charset=\"utf-8\"",
        "Content-Transfer-Encoding": "base64",
        "Errors-To": "fwts-devel-bounces@lists.ubuntu.com",
        "Sender": "\"fwts-devel\" <fwts-devel-bounces@lists.ubuntu.com>"
    },
    "content": "From: edhay <edhaya.chandran@arm.com>\n\nPower State Coordination Interface (PSCI) is a standard to manage power states in systems\nbased on Arm architectures—especially in multi-core or multi-cluster environments.\nPSCI provides a firmware interface that allows operating systems to control\nthe power states of CPUs and other system components in a standardized way.\nActual implementation of these calls reside in secure firmware like Arm Trusted Firmware.\n\nArm defines these interfaces in\nArm Power State Coordination Interface specification\nhttps://developer.arm.com/documentation/den0022/latest/\n\nFollowing new tests are added:\n 1. Check if PSCI is supported as per ACPI FADT table\n 2. Test for PSCI_VERSION\n 3. Test for PSCI_FEATURES: Check for the implementation of all\n    the 22 PSCI functions\n 4. Test for AFFINITY_INFO\n 5. psci_features_bbr_check: Checks if all the mandatory PSCI functions\n       according to the Arm BBR specification is implemented.\n       enabled only with --sbbr or --ebbr flags\n\n This suite has dependency on smccc_test kernel module and the same\n should loaded\n\n usage\n    sudo fwts psci\n    sudo fwts psci --sbbr\n    sudo fwts psci --ebbr\n\nRelated change: Moved smccc init and related code to fwts helper lib\n\nSigned-off-by: G Edhaya Chandran <edhaya.chandran@arm.com>\n---\n smccc_test/smccc_test.c      |  63 ++++\n smccc_test/smccc_test.h      |   6 +\n src/Makefile.am              |   1 +\n src/lib/include/fwts_smccc.h |  39 +++\n src/lib/src/Makefile.am      |   2 +\n src/lib/src/fwts_smccc.c     | 116 ++++++++\n src/smccc/psci.c             | 545 +++++++++++++++++++++++++++++++++++\n src/smccc/smccc.c            |  88 +-----\n 8 files changed, 773 insertions(+), 87 deletions(-)\n create mode 100644 src/lib/include/fwts_smccc.h\n create mode 100644 src/lib/src/fwts_smccc.c\n create mode 100644 src/smccc/psci.c",
    "diff": "diff --git a/smccc_test/smccc_test.c b/smccc_test/smccc_test.c\nindex b4396092..0be95027 100644\n--- a/smccc_test/smccc_test.c\n+++ b/smccc_test/smccc_test.c\n@@ -85,6 +85,18 @@ MODULE_LICENSE(\"GPL\");\n #define SMCCC_ARCH_SOC_ID\t0x80000002\n #endif\n \n+#ifndef PSCI_VERSION\n+#define PSCI_VERSION\t0x84000000\n+#endif\n+\n+#ifndef PSCI_FEATURES\n+#define PSCI_FEATURES\t0x8400000A\n+#endif\n+\n+#ifndef AFFINITY_INFO\n+#define AFFINITY_INFO\t0x84000004\n+#endif\n+\n /*\n  *  smccc_test_copy_to_user()\n  *\tcopy arm_res a* registers to user space test_arg w array\n@@ -199,6 +211,51 @@ static long smccc_test_arch_soc_id(unsigned long arg)\n \treturn smccc_test_copy_to_user(arg, &arm_res, conduit);\n }\n \n+static long smccc_test_psci_version(unsigned long arg)\n+{\n+\tstruct arm_smccc_res arm_res = { };\n+\tstruct smccc_test_arg test_arg;\n+\tint ret, conduit;\n+\n+\tret = smccc_test_copy_from_user(&test_arg, arg);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tconduit = arm_smccc_1_1_invoke(PSCI_VERSION, 0, 0, 0, 0, 0, 0, 0, &arm_res);\n+\n+\treturn smccc_test_copy_to_user(arg, &arm_res, conduit);\n+}\n+\n+static long smccc_test_psci_features(unsigned long arg)\n+{\n+\tstruct arm_smccc_res arm_res = { };\n+\tstruct smccc_test_arg test_arg;\n+\tint ret, conduit;\n+\n+\tret = smccc_test_copy_from_user(&test_arg, arg);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tconduit = arm_smccc_1_1_invoke(PSCI_FEATURES, test_arg.w[1], 0, 0, 0, 0, 0, 0, &arm_res);\n+\n+\treturn smccc_test_copy_to_user(arg, &arm_res, conduit);\n+}\n+\n+static long smccc_test_affinity_info(unsigned long arg)\n+{\n+\tstruct arm_smccc_res arm_res = { };\n+\tstruct smccc_test_arg test_arg;\n+\tint ret, conduit;\n+\n+\tret = smccc_test_copy_from_user(&test_arg, arg);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tconduit = arm_smccc_1_1_invoke(AFFINITY_INFO, test_arg.w[1], test_arg.w[2], 0, 0, 0, 0, 0, &arm_res);\n+\n+\treturn smccc_test_copy_to_user(arg, &arm_res, conduit);\n+}\n+\n static long smccc_test_ioctl(struct file *file, unsigned int cmd,\n \t\t\t     unsigned long arg)\n {\n@@ -229,6 +286,12 @@ static long smccc_test_ioctl(struct file *file, unsigned int cmd,\n \t\treturn smccc_test_arch_features(arg);\n \tcase SMCCC_TEST_ARCH_SOC_ID:\n \t\treturn smccc_test_arch_soc_id(arg);\n+\tcase SMCCC_TEST_PSCI_VERSION:\n+\t\treturn smccc_test_psci_version(arg);\n+\tcase SMCCC_TEST_PSCI_FEATURES:\n+\t\treturn smccc_test_psci_features(arg);\n+\tcase SMCCC_TEST_AFFINITY_INFO:\n+\t\treturn smccc_test_affinity_info(arg);\n \tdefault:\n \t\tbreak;\n \t}\ndiff --git a/smccc_test/smccc_test.h b/smccc_test/smccc_test.h\nindex 0901ff52..b93d2919 100644\n--- a/smccc_test/smccc_test.h\n+++ b/smccc_test/smccc_test.h\n@@ -45,4 +45,10 @@ struct smccc_test_arg {\n         _IOWR('p', 0x07, struct smccc_test_arg)\n #define SMCCC_TEST_ARCH_SOC_ID \\\n         _IOWR('p', 0x08, struct smccc_test_arg)\n+#define SMCCC_TEST_PSCI_VERSION \\\n+        _IOWR('p', 0x09, struct smccc_test_arg)\n+#define SMCCC_TEST_PSCI_FEATURES \\\n+        _IOWR('p', 0x0A, struct smccc_test_arg)\n+#define SMCCC_TEST_AFFINITY_INFO \\\n+        _IOWR('p', 0x0B, struct smccc_test_arg)\n #endif\ndiff --git a/src/Makefile.am b/src/Makefile.am\nindex 3a6808f9..a98a75a1 100644\n--- a/src/Makefile.am\n+++ b/src/Makefile.am\n@@ -208,6 +208,7 @@ fwts_SOURCES = main.c \t\t\t\t\\\n \tpci/crs/crs.c \t\t\t\t\\\n \tpci/maxreadreq/maxreadreq.c \t\t\\\n \tsmccc/smccc.c\t\t\t\t\\\n+\tsmccc/psci.c\t\t\t\t\\\n \ttpm/tpmevlog/tpmevlog.c\t\t\t\\\n \ttpm/tpmevlogdump/tpmevlogdump.c\t\t\\\n \tuefi/csm/csm.c \t\t\t\t\\\ndiff --git a/src/lib/include/fwts_smccc.h b/src/lib/include/fwts_smccc.h\nnew file mode 100644\nindex 00000000..94fea774\n--- /dev/null\n+++ b/src/lib/include/fwts_smccc.h\n@@ -0,0 +1,39 @@\n+/*\n+ * Copyright (C) 2026 Arm Ltd.\n+ *\n+ * This program is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU General Public License\n+ * as published by the Free Software Foundation; either version 2\n+ * of the License, or (at your option) any later version.\n+ *\n+ * This program is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n+ * GNU General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU General Public License\n+ * along with this program; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n+ *\n+ */\n+#ifndef __FWTS_SMCCC_H__\n+#define __FWTS_SMCCC_H__\n+\n+#include <stdint.h>\n+#include \"fwts.h\"\n+\n+/* SMCCC conduit types */\n+enum {\n+\tFWTS_SMCCC_CONDUIT_NONE,\n+\tFWTS_SMCCC_CONDUIT_SMC,\n+\tFWTS_SMCCC_CONDUIT_HVC,\n+};\n+\n+extern int smccc_fd;\n+\n+int smccc_init(fwts_framework *fw);\n+int smccc_deinit(fwts_framework *fw);\n+char *smccc_pci_conduit_name(struct smccc_test_arg *arg);\n+int smccc_pci_conduit_check(fwts_framework *fw, struct smccc_test_arg *arg);\n+\n+#endif\ndiff --git a/src/lib/src/Makefile.am b/src/lib/src/Makefile.am\nindex 15d8d106..6534f38f 100644\n--- a/src/lib/src/Makefile.am\n+++ b/src/lib/src/Makefile.am\n@@ -21,6 +21,7 @@ AM_CPPFLAGS = \\\n \t-I$(top_srcdir)/src/libfwtsiasl\t\t\t\\\n \t-I$(top_srcdir)/src/acpica/source/include\t\\\n \t-I$(top_srcdir)/src/acpica/source/compiler\t\\\n+\t-I$(top_srcdir)/smccc_test                      \\\n \t-DDATAROOTDIR=\\\"$(datarootdir)\\\"\t\t\\\n \t-Wall -Werror -Wextra\t\t\t\t\\\n \t-Wno-address-of-packed-member\n@@ -107,6 +108,7 @@ libfwts_la_SOURCES = \t\t\\\n \tfwts_scan_efi_systab.c \t\\\n \tfwts_set.c \t\t\\\n \tfwts_smbios.c \t\t\\\n+\tfwts_smccc.c \t\t\\\n \tfwts_stringextras.c \t\\\n \tfwts_summary.c \t\t\\\n \tfwts_text_list.c \t\\\ndiff --git a/src/lib/src/fwts_smccc.c b/src/lib/src/fwts_smccc.c\nnew file mode 100644\nindex 00000000..4ec228ed\n--- /dev/null\n+++ b/src/lib/src/fwts_smccc.c\n@@ -0,0 +1,116 @@\n+/*\n+ * Copyright (C) 2026 Arm Ltd.\n+ *\n+ * This program is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU General Public License\n+ * as published by the Free Software Foundation; either version 2\n+ * of the License, or (at your option) any later version.\n+ *\n+ * This program is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n+ * GNU General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU General Public License\n+ * along with this program; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n+ *\n+ */\n+\n+\n+#include <sys/types.h>\n+#include <sys/stat.h>\n+#include <fcntl.h>\n+#include <unistd.h>\n+#include <errno.h>\n+#include \"fwts.h\"\n+#include \"smccc_test.h\"\n+#include \"fwts_smccc.h\"\n+\n+#ifdef FWTS_ARCH_AARCH64\n+\n+int smccc_fd = -1;\n+\n+static const char *module_name = \"smccc_test\";\n+static const char *dev_name = \"/dev/smccc_test\";\n+static bool module_loaded;\n+\n+\n+\n+int smccc_init(fwts_framework *fw)\n+{\n+\tif (fwts_module_load(fw, module_name) != FWTS_OK) {\n+\t\tmodule_loaded = false;\n+\t\tsmccc_fd = -1;\n+\t\treturn FWTS_ERROR;\n+\t}\n+\n+\tsmccc_fd = open(dev_name, O_RDWR);\n+\tif (smccc_fd < 0) {\n+\t\tsmccc_fd = -1;\n+\t\tfwts_log_error(fw, \"Cannot open %s, errno=%d (%s)\\n\",\n+\t\t\tdev_name, errno, strerror(errno));\n+\t}\n+\n+\treturn FWTS_OK;\n+}\n+\n+int smccc_deinit(fwts_framework *fw)\n+{\n+\tif (smccc_fd >= 0) {\n+\t\tclose(smccc_fd);\n+\t\tsmccc_fd = -1;\n+\t}\n+\n+\tif (module_loaded && fwts_module_unload(fw, module_name) != FWTS_OK)\n+\t\treturn FWTS_ERROR;\n+\n+\tmodule_loaded = true;\n+\n+\treturn FWTS_OK;\n+}\n+\n+/*\n+ *  smccc_pci_conduit_name()\n+ *\tmap the conduit number to human readable string\n+ */\n+char *smccc_pci_conduit_name(struct smccc_test_arg *arg)\n+{\n+\tstatic char unknown[32];\n+\n+\tswitch (arg->conduit) {\n+\tcase FWTS_SMCCC_CONDUIT_NONE:\n+\t\treturn \"SMCCC_CONDUIT_NONE\";\n+\tcase FWTS_SMCCC_CONDUIT_HVC:\n+\t\treturn \"SMCCC_CONDUIT_HVC\";\n+\tcase FWTS_SMCCC_CONDUIT_SMC:\n+\t\treturn \"SMCCC_CONDUIT_SMC\";\n+\tdefault:\n+\t\tbreak;\n+\t}\n+\n+\tsnprintf(unknown, sizeof(unknown), \"Unknown: 0x%x\", arg->conduit);\n+\treturn unknown;\n+}\n+\n+/*\n+ *  smccc_pci_conduit_check()\n+ *\tcheck if conduit number is valid\n+ */\n+int smccc_pci_conduit_check(fwts_framework *fw, struct smccc_test_arg *arg)\n+{\n+\tswitch (arg->conduit) {\n+\tcase FWTS_SMCCC_CONDUIT_HVC:\n+\t\treturn FWTS_OK;\n+\tcase FWTS_SMCCC_CONDUIT_SMC:\n+\t\treturn FWTS_OK;\n+\tdefault:\n+\t\tfwts_log_error(fw, \"Invalid SMCCC conduit used: %s\\n\",\n+\t\t\t       smccc_pci_conduit_name(arg));\n+\t\treturn FWTS_ERROR;\n+\t}\n+\treturn FWTS_OK;\n+}\n+\n+\n+#endif\ndiff --git a/src/smccc/psci.c b/src/smccc/psci.c\nnew file mode 100644\nindex 00000000..99692214\n--- /dev/null\n+++ b/src/smccc/psci.c\n@@ -0,0 +1,545 @@\n+/*\n+ *\n+ * Copyright (C) 2025 Canonical\n+ * Copyright (C) 2025 Arm\n+ *\n+ * This program is free software; you can redistribute it and/or\n+ * modify it under the terms of the GNU General Public License\n+ * as published by the Free Software Foundation; either version 2\n+ * of the License, or (at your option) any later version.\n+ *\n+ * This program is distributed in the hope that it will be useful,\n+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\n+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n+ * GNU General Public License for more details.\n+ *\n+ * You should have received a copy of the GNU General Public License\n+ * along with this program; if not, write to the Free Software\n+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n+ *\n+ */\n+#include \"fwts.h\"\n+\n+#ifdef FWTS_ARCH_AARCH64\n+\n+#include <errno.h>\n+#include <inttypes.h>\n+#include <stdio.h>\n+#include <stddef.h>\n+#include <stdbool.h>\n+#include <string.h>\n+#include <sys/ioctl.h>\n+#include <fcntl.h>\n+\n+#include \"smccc_test.h\"\n+#include \"fwts_smccc.h\"\n+\n+/*\n+ * ARM PSCI tests,\n+ *   https://developer.arm.com/documentation/den0022/latest/\n+ */\n+\n+#define\tPSCI_VERSION            0x84000000\n+#define\tCPU_SUSPEND             0x84000001\n+#define\tCPU_OFF                 0x84000002\n+#define\tCPU_ON                  0x84000003\n+#define\tAFFINITY_INFO           0x84000004\n+#define\tMIGRATE                 0x84000005\n+#define\tMIGRATE_INFO_TYPE       0x84000006\n+#define\tMIGRATE_INFO_UP_CPU     0x84000007\n+#define\tSYSTEM_OFF              0x84000008\n+#define\tSYSTEM_RESET            0x84000009\n+#define\tPSCI_FEATURES           0x8400000A\n+#define\tCPU_FREEZE              0x8400000B\n+#define\tCPU_DEFAULT_SUSPEND     0x8400000C\n+#define\tNODE_HW_STATE           0x8400000D\n+#define\tSYSTEM_SUSPEND          0x8400000E\n+#define\tPSCI_SET_SUSPEND_MODE   0x8400000F\n+#define\tPSCI_STAT_RESIDENCY     0x84000010\n+#define\tPSCI_STAT_COUNT         0x84000011\n+#define\tSYSTEM_RESET2           0x84000012\n+#define\tMEM_PROTECT             0x84000013\n+#define\tMEM_PROTECT_CHECK_RANGE 0x84000014\n+#define\tSYSTEM_OFF2             0x84000015\n+\n+#define PSCI_VERSION_0_2 0x00002\n+#define PSCI_VERSION_1_0 0x10000\n+#define PSCI_VERSION_1_1 0x10001\n+#define PSCI_VERSION_1_2 0x10002\n+\n+enum PSCI_ret_code {\n+    PSCI_SUCCESS = 0,\n+    PSCI_NOT_SUPPORTED = -1\n+};\n+\n+typedef struct {\n+\tconst uint32_t\tPSCI_func_id;\n+\tconst char\t*PSCI_func_id_name;\n+\tbool\t\timplemented;\n+} PSCI_func_id_t;\n+\n+static PSCI_func_id_t PSCI_func_id_list[] = {\n+    { PSCI_VERSION,             \"PSCI_VERSION\",             false },\n+    { CPU_SUSPEND,              \"CPU_SUSPEND\",              false },\n+    { CPU_OFF,                  \"CPU_OFF\",                  false },\n+    { CPU_ON,                   \"CPU_ON\",                   false },\n+    { AFFINITY_INFO,            \"AFFINITY_INFO\",            false },\n+    { MIGRATE,                  \"MIGRATE\",                  false },\n+    { MIGRATE_INFO_TYPE,        \"MIGRATE_INFO_TYPE\",        false },\n+    { MIGRATE_INFO_UP_CPU,      \"MIGRATE_INFO_UP_CPU \",     false },\n+    { SYSTEM_OFF,               \"SYSTEM_OFF\",               false },\n+    { SYSTEM_RESET,             \"SYSTEM_RESET\",             false },\n+    { PSCI_FEATURES,            \"PSCI_FEATURES\",            false },\n+    { CPU_FREEZE,               \"CPU_FREEZE\",               false },\n+    { CPU_DEFAULT_SUSPEND,      \"CPU_DEFAULT_SUSPEND\",      false },\n+    { NODE_HW_STATE,            \"NODE_HW_STATE\",            false },\n+    { SYSTEM_SUSPEND,           \"SYSTEM_SUSPEND\",           false },\n+    { PSCI_SET_SUSPEND_MODE,    \"PSCI_SET_SUSPEND_MODE\",    false },\n+    { PSCI_STAT_RESIDENCY,      \"PSCI_STAT_RESIDENCY\",      false },\n+    { PSCI_STAT_COUNT,          \"PSCI_STAT_COUNT\",          false },\n+    { SYSTEM_RESET2,            \"SYSTEM_RESET2\",            false },\n+    { MEM_PROTECT,              \"MEM_PROTECT\",              false },\n+    { MEM_PROTECT_CHECK_RANGE,  \"MEM_PROTECT_CHECK_RANGE\",  false },\n+    { SYSTEM_OFF2,              \"SYSTEM_OFF2\",              false }\n+};\n+\n+static uint16_t psci_major_version = 0;\n+static uint16_t psci_minor_version = 0;\n+static uint32_t psci_version = 0;\n+\n+/*\n+ *  check_for_psci_support()\n+ *  This test checks if PSCI is supported in the system by checking the FADT table\n+ */\n+static int check_for_psci_support(fwts_framework *fw)\n+{\n+    static const fwts_acpi_gas null_gas;\n+    fwts_acpi_table_info *table = NULL;\n+    const fwts_acpi_table_fadt *fadt;\n+    int fadt_size;\n+    bool passed = true;\n+\n+    if (fwts_acpi_find_table(fw, \"FACP\", 0, &table) != FWTS_OK) {\n+        fwts_log_error(fw, \"Cannot read ACPI table FACP.\");\n+        return FWTS_ERROR;\n+    }\n+    if (table == NULL) {\n+        fwts_log_error(fw, \"ACPI table FACP does not exist!\");\n+        return FWTS_ERROR;\n+    }\n+\n+    fadt = (const fwts_acpi_table_fadt *)table->data;\n+    fadt_size = table->length;\n+    if (fadt_size == 0) {\n+        fwts_log_error(fw, \"ACPI table FACP has zero length!\");\n+        return FWTS_ERROR;\n+    }\n+\n+    bool PSCI_compliant = fadt->arm_boot_flags & FWTS_FACP_ARM_BOOT_ARCH_PSCI_COMPLIANT;\n+    if (PSCI_compliant) {\n+        fwts_log_info_verbatim(fw, \"Arm PSCI: FADT ARM_BOOT_ARCH PSCI compliant flag is set\");\n+    } else {\n+        fwts_log_error(fw, \"Arm PSCI: FADT ARM_BOOT_ARCH PSCI compliant flag is not set.\"\n+            \" PSCI is not supported\");\n+       return FWTS_ERROR;\n+    }\n+\n+    bool HVC_Conduit = fadt->arm_boot_flags & FWTS_FACP_ARM_BOOT_ARCH_PSCI_USE_HVC;\n+    if (HVC_Conduit) {\n+        fwts_log_info_verbatim(fw, \"Arm PSCI: PSCI uses HVC conduit\");\n+    } else {\n+        fwts_log_info_verbatim(fw, \"Arm PSCI: PSCI uses SMC conduit\");\n+    }\n+\n+    if (memcmp((const void *)&fadt->sleep_control_reg,\n+        (const void *)&null_gas,\n+        sizeof(fwts_acpi_gas))) {\n+        passed = false;\n+        fwts_log_error(fw, \"Arm PSCI: FADT SLEEP_CONTROL_REG is not zeroed (Recommended)\"\n+            \". Non-zero general register structure detected. Must be coded as all zeros\");\n+    }\n+\n+    if (memcmp((const void *)&fadt->sleep_status_reg,\n+           (const void *)&null_gas,\n+            sizeof(fwts_acpi_gas))) {\n+        passed = false;\n+        fwts_log_error(fw, \"Arm PSCI: FADT SLEEP_STATUS_REG is not zeroed (Recommended)\"\n+            \". Non-zero general register structure detected. Must be coded as all zeros\");\n+    }\n+\n+    if (passed == false)\n+    {\n+        fwts_failed(fw, LOG_LEVEL_MEDIUM, \"SleepNonZero\",\n+            \"FADT SLEEP_* registers field are non-zero.\");\n+        return (FWTS_ERROR);\n+    }\n+\n+    fwts_passed(fw, \"Check for Arm PSCI support test passed\");\n+    return FWTS_OK;\n+}\n+\n+\n+/*\n+ *  psci_version_test()\n+ * test PSCI function VERSION\n+ */\n+static int psci_version_test(fwts_framework *fw)\n+{\n+    int ret;\n+    struct smccc_test_arg arg = { };\n+\n+    arg.size = sizeof(arg);\n+    arg.w[0] = PSCI_VERSION;\n+\n+    ret = ioctl(smccc_fd, SMCCC_TEST_PSCI_VERSION, &arg);\n+    if (ret < 0) {\n+        fwts_log_error(fw, \"SMCCC test driver ioctl PSCI_TEST_VERSION \"\n+            \"failed, errno=%d (%s)\\n\", errno, strerror(errno));\n+        return FWTS_ERROR;\n+    }\n+    if (smccc_pci_conduit_check(fw, &arg) != FWTS_OK)\n+        return FWTS_ERROR;\n+\n+    fwts_log_info_verbatim(fw, \"  SMCCC conduit type: 0x%\" PRIx32 \" ('%s')\",\n+        arg.conduit, smccc_pci_conduit_name(&arg));\n+\n+    psci_major_version = arg.w[0] >> 16;\n+    psci_minor_version = arg.w[0] & 0x0000ffff;\n+    fwts_log_info_verbatim(fw, \"Arm PSCI: Major version: %\" PRIu16 \" , Minor version: %\" PRIu16 \" \",\n+        psci_major_version, psci_minor_version);\n+\n+    psci_version = (psci_major_version << 16) + psci_minor_version;\n+\n+    fwts_passed(fw, \"Arm PSCI_VERSION test passed\");\n+    return FWTS_OK;\n+}\n+\n+\n+/*\n+ * get_implementation_status()\n+ * Query the implementation status by function_id\n+*/\n+static bool get_implementation_status(const uint32_t func_id)\n+{\n+    int k=0;\n+    for (k=0; k < FWTS_ARRAY_SIZE(PSCI_func_id_list); k++) {\n+        if (PSCI_func_id_list[k].PSCI_func_id == func_id)\n+            return (PSCI_func_id_list[k].implemented);\n+    }\n+\n+    return false;\n+}\n+\n+/*\n+ * psci_features_bbr_check()\n+ * Asserts based on the BBR specification rules in\n+ * Section 4.2 which refers to the table 6.9 in the\n+ * PSCI specification https://developer.arm.com/documentation/den0022/latest/\n+ * This function can be run only if SBBR or EBBR flag is set\n+ * while running FWTS\n+ */\n+\n+ static int psci_features_bbr_check(fwts_framework *fw)\n+ {\n+    bool bbr_check_failed = false;\n+    uint16_t assert_failed_count = 0;\n+    int i=0;\n+\n+    fwts_log_info_verbatim(fw, \"Arm BBR PSCI implementation check - the detected PSCI version is %\" PRIu16 \".%\" PRIu16 \"\",\n+        psci_major_version, psci_minor_version);\n+\n+    for (i=0; i < FWTS_ARRAY_SIZE(PSCI_func_id_list); i++) {\n+        if(PSCI_func_id_list[i].implemented == false) {\n+            switch (PSCI_func_id_list[i].PSCI_func_id) {\n+                case PSCI_VERSION:\n+                case CPU_SUSPEND:\n+                case CPU_OFF:\n+                case CPU_ON:\n+                case AFFINITY_INFO:\n+                case SYSTEM_OFF:\n+                case SYSTEM_RESET: {\n+                    /* These PSCI functions are mandatory for all versions */\n+                    bbr_check_failed = true;\n+                }\n+                break;\n+\n+                case PSCI_FEATURES: {\n+                    /* PSCI_FEATURES is mandatory for all PSCI versions >= 1.0 */\n+                    if (psci_version >= PSCI_VERSION_1_0)\n+                    {\n+                        bbr_check_failed = true;\n+                    }\n+                }\n+                break;\n+\n+                default: {\n+                    fwts_log_info_verbatim(fw, \"Info: \\\"Optional\\\" Function: 0x%8.8\" PRIx32 \" (%s) is not Implemented.\",\n+                        PSCI_func_id_list[i].PSCI_func_id,\n+                        PSCI_func_id_list[i].PSCI_func_id_name);\n+                }\n+            }\n+            if (bbr_check_failed == true) {\n+                fwts_log_error(fw, \"failed: As per Arm BBR specifciation, \"\n+                    \"the implementation of %s is \\\"Mandatory\\\" in PSCI v%d.%d but is not implemented\"\n+                    , PSCI_func_id_list[i].PSCI_func_id_name\n+                    , psci_major_version, psci_minor_version);\n+                bbr_check_failed = false;\n+\n+                assert_failed_count++;\n+            }\n+        }\n+\n+        /* Additional checks */\n+        /* Some PSCI functions are mandatory conditionally. Such cases are checked below */\n+        if (PSCI_func_id_list[i].implemented == true) {\n+            switch (PSCI_func_id_list[i].PSCI_func_id) {\n+                case MIGRATE: {\n+                    /* If MIGRATE is implemented then MIGRATE_INFO_UP_CPU is mandatory */\n+                    if (false == get_implementation_status(MIGRATE_INFO_UP_CPU)) {\n+                        fwts_log_error(fw, \"failed: MIGRATE is implemented however MIGRATE_INFO_UP_CPU\"\n+                            \" is not implemented\");\n+                        assert_failed_count++;\n+                    }\n+                }\n+                break;\n+\n+                case PSCI_STAT_RESIDENCY: {\n+                    /* If PSCI_STAT_RESIDENCY is implemented then PSCI_STAT_COUNT is mandatory */\n+                    if (false == get_implementation_status(PSCI_STAT_COUNT)) {\n+                        fwts_log_error(fw, \"failed: PSCI_STAT_RESIDENCY is implemented however PSCI_STAT_COUNT\"\n+                            \" is not implemented\");\n+                        assert_failed_count++;\n+                    }\n+                }\n+                break;\n+\n+                case PSCI_STAT_COUNT: {\n+                    /* If PSCI_STAT_COUNT is implemented then PSCI_STAT_RESIDENCY is mandatory */\n+                    if (false == get_implementation_status(PSCI_STAT_RESIDENCY)) {\n+                        fwts_log_error(fw, \"failed: PSCI_STAT_COUNT is implemented however PSCI_STAT_RESIDENCY\"\n+                            \" is not implemented\");\n+                        assert_failed_count++;\n+                    }\n+                }\n+                break;\n+\n+                case MEM_PROTECT: {\n+                    /* If MEM_PROTECT is implemented then MEM_PROTECT_CHECK_RANGE is mandatory */\n+                    if (false == get_implementation_status(MEM_PROTECT_CHECK_RANGE)) {\n+                        fwts_log_error(fw, \"failed: MEM_PROTECT is implemented however MEM_PROTECT_CHECK_RANGE\"\n+                            \" is not implemented\");\n+                        assert_failed_count++;\n+                    }\n+                }\n+                break;\n+\n+                case MEM_PROTECT_CHECK_RANGE: {\n+                    /* If MEM_PROTECT_CHECK_RANGE is implemented then MEM_PROTECT is mandatory */\n+                    if (false == get_implementation_status(MEM_PROTECT)) {\n+                        fwts_log_error(fw, \"failed: MEM_PROTECT_CHECK_RANGE is implemented however MEM_PROTECT\"\n+                            \" is not implemented\");\n+                        assert_failed_count++;\n+                    }\n+                }\n+                break;\n+            }\n+\n+        }\n+    }\n+\n+    if (assert_failed_count > 0) {\n+        fwts_log_error(fw, \"Arm SBBR check for Arm PSCI_FEATURES failed. %d checks failed\",\n+            assert_failed_count);\n+        return FWTS_ERROR;\n+    }\n+\n+    fwts_log_info_verbatim(fw, \"Arm SBBR check for Arm PSCI_FEATURES test passed\");\n+    return FWTS_OK;\n+ }\n+\n+\n+/*\n+ *  psci_features_test()\n+ *  test PSCI function PSCI_FEATURES for each PSCI function\n+ */\n+ static int psci_features_test(fwts_framework *fw)\n+ {\n+    int ret;\n+    int i = 0;\n+    struct smccc_test_arg arg = { };\n+    bool feaatures_test_failed = 0;\n+\n+    if (psci_version == PSCI_VERSION_0_2) {\n+        fwts_skipped(fw, \"PSCI_FEATURES is Not Applicable for PSCI version %\" PRIu16 \".%\" PRIu16 \"\",\n+            psci_major_version, psci_minor_version);\n+        return FWTS_SKIP;\n+    }\n+\n+    fwts_log_info_verbatim(fw, \"========================= PSCI_FEATURES query ===========================\");\n+    fwts_log_info_verbatim(fw, \" #       Function Name                   Function ID     Implementation Status\");\n+    for (i = 0; i < FWTS_ARRAY_SIZE(PSCI_func_id_list); i++) {\n+        memset(&arg, 0, sizeof(arg));\n+        arg.size = sizeof(arg);\n+        arg.w[0] = PSCI_FEATURES;\n+\n+        /* arg.w[1] should contain, the function id of the\n+           PSCI function to query about */\n+        arg.w[1] = PSCI_func_id_list[i].PSCI_func_id;\n+\n+        ret = ioctl(smccc_fd, SMCCC_TEST_PSCI_FEATURES, &arg);\n+        if (ret < 0) {\n+            fwts_log_error(fw, \"SMCCC test driver ioctl PSCI_FEATURES \"\n+                \"failed, ret=%d, errno=%d (%s)\\n\", ret, errno, strerror(errno));\n+            return FWTS_ERROR;\n+        }\n+        if (smccc_pci_conduit_check(fw, &arg) != FWTS_OK)\n+            return FWTS_ERROR;\n+\n+        int32_t return_value = arg.w[0];\n+\n+        if (return_value == PSCI_NOT_SUPPORTED) {\n+            fwts_log_info_verbatim(fw, \"%2d       %-24s        0x%8.8\" PRIx32\"      NOT IMPLEMENTED\",\n+                i+1,\n+                PSCI_func_id_list[i].PSCI_func_id_name,\n+                PSCI_func_id_list[i].PSCI_func_id);\n+            PSCI_func_id_list[i].implemented = false;\n+        } else if (((arg.w[0] >> 31) & 0x1) == 0) { /* if bit 31 is 0, then the function is supported */\n+            fwts_log_info_verbatim(fw, \"%2d       %-24s        0x%8.8\" PRIx32\"      IMPLEMENTED\",\n+                i+1,\n+                PSCI_func_id_list[i].PSCI_func_id_name,\n+                PSCI_func_id_list[i].PSCI_func_id);\n+            PSCI_func_id_list[i].implemented = true;\n+        } else if (((arg.w[0] >> 31) & 0x1) == 1) { /* if bit 31 is 1, then the implementation is incorrect as per spec */\n+            fwts_log_info_verbatim(fw, \"%2d       %-24s        0x%8.8\" PRIx32\"    \"\n+                \"  Error Invalid return - Please check the implementation\",\n+                i+1,\n+                PSCI_func_id_list[i].PSCI_func_id_name,\n+                PSCI_func_id_list[i].PSCI_func_id);\n+                PSCI_func_id_list[i].implemented = false;\n+            feaatures_test_failed = 1;\n+        }\n+    }\n+    fwts_log_nl(fw); \n+    /* if --sbbr flag or --ebbr is set, additionally call the BBR assertions function */\n+    if (fw->flags & FWTS_FLAG_SBBR || fw->flags & FWTS_FLAG_EBBR) {\n+        if (psci_features_bbr_check(fw) == FWTS_ERROR) {\n+            fwts_failed(fw, LOG_LEVEL_HIGH, \"psci_features_bbr_check check \",\n+                \"for Arm BBR specification rules failed.\\n\");\n+            return (FWTS_ERROR);\n+        }\n+    }\n+\n+    if (feaatures_test_failed == 1) {\n+        fwts_failed(fw, LOG_LEVEL_HIGH, \"Arm Arm PSCI_FEATURES test\", \"failed\");\n+        return FWTS_ERROR;\n+    }\n+\n+    fwts_passed(fw, \"Arm PSCI_FEATURES test passed\");\n+    return FWTS_OK;\n+ }\n+\n+static inline uint64_t read_mpidr_el1(void)\n+{\n+    uint64_t mpidr;\n+    asm volatile(\"mrs %0, mpidr_el1\" : \"=r\" (mpidr));\n+    return mpidr;\n+}\n+\n+static int affinity_info_test(fwts_framework *fw)\n+{\n+    int ret;\n+    struct smccc_test_arg arg = { };\n+\n+    uint64_t mpidr = read_mpidr_el1();\n+    fwts_log_info_verbatim(fw, \"Info: mpidr = 0x%16.16\" PRIx64\"\", mpidr);\n+\n+\n+    uint32_t aff0 = mpidr & 0xFF;\n+    uint32_t aff1 = (mpidr >> 8) & 0xFF;\n+    uint32_t aff2 = (mpidr >> 16) & 0xFF;\n+    /* aff3 is unused */\n+\n+    uint32_t target_affinity = 0;\n+    target_affinity |= aff0;\n+    target_affinity |= (aff1 << 8);\n+    target_affinity |= (aff2 << 16);\n+\n+    fwts_log_info_verbatim(fw, \"Info: target_affinity = 0x%8.8\" PRIx32\"\", target_affinity);\n+\n+    uint32_t lowest_affinity_level = 0; /* All affinity levels are valid */\n+\n+    arg.size = sizeof(arg);\n+    arg.w[0] = AFFINITY_INFO;\n+    arg.w[1] = target_affinity;\n+    arg.w[2] = lowest_affinity_level;\n+\n+    ret = ioctl(smccc_fd, SMCCC_TEST_AFFINITY_INFO, &arg);\n+    if (ret < 0) {\n+        fwts_log_error(fw, \"SMCCC test driver ioctl SMCCC_TEST_AFFINITY_INFO \"\n+            \"failed, errno=%d (%s)\\n\", errno, strerror(errno));\n+        return FWTS_ERROR;\n+    }\n+    if (smccc_pci_conduit_check(fw, &arg) != FWTS_OK)\n+        return FWTS_ERROR;\n+\n+    fwts_log_info_verbatim(fw, \"  SMCCC conduit type: 0x%x ('%s')\",\n+        arg.conduit, smccc_pci_conduit_name(&arg));\n+\n+    int32_t result = arg.w[0];\n+    switch(result) {\n+        case 2: {\n+            fwts_log_info_verbatim(fw,\n+                \"Test AFFINITY_INFO returned value = %d (ON_PENDING)\", result);\n+        }\n+        break;\n+        case 1: {\n+            fwts_log_info_verbatim(fw,\n+                \"Test AFFINITY_INFO returned value = %d (OFF)\", result);\n+        }\n+        break;\n+        case 0: {\n+            fwts_log_info_verbatim(fw,\n+                \"Test AFFINITY_INFO returned value = %d (ON)\", result);\n+        }\n+        break;\n+        case -2: {\n+            fwts_log_info_verbatim(fw,\n+                \"Test AFFINITY_INFO returned value = %d (INVALID_PARAMETERS)\", result);\n+        }\n+        break;\n+        case -8: {\n+            fwts_log_info_verbatim(fw,\n+                \"Test AFFINITY_INFO returned value = %d (DISABLED)\", result);\n+        }\n+        break;\n+        default: {\n+            fwts_log_info_verbatim(fw,\n+                \"Test AFFINITY_INFO returned value = %d , an unexpected value\", result);\n+            fwts_failed(fw, LOG_LEVEL_HIGH, \"Arm PSCI AFFINITY_INFO \",\n+                \"test failed\");\n+            return FWTS_ERROR;\n+        }\n+    }\n+\n+    fwts_passed(fw, \"Arm PSCI AFFINITY_INFO test passed\");\n+    return FWTS_OK;\n+}\n+\n+static fwts_framework_minor_test psci_tests[] = {\n+    { check_for_psci_support,   \"Check for Arm PSCI support\" },\n+    { psci_version_test,        \"Test PSCI_VERSION\" },\n+    { psci_features_test,       \"Test PSCI_FEATURES\" },\n+    { affinity_info_test,       \"Test AFFINITY_INFO\" },\n+    { NULL, NULL }\n+};\n+\n+static fwts_framework_ops psciops = {\n+    .description = \"ARM64 PSCI tests.\",\n+    .init        = smccc_init,\n+    .deinit      = smccc_deinit,\n+    .minor_tests = psci_tests\n+};\n+\n+FWTS_REGISTER(\"psci\", &psciops, FWTS_TEST_ANYTIME, FWTS_FLAG_UNSAFE | FWTS_FLAG_ROOT_PRIV)\n+\n+#endif\ndiff --git a/src/smccc/smccc.c b/src/smccc/smccc.c\nindex 307e7ebd..5ca0df5d 100644\n--- a/src/smccc/smccc.c\n+++ b/src/smccc/smccc.c\n@@ -31,19 +31,13 @@\n #include <fcntl.h>\n \n #include \"smccc_test.h\"\n+#include \"fwts_smccc.h\"\n \n /*\n  * ARM SMCCC tests,\n  *   https://developer.arm.com/documentation/den0115/latest\n  */\n \n-/* SMCCC conduit types */\n-enum {\n-\tFWTS_SMCCC_CONDUIT_NONE,\n-\tFWTS_SMCCC_CONDUIT_SMC,\n-\tFWTS_SMCCC_CONDUIT_HVC,\n-};\n-\n /* SMCCC API function ids */\n #define PCI_VERSION\t (0x84000130)\n #define PCI_FEATURES\t (0x84000131)\n@@ -81,11 +75,6 @@ static pci_func_id_t pci_func_ids[] = {\n \t{ PCI_GET_SEG_INFO,\t\"PCI_GET_SEG_INFO\",\tfalse },\n };\n \n-static const char *module_name = \"smccc_test\";\n-static const char *dev_name = \"/dev/smccc_test\";\n-static bool module_loaded;\n-static int smccc_fd = -1;\n-\n typedef struct {\n \tconst uint32_t\tSMCCC_func_id;\n \tconst char\t*SMCCC_func_id_name;\n@@ -103,81 +92,6 @@ static SMCCC_func_id_t SMCCC_func_id_list[] = {\n static uint16_t smccc_major_version = 0;\n static uint16_t smccc_minor_version = 0;\n \n-static int smccc_init(fwts_framework *fw)\n-{\n-\tif (fwts_module_load(fw, module_name) != FWTS_OK) {\n-\t\tmodule_loaded = false;\n-\t\tsmccc_fd = -1;\n-\t\treturn FWTS_ERROR;\n-\t}\n-\n-\tsmccc_fd = open(dev_name, O_RDWR);\n-\tif (smccc_fd < 0) {\n-\t\tsmccc_fd = -1;\n-\t\tfwts_log_error(fw, \"Cannot open %s, errno=%d (%s)\\n\",\n-\t\t\tdev_name, errno, strerror(errno));\n-\t}\n-\n-\treturn FWTS_OK;\n-}\n-\n-static int smccc_deinit(fwts_framework *fw)\n-{\n-\tif (smccc_fd >= 0) {\n-\t\tclose(smccc_fd);\n-\t\tsmccc_fd = -1;\n-\t}\n-\n-\tif (module_loaded && fwts_module_unload(fw, module_name) != FWTS_OK)\n-\t\treturn FWTS_ERROR;\n-\n-\tmodule_loaded = true;\n-\n-\treturn FWTS_OK;\n-}\n-\n-/*\n- *  smccc_pci_conduit_name()\n- *\tmap the conduit number to human readable string\n- */\n-static char *smccc_pci_conduit_name(struct smccc_test_arg *arg)\n-{\n-\tstatic char unknown[32];\n-\n-\tswitch (arg->conduit) {\n-\tcase FWTS_SMCCC_CONDUIT_NONE:\n-\t\treturn \"SMCCC_CONDUIT_NONE\";\n-\tcase FWTS_SMCCC_CONDUIT_HVC:\n-\t\treturn \"SMCCC_CONDUIT_HVC\";\n-\tcase FWTS_SMCCC_CONDUIT_SMC:\n-\t\treturn \"SMCCC_CONDUIT_SMC\";\n-\tdefault:\n-\t\tbreak;\n-\t}\n-\n-\tsnprintf(unknown, sizeof(unknown), \"Unknown: 0x%x\", arg->conduit);\n-\treturn unknown;\n-}\n-\n-/*\n- *  smccc_pci_conduit_check()\n- *\tcheck if conduit number is valid\n- */\n-static int smccc_pci_conduit_check(fwts_framework *fw, struct smccc_test_arg *arg)\n-{\n-\tswitch (arg->conduit) {\n-\tcase FWTS_SMCCC_CONDUIT_HVC:\n-\t\treturn FWTS_OK;\n-\tcase FWTS_SMCCC_CONDUIT_SMC:\n-\t\treturn FWTS_OK;\n-\tdefault:\n-\t\tfwts_log_error(fw, \"Invalid SMCCC conduit used: %s\\n\",\n-\t\t\t       smccc_pci_conduit_name(arg));\n-\t\treturn FWTS_ERROR;\n-\t}\n-\treturn FWTS_OK;\n-}\n-\n /*\n  *  smccc_pci_func_implemented()\n  *\treturn true if function has been implemented, only valid\n",
    "prefixes": [
        "V2"
    ]
}