xref: /openbmc/qemu/target/arm/tcg/sve_ldst_internal.h (revision debca86cad28192f82f741700bc38845f17d5c10)
1*c4601322SRichard Henderson /*
2*c4601322SRichard Henderson  * ARM SVE Load/Store Helpers
3*c4601322SRichard Henderson  *
4*c4601322SRichard Henderson  * Copyright (c) 2018-2022 Linaro
5*c4601322SRichard Henderson  *
6*c4601322SRichard Henderson  * This library is free software; you can redistribute it and/or
7*c4601322SRichard Henderson  * modify it under the terms of the GNU Lesser General Public
8*c4601322SRichard Henderson  * License as published by the Free Software Foundation; either
9*c4601322SRichard Henderson  * version 2.1 of the License, or (at your option) any later version.
10*c4601322SRichard Henderson  *
11*c4601322SRichard Henderson  * This library is distributed in the hope that it will be useful,
12*c4601322SRichard Henderson  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*c4601322SRichard Henderson  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14*c4601322SRichard Henderson  * Lesser General Public License for more details.
15*c4601322SRichard Henderson  *
16*c4601322SRichard Henderson  * You should have received a copy of the GNU Lesser General Public
17*c4601322SRichard Henderson  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18*c4601322SRichard Henderson  */
19*c4601322SRichard Henderson 
20*c4601322SRichard Henderson #ifndef TARGET_ARM_SVE_LDST_INTERNAL_H
21*c4601322SRichard Henderson #define TARGET_ARM_SVE_LDST_INTERNAL_H
22*c4601322SRichard Henderson 
23*c4601322SRichard Henderson #include "exec/cpu_ldst.h"
24*c4601322SRichard Henderson 
25*c4601322SRichard Henderson /*
26*c4601322SRichard Henderson  * Load one element into @vd + @reg_off from @host.
27*c4601322SRichard Henderson  * The controlling predicate is known to be true.
28*c4601322SRichard Henderson  */
29*c4601322SRichard Henderson typedef void sve_ldst1_host_fn(void *vd, intptr_t reg_off, void *host);
30*c4601322SRichard Henderson 
31*c4601322SRichard Henderson /*
32*c4601322SRichard Henderson  * Load one element into @vd + @reg_off from (@env, @vaddr, @ra).
33*c4601322SRichard Henderson  * The controlling predicate is known to be true.
34*c4601322SRichard Henderson  */
35*c4601322SRichard Henderson typedef void sve_ldst1_tlb_fn(CPUARMState *env, void *vd, intptr_t reg_off,
36*c4601322SRichard Henderson                               target_ulong vaddr, uintptr_t retaddr);
37*c4601322SRichard Henderson 
38*c4601322SRichard Henderson /*
39*c4601322SRichard Henderson  * Generate the above primitives.
40*c4601322SRichard Henderson  */
41*c4601322SRichard Henderson 
42*c4601322SRichard Henderson #define DO_LD_HOST(NAME, H, TYPEE, TYPEM, HOST)                              \
43*c4601322SRichard Henderson static inline void sve_##NAME##_host(void *vd, intptr_t reg_off, void *host) \
44*c4601322SRichard Henderson { TYPEM val = HOST(host); *(TYPEE *)(vd + H(reg_off)) = val; }
45*c4601322SRichard Henderson 
46*c4601322SRichard Henderson #define DO_ST_HOST(NAME, H, TYPEE, TYPEM, HOST)                              \
47*c4601322SRichard Henderson static inline void sve_##NAME##_host(void *vd, intptr_t reg_off, void *host) \
48*c4601322SRichard Henderson { TYPEM val = *(TYPEE *)(vd + H(reg_off)); HOST(host, val); }
49*c4601322SRichard Henderson 
50*c4601322SRichard Henderson #define DO_LD_TLB(NAME, H, TYPEE, TYPEM, TLB)                              \
51*c4601322SRichard Henderson static inline void sve_##NAME##_tlb(CPUARMState *env, void *vd,            \
52*c4601322SRichard Henderson                         intptr_t reg_off, target_ulong addr, uintptr_t ra) \
53*c4601322SRichard Henderson {                                                                          \
54*c4601322SRichard Henderson     TYPEM val = TLB(env, useronly_clean_ptr(addr), ra);                    \
55*c4601322SRichard Henderson     *(TYPEE *)(vd + H(reg_off)) = val;                                     \
56*c4601322SRichard Henderson }
57*c4601322SRichard Henderson 
58*c4601322SRichard Henderson #define DO_ST_TLB(NAME, H, TYPEE, TYPEM, TLB)                              \
59*c4601322SRichard Henderson static inline void sve_##NAME##_tlb(CPUARMState *env, void *vd,            \
60*c4601322SRichard Henderson                         intptr_t reg_off, target_ulong addr, uintptr_t ra) \
61*c4601322SRichard Henderson {                                                                          \
62*c4601322SRichard Henderson     TYPEM val = *(TYPEE *)(vd + H(reg_off));                               \
63*c4601322SRichard Henderson     TLB(env, useronly_clean_ptr(addr), val, ra);                           \
64*c4601322SRichard Henderson }
65*c4601322SRichard Henderson 
66*c4601322SRichard Henderson #define DO_LD_PRIM_1(NAME, H, TE, TM)                   \
67*c4601322SRichard Henderson     DO_LD_HOST(NAME, H, TE, TM, ldub_p)                 \
68*c4601322SRichard Henderson     DO_LD_TLB(NAME, H, TE, TM, cpu_ldub_data_ra)
69*c4601322SRichard Henderson 
70*c4601322SRichard Henderson DO_LD_PRIM_1(ld1bb,  H1,   uint8_t,  uint8_t)
71*c4601322SRichard Henderson DO_LD_PRIM_1(ld1bhu, H1_2, uint16_t, uint8_t)
72*c4601322SRichard Henderson DO_LD_PRIM_1(ld1bhs, H1_2, uint16_t,  int8_t)
73*c4601322SRichard Henderson DO_LD_PRIM_1(ld1bsu, H1_4, uint32_t, uint8_t)
74*c4601322SRichard Henderson DO_LD_PRIM_1(ld1bss, H1_4, uint32_t,  int8_t)
75*c4601322SRichard Henderson DO_LD_PRIM_1(ld1bdu, H1_8, uint64_t, uint8_t)
76*c4601322SRichard Henderson DO_LD_PRIM_1(ld1bds, H1_8, uint64_t,  int8_t)
77*c4601322SRichard Henderson 
78*c4601322SRichard Henderson #define DO_ST_PRIM_1(NAME, H, TE, TM)                   \
79*c4601322SRichard Henderson     DO_ST_HOST(st1##NAME, H, TE, TM, stb_p)             \
80*c4601322SRichard Henderson     DO_ST_TLB(st1##NAME, H, TE, TM, cpu_stb_data_ra)
81*c4601322SRichard Henderson 
82*c4601322SRichard Henderson DO_ST_PRIM_1(bb,   H1,  uint8_t, uint8_t)
83*c4601322SRichard Henderson DO_ST_PRIM_1(bh, H1_2, uint16_t, uint8_t)
84*c4601322SRichard Henderson DO_ST_PRIM_1(bs, H1_4, uint32_t, uint8_t)
85*c4601322SRichard Henderson DO_ST_PRIM_1(bd, H1_8, uint64_t, uint8_t)
86*c4601322SRichard Henderson 
87*c4601322SRichard Henderson #define DO_LD_PRIM_2(NAME, H, TE, TM, LD) \
88*c4601322SRichard Henderson     DO_LD_HOST(ld1##NAME##_be, H, TE, TM, LD##_be_p)    \
89*c4601322SRichard Henderson     DO_LD_HOST(ld1##NAME##_le, H, TE, TM, LD##_le_p)    \
90*c4601322SRichard Henderson     DO_LD_TLB(ld1##NAME##_be, H, TE, TM, cpu_##LD##_be_data_ra) \
91*c4601322SRichard Henderson     DO_LD_TLB(ld1##NAME##_le, H, TE, TM, cpu_##LD##_le_data_ra)
92*c4601322SRichard Henderson 
93*c4601322SRichard Henderson #define DO_ST_PRIM_2(NAME, H, TE, TM, ST) \
94*c4601322SRichard Henderson     DO_ST_HOST(st1##NAME##_be, H, TE, TM, ST##_be_p)    \
95*c4601322SRichard Henderson     DO_ST_HOST(st1##NAME##_le, H, TE, TM, ST##_le_p)    \
96*c4601322SRichard Henderson     DO_ST_TLB(st1##NAME##_be, H, TE, TM, cpu_##ST##_be_data_ra) \
97*c4601322SRichard Henderson     DO_ST_TLB(st1##NAME##_le, H, TE, TM, cpu_##ST##_le_data_ra)
98*c4601322SRichard Henderson 
99*c4601322SRichard Henderson DO_LD_PRIM_2(hh,  H1_2, uint16_t, uint16_t, lduw)
100*c4601322SRichard Henderson DO_LD_PRIM_2(hsu, H1_4, uint32_t, uint16_t, lduw)
101*c4601322SRichard Henderson DO_LD_PRIM_2(hss, H1_4, uint32_t,  int16_t, lduw)
102*c4601322SRichard Henderson DO_LD_PRIM_2(hdu, H1_8, uint64_t, uint16_t, lduw)
103*c4601322SRichard Henderson DO_LD_PRIM_2(hds, H1_8, uint64_t,  int16_t, lduw)
104*c4601322SRichard Henderson 
105*c4601322SRichard Henderson DO_ST_PRIM_2(hh, H1_2, uint16_t, uint16_t, stw)
106*c4601322SRichard Henderson DO_ST_PRIM_2(hs, H1_4, uint32_t, uint16_t, stw)
107*c4601322SRichard Henderson DO_ST_PRIM_2(hd, H1_8, uint64_t, uint16_t, stw)
108*c4601322SRichard Henderson 
109*c4601322SRichard Henderson DO_LD_PRIM_2(ss,  H1_4, uint32_t, uint32_t, ldl)
110*c4601322SRichard Henderson DO_LD_PRIM_2(sdu, H1_8, uint64_t, uint32_t, ldl)
111*c4601322SRichard Henderson DO_LD_PRIM_2(sds, H1_8, uint64_t,  int32_t, ldl)
112*c4601322SRichard Henderson 
113*c4601322SRichard Henderson DO_ST_PRIM_2(ss, H1_4, uint32_t, uint32_t, stl)
114*c4601322SRichard Henderson DO_ST_PRIM_2(sd, H1_8, uint64_t, uint32_t, stl)
115*c4601322SRichard Henderson 
116*c4601322SRichard Henderson DO_LD_PRIM_2(dd, H1_8, uint64_t, uint64_t, ldq)
117*c4601322SRichard Henderson DO_ST_PRIM_2(dd, H1_8, uint64_t, uint64_t, stq)
118*c4601322SRichard Henderson 
119*c4601322SRichard Henderson #undef DO_LD_TLB
120*c4601322SRichard Henderson #undef DO_ST_TLB
121*c4601322SRichard Henderson #undef DO_LD_HOST
122*c4601322SRichard Henderson #undef DO_LD_PRIM_1
123*c4601322SRichard Henderson #undef DO_ST_PRIM_1
124*c4601322SRichard Henderson #undef DO_LD_PRIM_2
125*c4601322SRichard Henderson #undef DO_ST_PRIM_2
126*c4601322SRichard Henderson 
127*c4601322SRichard Henderson /*
128*c4601322SRichard Henderson  * Resolve the guest virtual address to info->host and info->flags.
129*c4601322SRichard Henderson  * If @nofault, return false if the page is invalid, otherwise
130*c4601322SRichard Henderson  * exit via page fault exception.
131*c4601322SRichard Henderson  */
132*c4601322SRichard Henderson 
133*c4601322SRichard Henderson typedef struct {
134*c4601322SRichard Henderson     void *host;
135*c4601322SRichard Henderson     int flags;
136*c4601322SRichard Henderson     MemTxAttrs attrs;
137*c4601322SRichard Henderson     bool tagged;
138*c4601322SRichard Henderson } SVEHostPage;
139*c4601322SRichard Henderson 
140*c4601322SRichard Henderson bool sve_probe_page(SVEHostPage *info, bool nofault, CPUARMState *env,
141*c4601322SRichard Henderson                     target_ulong addr, int mem_off, MMUAccessType access_type,
142*c4601322SRichard Henderson                     int mmu_idx, uintptr_t retaddr);
143*c4601322SRichard Henderson 
144*c4601322SRichard Henderson /*
145*c4601322SRichard Henderson  * Analyse contiguous data, protected by a governing predicate.
146*c4601322SRichard Henderson  */
147*c4601322SRichard Henderson 
148*c4601322SRichard Henderson typedef enum {
149*c4601322SRichard Henderson     FAULT_NO,
150*c4601322SRichard Henderson     FAULT_FIRST,
151*c4601322SRichard Henderson     FAULT_ALL,
152*c4601322SRichard Henderson } SVEContFault;
153*c4601322SRichard Henderson 
154*c4601322SRichard Henderson typedef struct {
155*c4601322SRichard Henderson     /*
156*c4601322SRichard Henderson      * First and last element wholly contained within the two pages.
157*c4601322SRichard Henderson      * mem_off_first[0] and reg_off_first[0] are always set >= 0.
158*c4601322SRichard Henderson      * reg_off_last[0] may be < 0 if the first element crosses pages.
159*c4601322SRichard Henderson      * All of mem_off_first[1], reg_off_first[1] and reg_off_last[1]
160*c4601322SRichard Henderson      * are set >= 0 only if there are complete elements on a second page.
161*c4601322SRichard Henderson      *
162*c4601322SRichard Henderson      * The reg_off_* offsets are relative to the internal vector register.
163*c4601322SRichard Henderson      * The mem_off_first offset is relative to the memory address; the
164*c4601322SRichard Henderson      * two offsets are different when a load operation extends, a store
165*c4601322SRichard Henderson      * operation truncates, or for multi-register operations.
166*c4601322SRichard Henderson      */
167*c4601322SRichard Henderson     int16_t mem_off_first[2];
168*c4601322SRichard Henderson     int16_t reg_off_first[2];
169*c4601322SRichard Henderson     int16_t reg_off_last[2];
170*c4601322SRichard Henderson 
171*c4601322SRichard Henderson     /*
172*c4601322SRichard Henderson      * One element that is misaligned and spans both pages,
173*c4601322SRichard Henderson      * or -1 if there is no such active element.
174*c4601322SRichard Henderson      */
175*c4601322SRichard Henderson     int16_t mem_off_split;
176*c4601322SRichard Henderson     int16_t reg_off_split;
177*c4601322SRichard Henderson 
178*c4601322SRichard Henderson     /*
179*c4601322SRichard Henderson      * The byte offset at which the entire operation crosses a page boundary.
180*c4601322SRichard Henderson      * Set >= 0 if and only if the entire operation spans two pages.
181*c4601322SRichard Henderson      */
182*c4601322SRichard Henderson     int16_t page_split;
183*c4601322SRichard Henderson 
184*c4601322SRichard Henderson     /* TLB data for the two pages. */
185*c4601322SRichard Henderson     SVEHostPage page[2];
186*c4601322SRichard Henderson } SVEContLdSt;
187*c4601322SRichard Henderson 
188*c4601322SRichard Henderson /*
189*c4601322SRichard Henderson  * Find first active element on each page, and a loose bound for the
190*c4601322SRichard Henderson  * final element on each page.  Identify any single element that spans
191*c4601322SRichard Henderson  * the page boundary.  Return true if there are any active elements.
192*c4601322SRichard Henderson  */
193*c4601322SRichard Henderson bool sve_cont_ldst_elements(SVEContLdSt *info, target_ulong addr, uint64_t *vg,
194*c4601322SRichard Henderson                             intptr_t reg_max, int esz, int msize);
195*c4601322SRichard Henderson 
196*c4601322SRichard Henderson /*
197*c4601322SRichard Henderson  * Resolve the guest virtual addresses to info->page[].
198*c4601322SRichard Henderson  * Control the generation of page faults with @fault.  Return false if
199*c4601322SRichard Henderson  * there is no work to do, which can only happen with @fault == FAULT_NO.
200*c4601322SRichard Henderson  */
201*c4601322SRichard Henderson bool sve_cont_ldst_pages(SVEContLdSt *info, SVEContFault fault,
202*c4601322SRichard Henderson                          CPUARMState *env, target_ulong addr,
203*c4601322SRichard Henderson                          MMUAccessType access_type, uintptr_t retaddr);
204*c4601322SRichard Henderson 
205*c4601322SRichard Henderson #ifdef CONFIG_USER_ONLY
206*c4601322SRichard Henderson static inline void
sve_cont_ldst_watchpoints(SVEContLdSt * info,CPUARMState * env,uint64_t * vg,target_ulong addr,int esize,int msize,int wp_access,uintptr_t retaddr)207*c4601322SRichard Henderson sve_cont_ldst_watchpoints(SVEContLdSt *info, CPUARMState *env, uint64_t *vg,
208*c4601322SRichard Henderson                           target_ulong addr, int esize, int msize,
209*c4601322SRichard Henderson                           int wp_access, uintptr_t retaddr)
210*c4601322SRichard Henderson { }
211*c4601322SRichard Henderson #else
212*c4601322SRichard Henderson void sve_cont_ldst_watchpoints(SVEContLdSt *info, CPUARMState *env,
213*c4601322SRichard Henderson                                uint64_t *vg, target_ulong addr,
214*c4601322SRichard Henderson                                int esize, int msize, int wp_access,
215*c4601322SRichard Henderson                                uintptr_t retaddr);
216*c4601322SRichard Henderson #endif
217*c4601322SRichard Henderson 
218*c4601322SRichard Henderson void sve_cont_ldst_mte_check(SVEContLdSt *info, CPUARMState *env, uint64_t *vg,
219*c4601322SRichard Henderson                              target_ulong addr, int esize, int msize,
220*c4601322SRichard Henderson                              uint32_t mtedesc, uintptr_t ra);
221*c4601322SRichard Henderson 
222*c4601322SRichard Henderson #endif /* TARGET_ARM_SVE_LDST_INTERNAL_H */
223