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 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