blob: 7a087ffade42b0474340cea085dcf2a36801b0e4 [file] [log] [blame]
/*
* Copyright (c) 2023-2025, Arm Limited. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdlib.h>
#include <assert.h>
#include <arch_features.h>
#include <debug.h>
#include <test_helpers.h>
#include <lib/extensions/fpu.h>
#include <lib/extensions/sme.h>
#include <lib/extensions/sve.h>
#include <host_realm_helper.h>
#include <host_realm_mem_layout.h>
#include <host_realm_simd.h>
#include <host_shared_data.h>
#include "host_realm_simd_common.h"
#define NS_SVE_OP_ARRAYSIZE 1024U
#define SVE_TEST_ITERATIONS 50U
static int ns_sve_op_1[NS_SVE_OP_ARRAYSIZE];
static int ns_sve_op_2[NS_SVE_OP_ARRAYSIZE];
/* Defined in host_realm_simd_common.c */
extern sve_z_regs_t ns_sve_z_regs_write;
extern sve_z_regs_t ns_sve_z_regs_read;
static struct realm realm;
/* Skip test if SVE is not supported in H/W or in RMI features */
#define CHECK_SVE_SUPPORT_IN_HW_AND_IN_RMI(_reg0) \
do { \
SKIP_TEST_IF_SVE_NOT_SUPPORTED(); \
\
/* Get RMM support for SVE and its max SVE VL */ \
if (host_rmi_features(0UL, &_reg0) != REALM_SUCCESS) { \
ERROR("Failed to get RMI feat_reg0\n"); \
return TEST_RESULT_FAIL; \
} \
\
/* SVE not supported in RMI features? */ \
if ((_reg0 & RMI_FEATURE_REGISTER_0_SVE_EN) == 0UL) { \
ERROR("SVE not in RMI features, skipping\n"); \
return TEST_RESULT_SKIPPED; \
} \
} while (false)
/*
* RMI should report SVE VL in RMI features and it must be the same value as the
* max SVE VL seen by the NS world.
*/
test_result_t host_check_rmi_reports_proper_sve_vl(void)
{
u_register_t rmi_feat_reg0;
uint8_t rmi_sve_vq;
uint8_t ns_sve_vq;
SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
CHECK_SVE_SUPPORT_IN_HW_AND_IN_RMI(rmi_feat_reg0);
rmi_sve_vq = EXTRACT(RMI_FEATURE_REGISTER_0_SVE_VL, rmi_feat_reg0);
/*
* Configure NS to arch supported max VL and get the value reported
* by rdvl
*/
sve_config_vq(SVE_VQ_ARCH_MAX);
ns_sve_vq = SVE_VL_TO_VQ(sve_rdvl_1());
if (rmi_sve_vq != ns_sve_vq) {
ERROR("RMI max SVE VL %u bits don't match NS max "
"SVE VL %u bits\n", SVE_VQ_TO_BITS(rmi_sve_vq),
SVE_VQ_TO_BITS(ns_sve_vq));
return TEST_RESULT_FAIL;
}
return TEST_RESULT_SUCCESS;
}
/* Test Realm creation with SVE enabled and run command rdvl */
test_result_t host_sve_realm_cmd_rdvl(void)
{
host_shared_data_t *sd;
struct sve_cmd_rdvl *rl_output;
uint8_t sve_vq, rl_max_sve_vq;
u_register_t rmi_feat_reg0;
test_result_t rc;
bool realm_rc;
SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
CHECK_SVE_SUPPORT_IN_HW_AND_IN_RMI(rmi_feat_reg0);
sve_vq = EXTRACT(RMI_FEATURE_REGISTER_0_SVE_VL, rmi_feat_reg0);
rc = host_create_sve_realm_payload(&realm, true, sve_vq, 1U, 0U);
if (rc != TEST_RESULT_SUCCESS) {
ERROR("Failed to create Realm with SVE\n");
return TEST_RESULT_FAIL;
}
realm_rc = host_enter_realm_execute(&realm, REALM_SVE_RDVL,
RMI_EXIT_HOST_CALL, 0U);
if (realm_rc != true) {
rc = TEST_RESULT_FAIL;
goto rm_realm;
}
/* Check if rdvl matches the SVE VL created */
sd = host_get_shared_structure(&realm, PRIMARY_PLANE_ID, 0U);
rl_output = (struct sve_cmd_rdvl *)sd->realm_cmd_output_buffer;
rl_max_sve_vq = SVE_VL_TO_VQ(rl_output->rdvl);
if (sve_vq == rl_max_sve_vq) {
rc = TEST_RESULT_SUCCESS;
} else {
ERROR("Realm created with max VL: %u bits, but Realm reported "
"max VL as: %u bits\n", SVE_VQ_TO_BITS(sve_vq),
SVE_VQ_TO_BITS(rl_max_sve_vq));
rc = TEST_RESULT_FAIL;
}
rm_realm:
if (!host_destroy_realm(&realm)) {
return TEST_RESULT_FAIL;
}
return rc;
}
/* Test Realm creation with SVE enabled but with invalid SVE VL */
test_result_t host_sve_realm_test_invalid_vl(void)
{
u_register_t rmi_feat_reg0;
test_result_t rc;
uint8_t sve_vq;
SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
CHECK_SVE_SUPPORT_IN_HW_AND_IN_RMI(rmi_feat_reg0);
sve_vq = EXTRACT(RMI_FEATURE_REGISTER_0_SVE_VL, rmi_feat_reg0);
/*
* TODO: The TFTF framework packs the sve_vl to feature flag for which the max value
* is 15 and then unpacks it to rmi_realm_params. Hence the value is clipped to 4 bits
* and hence it is not possible for test to send a value higher than this. Refactor
* this part of TFTF and then remove this limitation.
*/
if (sve_vq == SVE_VQ_ARCH_MAX) {
INFO("RMI supports arch max SVE VL %u, skipping\n", (sve_vq + 1));
return TEST_RESULT_SKIPPED;
}
rc = host_create_sve_realm_payload(&realm, true, (sve_vq + 1), 1U, 0U);
if (rc == TEST_RESULT_SUCCESS) {
ERROR("Error: Realm created with invalid SVE VL %u\n", (sve_vq + 1));
host_destroy_realm(&realm);
return TEST_RESULT_FAIL;
}
return TEST_RESULT_SUCCESS;
}
static test_result_t _host_sve_realm_check_id_registers(bool sve_en)
{
host_shared_data_t *sd;
struct sve_cmd_id_regs *r_regs;
u_register_t rmi_feat_reg0;
test_result_t rc;
bool realm_rc;
uint8_t sve_vq = 0U;
SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
if (sve_en) {
CHECK_SVE_SUPPORT_IN_HW_AND_IN_RMI(rmi_feat_reg0);
sve_vq = EXTRACT(RMI_FEATURE_REGISTER_0_SVE_VL, rmi_feat_reg0);
}
rc = host_create_sve_realm_payload(&realm, sve_en, sve_vq, 1U, 0U);
if (rc != TEST_RESULT_SUCCESS) {
return rc;
}
realm_rc = host_enter_realm_execute(&realm, REALM_SVE_ID_REGISTERS,
RMI_EXIT_HOST_CALL, 0U);
if (!realm_rc) {
rc = TEST_RESULT_FAIL;
goto rm_realm;
}
sd = host_get_shared_structure(&realm, PRIMARY_PLANE_ID, 0U);
r_regs = (struct sve_cmd_id_regs *)sd->realm_cmd_output_buffer;
/* Check ID register SVE flags */
if (sve_en) {
rc = TEST_RESULT_SUCCESS;
if (EXTRACT(ID_AA64PFR0_SVE, r_regs->id_aa64pfr0_el1) == 0UL) {
ERROR("ID_AA64PFR0_EL1: SVE not enabled\n");
rc = TEST_RESULT_FAIL;
}
if (r_regs->id_aa64zfr0_el1 == 0UL) {
ERROR("ID_AA64ZFR0_EL1: No SVE features present\n");
rc = TEST_RESULT_FAIL;
}
} else {
rc = TEST_RESULT_SUCCESS;
if (EXTRACT(ID_AA64PFR0_SVE, r_regs->id_aa64pfr0_el1) != 0UL) {
ERROR("ID_AA64PFR0_EL1: SVE enabled\n");
rc = TEST_RESULT_FAIL;
}
if (r_regs->id_aa64zfr0_el1 != 0UL) {
ERROR("ID_AA64ZFR0_EL1: Realm reported non-zero value\n");
rc = TEST_RESULT_FAIL;
}
}
rm_realm:
host_destroy_realm(&realm);
return rc;
}
/* Test ID_AA64PFR0_EL1, ID_AA64ZFR0_EL1_SVE values in SVE Realm */
test_result_t host_sve_realm_cmd_id_registers(void)
{
return _host_sve_realm_check_id_registers(true);
}
/* Test ID_AA64PFR0_EL1, ID_AA64ZFR0_EL1_SVE values in non SVE Realm */
test_result_t host_non_sve_realm_cmd_id_registers(void)
{
return _host_sve_realm_check_id_registers(false);
}
static void print_sve_vl_bitmap(uint32_t vl_bitmap)
{
for (uint8_t vq = 0U; vq <= SVE_VQ_ARCH_MAX; vq++) {
if ((vl_bitmap & BIT_32(vq)) != 0U) {
INFO("\t%u\n", SVE_VQ_TO_BITS(vq));
}
}
}
/* Create SVE Realm and probe all the supported VLs */
test_result_t host_sve_realm_cmd_probe_vl(void)
{
host_shared_data_t *sd;
struct sve_cmd_probe_vl *rl_output;
uint32_t vl_bitmap_expected;
u_register_t rmi_feat_reg0;
test_result_t rc;
bool realm_rc;
uint8_t sve_vq;
SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
CHECK_SVE_SUPPORT_IN_HW_AND_IN_RMI(rmi_feat_reg0);
sve_vq = EXTRACT(RMI_FEATURE_REGISTER_0_SVE_VL, rmi_feat_reg0);
rc = host_create_sve_realm_payload(&realm, true, sve_vq, 1U, 0U);
if (rc != TEST_RESULT_SUCCESS) {
return rc;
}
/*
* Configure TFTF with sve_vq and probe all VLs and compare it with
* the bitmap returned from Realm
*/
vl_bitmap_expected = sve_probe_vl(sve_vq);
realm_rc = host_enter_realm_execute(&realm, REALM_SVE_PROBE_VL,
RMI_EXIT_HOST_CALL, 0U);
if (!realm_rc) {
rc = TEST_RESULT_FAIL;
goto rm_realm;
}
sd = host_get_shared_structure(&realm, PRIMARY_PLANE_ID, 0U);
rl_output = (struct sve_cmd_probe_vl *)sd->realm_cmd_output_buffer;
INFO("Supported SVE vector length in bits (expected):\n");
print_sve_vl_bitmap(vl_bitmap_expected);
INFO("Supported SVE vector length in bits (probed):\n");
print_sve_vl_bitmap(rl_output->vl_bitmap);
if (vl_bitmap_expected == rl_output->vl_bitmap) {
rc = TEST_RESULT_SUCCESS;
} else {
rc = TEST_RESULT_FAIL;
}
rm_realm:
if (!host_destroy_realm(&realm)) {
return TEST_RESULT_FAIL;
}
return rc;
}
/* Check whether RMM preserves NS ZCR_EL2 register. */
test_result_t host_sve_realm_check_config_register(void)
{
u_register_t ns_zcr_el2, ns_zcr_el2_cur;
u_register_t rmi_feat_reg0;
test_result_t rc;
uint8_t vq;
SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
CHECK_SVE_SUPPORT_IN_HW_AND_IN_RMI(rmi_feat_reg0);
vq = EXTRACT(RMI_FEATURE_REGISTER_0_SVE_VL, rmi_feat_reg0);
rc = host_create_sve_realm_payload(&realm, true, vq, 1U, 0U);
if (rc != TEST_RESULT_SUCCESS) {
return rc;
}
/*
* Configure TFTF from 0 to SVE_VQ_ARCH_MAX, and in each iteration check
* if NS ZCR_EL2 is same before and after call to run Realm.
*/
rc = TEST_RESULT_SUCCESS;
for (vq = 0U; vq <= SVE_VQ_ARCH_MAX; vq++) {
bool realm_rc;
sve_config_vq(vq);
ns_zcr_el2 = read_zcr_el2();
/* Call Realm to run SVE command */
realm_rc = host_enter_realm_execute(&realm, REALM_SVE_RDVL,
RMI_EXIT_HOST_CALL, 0U);
if (!realm_rc) {
ERROR("Realm command REALM_SVE_RDVL failed\n");
rc = TEST_RESULT_FAIL;
break;
}
ns_zcr_el2_cur = read_zcr_el2();
if (ns_zcr_el2 != ns_zcr_el2_cur) {
ERROR("NS ZCR_EL2 expected: 0x%lx, got: 0x%lx\n",
ns_zcr_el2, ns_zcr_el2_cur);
rc = TEST_RESULT_FAIL;
}
}
if (!host_destroy_realm(&realm)) {
return TEST_RESULT_FAIL;
}
return rc;
}
/*
* Sends command to Realm to do SVE operations, while NS is also doing SVE
* operations.
* Returns:
* false - On success
* true - On failure
*/
static bool callback_realm_do_sve(void)
{
return !host_enter_realm_execute(&realm, REALM_SVE_OPS,
RMI_EXIT_HOST_CALL, 0U);
}
/*
* Sends command to Realm to do SVE operations, while NS is also doing SVE
* operations.
* Returns:
* false - On success
* true - On failure
*/
static bool callback_realm_do_fpu(void)
{
return !host_enter_realm_execute(&realm, REALM_REQ_FPU_FILL_CMD,
RMI_EXIT_HOST_CALL, 0U);
}
static test_result_t run_sve_vectors_operations(bool realm_sve_en,
uint8_t realm_sve_vq,
int ns_sve_mode)
{
bool (*realm_callback)(void);
test_result_t rc;
bool cb_err;
unsigned int i;
int val;
rc = host_create_sve_realm_payload(&realm, realm_sve_en, realm_sve_vq, 1U, 0U);
if (rc != TEST_RESULT_SUCCESS) {
return rc;
}
/* Get at random value to do sve_subtract */
val = rand();
for (i = 0U; i < NS_SVE_OP_ARRAYSIZE; i++) {
ns_sve_op_1[i] = val - i;
ns_sve_op_2[i] = 1;
}
if (realm_sve_en) {
realm_callback = callback_realm_do_sve;
} else {
realm_callback = callback_realm_do_fpu;
}
for (i = 0U; i < SVE_TEST_ITERATIONS; i++) {
/* Config NS world with random SVE VL or SVE SVL */
if (ns_sve_mode == NS_NORMAL_SVE) {
sve_config_vq(SVE_GET_RANDOM_VQ);
} else {
sme_config_svq(SME_GET_RANDOM_SVQ);
}
/* Perform SVE operations with intermittent calls to Realm */
cb_err = sve_subtract_arrays_interleaved(ns_sve_op_1,
ns_sve_op_1,
ns_sve_op_2,
NS_SVE_OP_ARRAYSIZE,
realm_callback);
if (cb_err) {
ERROR("Callback to realm failed\n");
rc = TEST_RESULT_FAIL;
goto rm_realm;
}
}
/* Check result of SVE operations. */
rc = TEST_RESULT_SUCCESS;
for (i = 0U; i < NS_SVE_OP_ARRAYSIZE; i++) {
if (ns_sve_op_1[i] != (val - i - SVE_TEST_ITERATIONS)) {
ERROR("%s op failed at idx: %u, expected: 0x%x received:"
" 0x%x\n", (ns_sve_mode == NS_NORMAL_SVE) ?
"SVE" : "SVE", i,
(val - i - SVE_TEST_ITERATIONS), ns_sve_op_1[i]);
rc = TEST_RESULT_FAIL;
}
}
rm_realm:
if (!host_destroy_realm(&realm)) {
return TEST_RESULT_FAIL;
}
return rc;
}
/*
* Intermittently switch to Realm while doing NS is doing SVE ops in Normal
* SVE mode.
*
* This testcase runs for SVE only config or SVE + SME config
*/
test_result_t host_sve_realm_check_vectors_operations(void)
{
u_register_t rmi_feat_reg0;
uint8_t realm_sve_vq;
SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
CHECK_SVE_SUPPORT_IN_HW_AND_IN_RMI(rmi_feat_reg0);
realm_sve_vq = EXTRACT(RMI_FEATURE_REGISTER_0_SVE_VL, rmi_feat_reg0);
/* Run SVE operations in Normal SVE mode */
return run_sve_vectors_operations(true, realm_sve_vq, NS_NORMAL_SVE);
}
/*
* Intermittently switch to Realm while doing NS is doing SVE ops in Streaming
* SVE mode
*
* This testcase runs for SME only config or SVE + SME config
*/
test_result_t host_sve_realm_check_streaming_vectors_operations(void)
{
u_register_t rmi_feat_reg0;
test_result_t rc;
uint8_t realm_sve_vq;
bool realm_sve_en;
SKIP_TEST_IF_SME_NOT_SUPPORTED();
SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
if (is_armv8_2_sve_present()) {
CHECK_SVE_SUPPORT_IN_HW_AND_IN_RMI(rmi_feat_reg0);
realm_sve_en = true;
realm_sve_vq = EXTRACT(RMI_FEATURE_REGISTER_0_SVE_VL,
rmi_feat_reg0);
} else {
realm_sve_en = 0;
realm_sve_vq = 0;
}
/* Enter Streaming SVE mode */
sme_smstart(SMSTART_SM);
/* Run SVE operations in Streaming SVE mode */
rc = run_sve_vectors_operations(realm_sve_en, realm_sve_vq,
NS_STREAMING_SVE);
/* Exit Streaming SVE mode */
sme_smstop(SMSTOP_SM);
return rc;
}
/*
* Check if RMM leaks Realm SVE registers.
* This test is skipped if the supported max VQ is 128 bits, as we won't be able
* to run NS and Realm context with lower and higher VQ respectively.
* This test does the below steps:
*
* 1. Set NS SVE VQ to max and write known pattern
* 2. NS programs ZCR_EL2 with VQ as 0 (128 bits).
* 3. Create Realm with max VQ (higher than NS SVE VQ).
* 4. Call Realm to fill in Z registers
* 5. Once Realm returns, NS sets ZCR_EL2 with max VQ and reads the Z registers
* 6. The upper bits of Z registers must be either 0 or the old values filled by
* NS world at step 1.
*/
test_result_t host_sve_realm_check_vectors_leaked(void)
{
u_register_t rmi_feat_reg0;
test_result_t rc;
uint64_t bitmap;
bool realm_rc;
uint8_t sve_vq;
SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
CHECK_SVE_SUPPORT_IN_HW_AND_IN_RMI(rmi_feat_reg0);
sve_vq = EXTRACT(RMI_FEATURE_REGISTER_0_SVE_VL, rmi_feat_reg0);
/* Skip test if the supported max VQ is 128 bits */
if (sve_vq == SVE_VQ_ARCH_MIN) {
return TEST_RESULT_SKIPPED;
}
/* 1. Set NS SVE VQ to max and write known pattern */
sve_config_vq(sve_vq);
(void)memset((void *)&ns_sve_z_regs_write, 0xAA,
SVE_VQ_TO_BYTES(sve_vq) * SVE_NUM_VECTORS);
sve_z_regs_write(&ns_sve_z_regs_write);
/* 2. NS programs ZCR_EL2 with VQ as 0 */
sve_config_vq(SVE_VQ_ARCH_MIN);
/* 3. Create Realm with max VQ (higher than NS SVE VQ) */
rc = host_create_sve_realm_payload(&realm, true, sve_vq, 1U, 0U);
if (rc != TEST_RESULT_SUCCESS) {
return rc;
}
/* 4. Call Realm to fill in Z registers */
realm_rc = host_enter_realm_execute(&realm, REALM_SVE_FILL_REGS,
RMI_EXIT_HOST_CALL, 0U);
if (!realm_rc) {
rc = TEST_RESULT_FAIL;
goto rm_realm;
}
/* 5. NS sets ZCR_EL2 with max VQ and reads the Z registers */
sve_config_vq(sve_vq);
sve_z_regs_read(&ns_sve_z_regs_read);
/*
* 6. The upper bits in Z vectors (sve_vq - SVE_VQ_ARCH_MIN) must
* be either 0 or the old values filled by NS world.
* TODO: check if upper bits are zero
*/
bitmap = sve_z_regs_compare(&ns_sve_z_regs_write, &ns_sve_z_regs_read);
if (bitmap != 0UL) {
ERROR("SVE Z regs compare failed (bitmap: 0x%016llx)\n",
bitmap);
rc = TEST_RESULT_FAIL;
} else {
rc = TEST_RESULT_SUCCESS;
}
rm_realm:
if (!host_destroy_realm(&realm)) {
return TEST_RESULT_FAIL;
}
return rc;
}
/*
* Create a non SVE Realm and try to access SVE, the Realm must receive
* undefined abort.
*/
test_result_t host_non_sve_realm_check_undef_abort(void)
{
test_result_t rc;
bool realm_rc;
SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
SKIP_TEST_IF_SVE_NOT_SUPPORTED();
rc = host_create_sve_realm_payload(&realm, false, 0, 1U, 0U);
if (rc != TEST_RESULT_SUCCESS) {
return rc;
}
realm_rc = host_enter_realm_execute(&realm, REALM_SVE_UNDEF_ABORT,
RMI_EXIT_HOST_CALL, 0U);
if (!realm_rc) {
ERROR("Realm didn't receive undefined abort\n");
rc = TEST_RESULT_FAIL;
} else {
rc = TEST_RESULT_SUCCESS;
}
if (!host_destroy_realm(&realm)) {
return TEST_RESULT_FAIL;
}
return rc;
}
/*
* Create a Realm and check SME specific ID registers. Realm must report SME
* not present in ID_AA64PFR1_EL1 and no SME features present in
* ID_AA64SMFR0_EL1
*/
test_result_t host_realm_check_sme_id_registers(void)
{
host_shared_data_t *sd;
struct sme_cmd_id_regs *r_regs;
test_result_t rc;
bool realm_rc;
SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
rc = host_create_sve_realm_payload(&realm, false, 0, 1U, 0U);
if (rc != TEST_RESULT_SUCCESS) {
return rc;
}
realm_rc = host_enter_realm_execute(&realm, REALM_SME_ID_REGISTERS,
RMI_EXIT_HOST_CALL, 0U);
if (!realm_rc) {
rc = TEST_RESULT_FAIL;
goto rm_realm;
}
sd = host_get_shared_structure(&realm, PRIMARY_PLANE_ID, 0U);
r_regs = (struct sme_cmd_id_regs *)sd->realm_cmd_output_buffer;
/* Check ID register SME flags */
rc = TEST_RESULT_SUCCESS;
if (EXTRACT(ID_AA64PFR1_EL1_SME, r_regs->id_aa64pfr1_el1) >=
ID_AA64PFR1_EL1_SME_SUPPORTED) {
ERROR("ID_AA64PFR1_EL1: SME enabled\n");
rc = TEST_RESULT_FAIL;
}
if (r_regs->id_aa64smfr0_el1 != 0UL) {
ERROR("ID_AA64SMFR0_EL1: Realm reported non-zero value\n");
rc = TEST_RESULT_FAIL;
}
rm_realm:
host_destroy_realm(&realm);
return rc;
}
/*
* Create a Realm and try to access SME, the Realm must receive undefined abort.
*/
test_result_t host_realm_check_sme_undef_abort(void)
{
test_result_t rc;
bool realm_rc;
SKIP_TEST_IF_SME_NOT_SUPPORTED();
SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
rc = host_create_sve_realm_payload(&realm, false, 0, 1U, 0U);
if (rc != TEST_RESULT_SUCCESS) {
return rc;
}
realm_rc = host_enter_realm_execute(&realm, REALM_SME_UNDEF_ABORT,
RMI_EXIT_HOST_CALL, 0U);
if (!realm_rc) {
ERROR("Realm didn't receive undefined abort\n");
rc = TEST_RESULT_FAIL;
} else {
rc = TEST_RESULT_SUCCESS;
}
host_destroy_realm(&realm);
return rc;
}
/*
* Check whether RMM preserves NS SME config values and flags
* 1. SMCR_EL2.LEN field
* 2. SMCR_EL2.FA64 flag
* 3. Streaming SVE mode status
*
* This test case runs for SVE + SME config and SME only config and skipped for
* non SME config.
*/
test_result_t host_realm_check_sme_configs(void)
{
u_register_t ns_smcr_el2, ns_smcr_el2_cur;
u_register_t rmi_feat_reg0;
bool ssve_mode;
test_result_t rc;
uint8_t sve_vq;
uint8_t sme_svq;
bool sve_en;
SKIP_TEST_IF_SME_NOT_SUPPORTED();
SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
if (is_armv8_2_sve_present()) {
CHECK_SVE_SUPPORT_IN_HW_AND_IN_RMI(rmi_feat_reg0);
sve_en = true;
sve_vq = EXTRACT(RMI_FEATURE_REGISTER_0_SVE_VL, rmi_feat_reg0);
} else {
sve_en = false;
sve_vq = 0;
}
rc = host_create_sve_realm_payload(&realm, sve_en, sve_vq, 1U, 0U);
if (rc != TEST_RESULT_SUCCESS) {
return rc;
}
/*
* Configure TFTF from 0 to SME_SVQ_ARCH_MAX, and in each iteration
* randomly enable or disable FA64 and Streaming SVE mode. Ater calling
* Realm, check the NS SME configuration status.
*/
rc = TEST_RESULT_SUCCESS;
for (sme_svq = 0U; sme_svq <= SME_SVQ_ARCH_MAX; sme_svq++) {
bool realm_rc;
sme_config_svq(sme_svq);
/* randomly enable or disable FEAT_SME_FA64 */
if (sme_svq % 2) {
sme_enable_fa64();
sme_smstart(SMSTART_SM);
ssve_mode = true;
} else {
sme_disable_fa64();
sme_smstop(SMSTOP_SM);
ssve_mode = false;
}
ns_smcr_el2 = read_smcr_el2();
/*
* If SVE is supported then we would have created a Realm with
* SVE support, so run SVE command else run FPU command
*/
if (sve_en) {
realm_rc = host_enter_realm_execute(&realm, REALM_SVE_RDVL,
RMI_EXIT_HOST_CALL,
0U);
} else {
realm_rc = host_enter_realm_execute(&realm,
REALM_REQ_FPU_FILL_CMD,
RMI_EXIT_HOST_CALL, 0U);
}
if (!realm_rc) {
ERROR("Realm command REALM_SVE_RDVL failed\n");
rc = TEST_RESULT_FAIL;
break;
}
ns_smcr_el2_cur = read_smcr_el2();
if (ns_smcr_el2 != ns_smcr_el2_cur) {
ERROR("NS SMCR_EL2 expected: 0x%lx, got: 0x%lx\n",
ns_smcr_el2, ns_smcr_el2_cur);
rc = TEST_RESULT_FAIL;
}
if (sme_smstat_sm() != ssve_mode) {
if (ssve_mode) {
ERROR("NS Streaming SVE mode is disabled\n");
} else {
ERROR("NS Streaming SVE mode is enabled\n");
}
rc = TEST_RESULT_FAIL;
}
}
/* Exit Streaming SVE mode if test case enabled it */
if (ssve_mode) {
sme_smstop(SMSTOP_SM);
}
if (!host_destroy_realm(&realm)) {
return TEST_RESULT_FAIL;
}
return rc;
}
test_result_t host_realm_check_sve_in_planes(void)
{
u_register_t rmi_feat_reg0;
uint8_t sve_vq;
test_result_t rc;
SKIP_TEST_IF_SME_NOT_SUPPORTED();
SKIP_TEST_IF_RME_NOT_SUPPORTED_OR_RMM_IS_TRP();
CHECK_SVE_SUPPORT_IN_HW_AND_IN_RMI(rmi_feat_reg0);
sve_vq = EXTRACT(RMI_FEATURE_REGISTER_0_SVE_VL, rmi_feat_reg0);
/*
* This test will create a realm with two RECs.
* - REC 0 will execute REALM_SVE_TEST_PLANE_N_FIRST_P0
* - REC 1 will ececute REALM_SVE_TEST_PLANE_N_FIRST_PN
*/
rc = host_create_sve_realm_payload(&realm, true, sve_vq, 2U, 1U);
if (rc != TEST_RESULT_SUCCESS) {
return rc;
}
/* Setup the configuration for Plane 1 on both RECs */
for (unsigned int i = 0U; i < 2U; i++) {
host_shared_data_set_realm_cmd(&realm, REALM_SVE_PLANE_N_ACCESS, 1U, i);
host_shared_data_set_host_val(&realm, 1U, i, HOST_ARG1_INDEX,
SIMD_TRAP_ATTEMPTS);
host_realm_set_aux_plane_args(&realm, 1U, i);
/* Rest of P0 parameters */
host_shared_data_set_host_val(&realm, PRIMARY_PLANE_ID, i,
HOST_ARG3_INDEX, i);
/* Enter the REC */
rc = host_enter_realm_execute(&realm, REALM_SVE_TEST_PLANE_N,
RMI_EXIT_HOST_CALL, i);
if (!rc) {
ERROR("Realm command REALM_SVE_TEST_PLANE_N failed\n");
rc = TEST_RESULT_FAIL;
break;
}
}
if (!host_destroy_realm(&realm)) {
return TEST_RESULT_FAIL;
}
return rc;
}