target/arm: Implement FEAT_PACQARMA3
Implement the QARMA3 cryptographic algorithm for PAC calculation. Implement a cpu feature to select the algorithm and document it. Signed-off-by: Aaron Lindsay <aaron@os.amperecomputing.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20230829232335.965414-6-richard.henderson@linaro.org Message-Id: <20230609172324.982888-4-aaron@os.amperecomputing.com> [rth: Merge cpu feature addition from another patch.] Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
6c3427eec5
commit
399e5e7125
@ -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
|
||||
==================
|
||||
|
@ -57,6 +57,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)
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user