xref: /qemu/linux-user/aarch64/target_prctl.h (revision 118d4ed0)
1 /*
2  * AArch64 specific prctl functions for linux-user
3  *
4  * SPDX-License-Identifier: GPL-2.0-or-later
5  */
6 #ifndef AARCH64_TARGET_PRCTL_H
7 #define AARCH64_TARGET_PRCTL_H
8 
9 static abi_long do_prctl_get_vl(CPUArchState *env)
10 {
11     ARMCPU *cpu = env_archcpu(env);
12     if (cpu_isar_feature(aa64_sve, cpu)) {
13         return sve_vq(env) * 16;
14     }
15     return -TARGET_EINVAL;
16 }
17 #define do_prctl_get_vl do_prctl_get_vl
18 
19 static abi_long do_prctl_set_vl(CPUArchState *env, abi_long arg2)
20 {
21     /*
22      * We cannot support either PR_SVE_SET_VL_ONEXEC or PR_SVE_VL_INHERIT.
23      * Note the kernel definition of sve_vl_valid allows for VQ=512,
24      * i.e. VL=8192, even though the current architectural maximum is VQ=16.
25      */
26     if (cpu_isar_feature(aa64_sve, env_archcpu(env))
27         && arg2 >= 0 && arg2 <= 512 * 16 && !(arg2 & 15)) {
28         uint32_t vq, old_vq;
29 
30         old_vq = sve_vq(env);
31 
32         /*
33          * Bound the value of arg2, so that we know that it fits into
34          * the 4-bit field in ZCR_EL1.  Rely on the hflags rebuild to
35          * sort out the length supported by the cpu.
36          */
37         vq = MAX(arg2 / 16, 1);
38         vq = MIN(vq, ARM_MAX_VQ);
39         env->vfp.zcr_el[1] = vq - 1;
40         arm_rebuild_hflags(env);
41 
42         vq = sve_vq(env);
43         if (vq < old_vq) {
44             aarch64_sve_narrow_vq(env, vq);
45         }
46         return vq * 16;
47     }
48     return -TARGET_EINVAL;
49 }
50 #define do_prctl_set_vl do_prctl_set_vl
51 
52 static abi_long do_prctl_reset_keys(CPUArchState *env, abi_long arg2)
53 {
54     ARMCPU *cpu = env_archcpu(env);
55 
56     if (cpu_isar_feature(aa64_pauth, cpu)) {
57         int all = (PR_PAC_APIAKEY | PR_PAC_APIBKEY |
58                    PR_PAC_APDAKEY | PR_PAC_APDBKEY | PR_PAC_APGAKEY);
59         int ret = 0;
60         Error *err = NULL;
61 
62         if (arg2 == 0) {
63             arg2 = all;
64         } else if (arg2 & ~all) {
65             return -TARGET_EINVAL;
66         }
67         if (arg2 & PR_PAC_APIAKEY) {
68             ret |= qemu_guest_getrandom(&env->keys.apia,
69                                         sizeof(ARMPACKey), &err);
70         }
71         if (arg2 & PR_PAC_APIBKEY) {
72             ret |= qemu_guest_getrandom(&env->keys.apib,
73                                         sizeof(ARMPACKey), &err);
74         }
75         if (arg2 & PR_PAC_APDAKEY) {
76             ret |= qemu_guest_getrandom(&env->keys.apda,
77                                         sizeof(ARMPACKey), &err);
78         }
79         if (arg2 & PR_PAC_APDBKEY) {
80             ret |= qemu_guest_getrandom(&env->keys.apdb,
81                                         sizeof(ARMPACKey), &err);
82         }
83         if (arg2 & PR_PAC_APGAKEY) {
84             ret |= qemu_guest_getrandom(&env->keys.apga,
85                                         sizeof(ARMPACKey), &err);
86         }
87         if (ret != 0) {
88             /*
89              * Some unknown failure in the crypto.  The best
90              * we can do is log it and fail the syscall.
91              * The real syscall cannot fail this way.
92              */
93             qemu_log_mask(LOG_UNIMP, "PR_PAC_RESET_KEYS: Crypto failure: %s",
94                           error_get_pretty(err));
95             error_free(err);
96             return -TARGET_EIO;
97         }
98         return 0;
99     }
100     return -TARGET_EINVAL;
101 }
102 #define do_prctl_reset_keys do_prctl_reset_keys
103 
104 static abi_long do_prctl_set_tagged_addr_ctrl(CPUArchState *env, abi_long arg2)
105 {
106     abi_ulong valid_mask = PR_TAGGED_ADDR_ENABLE;
107     ARMCPU *cpu = env_archcpu(env);
108 
109     if (cpu_isar_feature(aa64_mte, cpu)) {
110         valid_mask |= PR_MTE_TCF_MASK;
111         valid_mask |= PR_MTE_TAG_MASK;
112     }
113 
114     if (arg2 & ~valid_mask) {
115         return -TARGET_EINVAL;
116     }
117     env->tagged_addr_enable = arg2 & PR_TAGGED_ADDR_ENABLE;
118 
119     if (cpu_isar_feature(aa64_mte, cpu)) {
120         switch (arg2 & PR_MTE_TCF_MASK) {
121         case PR_MTE_TCF_NONE:
122         case PR_MTE_TCF_SYNC:
123         case PR_MTE_TCF_ASYNC:
124             break;
125         default:
126             return -EINVAL;
127         }
128 
129         /*
130          * Write PR_MTE_TCF to SCTLR_EL1[TCF0].
131          * Note that the syscall values are consistent with hw.
132          */
133         env->cp15.sctlr_el[1] =
134             deposit64(env->cp15.sctlr_el[1], 38, 2, arg2 >> PR_MTE_TCF_SHIFT);
135 
136         /*
137          * Write PR_MTE_TAG to GCR_EL1[Exclude].
138          * Note that the syscall uses an include mask,
139          * and hardware uses an exclude mask -- invert.
140          */
141         env->cp15.gcr_el1 =
142             deposit64(env->cp15.gcr_el1, 0, 16, ~arg2 >> PR_MTE_TAG_SHIFT);
143         arm_rebuild_hflags(env);
144     }
145     return 0;
146 }
147 #define do_prctl_set_tagged_addr_ctrl do_prctl_set_tagged_addr_ctrl
148 
149 static abi_long do_prctl_get_tagged_addr_ctrl(CPUArchState *env)
150 {
151     ARMCPU *cpu = env_archcpu(env);
152     abi_long ret = 0;
153 
154     if (env->tagged_addr_enable) {
155         ret |= PR_TAGGED_ADDR_ENABLE;
156     }
157     if (cpu_isar_feature(aa64_mte, cpu)) {
158         /* See do_prctl_set_tagged_addr_ctrl. */
159         ret |= extract64(env->cp15.sctlr_el[1], 38, 2) << PR_MTE_TCF_SHIFT;
160         ret = deposit64(ret, PR_MTE_TAG_SHIFT, 16, ~env->cp15.gcr_el1);
161     }
162     return ret;
163 }
164 #define do_prctl_get_tagged_addr_ctrl do_prctl_get_tagged_addr_ctrl
165 
166 #endif /* AARCH64_TARGET_PRCTL_H */
167