1 /*
2  *  Software MMU support
3  *
4  * Generate inline load/store functions for one MMU mode and data
5  * size.
6  *
7  * Generate a store function as well as signed and unsigned loads.
8  *
9  * Not used directly but included from cpu_ldst.h.
10  *
11  *  Copyright (c) 2003 Fabrice Bellard
12  *
13  * This library is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU Lesser General Public
15  * License as published by the Free Software Foundation; either
16  * version 2 of the License, or (at your option) any later version.
17  *
18  * This library is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  * Lesser General Public License for more details.
22  *
23  * You should have received a copy of the GNU Lesser General Public
24  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
25  */
26 
27 #if !defined(SOFTMMU_CODE_ACCESS)
28 #include "trace-root.h"
29 #endif
30 
31 #include "trace/mem.h"
32 
33 #if DATA_SIZE == 8
34 #define SUFFIX q
35 #define USUFFIX q
36 #define DATA_TYPE uint64_t
37 #define SHIFT 3
38 #elif DATA_SIZE == 4
39 #define SUFFIX l
40 #define USUFFIX l
41 #define DATA_TYPE uint32_t
42 #define SHIFT 2
43 #elif DATA_SIZE == 2
44 #define SUFFIX w
45 #define USUFFIX uw
46 #define DATA_TYPE uint16_t
47 #define DATA_STYPE int16_t
48 #define SHIFT 1
49 #elif DATA_SIZE == 1
50 #define SUFFIX b
51 #define USUFFIX ub
52 #define DATA_TYPE uint8_t
53 #define DATA_STYPE int8_t
54 #define SHIFT 0
55 #else
56 #error unsupported data size
57 #endif
58 
59 #if DATA_SIZE == 8
60 #define RES_TYPE uint64_t
61 #else
62 #define RES_TYPE uint32_t
63 #endif
64 
65 #ifdef SOFTMMU_CODE_ACCESS
66 #define ADDR_READ addr_code
67 #define MMUSUFFIX _cmmu
68 #define URETSUFFIX SUFFIX
69 #define SRETSUFFIX SUFFIX
70 #else
71 #define ADDR_READ addr_read
72 #define MMUSUFFIX _mmu
73 #define URETSUFFIX USUFFIX
74 #define SRETSUFFIX glue(s, SUFFIX)
75 #endif
76 
77 /* generic load/store macros */
78 
79 static inline RES_TYPE
glue(glue (glue (cpu_ld,USUFFIX),MEMSUFFIX),_ra)80 glue(glue(glue(cpu_ld, USUFFIX), MEMSUFFIX), _ra)(CPUArchState *env,
81                                                   target_ulong ptr,
82                                                   uintptr_t retaddr)
83 {
84     int page_index;
85     RES_TYPE res;
86     target_ulong addr;
87     int mmu_idx;
88     TCGMemOpIdx oi;
89 
90 #if !defined(SOFTMMU_CODE_ACCESS)
91     trace_guest_mem_before_exec(
92         ENV_GET_CPU(env), ptr,
93         trace_mem_build_info(SHIFT, false, MO_TE, false));
94 #endif
95 
96     addr = ptr;
97     page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
98     mmu_idx = CPU_MMU_INDEX;
99     if (unlikely(env->tlb_table[mmu_idx][page_index].ADDR_READ !=
100                  (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) {
101         oi = make_memop_idx(SHIFT, mmu_idx);
102         res = glue(glue(helper_ret_ld, URETSUFFIX), MMUSUFFIX)(env, addr,
103                                                             oi, retaddr);
104     } else {
105         uintptr_t hostaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
106         res = glue(glue(ld, USUFFIX), _p)((uint8_t *)hostaddr);
107     }
108     return res;
109 }
110 
111 static inline RES_TYPE
glue(glue (cpu_ld,USUFFIX),MEMSUFFIX)112 glue(glue(cpu_ld, USUFFIX), MEMSUFFIX)(CPUArchState *env, target_ulong ptr)
113 {
114     return glue(glue(glue(cpu_ld, USUFFIX), MEMSUFFIX), _ra)(env, ptr, 0);
115 }
116 
117 #if DATA_SIZE <= 2
118 static inline int
glue(glue (glue (cpu_lds,SUFFIX),MEMSUFFIX),_ra)119 glue(glue(glue(cpu_lds, SUFFIX), MEMSUFFIX), _ra)(CPUArchState *env,
120                                                   target_ulong ptr,
121                                                   uintptr_t retaddr)
122 {
123     int res, page_index;
124     target_ulong addr;
125     int mmu_idx;
126     TCGMemOpIdx oi;
127 
128 #if !defined(SOFTMMU_CODE_ACCESS)
129     trace_guest_mem_before_exec(
130         ENV_GET_CPU(env), ptr,
131         trace_mem_build_info(SHIFT, true, MO_TE, false));
132 #endif
133 
134     addr = ptr;
135     page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
136     mmu_idx = CPU_MMU_INDEX;
137     if (unlikely(env->tlb_table[mmu_idx][page_index].ADDR_READ !=
138                  (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) {
139         oi = make_memop_idx(SHIFT, mmu_idx);
140         res = (DATA_STYPE)glue(glue(helper_ret_ld, SRETSUFFIX),
141                                MMUSUFFIX)(env, addr, oi, retaddr);
142     } else {
143         uintptr_t hostaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
144         res = glue(glue(lds, SUFFIX), _p)((uint8_t *)hostaddr);
145     }
146     return res;
147 }
148 
149 static inline int
glue(glue (cpu_lds,SUFFIX),MEMSUFFIX)150 glue(glue(cpu_lds, SUFFIX), MEMSUFFIX)(CPUArchState *env, target_ulong ptr)
151 {
152     return glue(glue(glue(cpu_lds, SUFFIX), MEMSUFFIX), _ra)(env, ptr, 0);
153 }
154 #endif
155 
156 #ifndef SOFTMMU_CODE_ACCESS
157 
158 /* generic store macro */
159 
160 static inline void
glue(glue (glue (cpu_st,SUFFIX),MEMSUFFIX),_ra)161 glue(glue(glue(cpu_st, SUFFIX), MEMSUFFIX), _ra)(CPUArchState *env,
162                                                  target_ulong ptr,
163                                                  RES_TYPE v, uintptr_t retaddr)
164 {
165     int page_index;
166     target_ulong addr;
167     int mmu_idx;
168     TCGMemOpIdx oi;
169 
170 #if !defined(SOFTMMU_CODE_ACCESS)
171     trace_guest_mem_before_exec(
172         ENV_GET_CPU(env), ptr,
173         trace_mem_build_info(SHIFT, false, MO_TE, true));
174 #endif
175 
176     addr = ptr;
177     page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
178     mmu_idx = CPU_MMU_INDEX;
179     if (unlikely(env->tlb_table[mmu_idx][page_index].addr_write !=
180                  (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) {
181         oi = make_memop_idx(SHIFT, mmu_idx);
182         glue(glue(helper_ret_st, SUFFIX), MMUSUFFIX)(env, addr, v, oi,
183                                                      retaddr);
184     } else {
185         uintptr_t hostaddr = addr + env->tlb_table[mmu_idx][page_index].addend;
186         glue(glue(st, SUFFIX), _p)((uint8_t *)hostaddr, v);
187     }
188 }
189 
190 static inline void
glue(glue (cpu_st,SUFFIX),MEMSUFFIX)191 glue(glue(cpu_st, SUFFIX), MEMSUFFIX)(CPUArchState *env, target_ulong ptr,
192                                       RES_TYPE v)
193 {
194     glue(glue(glue(cpu_st, SUFFIX), MEMSUFFIX), _ra)(env, ptr, v, 0);
195 }
196 
197 #endif /* !SOFTMMU_CODE_ACCESS */
198 
199 #undef RES_TYPE
200 #undef DATA_TYPE
201 #undef DATA_STYPE
202 #undef SUFFIX
203 #undef USUFFIX
204 #undef DATA_SIZE
205 #undef MMUSUFFIX
206 #undef ADDR_READ
207 #undef URETSUFFIX
208 #undef SRETSUFFIX
209 #undef SHIFT
210