xref: /qemu/linux-user/aarch64/target_prctl.h (revision b83a80e8)
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 ((cpu->env.vfp.zcr_el[1] & 0xf) + 1) * 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         ARMCPU *cpu = env_archcpu(env);
29         uint32_t vq, old_vq;
30 
31         old_vq = (env->vfp.zcr_el[1] & 0xf) + 1;
32         vq = MAX(arg2 / 16, 1);
33         vq = MIN(vq, cpu->sve_max_vq);
34 
35         if (vq < old_vq) {
36             aarch64_sve_narrow_vq(env, vq);
37         }
38         env->vfp.zcr_el[1] = vq - 1;
39         arm_rebuild_hflags(env);
40         return vq * 16;
41     }
42     return -TARGET_EINVAL;
43 }
44 #define do_prctl_set_vl do_prctl_set_vl
45 
46 static abi_long do_prctl_reset_keys(CPUArchState *env, abi_long arg2)
47 {
48     ARMCPU *cpu = env_archcpu(env);
49 
50     if (cpu_isar_feature(aa64_pauth, cpu)) {
51         int all = (PR_PAC_APIAKEY | PR_PAC_APIBKEY |
52                    PR_PAC_APDAKEY | PR_PAC_APDBKEY | PR_PAC_APGAKEY);
53         int ret = 0;
54         Error *err = NULL;
55 
56         if (arg2 == 0) {
57             arg2 = all;
58         } else if (arg2 & ~all) {
59             return -TARGET_EINVAL;
60         }
61         if (arg2 & PR_PAC_APIAKEY) {
62             ret |= qemu_guest_getrandom(&env->keys.apia,
63                                         sizeof(ARMPACKey), &err);
64         }
65         if (arg2 & PR_PAC_APIBKEY) {
66             ret |= qemu_guest_getrandom(&env->keys.apib,
67                                         sizeof(ARMPACKey), &err);
68         }
69         if (arg2 & PR_PAC_APDAKEY) {
70             ret |= qemu_guest_getrandom(&env->keys.apda,
71                                         sizeof(ARMPACKey), &err);
72         }
73         if (arg2 & PR_PAC_APDBKEY) {
74             ret |= qemu_guest_getrandom(&env->keys.apdb,
75                                         sizeof(ARMPACKey), &err);
76         }
77         if (arg2 & PR_PAC_APGAKEY) {
78             ret |= qemu_guest_getrandom(&env->keys.apga,
79                                         sizeof(ARMPACKey), &err);
80         }
81         if (ret != 0) {
82             /*
83              * Some unknown failure in the crypto.  The best
84              * we can do is log it and fail the syscall.
85              * The real syscall cannot fail this way.
86              */
87             qemu_log_mask(LOG_UNIMP, "PR_PAC_RESET_KEYS: Crypto failure: %s",
88                           error_get_pretty(err));
89             error_free(err);
90             return -TARGET_EIO;
91         }
92         return 0;
93     }
94     return -TARGET_EINVAL;
95 }
96 #define do_prctl_reset_keys do_prctl_reset_keys
97 
98 static abi_long do_prctl_set_tagged_addr_ctrl(CPUArchState *env, abi_long arg2)
99 {
100     abi_ulong valid_mask = PR_TAGGED_ADDR_ENABLE;
101     ARMCPU *cpu = env_archcpu(env);
102 
103     if (cpu_isar_feature(aa64_mte, cpu)) {
104         valid_mask |= PR_MTE_TCF_MASK;
105         valid_mask |= PR_MTE_TAG_MASK;
106     }
107 
108     if (arg2 & ~valid_mask) {
109         return -TARGET_EINVAL;
110     }
111     env->tagged_addr_enable = arg2 & PR_TAGGED_ADDR_ENABLE;
112 
113     if (cpu_isar_feature(aa64_mte, cpu)) {
114         switch (arg2 & PR_MTE_TCF_MASK) {
115         case PR_MTE_TCF_NONE:
116         case PR_MTE_TCF_SYNC:
117         case PR_MTE_TCF_ASYNC:
118             break;
119         default:
120             return -EINVAL;
121         }
122 
123         /*
124          * Write PR_MTE_TCF to SCTLR_EL1[TCF0].
125          * Note that the syscall values are consistent with hw.
126          */
127         env->cp15.sctlr_el[1] =
128             deposit64(env->cp15.sctlr_el[1], 38, 2, arg2 >> PR_MTE_TCF_SHIFT);
129 
130         /*
131          * Write PR_MTE_TAG to GCR_EL1[Exclude].
132          * Note that the syscall uses an include mask,
133          * and hardware uses an exclude mask -- invert.
134          */
135         env->cp15.gcr_el1 =
136             deposit64(env->cp15.gcr_el1, 0, 16, ~arg2 >> PR_MTE_TAG_SHIFT);
137         arm_rebuild_hflags(env);
138     }
139     return 0;
140 }
141 #define do_prctl_set_tagged_addr_ctrl do_prctl_set_tagged_addr_ctrl
142 
143 static abi_long do_prctl_get_tagged_addr_ctrl(CPUArchState *env)
144 {
145     ARMCPU *cpu = env_archcpu(env);
146     abi_long ret = 0;
147 
148     if (env->tagged_addr_enable) {
149         ret |= PR_TAGGED_ADDR_ENABLE;
150     }
151     if (cpu_isar_feature(aa64_mte, cpu)) {
152         /* See do_prctl_set_tagged_addr_ctrl. */
153         ret |= extract64(env->cp15.sctlr_el[1], 38, 2) << PR_MTE_TCF_SHIFT;
154         ret = deposit64(ret, PR_MTE_TAG_SHIFT, 16, ~env->cp15.gcr_el1);
155     }
156     return ret;
157 }
158 #define do_prctl_get_tagged_addr_ctrl do_prctl_get_tagged_addr_ctrl
159 
160 #endif /* AARCH64_TARGET_PRCTL_H */
161