Peter Maydell <peter.mayd...@linaro.org> writes:

> On Sat, 14 Jun 2025 at 13:50, <r...@wjsota.com> wrote:
>>
>> Hi!
>>
>> Is `qemu-aarch64 -cpu neoverse-n1` supposed to emulate the `retaa` 
>> instruction?
>>
>> I have a binary called `main_pac` compiled from 
>> https://learn.arm.com/learning-paths/servers-and-cloud-computing/pac/example/
>>  .
>>
>> The compiling command is `aarch64-linux-gnu-gcc -march=armv8.5-a
>> -fPIC -pedantic -Wall -Wextra -ggdb3 -O0
>> -mbranch-protection=standard -fno-stack-protector -fPIE -static
>> main.c -o main_pac`. The binary includes the `paciasp` and `retaa`
>> instructions associated with ARM PAC.
>>
>> ```
>> (gdb) disas main
>> Dump of assembler code for function main:
>>    0x0000000000400858 <+0>:     paciasp

This instruction is in the HINT opcode space so can be NOP.

>>    0x000000000040085c <+4>:     stp     x29, x30, [sp, #-32]!
>>    […]
>>    0x0000000000400898 <+64>:    ldp     x29, x30, [sp], #32
>>    0x000000000040089c <+68>:    retaa
>> End of assembler dump.
>> (gdb) quit
>> ```
>>
>> When emulated using `qemu-aarch64 -cpu neoverse-n1` , the program completes 
>> without issues.
>> ```
>> user@dell-op7020:~/learning/arm_learning_path_pac$ qemu-aarch64 -cpu 
>> neoverse-n1 main_pac test
>> Hello World!

The code just does:

  static bool trans_RETA(DisasContext *s, arg_reta *a)
  {
      TCGv_i64 dst;

      dst = auth_branch_target(s, cpu_reg(s, 30), cpu_X[31], !a->m);
      gen_a64_set_pc(s, dst);
      s->base.is_jmp = DISAS_JUMP;
      return true;
  }


Where auth_branch_target does:

  static TCGv_i64 auth_branch_target(DisasContext *s, TCGv_i64 dst,
                                     TCGv_i64 modifier, bool use_key_a)
  {
      TCGv_i64 truedst;
      /*
       * Return the branch target for a BRAA/RETA/etc, which is either
       * just the destination dst, or that value with the pauth check
       * done and the code removed from the high bits.
       */
      if (!s->pauth_active) {
          return dst;
      }

      truedst = tcg_temp_new_i64();
      if (use_key_a) {
          gen_helper_autia_combined(truedst, tcg_env, dst, modifier);
      } else {
          gen_helper_autib_combined(truedst, tcg_env, dst, modifier);
      }
      return truedst;
  }

Essentially if no pauth is active then just returns dest. I think this
matches the pseudocode:

  GCSInstruction inst_type;
  bits(64) target = X[30, 64];

  constant bits(64) modifier = SP[64];
  bits(64) modifier2;
  boolean use_modifier2 = FALSE;
  if IsFeatureImplemented(FEAT_PAuth_LR) && PSTATE.PACM == '1' then
      modifier2 = X[16, 64];
      use_modifier2 = TRUE;

  if use_key_a then
      if use_modifier2 && IsFeatureImplemented(FEAT_PAuth_LR) then
          target = AuthIA2(target, modifier, modifier2, auth_then_branch);
      else
          target = AuthIA(target, modifier, auth_then_branch);
  else
      if use_modifier2 && IsFeatureImplemented(FEAT_PAuth_LR) then
          target = AuthIB2(target, modifier, modifier2, auth_then_branch);
      else
          target = AuthIB(target, modifier, auth_then_branch);

  if IsFeatureImplemented(FEAT_GCS) && GCSPCREnabled(PSTATE.EL) then
      inst_type = if use_key_a then GCSInstType_PRETAA else GCSInstType_PRETAB;
      target = LoadCheckGCSRecord(target, inst_type);
      SetCurrentGCSPointer(GetCurrentGCSPointer() + 8);

  // Value in BTypeNext will be used to set PSTATE.BTYPE
  BTypeNext = '00';

  constant boolean branch_conditional = FALSE;
  BranchTo(target, BranchType_RET, branch_conditional);

which has no explicit UNDEF for the instruction. I think the
fall-through is to AuthIB:

  bits(64) AuthIB(bits(64) x, bits(64) y, boolean is_combined)
      constant bits(128) APIBKey_EL1 = APIBKeyHi_EL1<63:0> : 
APIBKeyLo_EL1<63:0>;
      if !IsAPIBKeyEnabled() then
          return x;
      else
          return Auth(x, y, APIBKey_EL1, FALSE, '1', is_combined);

So I think the correct response if no key is enabled is to return the
address as is unmolested. Which makes sense as you want PAuth code to be
run-able unaltered on systems without it.

>
> This might be a bug, but why are you compiling for armv8.5 and
> then trying to run the code on a CPU type that isn't armv8.5
> in the first place?
>
> thanks
> -- PMM

-- 
Alex Bennée
Virtualisation Tech Lead @ Linaro

Reply via email to