@@ -210,15 +210,20 @@ TCG VCPU Features
TCG VCPU features are CPU features that are specific to TCG.
Below is the list of TCG VCPU features and their descriptions.
-``pauth-impdef``
- When ``FEAT_Pauth`` is enabled, either the *impdef* (Implementation
- Defined) algorithm is enabled or the *architected* QARMA algorithm
- is enabled. By default the impdef algorithm is disabled, and QARMA
- is enabled.
+``pauth``
+ Enable or disable ``FEAT_Pauth`` entirely.
- The architected QARMA algorithm has good cryptographic properties,
- but can be quite slow to emulate. The impdef algorithm used by QEMU
- is non-cryptographic but significantly faster.
+``pauth-impdef``
+ When ``pauth`` is enabled, select the QEMU implementation defined algorithm.
+
+``pauth-qarma3``
+ When ``pauth`` is enabled, select the architected QARMA3 algorithm.
+
+Without either ``pauth-impdef`` or ``pauth-qarma3`` enabled,
+the architected QARMA5 algorithm is used. The architected QARMA5
+and QARMA3 algorithms have good cryptographic properties, but can
+be quite slow to emulate. The impdef algorithm used by QEMU is
+non-cryptographic but significantly faster.
SVE CPU Properties
==================
@@ -55,6 +55,9 @@ the following architecture extensions:
- FEAT_MTE (Memory Tagging Extension)
- FEAT_MTE2 (Memory Tagging Extension)
- FEAT_MTE3 (MTE Asymmetric Fault Handling)
+- FEAT_PACIMP (Pointer authentication - IMPLEMENTATION DEFINED algorithm)
+- FEAT_PACQARMA3 (Pointer authentication - QARMA3 algorithm)
+- FEAT_PACQARMA5 (Pointer authentication - QARMA5 algorithm)
- FEAT_PAN (Privileged access never)
- FEAT_PAN2 (AT S1E1R and AT S1E1W instruction variants affected by PSTATE.PAN)
- FEAT_PAN3 (Support for SCTLR_ELx.EPAN)
@@ -1072,6 +1072,7 @@ struct ArchCPU {
*/
bool prop_pauth;
bool prop_pauth_impdef;
+ bool prop_pauth_qarma3;
bool prop_lpa2;
/* DCZ blocksize, in log_2(words), ie low 4 bits of DCZID_EL0 */
@@ -95,7 +95,7 @@ static const char *cpu_model_advertised_features[] = {
"sve640", "sve768", "sve896", "sve1024", "sve1152", "sve1280",
"sve1408", "sve1536", "sve1664", "sve1792", "sve1920", "sve2048",
"kvm-no-adjvtime", "kvm-steal-time",
- "pauth", "pauth-impdef",
+ "pauth", "pauth-impdef", "pauth-qarma3",
NULL
};
@@ -474,7 +474,7 @@ void aarch64_add_sme_properties(Object *obj)
void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp)
{
ARMPauthFeature features = cpu_isar_feature(pauth_feature, cpu);
- uint64_t isar1;
+ uint64_t isar1, isar2;
/*
* These properties enable or disable Pauth as a whole, or change
@@ -490,6 +490,10 @@ void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp)
isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, API, 0);
isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, GPI, 0);
+ isar2 = cpu->isar.id_aa64isar2;
+ isar2 = FIELD_DP64(isar2, ID_AA64ISAR2, APA3, 0);
+ isar2 = FIELD_DP64(isar2, ID_AA64ISAR2, GPA3, 0);
+
if (kvm_enabled() || hvf_enabled()) {
/*
* Exit early if PAuth is enabled and fall through to disable it.
@@ -510,26 +514,39 @@ void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp)
}
if (cpu->prop_pauth) {
+ if (cpu->prop_pauth_impdef && cpu->prop_pauth_qarma3) {
+ error_setg(errp,
+ "cannot enable both pauth-impdef and pauth-qarma3");
+ return;
+ }
+
if (cpu->prop_pauth_impdef) {
isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, API, features);
isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, GPI, 1);
+ } else if (cpu->prop_pauth_qarma3) {
+ isar2 = FIELD_DP64(isar2, ID_AA64ISAR2, APA3, features);
+ isar2 = FIELD_DP64(isar2, ID_AA64ISAR2, GPA3, 1);
} else {
isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, APA, features);
isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, GPA, 1);
}
- } else if (cpu->prop_pauth_impdef) {
- error_setg(errp, "cannot enable pauth-impdef without pauth");
+ } else if (cpu->prop_pauth_impdef || cpu->prop_pauth_qarma3) {
+ error_setg(errp, "cannot enable pauth-impdef or "
+ "pauth-qarma3 without pauth");
error_append_hint(errp, "Add pauth=on to the CPU property list.\n");
}
}
cpu->isar.id_aa64isar1 = isar1;
+ cpu->isar.id_aa64isar2 = isar2;
}
static Property arm_cpu_pauth_property =
DEFINE_PROP_BOOL("pauth", ARMCPU, prop_pauth, true);
static Property arm_cpu_pauth_impdef_property =
DEFINE_PROP_BOOL("pauth-impdef", ARMCPU, prop_pauth_impdef, false);
+static Property arm_cpu_pauth_qarma3_property =
+ DEFINE_PROP_BOOL("pauth-qarma3", ARMCPU, prop_pauth_qarma3, false);
void aarch64_add_pauth_properties(Object *obj)
{
@@ -549,6 +566,7 @@ void aarch64_add_pauth_properties(Object *obj)
cpu->prop_pauth = cpu_isar_feature(aa64_pauth, cpu);
} else {
qdev_property_add_static(DEVICE(obj), &arm_cpu_pauth_impdef_property);
+ qdev_property_add_static(DEVICE(obj), &arm_cpu_pauth_qarma3_property);
}
}
@@ -96,6 +96,21 @@ static uint64_t pac_sub(uint64_t i)
return o;
}
+static uint64_t pac_sub1(uint64_t i)
+{
+ static const uint8_t sub1[16] = {
+ 0xa, 0xd, 0xe, 0x6, 0xf, 0x7, 0x3, 0x5,
+ 0x9, 0x8, 0x0, 0xc, 0xb, 0x1, 0x2, 0x4,
+ };
+ uint64_t o = 0;
+ int b;
+
+ for (b = 0; b < 64; b += 4) {
+ o |= (uint64_t)sub1[(i >> b) & 0xf] << b;
+ }
+ return o;
+}
+
static uint64_t pac_inv_sub(uint64_t i)
{
static const uint8_t inv_sub[16] = {
@@ -209,7 +224,7 @@ static uint64_t tweak_inv_shuffle(uint64_t i)
}
static uint64_t pauth_computepac_architected(uint64_t data, uint64_t modifier,
- ARMPACKey key)
+ ARMPACKey key, bool isqarma3)
{
static const uint64_t RC[5] = {
0x0000000000000000ull,
@@ -219,6 +234,7 @@ static uint64_t pauth_computepac_architected(uint64_t data, uint64_t modifier,
0x452821E638D01377ull,
};
const uint64_t alpha = 0xC0AC29B7C97C50DDull;
+ int iterations = isqarma3 ? 2 : 4;
/*
* Note that in the ARM pseudocode, key0 contains bits <127:64>
* and key1 contains bits <63:0> of the 128-bit key.
@@ -231,7 +247,7 @@ static uint64_t pauth_computepac_architected(uint64_t data, uint64_t modifier,
runningmod = modifier;
workingval = data ^ key0;
- for (i = 0; i <= 4; ++i) {
+ for (i = 0; i <= iterations; ++i) {
roundkey = key1 ^ runningmod;
workingval ^= roundkey;
workingval ^= RC[i];
@@ -239,32 +255,48 @@ static uint64_t pauth_computepac_architected(uint64_t data, uint64_t modifier,
workingval = pac_cell_shuffle(workingval);
workingval = pac_mult(workingval);
}
- workingval = pac_sub(workingval);
+ if (isqarma3) {
+ workingval = pac_sub1(workingval);
+ } else {
+ workingval = pac_sub(workingval);
+ }
runningmod = tweak_shuffle(runningmod);
}
roundkey = modk0 ^ runningmod;
workingval ^= roundkey;
workingval = pac_cell_shuffle(workingval);
workingval = pac_mult(workingval);
- workingval = pac_sub(workingval);
+ if (isqarma3) {
+ workingval = pac_sub1(workingval);
+ } else {
+ workingval = pac_sub(workingval);
+ }
workingval = pac_cell_shuffle(workingval);
workingval = pac_mult(workingval);
workingval ^= key1;
workingval = pac_cell_inv_shuffle(workingval);
- workingval = pac_inv_sub(workingval);
+ if (isqarma3) {
+ workingval = pac_sub1(workingval);
+ } else {
+ workingval = pac_inv_sub(workingval);
+ }
workingval = pac_mult(workingval);
workingval = pac_cell_inv_shuffle(workingval);
workingval ^= key0;
workingval ^= runningmod;
- for (i = 0; i <= 4; ++i) {
- workingval = pac_inv_sub(workingval);
- if (i < 4) {
+ for (i = 0; i <= iterations; ++i) {
+ if (isqarma3) {
+ workingval = pac_sub1(workingval);
+ } else {
+ workingval = pac_inv_sub(workingval);
+ }
+ if (i < iterations) {
workingval = pac_mult(workingval);
workingval = pac_cell_inv_shuffle(workingval);
}
runningmod = tweak_inv_shuffle(runningmod);
roundkey = key1 ^ runningmod;
- workingval ^= RC[4 - i];
+ workingval ^= RC[iterations - i];
workingval ^= roundkey;
workingval ^= alpha;
}
@@ -283,7 +315,9 @@ static uint64_t pauth_computepac(CPUARMState *env, uint64_t data,
uint64_t modifier, ARMPACKey key)
{
if (cpu_isar_feature(aa64_pauth_qarma5, env_archcpu(env))) {
- return pauth_computepac_architected(data, modifier, key);
+ return pauth_computepac_architected(data, modifier, key, false);
+ } else if (cpu_isar_feature(aa64_pauth_qarma3, env_archcpu(env))) {
+ return pauth_computepac_architected(data, modifier, key, true);
} else {
return pauth_computepac_impdef(data, modifier, key);
}
@@ -417,12 +417,22 @@ static void pauth_tests_default(QTestState *qts, const char *cpu_type)
{
assert_has_feature_enabled(qts, cpu_type, "pauth");
assert_has_feature_disabled(qts, cpu_type, "pauth-impdef");
+ assert_has_feature_disabled(qts, cpu_type, "pauth-qarma3");
assert_set_feature(qts, cpu_type, "pauth", false);
assert_set_feature(qts, cpu_type, "pauth", true);
assert_set_feature(qts, cpu_type, "pauth-impdef", true);
assert_set_feature(qts, cpu_type, "pauth-impdef", false);
- assert_error(qts, cpu_type, "cannot enable pauth-impdef without pauth",
+ assert_set_feature(qts, cpu_type, "pauth-qarma3", true);
+ assert_set_feature(qts, cpu_type, "pauth-qarma3", false);
+ assert_error(qts, cpu_type,
+ "cannot enable pauth-impdef or pauth-qarma3 without pauth",
"{ 'pauth': false, 'pauth-impdef': true }");
+ assert_error(qts, cpu_type,
+ "cannot enable pauth-impdef or pauth-qarma3 without pauth",
+ "{ 'pauth': false, 'pauth-qarma3': true }");
+ assert_error(qts, cpu_type,
+ "cannot enable both pauth-impdef and pauth-qarma3",
+ "{ 'pauth': true, 'pauth-impdef': true, 'pauth-qarma3': true }");
}
static void test_query_cpu_model_expansion(const void *data)