mirror of https://github.com/xemu-project/xemu.git
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.
|
TCG VCPU features are CPU features that are specific to TCG.
|
||||||
Below is the list of TCG VCPU features and their descriptions.
|
Below is the list of TCG VCPU features and their descriptions.
|
||||||
|
|
||||||
``pauth-impdef``
|
``pauth``
|
||||||
When ``FEAT_Pauth`` is enabled, either the *impdef* (Implementation
|
Enable or disable ``FEAT_Pauth`` entirely.
|
||||||
Defined) algorithm is enabled or the *architected* QARMA algorithm
|
|
||||||
is enabled. By default the impdef algorithm is disabled, and QARMA
|
|
||||||
is enabled.
|
|
||||||
|
|
||||||
The architected QARMA algorithm has good cryptographic properties,
|
``pauth-impdef``
|
||||||
but can be quite slow to emulate. The impdef algorithm used by QEMU
|
When ``pauth`` is enabled, select the QEMU implementation defined algorithm.
|
||||||
is non-cryptographic but significantly faster.
|
|
||||||
|
``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
|
SVE CPU Properties
|
||||||
==================
|
==================
|
||||||
|
|
|
@ -57,6 +57,9 @@ the following architecture extensions:
|
||||||
- FEAT_MTE (Memory Tagging Extension)
|
- FEAT_MTE (Memory Tagging Extension)
|
||||||
- FEAT_MTE2 (Memory Tagging Extension)
|
- FEAT_MTE2 (Memory Tagging Extension)
|
||||||
- FEAT_MTE3 (MTE Asymmetric Fault Handling)
|
- 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_PAN (Privileged access never)
|
||||||
- FEAT_PAN2 (AT S1E1R and AT S1E1W instruction variants affected by PSTATE.PAN)
|
- FEAT_PAN2 (AT S1E1R and AT S1E1W instruction variants affected by PSTATE.PAN)
|
||||||
- FEAT_PAN3 (Support for SCTLR_ELx.EPAN)
|
- FEAT_PAN3 (Support for SCTLR_ELx.EPAN)
|
||||||
|
|
|
@ -95,7 +95,7 @@ static const char *cpu_model_advertised_features[] = {
|
||||||
"sve640", "sve768", "sve896", "sve1024", "sve1152", "sve1280",
|
"sve640", "sve768", "sve896", "sve1024", "sve1152", "sve1280",
|
||||||
"sve1408", "sve1536", "sve1664", "sve1792", "sve1920", "sve2048",
|
"sve1408", "sve1536", "sve1664", "sve1792", "sve1920", "sve2048",
|
||||||
"kvm-no-adjvtime", "kvm-steal-time",
|
"kvm-no-adjvtime", "kvm-steal-time",
|
||||||
"pauth", "pauth-impdef",
|
"pauth", "pauth-impdef", "pauth-qarma3",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1072,6 +1072,7 @@ struct ArchCPU {
|
||||||
*/
|
*/
|
||||||
bool prop_pauth;
|
bool prop_pauth;
|
||||||
bool prop_pauth_impdef;
|
bool prop_pauth_impdef;
|
||||||
|
bool prop_pauth_qarma3;
|
||||||
bool prop_lpa2;
|
bool prop_lpa2;
|
||||||
|
|
||||||
/* DCZ blocksize, in log_2(words), ie low 4 bits of DCZID_EL0 */
|
/* 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)
|
void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp)
|
||||||
{
|
{
|
||||||
ARMPauthFeature features = cpu_isar_feature(pauth_feature, cpu);
|
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
|
* 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, API, 0);
|
||||||
isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, GPI, 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()) {
|
if (kvm_enabled() || hvf_enabled()) {
|
||||||
/*
|
/*
|
||||||
* Exit early if PAuth is enabled and fall through to disable it.
|
* 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) {
|
||||||
|
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) {
|
if (cpu->prop_pauth_impdef) {
|
||||||
isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, API, features);
|
isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, API, features);
|
||||||
isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, GPI, 1);
|
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 {
|
} else {
|
||||||
isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, APA, features);
|
isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, APA, features);
|
||||||
isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, GPA, 1);
|
isar1 = FIELD_DP64(isar1, ID_AA64ISAR1, GPA, 1);
|
||||||
}
|
}
|
||||||
} else if (cpu->prop_pauth_impdef) {
|
} else if (cpu->prop_pauth_impdef || cpu->prop_pauth_qarma3) {
|
||||||
error_setg(errp, "cannot enable pauth-impdef without pauth");
|
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");
|
error_append_hint(errp, "Add pauth=on to the CPU property list.\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cpu->isar.id_aa64isar1 = isar1;
|
cpu->isar.id_aa64isar1 = isar1;
|
||||||
|
cpu->isar.id_aa64isar2 = isar2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Property arm_cpu_pauth_property =
|
static Property arm_cpu_pauth_property =
|
||||||
DEFINE_PROP_BOOL("pauth", ARMCPU, prop_pauth, true);
|
DEFINE_PROP_BOOL("pauth", ARMCPU, prop_pauth, true);
|
||||||
static Property arm_cpu_pauth_impdef_property =
|
static Property arm_cpu_pauth_impdef_property =
|
||||||
DEFINE_PROP_BOOL("pauth-impdef", ARMCPU, prop_pauth_impdef, false);
|
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)
|
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);
|
cpu->prop_pauth = cpu_isar_feature(aa64_pauth, cpu);
|
||||||
} else {
|
} else {
|
||||||
qdev_property_add_static(DEVICE(obj), &arm_cpu_pauth_impdef_property);
|
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;
|
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 uint64_t pac_inv_sub(uint64_t i)
|
||||||
{
|
{
|
||||||
static const uint8_t inv_sub[16] = {
|
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,
|
static uint64_t pauth_computepac_architected(uint64_t data, uint64_t modifier,
|
||||||
ARMPACKey key)
|
ARMPACKey key, bool isqarma3)
|
||||||
{
|
{
|
||||||
static const uint64_t RC[5] = {
|
static const uint64_t RC[5] = {
|
||||||
0x0000000000000000ull,
|
0x0000000000000000ull,
|
||||||
|
@ -219,6 +234,7 @@ static uint64_t pauth_computepac_architected(uint64_t data, uint64_t modifier,
|
||||||
0x452821E638D01377ull,
|
0x452821E638D01377ull,
|
||||||
};
|
};
|
||||||
const uint64_t alpha = 0xC0AC29B7C97C50DDull;
|
const uint64_t alpha = 0xC0AC29B7C97C50DDull;
|
||||||
|
int iterations = isqarma3 ? 2 : 4;
|
||||||
/*
|
/*
|
||||||
* Note that in the ARM pseudocode, key0 contains bits <127:64>
|
* Note that in the ARM pseudocode, key0 contains bits <127:64>
|
||||||
* and key1 contains bits <63:0> of the 128-bit key.
|
* 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;
|
runningmod = modifier;
|
||||||
workingval = data ^ key0;
|
workingval = data ^ key0;
|
||||||
|
|
||||||
for (i = 0; i <= 4; ++i) {
|
for (i = 0; i <= iterations; ++i) {
|
||||||
roundkey = key1 ^ runningmod;
|
roundkey = key1 ^ runningmod;
|
||||||
workingval ^= roundkey;
|
workingval ^= roundkey;
|
||||||
workingval ^= RC[i];
|
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_cell_shuffle(workingval);
|
||||||
workingval = pac_mult(workingval);
|
workingval = pac_mult(workingval);
|
||||||
}
|
}
|
||||||
workingval = pac_sub(workingval);
|
if (isqarma3) {
|
||||||
|
workingval = pac_sub1(workingval);
|
||||||
|
} else {
|
||||||
|
workingval = pac_sub(workingval);
|
||||||
|
}
|
||||||
runningmod = tweak_shuffle(runningmod);
|
runningmod = tweak_shuffle(runningmod);
|
||||||
}
|
}
|
||||||
roundkey = modk0 ^ runningmod;
|
roundkey = modk0 ^ runningmod;
|
||||||
workingval ^= roundkey;
|
workingval ^= roundkey;
|
||||||
workingval = pac_cell_shuffle(workingval);
|
workingval = pac_cell_shuffle(workingval);
|
||||||
workingval = pac_mult(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_cell_shuffle(workingval);
|
||||||
workingval = pac_mult(workingval);
|
workingval = pac_mult(workingval);
|
||||||
workingval ^= key1;
|
workingval ^= key1;
|
||||||
workingval = pac_cell_inv_shuffle(workingval);
|
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_mult(workingval);
|
||||||
workingval = pac_cell_inv_shuffle(workingval);
|
workingval = pac_cell_inv_shuffle(workingval);
|
||||||
workingval ^= key0;
|
workingval ^= key0;
|
||||||
workingval ^= runningmod;
|
workingval ^= runningmod;
|
||||||
for (i = 0; i <= 4; ++i) {
|
for (i = 0; i <= iterations; ++i) {
|
||||||
workingval = pac_inv_sub(workingval);
|
if (isqarma3) {
|
||||||
if (i < 4) {
|
workingval = pac_sub1(workingval);
|
||||||
|
} else {
|
||||||
|
workingval = pac_inv_sub(workingval);
|
||||||
|
}
|
||||||
|
if (i < iterations) {
|
||||||
workingval = pac_mult(workingval);
|
workingval = pac_mult(workingval);
|
||||||
workingval = pac_cell_inv_shuffle(workingval);
|
workingval = pac_cell_inv_shuffle(workingval);
|
||||||
}
|
}
|
||||||
runningmod = tweak_inv_shuffle(runningmod);
|
runningmod = tweak_inv_shuffle(runningmod);
|
||||||
roundkey = key1 ^ runningmod;
|
roundkey = key1 ^ runningmod;
|
||||||
workingval ^= RC[4 - i];
|
workingval ^= RC[iterations - i];
|
||||||
workingval ^= roundkey;
|
workingval ^= roundkey;
|
||||||
workingval ^= alpha;
|
workingval ^= alpha;
|
||||||
}
|
}
|
||||||
|
@ -283,7 +315,9 @@ static uint64_t pauth_computepac(CPUARMState *env, uint64_t data,
|
||||||
uint64_t modifier, ARMPACKey key)
|
uint64_t modifier, ARMPACKey key)
|
||||||
{
|
{
|
||||||
if (cpu_isar_feature(aa64_pauth_qarma5, env_archcpu(env))) {
|
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 {
|
} else {
|
||||||
return pauth_computepac_impdef(data, modifier, key);
|
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_enabled(qts, cpu_type, "pauth");
|
||||||
assert_has_feature_disabled(qts, cpu_type, "pauth-impdef");
|
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", false);
|
||||||
assert_set_feature(qts, cpu_type, "pauth", true);
|
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", true);
|
||||||
assert_set_feature(qts, cpu_type, "pauth-impdef", false);
|
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 }");
|
"{ '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)
|
static void test_query_cpu_model_expansion(const void *data)
|
||||||
|
|
Loading…
Reference in New Issue