]> git.proxmox.com Git - mirror_qemu.git/blame - memory_ldst.inc.c
Merge remote-tracking branch 'remotes/bonzini/tags/for-upstream' into staging
[mirror_qemu.git] / memory_ldst.inc.c
CommitLineData
0ce265ff
PB
1/*
2 * Physical memory access templates
3 *
4 * Copyright (c) 2003 Fabrice Bellard
5 * Copyright (c) 2015 Linaro, Inc.
6 * Copyright (c) 2016 Red Hat, Inc.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 */
21
22/* warning: addr must be aligned */
23static inline uint32_t glue(address_space_ldl_internal, SUFFIX)(ARG1_DECL,
24 hwaddr addr, MemTxAttrs attrs, MemTxResult *result,
25 enum device_endian endian)
26{
27 uint8_t *ptr;
28 uint64_t val;
29 MemoryRegion *mr;
30 hwaddr l = 4;
31 hwaddr addr1;
32 MemTxResult r;
33 bool release_lock = false;
34
35 RCU_READ_LOCK();
bc6b1cec 36 mr = TRANSLATE(addr, &addr1, &l, false, attrs);
a99761d3 37 if (l < 4 || !memory_access_is_direct(mr, false)) {
0ce265ff
PB
38 release_lock |= prepare_mmio_access(mr);
39
40 /* I/O case */
41 r = memory_region_dispatch_read(mr, addr1, &val, 4, attrs);
42#if defined(TARGET_WORDS_BIGENDIAN)
43 if (endian == DEVICE_LITTLE_ENDIAN) {
44 val = bswap32(val);
45 }
46#else
47 if (endian == DEVICE_BIG_ENDIAN) {
48 val = bswap32(val);
49 }
50#endif
51 } else {
52 /* RAM case */
a99761d3 53 ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
0ce265ff
PB
54 switch (endian) {
55 case DEVICE_LITTLE_ENDIAN:
56 val = ldl_le_p(ptr);
57 break;
58 case DEVICE_BIG_ENDIAN:
59 val = ldl_be_p(ptr);
60 break;
61 default:
62 val = ldl_p(ptr);
63 break;
64 }
65 r = MEMTX_OK;
66 }
67 if (result) {
68 *result = r;
69 }
70 if (release_lock) {
71 qemu_mutex_unlock_iothread();
72 }
73 RCU_READ_UNLOCK();
74 return val;
75}
76
77uint32_t glue(address_space_ldl, SUFFIX)(ARG1_DECL,
78 hwaddr addr, MemTxAttrs attrs, MemTxResult *result)
79{
80 return glue(address_space_ldl_internal, SUFFIX)(ARG1, addr, attrs, result,
81 DEVICE_NATIVE_ENDIAN);
82}
83
84uint32_t glue(address_space_ldl_le, SUFFIX)(ARG1_DECL,
85 hwaddr addr, MemTxAttrs attrs, MemTxResult *result)
86{
87 return glue(address_space_ldl_internal, SUFFIX)(ARG1, addr, attrs, result,
88 DEVICE_LITTLE_ENDIAN);
89}
90
91uint32_t glue(address_space_ldl_be, SUFFIX)(ARG1_DECL,
92 hwaddr addr, MemTxAttrs attrs, MemTxResult *result)
93{
94 return glue(address_space_ldl_internal, SUFFIX)(ARG1, addr, attrs, result,
95 DEVICE_BIG_ENDIAN);
96}
97
0ce265ff
PB
98/* warning: addr must be aligned */
99static inline uint64_t glue(address_space_ldq_internal, SUFFIX)(ARG1_DECL,
100 hwaddr addr, MemTxAttrs attrs, MemTxResult *result,
101 enum device_endian endian)
102{
103 uint8_t *ptr;
104 uint64_t val;
105 MemoryRegion *mr;
106 hwaddr l = 8;
107 hwaddr addr1;
108 MemTxResult r;
109 bool release_lock = false;
110
111 RCU_READ_LOCK();
bc6b1cec 112 mr = TRANSLATE(addr, &addr1, &l, false, attrs);
a99761d3 113 if (l < 8 || !memory_access_is_direct(mr, false)) {
0ce265ff
PB
114 release_lock |= prepare_mmio_access(mr);
115
116 /* I/O case */
117 r = memory_region_dispatch_read(mr, addr1, &val, 8, attrs);
118#if defined(TARGET_WORDS_BIGENDIAN)
119 if (endian == DEVICE_LITTLE_ENDIAN) {
120 val = bswap64(val);
121 }
122#else
123 if (endian == DEVICE_BIG_ENDIAN) {
124 val = bswap64(val);
125 }
126#endif
127 } else {
128 /* RAM case */
a99761d3 129 ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
0ce265ff
PB
130 switch (endian) {
131 case DEVICE_LITTLE_ENDIAN:
132 val = ldq_le_p(ptr);
133 break;
134 case DEVICE_BIG_ENDIAN:
135 val = ldq_be_p(ptr);
136 break;
137 default:
138 val = ldq_p(ptr);
139 break;
140 }
141 r = MEMTX_OK;
142 }
143 if (result) {
144 *result = r;
145 }
146 if (release_lock) {
147 qemu_mutex_unlock_iothread();
148 }
149 RCU_READ_UNLOCK();
150 return val;
151}
152
153uint64_t glue(address_space_ldq, SUFFIX)(ARG1_DECL,
154 hwaddr addr, MemTxAttrs attrs, MemTxResult *result)
155{
156 return glue(address_space_ldq_internal, SUFFIX)(ARG1, addr, attrs, result,
157 DEVICE_NATIVE_ENDIAN);
158}
159
160uint64_t glue(address_space_ldq_le, SUFFIX)(ARG1_DECL,
161 hwaddr addr, MemTxAttrs attrs, MemTxResult *result)
162{
163 return glue(address_space_ldq_internal, SUFFIX)(ARG1, addr, attrs, result,
164 DEVICE_LITTLE_ENDIAN);
165}
166
167uint64_t glue(address_space_ldq_be, SUFFIX)(ARG1_DECL,
168 hwaddr addr, MemTxAttrs attrs, MemTxResult *result)
169{
170 return glue(address_space_ldq_internal, SUFFIX)(ARG1, addr, attrs, result,
171 DEVICE_BIG_ENDIAN);
172}
173
0ce265ff
PB
174uint32_t glue(address_space_ldub, SUFFIX)(ARG1_DECL,
175 hwaddr addr, MemTxAttrs attrs, MemTxResult *result)
176{
177 uint8_t *ptr;
178 uint64_t val;
179 MemoryRegion *mr;
180 hwaddr l = 1;
181 hwaddr addr1;
182 MemTxResult r;
183 bool release_lock = false;
184
185 RCU_READ_LOCK();
bc6b1cec 186 mr = TRANSLATE(addr, &addr1, &l, false, attrs);
a99761d3 187 if (!memory_access_is_direct(mr, false)) {
0ce265ff
PB
188 release_lock |= prepare_mmio_access(mr);
189
190 /* I/O case */
191 r = memory_region_dispatch_read(mr, addr1, &val, 1, attrs);
192 } else {
193 /* RAM case */
a99761d3 194 ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
0ce265ff
PB
195 val = ldub_p(ptr);
196 r = MEMTX_OK;
197 }
198 if (result) {
199 *result = r;
200 }
201 if (release_lock) {
202 qemu_mutex_unlock_iothread();
203 }
204 RCU_READ_UNLOCK();
205 return val;
206}
207
0ce265ff
PB
208/* warning: addr must be aligned */
209static inline uint32_t glue(address_space_lduw_internal, SUFFIX)(ARG1_DECL,
210 hwaddr addr, MemTxAttrs attrs, MemTxResult *result,
211 enum device_endian endian)
212{
213 uint8_t *ptr;
214 uint64_t val;
215 MemoryRegion *mr;
216 hwaddr l = 2;
217 hwaddr addr1;
218 MemTxResult r;
219 bool release_lock = false;
220
221 RCU_READ_LOCK();
bc6b1cec 222 mr = TRANSLATE(addr, &addr1, &l, false, attrs);
a99761d3 223 if (l < 2 || !memory_access_is_direct(mr, false)) {
0ce265ff
PB
224 release_lock |= prepare_mmio_access(mr);
225
226 /* I/O case */
227 r = memory_region_dispatch_read(mr, addr1, &val, 2, attrs);
228#if defined(TARGET_WORDS_BIGENDIAN)
229 if (endian == DEVICE_LITTLE_ENDIAN) {
230 val = bswap16(val);
231 }
232#else
233 if (endian == DEVICE_BIG_ENDIAN) {
234 val = bswap16(val);
235 }
236#endif
237 } else {
238 /* RAM case */
a99761d3 239 ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
0ce265ff
PB
240 switch (endian) {
241 case DEVICE_LITTLE_ENDIAN:
242 val = lduw_le_p(ptr);
243 break;
244 case DEVICE_BIG_ENDIAN:
245 val = lduw_be_p(ptr);
246 break;
247 default:
248 val = lduw_p(ptr);
249 break;
250 }
251 r = MEMTX_OK;
252 }
253 if (result) {
254 *result = r;
255 }
256 if (release_lock) {
257 qemu_mutex_unlock_iothread();
258 }
259 RCU_READ_UNLOCK();
260 return val;
261}
262
263uint32_t glue(address_space_lduw, SUFFIX)(ARG1_DECL,
264 hwaddr addr, MemTxAttrs attrs, MemTxResult *result)
265{
266 return glue(address_space_lduw_internal, SUFFIX)(ARG1, addr, attrs, result,
267 DEVICE_NATIVE_ENDIAN);
268}
269
270uint32_t glue(address_space_lduw_le, SUFFIX)(ARG1_DECL,
271 hwaddr addr, MemTxAttrs attrs, MemTxResult *result)
272{
273 return glue(address_space_lduw_internal, SUFFIX)(ARG1, addr, attrs, result,
274 DEVICE_LITTLE_ENDIAN);
275}
276
277uint32_t glue(address_space_lduw_be, SUFFIX)(ARG1_DECL,
278 hwaddr addr, MemTxAttrs attrs, MemTxResult *result)
279{
280 return glue(address_space_lduw_internal, SUFFIX)(ARG1, addr, attrs, result,
281 DEVICE_BIG_ENDIAN);
282}
283
0ce265ff
PB
284/* warning: addr must be aligned. The ram page is not masked as dirty
285 and the code inside is not invalidated. It is useful if the dirty
286 bits are used to track modified PTEs */
287void glue(address_space_stl_notdirty, SUFFIX)(ARG1_DECL,
288 hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result)
289{
290 uint8_t *ptr;
291 MemoryRegion *mr;
292 hwaddr l = 4;
293 hwaddr addr1;
294 MemTxResult r;
295 uint8_t dirty_log_mask;
296 bool release_lock = false;
297
298 RCU_READ_LOCK();
bc6b1cec 299 mr = TRANSLATE(addr, &addr1, &l, true, attrs);
a99761d3 300 if (l < 4 || !memory_access_is_direct(mr, true)) {
0ce265ff
PB
301 release_lock |= prepare_mmio_access(mr);
302
303 r = memory_region_dispatch_write(mr, addr1, val, 4, attrs);
304 } else {
a99761d3 305 ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
0ce265ff
PB
306 stl_p(ptr, val);
307
308 dirty_log_mask = memory_region_get_dirty_log_mask(mr);
309 dirty_log_mask &= ~(1 << DIRTY_MEMORY_CODE);
310 cpu_physical_memory_set_dirty_range(memory_region_get_ram_addr(mr) + addr,
311 4, dirty_log_mask);
312 r = MEMTX_OK;
313 }
314 if (result) {
315 *result = r;
316 }
317 if (release_lock) {
318 qemu_mutex_unlock_iothread();
319 }
320 RCU_READ_UNLOCK();
321}
322
0ce265ff
PB
323/* warning: addr must be aligned */
324static inline void glue(address_space_stl_internal, SUFFIX)(ARG1_DECL,
325 hwaddr addr, uint32_t val, MemTxAttrs attrs,
326 MemTxResult *result, enum device_endian endian)
327{
328 uint8_t *ptr;
329 MemoryRegion *mr;
330 hwaddr l = 4;
331 hwaddr addr1;
332 MemTxResult r;
333 bool release_lock = false;
334
335 RCU_READ_LOCK();
bc6b1cec 336 mr = TRANSLATE(addr, &addr1, &l, true, attrs);
a99761d3 337 if (l < 4 || !memory_access_is_direct(mr, true)) {
0ce265ff
PB
338 release_lock |= prepare_mmio_access(mr);
339
340#if defined(TARGET_WORDS_BIGENDIAN)
341 if (endian == DEVICE_LITTLE_ENDIAN) {
342 val = bswap32(val);
343 }
344#else
345 if (endian == DEVICE_BIG_ENDIAN) {
346 val = bswap32(val);
347 }
348#endif
349 r = memory_region_dispatch_write(mr, addr1, val, 4, attrs);
350 } else {
351 /* RAM case */
a99761d3 352 ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
0ce265ff
PB
353 switch (endian) {
354 case DEVICE_LITTLE_ENDIAN:
355 stl_le_p(ptr, val);
356 break;
357 case DEVICE_BIG_ENDIAN:
358 stl_be_p(ptr, val);
359 break;
360 default:
361 stl_p(ptr, val);
362 break;
363 }
a99761d3 364 invalidate_and_set_dirty(mr, addr1, 4);
0ce265ff
PB
365 r = MEMTX_OK;
366 }
367 if (result) {
368 *result = r;
369 }
370 if (release_lock) {
371 qemu_mutex_unlock_iothread();
372 }
373 RCU_READ_UNLOCK();
374}
375
376void glue(address_space_stl, SUFFIX)(ARG1_DECL,
377 hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result)
378{
379 glue(address_space_stl_internal, SUFFIX)(ARG1, addr, val, attrs,
380 result, DEVICE_NATIVE_ENDIAN);
381}
382
383void glue(address_space_stl_le, SUFFIX)(ARG1_DECL,
384 hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result)
385{
386 glue(address_space_stl_internal, SUFFIX)(ARG1, addr, val, attrs,
387 result, DEVICE_LITTLE_ENDIAN);
388}
389
390void glue(address_space_stl_be, SUFFIX)(ARG1_DECL,
391 hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result)
392{
393 glue(address_space_stl_internal, SUFFIX)(ARG1, addr, val, attrs,
394 result, DEVICE_BIG_ENDIAN);
395}
396
0ce265ff
PB
397void glue(address_space_stb, SUFFIX)(ARG1_DECL,
398 hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result)
399{
400 uint8_t *ptr;
401 MemoryRegion *mr;
402 hwaddr l = 1;
403 hwaddr addr1;
404 MemTxResult r;
405 bool release_lock = false;
406
407 RCU_READ_LOCK();
bc6b1cec 408 mr = TRANSLATE(addr, &addr1, &l, true, attrs);
a99761d3 409 if (!memory_access_is_direct(mr, true)) {
0ce265ff
PB
410 release_lock |= prepare_mmio_access(mr);
411 r = memory_region_dispatch_write(mr, addr1, val, 1, attrs);
412 } else {
413 /* RAM case */
a99761d3 414 ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
0ce265ff 415 stb_p(ptr, val);
a99761d3 416 invalidate_and_set_dirty(mr, addr1, 1);
0ce265ff
PB
417 r = MEMTX_OK;
418 }
419 if (result) {
420 *result = r;
421 }
422 if (release_lock) {
423 qemu_mutex_unlock_iothread();
424 }
425 RCU_READ_UNLOCK();
426}
427
0ce265ff
PB
428/* warning: addr must be aligned */
429static inline void glue(address_space_stw_internal, SUFFIX)(ARG1_DECL,
430 hwaddr addr, uint32_t val, MemTxAttrs attrs,
431 MemTxResult *result, enum device_endian endian)
432{
433 uint8_t *ptr;
434 MemoryRegion *mr;
435 hwaddr l = 2;
436 hwaddr addr1;
437 MemTxResult r;
438 bool release_lock = false;
439
440 RCU_READ_LOCK();
bc6b1cec 441 mr = TRANSLATE(addr, &addr1, &l, true, attrs);
a99761d3 442 if (l < 2 || !memory_access_is_direct(mr, true)) {
0ce265ff
PB
443 release_lock |= prepare_mmio_access(mr);
444
445#if defined(TARGET_WORDS_BIGENDIAN)
446 if (endian == DEVICE_LITTLE_ENDIAN) {
447 val = bswap16(val);
448 }
449#else
450 if (endian == DEVICE_BIG_ENDIAN) {
451 val = bswap16(val);
452 }
453#endif
454 r = memory_region_dispatch_write(mr, addr1, val, 2, attrs);
455 } else {
456 /* RAM case */
a99761d3 457 ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
0ce265ff
PB
458 switch (endian) {
459 case DEVICE_LITTLE_ENDIAN:
460 stw_le_p(ptr, val);
461 break;
462 case DEVICE_BIG_ENDIAN:
463 stw_be_p(ptr, val);
464 break;
465 default:
466 stw_p(ptr, val);
467 break;
468 }
a99761d3 469 invalidate_and_set_dirty(mr, addr1, 2);
0ce265ff
PB
470 r = MEMTX_OK;
471 }
472 if (result) {
473 *result = r;
474 }
475 if (release_lock) {
476 qemu_mutex_unlock_iothread();
477 }
478 RCU_READ_UNLOCK();
479}
480
481void glue(address_space_stw, SUFFIX)(ARG1_DECL,
482 hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result)
483{
484 glue(address_space_stw_internal, SUFFIX)(ARG1, addr, val, attrs, result,
485 DEVICE_NATIVE_ENDIAN);
486}
487
488void glue(address_space_stw_le, SUFFIX)(ARG1_DECL,
489 hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result)
490{
491 glue(address_space_stw_internal, SUFFIX)(ARG1, addr, val, attrs, result,
492 DEVICE_LITTLE_ENDIAN);
493}
494
495void glue(address_space_stw_be, SUFFIX)(ARG1_DECL,
496 hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result)
497{
498 glue(address_space_stw_internal, SUFFIX)(ARG1, addr, val, attrs, result,
499 DEVICE_BIG_ENDIAN);
500}
501
0ce265ff
PB
502static void glue(address_space_stq_internal, SUFFIX)(ARG1_DECL,
503 hwaddr addr, uint64_t val, MemTxAttrs attrs,
504 MemTxResult *result, enum device_endian endian)
505{
506 uint8_t *ptr;
507 MemoryRegion *mr;
508 hwaddr l = 8;
509 hwaddr addr1;
510 MemTxResult r;
511 bool release_lock = false;
512
513 RCU_READ_LOCK();
bc6b1cec 514 mr = TRANSLATE(addr, &addr1, &l, true, attrs);
a99761d3 515 if (l < 8 || !memory_access_is_direct(mr, true)) {
0ce265ff
PB
516 release_lock |= prepare_mmio_access(mr);
517
518#if defined(TARGET_WORDS_BIGENDIAN)
519 if (endian == DEVICE_LITTLE_ENDIAN) {
520 val = bswap64(val);
521 }
522#else
523 if (endian == DEVICE_BIG_ENDIAN) {
524 val = bswap64(val);
525 }
526#endif
527 r = memory_region_dispatch_write(mr, addr1, val, 8, attrs);
528 } else {
529 /* RAM case */
a99761d3 530 ptr = qemu_map_ram_ptr(mr->ram_block, addr1);
0ce265ff
PB
531 switch (endian) {
532 case DEVICE_LITTLE_ENDIAN:
533 stq_le_p(ptr, val);
534 break;
535 case DEVICE_BIG_ENDIAN:
536 stq_be_p(ptr, val);
537 break;
538 default:
539 stq_p(ptr, val);
540 break;
541 }
a99761d3 542 invalidate_and_set_dirty(mr, addr1, 8);
0ce265ff
PB
543 r = MEMTX_OK;
544 }
545 if (result) {
546 *result = r;
547 }
548 if (release_lock) {
549 qemu_mutex_unlock_iothread();
550 }
551 RCU_READ_UNLOCK();
552}
553
554void glue(address_space_stq, SUFFIX)(ARG1_DECL,
555 hwaddr addr, uint64_t val, MemTxAttrs attrs, MemTxResult *result)
556{
557 glue(address_space_stq_internal, SUFFIX)(ARG1, addr, val, attrs, result,
558 DEVICE_NATIVE_ENDIAN);
559}
560
561void glue(address_space_stq_le, SUFFIX)(ARG1_DECL,
562 hwaddr addr, uint64_t val, MemTxAttrs attrs, MemTxResult *result)
563{
564 glue(address_space_stq_internal, SUFFIX)(ARG1, addr, val, attrs, result,
565 DEVICE_LITTLE_ENDIAN);
566}
567
568void glue(address_space_stq_be, SUFFIX)(ARG1_DECL,
569 hwaddr addr, uint64_t val, MemTxAttrs attrs, MemTxResult *result)
570{
571 glue(address_space_stq_internal, SUFFIX)(ARG1, addr, val, attrs, result,
572 DEVICE_BIG_ENDIAN);
573}
574
0ce265ff
PB
575#undef ARG1_DECL
576#undef ARG1
577#undef SUFFIX
578#undef TRANSLATE
0ce265ff
PB
579#undef RCU_READ_LOCK
580#undef RCU_READ_UNLOCK