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
79static inline RES_TYPE
80glue(glue(glue(cpu_ld, USUFFIX), MEMSUFFIX), _ra)(CPUArchState *env,
81 target_ulong ptr,
82 uintptr_t retaddr)
83{
84 CPUTLBEntry *entry;
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_cpu(env), ptr,
93 trace_mem_build_info(SHIFT, false, MO_TE, false));
94#endif
95
96 addr = ptr;
97 mmu_idx = CPU_MMU_INDEX;
98 entry = tlb_entry(env, mmu_idx, addr);
99 if (unlikely(entry->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 + entry->addend;
106 res = glue(glue(ld, USUFFIX), _p)((uint8_t *)hostaddr);
107 }
108 return res;
109}
110
111static inline RES_TYPE
112glue(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
118static inline int
119glue(glue(glue(cpu_lds, SUFFIX), MEMSUFFIX), _ra)(CPUArchState *env,
120 target_ulong ptr,
121 uintptr_t retaddr)
122{
123 CPUTLBEntry *entry;
124 int res;
125 target_ulong addr;
126 int mmu_idx;
127 TCGMemOpIdx oi;
128
129#if !defined(SOFTMMU_CODE_ACCESS)
130 trace_guest_mem_before_exec(
131 env_cpu(env), ptr,
132 trace_mem_build_info(SHIFT, true, MO_TE, false));
133#endif
134
135 addr = ptr;
136 mmu_idx = CPU_MMU_INDEX;
137 entry = tlb_entry(env, mmu_idx, addr);
138 if (unlikely(entry->ADDR_READ !=
139 (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) {
140 oi = make_memop_idx(SHIFT, mmu_idx);
141 res = (DATA_STYPE)glue(glue(helper_ret_ld, SRETSUFFIX),
142 MMUSUFFIX)(env, addr, oi, retaddr);
143 } else {
144 uintptr_t hostaddr = addr + entry->addend;
145 res = glue(glue(lds, SUFFIX), _p)((uint8_t *)hostaddr);
146 }
147 return res;
148}
149
150static inline int
151glue(glue(cpu_lds, SUFFIX), MEMSUFFIX)(CPUArchState *env, target_ulong ptr)
152{
153 return glue(glue(glue(cpu_lds, SUFFIX), MEMSUFFIX), _ra)(env, ptr, 0);
154}
155#endif
156
157#ifndef SOFTMMU_CODE_ACCESS
158
159/* generic store macro */
160
161static inline void
162glue(glue(glue(cpu_st, SUFFIX), MEMSUFFIX), _ra)(CPUArchState *env,
163 target_ulong ptr,
164 RES_TYPE v, uintptr_t retaddr)
165{
166 CPUTLBEntry *entry;
167 target_ulong addr;
168 int mmu_idx;
169 TCGMemOpIdx oi;
170
171#if !defined(SOFTMMU_CODE_ACCESS)
172 trace_guest_mem_before_exec(
173 env_cpu(env), ptr,
174 trace_mem_build_info(SHIFT, false, MO_TE, true));
175#endif
176
177 addr = ptr;
178 mmu_idx = CPU_MMU_INDEX;
179 entry = tlb_entry(env, mmu_idx, addr);
180 if (unlikely(tlb_addr_write(entry) !=
181 (addr & (TARGET_PAGE_MASK | (DATA_SIZE - 1))))) {
182 oi = make_memop_idx(SHIFT, mmu_idx);
183 glue(glue(helper_ret_st, SUFFIX), MMUSUFFIX)(env, addr, v, oi,
184 retaddr);
185 } else {
186 uintptr_t hostaddr = addr + entry->addend;
187 glue(glue(st, SUFFIX), _p)((uint8_t *)hostaddr, v);
188 }
189}
190
191static inline void
192glue(glue(cpu_st, SUFFIX), MEMSUFFIX)(CPUArchState *env, target_ulong ptr,
193 RES_TYPE v)
194{
195 glue(glue(glue(cpu_st, SUFFIX), MEMSUFFIX), _ra)(env, ptr, v, 0);
196}
197
198#endif /* !SOFTMMU_CODE_ACCESS */
199
200#undef RES_TYPE
201#undef DATA_TYPE
202#undef DATA_STYPE
203#undef SUFFIX
204#undef USUFFIX
205#undef DATA_SIZE
206#undef MMUSUFFIX
207#undef ADDR_READ
208#undef URETSUFFIX
209#undef SRETSUFFIX
210#undef SHIFT
211