xref: /openbmc/qemu/linux-user/aarch64/target_prctl.h (revision fd72f5d0bae2bcdb695cb8da57b41c49c001f91f)
187e9bf23SRichard Henderson /*
287e9bf23SRichard Henderson  * AArch64 specific prctl functions for linux-user
387e9bf23SRichard Henderson  *
487e9bf23SRichard Henderson  * SPDX-License-Identifier: GPL-2.0-or-later
587e9bf23SRichard Henderson  */
687e9bf23SRichard Henderson #ifndef AARCH64_TARGET_PRCTL_H
787e9bf23SRichard Henderson #define AARCH64_TARGET_PRCTL_H
887e9bf23SRichard Henderson 
9*fd72f5d0SRichard Henderson static abi_long do_prctl_sve_get_vl(CPUArchState *env)
1087e9bf23SRichard Henderson {
1187e9bf23SRichard Henderson     ARMCPU *cpu = env_archcpu(env);
1287e9bf23SRichard Henderson     if (cpu_isar_feature(aa64_sve, cpu)) {
138b599e5cSRichard Henderson         return sve_vq(env) * 16;
1487e9bf23SRichard Henderson     }
1587e9bf23SRichard Henderson     return -TARGET_EINVAL;
1687e9bf23SRichard Henderson }
17*fd72f5d0SRichard Henderson #define do_prctl_sve_get_vl do_prctl_sve_get_vl
1887e9bf23SRichard Henderson 
19*fd72f5d0SRichard Henderson static abi_long do_prctl_sve_set_vl(CPUArchState *env, abi_long arg2)
2087e9bf23SRichard Henderson {
2187e9bf23SRichard Henderson     /*
2287e9bf23SRichard Henderson      * We cannot support either PR_SVE_SET_VL_ONEXEC or PR_SVE_VL_INHERIT.
2387e9bf23SRichard Henderson      * Note the kernel definition of sve_vl_valid allows for VQ=512,
2487e9bf23SRichard Henderson      * i.e. VL=8192, even though the current architectural maximum is VQ=16.
2587e9bf23SRichard Henderson      */
2687e9bf23SRichard Henderson     if (cpu_isar_feature(aa64_sve, env_archcpu(env))
2787e9bf23SRichard Henderson         && arg2 >= 0 && arg2 <= 512 * 16 && !(arg2 & 15)) {
2887e9bf23SRichard Henderson         uint32_t vq, old_vq;
2987e9bf23SRichard Henderson 
308b599e5cSRichard Henderson         old_vq = sve_vq(env);
3187e9bf23SRichard Henderson 
328b599e5cSRichard Henderson         /*
338b599e5cSRichard Henderson          * Bound the value of arg2, so that we know that it fits into
348b599e5cSRichard Henderson          * the 4-bit field in ZCR_EL1.  Rely on the hflags rebuild to
358b599e5cSRichard Henderson          * sort out the length supported by the cpu.
368b599e5cSRichard Henderson          */
378b599e5cSRichard Henderson         vq = MAX(arg2 / 16, 1);
388b599e5cSRichard Henderson         vq = MIN(vq, ARM_MAX_VQ);
398b599e5cSRichard Henderson         env->vfp.zcr_el[1] = vq - 1;
408b599e5cSRichard Henderson         arm_rebuild_hflags(env);
418b599e5cSRichard Henderson 
428b599e5cSRichard Henderson         vq = sve_vq(env);
4387e9bf23SRichard Henderson         if (vq < old_vq) {
4487e9bf23SRichard Henderson             aarch64_sve_narrow_vq(env, vq);
4587e9bf23SRichard Henderson         }
4687e9bf23SRichard Henderson         return vq * 16;
4787e9bf23SRichard Henderson     }
4887e9bf23SRichard Henderson     return -TARGET_EINVAL;
4987e9bf23SRichard Henderson }
50*fd72f5d0SRichard Henderson #define do_prctl_sve_set_vl do_prctl_sve_set_vl
5187e9bf23SRichard Henderson 
5287e9bf23SRichard Henderson static abi_long do_prctl_reset_keys(CPUArchState *env, abi_long arg2)
5387e9bf23SRichard Henderson {
5487e9bf23SRichard Henderson     ARMCPU *cpu = env_archcpu(env);
5587e9bf23SRichard Henderson 
5687e9bf23SRichard Henderson     if (cpu_isar_feature(aa64_pauth, cpu)) {
5787e9bf23SRichard Henderson         int all = (PR_PAC_APIAKEY | PR_PAC_APIBKEY |
5887e9bf23SRichard Henderson                    PR_PAC_APDAKEY | PR_PAC_APDBKEY | PR_PAC_APGAKEY);
5987e9bf23SRichard Henderson         int ret = 0;
6087e9bf23SRichard Henderson         Error *err = NULL;
6187e9bf23SRichard Henderson 
6287e9bf23SRichard Henderson         if (arg2 == 0) {
6387e9bf23SRichard Henderson             arg2 = all;
6487e9bf23SRichard Henderson         } else if (arg2 & ~all) {
6587e9bf23SRichard Henderson             return -TARGET_EINVAL;
6687e9bf23SRichard Henderson         }
6787e9bf23SRichard Henderson         if (arg2 & PR_PAC_APIAKEY) {
6887e9bf23SRichard Henderson             ret |= qemu_guest_getrandom(&env->keys.apia,
6987e9bf23SRichard Henderson                                         sizeof(ARMPACKey), &err);
7087e9bf23SRichard Henderson         }
7187e9bf23SRichard Henderson         if (arg2 & PR_PAC_APIBKEY) {
7287e9bf23SRichard Henderson             ret |= qemu_guest_getrandom(&env->keys.apib,
7387e9bf23SRichard Henderson                                         sizeof(ARMPACKey), &err);
7487e9bf23SRichard Henderson         }
7587e9bf23SRichard Henderson         if (arg2 & PR_PAC_APDAKEY) {
7687e9bf23SRichard Henderson             ret |= qemu_guest_getrandom(&env->keys.apda,
7787e9bf23SRichard Henderson                                         sizeof(ARMPACKey), &err);
7887e9bf23SRichard Henderson         }
7987e9bf23SRichard Henderson         if (arg2 & PR_PAC_APDBKEY) {
8087e9bf23SRichard Henderson             ret |= qemu_guest_getrandom(&env->keys.apdb,
8187e9bf23SRichard Henderson                                         sizeof(ARMPACKey), &err);
8287e9bf23SRichard Henderson         }
8387e9bf23SRichard Henderson         if (arg2 & PR_PAC_APGAKEY) {
8487e9bf23SRichard Henderson             ret |= qemu_guest_getrandom(&env->keys.apga,
8587e9bf23SRichard Henderson                                         sizeof(ARMPACKey), &err);
8687e9bf23SRichard Henderson         }
8787e9bf23SRichard Henderson         if (ret != 0) {
8887e9bf23SRichard Henderson             /*
8987e9bf23SRichard Henderson              * Some unknown failure in the crypto.  The best
9087e9bf23SRichard Henderson              * we can do is log it and fail the syscall.
9187e9bf23SRichard Henderson              * The real syscall cannot fail this way.
9287e9bf23SRichard Henderson              */
9387e9bf23SRichard Henderson             qemu_log_mask(LOG_UNIMP, "PR_PAC_RESET_KEYS: Crypto failure: %s",
9487e9bf23SRichard Henderson                           error_get_pretty(err));
9587e9bf23SRichard Henderson             error_free(err);
9687e9bf23SRichard Henderson             return -TARGET_EIO;
9787e9bf23SRichard Henderson         }
9887e9bf23SRichard Henderson         return 0;
9987e9bf23SRichard Henderson     }
10087e9bf23SRichard Henderson     return -TARGET_EINVAL;
10187e9bf23SRichard Henderson }
10287e9bf23SRichard Henderson #define do_prctl_reset_keys do_prctl_reset_keys
10387e9bf23SRichard Henderson 
10487e9bf23SRichard Henderson static abi_long do_prctl_set_tagged_addr_ctrl(CPUArchState *env, abi_long arg2)
10587e9bf23SRichard Henderson {
10687e9bf23SRichard Henderson     abi_ulong valid_mask = PR_TAGGED_ADDR_ENABLE;
10787e9bf23SRichard Henderson     ARMCPU *cpu = env_archcpu(env);
10887e9bf23SRichard Henderson 
10987e9bf23SRichard Henderson     if (cpu_isar_feature(aa64_mte, cpu)) {
11087e9bf23SRichard Henderson         valid_mask |= PR_MTE_TCF_MASK;
11187e9bf23SRichard Henderson         valid_mask |= PR_MTE_TAG_MASK;
11287e9bf23SRichard Henderson     }
11387e9bf23SRichard Henderson 
11487e9bf23SRichard Henderson     if (arg2 & ~valid_mask) {
11587e9bf23SRichard Henderson         return -TARGET_EINVAL;
11687e9bf23SRichard Henderson     }
11787e9bf23SRichard Henderson     env->tagged_addr_enable = arg2 & PR_TAGGED_ADDR_ENABLE;
11887e9bf23SRichard Henderson 
11987e9bf23SRichard Henderson     if (cpu_isar_feature(aa64_mte, cpu)) {
12087e9bf23SRichard Henderson         switch (arg2 & PR_MTE_TCF_MASK) {
12187e9bf23SRichard Henderson         case PR_MTE_TCF_NONE:
12287e9bf23SRichard Henderson         case PR_MTE_TCF_SYNC:
12387e9bf23SRichard Henderson         case PR_MTE_TCF_ASYNC:
12487e9bf23SRichard Henderson             break;
12587e9bf23SRichard Henderson         default:
12687e9bf23SRichard Henderson             return -EINVAL;
12787e9bf23SRichard Henderson         }
12887e9bf23SRichard Henderson 
12987e9bf23SRichard Henderson         /*
13087e9bf23SRichard Henderson          * Write PR_MTE_TCF to SCTLR_EL1[TCF0].
13187e9bf23SRichard Henderson          * Note that the syscall values are consistent with hw.
13287e9bf23SRichard Henderson          */
13387e9bf23SRichard Henderson         env->cp15.sctlr_el[1] =
13487e9bf23SRichard Henderson             deposit64(env->cp15.sctlr_el[1], 38, 2, arg2 >> PR_MTE_TCF_SHIFT);
13587e9bf23SRichard Henderson 
13687e9bf23SRichard Henderson         /*
13787e9bf23SRichard Henderson          * Write PR_MTE_TAG to GCR_EL1[Exclude].
13887e9bf23SRichard Henderson          * Note that the syscall uses an include mask,
13987e9bf23SRichard Henderson          * and hardware uses an exclude mask -- invert.
14087e9bf23SRichard Henderson          */
14187e9bf23SRichard Henderson         env->cp15.gcr_el1 =
14287e9bf23SRichard Henderson             deposit64(env->cp15.gcr_el1, 0, 16, ~arg2 >> PR_MTE_TAG_SHIFT);
14387e9bf23SRichard Henderson         arm_rebuild_hflags(env);
14487e9bf23SRichard Henderson     }
14587e9bf23SRichard Henderson     return 0;
14687e9bf23SRichard Henderson }
14787e9bf23SRichard Henderson #define do_prctl_set_tagged_addr_ctrl do_prctl_set_tagged_addr_ctrl
14887e9bf23SRichard Henderson 
14987e9bf23SRichard Henderson static abi_long do_prctl_get_tagged_addr_ctrl(CPUArchState *env)
15087e9bf23SRichard Henderson {
15187e9bf23SRichard Henderson     ARMCPU *cpu = env_archcpu(env);
15287e9bf23SRichard Henderson     abi_long ret = 0;
15387e9bf23SRichard Henderson 
15487e9bf23SRichard Henderson     if (env->tagged_addr_enable) {
15587e9bf23SRichard Henderson         ret |= PR_TAGGED_ADDR_ENABLE;
15687e9bf23SRichard Henderson     }
15787e9bf23SRichard Henderson     if (cpu_isar_feature(aa64_mte, cpu)) {
15887e9bf23SRichard Henderson         /* See do_prctl_set_tagged_addr_ctrl. */
15987e9bf23SRichard Henderson         ret |= extract64(env->cp15.sctlr_el[1], 38, 2) << PR_MTE_TCF_SHIFT;
16087e9bf23SRichard Henderson         ret = deposit64(ret, PR_MTE_TAG_SHIFT, 16, ~env->cp15.gcr_el1);
16187e9bf23SRichard Henderson     }
16287e9bf23SRichard Henderson     return ret;
16387e9bf23SRichard Henderson }
16487e9bf23SRichard Henderson #define do_prctl_get_tagged_addr_ctrl do_prctl_get_tagged_addr_ctrl
16587e9bf23SRichard Henderson 
16687e9bf23SRichard Henderson #endif /* AARCH64_TARGET_PRCTL_H */
167