diff options
Diffstat (limited to 'target/arm/tcg/pauth_helper.c')
| -rw-r--r-- | target/arm/tcg/pauth_helper.c | 178 |
1 files changed, 146 insertions, 32 deletions
diff --git a/target/arm/tcg/pauth_helper.c b/target/arm/tcg/pauth_helper.c index 62af569341..4da2962ad5 100644 --- a/target/arm/tcg/pauth_helper.c +++ b/target/arm/tcg/pauth_helper.c @@ -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; } @@ -282,8 +314,10 @@ static uint64_t pauth_computepac_impdef(uint64_t data, uint64_t modifier, static uint64_t pauth_computepac(CPUARMState *env, uint64_t data, uint64_t modifier, ARMPACKey key) { - if (cpu_isar_feature(aa64_pauth_arch, env_archcpu(env))) { - return pauth_computepac_architected(data, modifier, key); + if (cpu_isar_feature(aa64_pauth_qarma5, env_archcpu(env))) { + 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); } @@ -292,8 +326,10 @@ static uint64_t pauth_computepac(CPUARMState *env, uint64_t data, static uint64_t pauth_addpac(CPUARMState *env, uint64_t ptr, uint64_t modifier, ARMPACKey *key, bool data) { + ARMCPU *cpu = env_archcpu(env); ARMMMUIdx mmu_idx = arm_stage1_mmu_idx(env); ARMVAParameters param = aa64_va_parameters(env, ptr, mmu_idx, data, false); + ARMPauthFeature pauth_feature = cpu_isar_feature(pauth_feature, cpu); uint64_t pac, ext_ptr, ext, test; int bot_bit, top_bit; @@ -317,17 +353,26 @@ static uint64_t pauth_addpac(CPUARMState *env, uint64_t ptr, uint64_t modifier, */ test = sextract64(ptr, bot_bit, top_bit - bot_bit); if (test != 0 && test != -1) { - /* - * Note that our top_bit is one greater than the pseudocode's - * version, hence "- 2" here. - */ - pac ^= MAKE_64BIT_MASK(top_bit - 2, 1); + if (pauth_feature >= PauthFeat_2) { + /* No action required */ + } else if (pauth_feature == PauthFeat_EPAC) { + pac = 0; + } else { + /* + * Note that our top_bit is one greater than the pseudocode's + * version, hence "- 2" here. + */ + pac ^= MAKE_64BIT_MASK(top_bit - 2, 1); + } } /* * Preserve the determination between upper and lower at bit 55, * and insert pointer authentication code. */ + if (pauth_feature >= PauthFeat_2) { + pac ^= ptr; + } if (param.tbi) { ptr &= ~MAKE_64BIT_MASK(bot_bit, 55 - bot_bit + 1); pac &= MAKE_64BIT_MASK(bot_bit, 54 - bot_bit + 1); @@ -351,21 +396,46 @@ static uint64_t pauth_original_ptr(uint64_t ptr, ARMVAParameters param) } } +static G_NORETURN +void pauth_fail_exception(CPUARMState *env, bool data, + int keynumber, uintptr_t ra) +{ + raise_exception_ra(env, EXCP_UDEF, syn_pacfail(data, keynumber), + exception_target_el(env), ra); +} + static uint64_t pauth_auth(CPUARMState *env, uint64_t ptr, uint64_t modifier, - ARMPACKey *key, bool data, int keynumber) + ARMPACKey *key, bool data, int keynumber, + uintptr_t ra, bool is_combined) { + ARMCPU *cpu = env_archcpu(env); ARMMMUIdx mmu_idx = arm_stage1_mmu_idx(env); ARMVAParameters param = aa64_va_parameters(env, ptr, mmu_idx, data, false); + ARMPauthFeature pauth_feature = cpu_isar_feature(pauth_feature, cpu); int bot_bit, top_bit; - uint64_t pac, orig_ptr, test; + uint64_t pac, orig_ptr, cmp_mask; orig_ptr = pauth_original_ptr(ptr, param); pac = pauth_computepac(env, orig_ptr, modifier, *key); bot_bit = 64 - param.tsz; top_bit = 64 - 8 * param.tbi; - test = (pac ^ ptr) & ~MAKE_64BIT_MASK(55, 1); - if (unlikely(extract64(test, bot_bit, top_bit - bot_bit))) { + cmp_mask = MAKE_64BIT_MASK(bot_bit, top_bit - bot_bit); + cmp_mask &= ~MAKE_64BIT_MASK(55, 1); + + if (pauth_feature >= PauthFeat_2) { + ARMPauthFeature fault_feature = + is_combined ? PauthFeat_FPACCOMBINED : PauthFeat_FPAC; + uint64_t result = ptr ^ (pac & cmp_mask); + + if (pauth_feature >= fault_feature + && ((result ^ sextract64(result, 55, 1)) & cmp_mask)) { + pauth_fail_exception(env, data, keynumber, ra); + } + return result; + } + + if ((pac ^ ptr) & cmp_mask) { int error_code = (keynumber << 1) | (keynumber ^ 1); if (param.tbi) { return deposit64(orig_ptr, 53, 2, error_code); @@ -466,44 +536,88 @@ uint64_t HELPER(pacga)(CPUARMState *env, uint64_t x, uint64_t y) return pac & 0xffffffff00000000ull; } -uint64_t HELPER(autia)(CPUARMState *env, uint64_t x, uint64_t y) +static uint64_t pauth_autia(CPUARMState *env, uint64_t x, uint64_t y, + uintptr_t ra, bool is_combined) { int el = arm_current_el(env); if (!pauth_key_enabled(env, el, SCTLR_EnIA)) { return x; } - pauth_check_trap(env, el, GETPC()); - return pauth_auth(env, x, y, &env->keys.apia, false, 0); + pauth_check_trap(env, el, ra); + return pauth_auth(env, x, y, &env->keys.apia, false, 0, ra, is_combined); } -uint64_t HELPER(autib)(CPUARMState *env, uint64_t x, uint64_t y) +uint64_t HELPER(autia)(CPUARMState *env, uint64_t x, uint64_t y) +{ + return pauth_autia(env, x, y, GETPC(), false); +} + +uint64_t HELPER(autia_combined)(CPUARMState *env, uint64_t x, uint64_t y) +{ + return pauth_autia(env, x, y, GETPC(), true); +} + +static uint64_t pauth_autib(CPUARMState *env, uint64_t x, uint64_t y, + uintptr_t ra, bool is_combined) { int el = arm_current_el(env); if (!pauth_key_enabled(env, el, SCTLR_EnIB)) { return x; } - pauth_check_trap(env, el, GETPC()); - return pauth_auth(env, x, y, &env->keys.apib, false, 1); + pauth_check_trap(env, el, ra); + return pauth_auth(env, x, y, &env->keys.apib, false, 1, ra, is_combined); } -uint64_t HELPER(autda)(CPUARMState *env, uint64_t x, uint64_t y) +uint64_t HELPER(autib)(CPUARMState *env, uint64_t x, uint64_t y) +{ + return pauth_autib(env, x, y, GETPC(), false); +} + +uint64_t HELPER(autib_combined)(CPUARMState *env, uint64_t x, uint64_t y) +{ + return pauth_autib(env, x, y, GETPC(), true); +} + +static uint64_t pauth_autda(CPUARMState *env, uint64_t x, uint64_t y, + uintptr_t ra, bool is_combined) { int el = arm_current_el(env); if (!pauth_key_enabled(env, el, SCTLR_EnDA)) { return x; } - pauth_check_trap(env, el, GETPC()); - return pauth_auth(env, x, y, &env->keys.apda, true, 0); + pauth_check_trap(env, el, ra); + return pauth_auth(env, x, y, &env->keys.apda, true, 0, ra, is_combined); } -uint64_t HELPER(autdb)(CPUARMState *env, uint64_t x, uint64_t y) +uint64_t HELPER(autda)(CPUARMState *env, uint64_t x, uint64_t y) +{ + return pauth_autda(env, x, y, GETPC(), false); +} + +uint64_t HELPER(autda_combined)(CPUARMState *env, uint64_t x, uint64_t y) +{ + return pauth_autda(env, x, y, GETPC(), true); +} + +static uint64_t pauth_autdb(CPUARMState *env, uint64_t x, uint64_t y, + uintptr_t ra, bool is_combined) { int el = arm_current_el(env); if (!pauth_key_enabled(env, el, SCTLR_EnDB)) { return x; } - pauth_check_trap(env, el, GETPC()); - return pauth_auth(env, x, y, &env->keys.apdb, true, 1); + pauth_check_trap(env, el, ra); + return pauth_auth(env, x, y, &env->keys.apdb, true, 1, ra, is_combined); +} + +uint64_t HELPER(autdb)(CPUARMState *env, uint64_t x, uint64_t y) +{ + return pauth_autdb(env, x, y, GETPC(), false); +} + +uint64_t HELPER(autdb_combined)(CPUARMState *env, uint64_t x, uint64_t y) +{ + return pauth_autdb(env, x, y, GETPC(), true); } uint64_t HELPER(xpaci)(CPUARMState *env, uint64_t a) |