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.1 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(); 36 mr = TRANSLATE(addr, &addr1, &l, false, attrs); 37 if (l < 4 || !memory_access_is_direct(mr, false)) { 38 release_lock |= prepare_mmio_access(mr); 39 40 /* I/O case */ 41 r = memory_region_dispatch_read(mr, addr1, &val, 42 MO_32 | devend_memop(endian), attrs); 43 } else { 44 /* RAM case */ 45 fuzz_dma_read_cb(addr, 4, mr); 46 ptr = qemu_map_ram_ptr(mr->ram_block, addr1); 47 switch (endian) { 48 case DEVICE_LITTLE_ENDIAN: 49 val = ldl_le_p(ptr); 50 break; 51 case DEVICE_BIG_ENDIAN: 52 val = ldl_be_p(ptr); 53 break; 54 default: 55 val = ldl_p(ptr); 56 break; 57 } 58 r = MEMTX_OK; 59 } 60 if (result) { 61 *result = r; 62 } 63 if (release_lock) { 64 bql_unlock(); 65 } 66 RCU_READ_UNLOCK(); 67 return val; 68} 69 70uint32_t glue(address_space_ldl, SUFFIX)(ARG1_DECL, 71 hwaddr addr, MemTxAttrs attrs, MemTxResult *result) 72{ 73 return glue(address_space_ldl_internal, SUFFIX)(ARG1, addr, attrs, result, 74 DEVICE_NATIVE_ENDIAN); 75} 76 77uint32_t glue(address_space_ldl_le, 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_LITTLE_ENDIAN); 82} 83 84uint32_t glue(address_space_ldl_be, 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_BIG_ENDIAN); 89} 90 91/* warning: addr must be aligned */ 92static inline uint64_t glue(address_space_ldq_internal, SUFFIX)(ARG1_DECL, 93 hwaddr addr, MemTxAttrs attrs, MemTxResult *result, 94 enum device_endian endian) 95{ 96 uint8_t *ptr; 97 uint64_t val; 98 MemoryRegion *mr; 99 hwaddr l = 8; 100 hwaddr addr1; 101 MemTxResult r; 102 bool release_lock = false; 103 104 RCU_READ_LOCK(); 105 mr = TRANSLATE(addr, &addr1, &l, false, attrs); 106 if (l < 8 || !memory_access_is_direct(mr, false)) { 107 release_lock |= prepare_mmio_access(mr); 108 109 /* I/O case */ 110 r = memory_region_dispatch_read(mr, addr1, &val, 111 MO_64 | devend_memop(endian), attrs); 112 } else { 113 /* RAM case */ 114 fuzz_dma_read_cb(addr, 8, mr); 115 ptr = qemu_map_ram_ptr(mr->ram_block, addr1); 116 switch (endian) { 117 case DEVICE_LITTLE_ENDIAN: 118 val = ldq_le_p(ptr); 119 break; 120 case DEVICE_BIG_ENDIAN: 121 val = ldq_be_p(ptr); 122 break; 123 default: 124 val = ldq_p(ptr); 125 break; 126 } 127 r = MEMTX_OK; 128 } 129 if (result) { 130 *result = r; 131 } 132 if (release_lock) { 133 bql_unlock(); 134 } 135 RCU_READ_UNLOCK(); 136 return val; 137} 138 139uint64_t glue(address_space_ldq, SUFFIX)(ARG1_DECL, 140 hwaddr addr, MemTxAttrs attrs, MemTxResult *result) 141{ 142 return glue(address_space_ldq_internal, SUFFIX)(ARG1, addr, attrs, result, 143 DEVICE_NATIVE_ENDIAN); 144} 145 146uint64_t glue(address_space_ldq_le, SUFFIX)(ARG1_DECL, 147 hwaddr addr, MemTxAttrs attrs, MemTxResult *result) 148{ 149 return glue(address_space_ldq_internal, SUFFIX)(ARG1, addr, attrs, result, 150 DEVICE_LITTLE_ENDIAN); 151} 152 153uint64_t glue(address_space_ldq_be, 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_BIG_ENDIAN); 158} 159 160uint8_t glue(address_space_ldub, SUFFIX)(ARG1_DECL, 161 hwaddr addr, MemTxAttrs attrs, MemTxResult *result) 162{ 163 uint8_t *ptr; 164 uint64_t val; 165 MemoryRegion *mr; 166 hwaddr l = 1; 167 hwaddr addr1; 168 MemTxResult r; 169 bool release_lock = false; 170 171 RCU_READ_LOCK(); 172 mr = TRANSLATE(addr, &addr1, &l, false, attrs); 173 if (!memory_access_is_direct(mr, false)) { 174 release_lock |= prepare_mmio_access(mr); 175 176 /* I/O case */ 177 r = memory_region_dispatch_read(mr, addr1, &val, MO_8, attrs); 178 } else { 179 /* RAM case */ 180 fuzz_dma_read_cb(addr, 1, mr); 181 ptr = qemu_map_ram_ptr(mr->ram_block, addr1); 182 val = ldub_p(ptr); 183 r = MEMTX_OK; 184 } 185 if (result) { 186 *result = r; 187 } 188 if (release_lock) { 189 bql_unlock(); 190 } 191 RCU_READ_UNLOCK(); 192 return val; 193} 194 195/* warning: addr must be aligned */ 196static inline uint16_t glue(address_space_lduw_internal, SUFFIX)(ARG1_DECL, 197 hwaddr addr, MemTxAttrs attrs, MemTxResult *result, 198 enum device_endian endian) 199{ 200 uint8_t *ptr; 201 uint64_t val; 202 MemoryRegion *mr; 203 hwaddr l = 2; 204 hwaddr addr1; 205 MemTxResult r; 206 bool release_lock = false; 207 208 RCU_READ_LOCK(); 209 mr = TRANSLATE(addr, &addr1, &l, false, attrs); 210 if (l < 2 || !memory_access_is_direct(mr, false)) { 211 release_lock |= prepare_mmio_access(mr); 212 213 /* I/O case */ 214 r = memory_region_dispatch_read(mr, addr1, &val, 215 MO_16 | devend_memop(endian), attrs); 216 } else { 217 /* RAM case */ 218 fuzz_dma_read_cb(addr, 2, mr); 219 ptr = qemu_map_ram_ptr(mr->ram_block, addr1); 220 switch (endian) { 221 case DEVICE_LITTLE_ENDIAN: 222 val = lduw_le_p(ptr); 223 break; 224 case DEVICE_BIG_ENDIAN: 225 val = lduw_be_p(ptr); 226 break; 227 default: 228 val = lduw_p(ptr); 229 break; 230 } 231 r = MEMTX_OK; 232 } 233 if (result) { 234 *result = r; 235 } 236 if (release_lock) { 237 bql_unlock(); 238 } 239 RCU_READ_UNLOCK(); 240 return val; 241} 242 243uint16_t glue(address_space_lduw, SUFFIX)(ARG1_DECL, 244 hwaddr addr, MemTxAttrs attrs, MemTxResult *result) 245{ 246 return glue(address_space_lduw_internal, SUFFIX)(ARG1, addr, attrs, result, 247 DEVICE_NATIVE_ENDIAN); 248} 249 250uint16_t glue(address_space_lduw_le, SUFFIX)(ARG1_DECL, 251 hwaddr addr, MemTxAttrs attrs, MemTxResult *result) 252{ 253 return glue(address_space_lduw_internal, SUFFIX)(ARG1, addr, attrs, result, 254 DEVICE_LITTLE_ENDIAN); 255} 256 257uint16_t glue(address_space_lduw_be, SUFFIX)(ARG1_DECL, 258 hwaddr addr, MemTxAttrs attrs, MemTxResult *result) 259{ 260 return glue(address_space_lduw_internal, SUFFIX)(ARG1, addr, attrs, result, 261 DEVICE_BIG_ENDIAN); 262} 263 264/* warning: addr must be aligned. The ram page is not masked as dirty 265 and the code inside is not invalidated. It is useful if the dirty 266 bits are used to track modified PTEs */ 267void glue(address_space_stl_notdirty, SUFFIX)(ARG1_DECL, 268 hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result) 269{ 270 uint8_t *ptr; 271 MemoryRegion *mr; 272 hwaddr l = 4; 273 hwaddr addr1; 274 MemTxResult r; 275 uint8_t dirty_log_mask; 276 bool release_lock = false; 277 278 RCU_READ_LOCK(); 279 mr = TRANSLATE(addr, &addr1, &l, true, attrs); 280 if (l < 4 || !memory_access_is_direct(mr, true)) { 281 release_lock |= prepare_mmio_access(mr); 282 283 r = memory_region_dispatch_write(mr, addr1, val, MO_32, attrs); 284 } else { 285 ptr = qemu_map_ram_ptr(mr->ram_block, addr1); 286 stl_p(ptr, val); 287 288 dirty_log_mask = memory_region_get_dirty_log_mask(mr); 289 dirty_log_mask &= ~(1 << DIRTY_MEMORY_CODE); 290 cpu_physical_memory_set_dirty_range(memory_region_get_ram_addr(mr) + addr, 291 4, dirty_log_mask); 292 r = MEMTX_OK; 293 } 294 if (result) { 295 *result = r; 296 } 297 if (release_lock) { 298 bql_unlock(); 299 } 300 RCU_READ_UNLOCK(); 301} 302 303/* warning: addr must be aligned */ 304static inline void glue(address_space_stl_internal, SUFFIX)(ARG1_DECL, 305 hwaddr addr, uint32_t val, MemTxAttrs attrs, 306 MemTxResult *result, enum device_endian endian) 307{ 308 uint8_t *ptr; 309 MemoryRegion *mr; 310 hwaddr l = 4; 311 hwaddr addr1; 312 MemTxResult r; 313 bool release_lock = false; 314 315 RCU_READ_LOCK(); 316 mr = TRANSLATE(addr, &addr1, &l, true, attrs); 317 if (l < 4 || !memory_access_is_direct(mr, true)) { 318 release_lock |= prepare_mmio_access(mr); 319 r = memory_region_dispatch_write(mr, addr1, val, 320 MO_32 | devend_memop(endian), attrs); 321 } else { 322 /* RAM case */ 323 ptr = qemu_map_ram_ptr(mr->ram_block, addr1); 324 switch (endian) { 325 case DEVICE_LITTLE_ENDIAN: 326 stl_le_p(ptr, val); 327 break; 328 case DEVICE_BIG_ENDIAN: 329 stl_be_p(ptr, val); 330 break; 331 default: 332 stl_p(ptr, val); 333 break; 334 } 335 invalidate_and_set_dirty(mr, addr1, 4); 336 r = MEMTX_OK; 337 } 338 if (result) { 339 *result = r; 340 } 341 if (release_lock) { 342 bql_unlock(); 343 } 344 RCU_READ_UNLOCK(); 345} 346 347void glue(address_space_stl, SUFFIX)(ARG1_DECL, 348 hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result) 349{ 350 glue(address_space_stl_internal, SUFFIX)(ARG1, addr, val, attrs, 351 result, DEVICE_NATIVE_ENDIAN); 352} 353 354void glue(address_space_stl_le, SUFFIX)(ARG1_DECL, 355 hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result) 356{ 357 glue(address_space_stl_internal, SUFFIX)(ARG1, addr, val, attrs, 358 result, DEVICE_LITTLE_ENDIAN); 359} 360 361void glue(address_space_stl_be, SUFFIX)(ARG1_DECL, 362 hwaddr addr, uint32_t val, MemTxAttrs attrs, MemTxResult *result) 363{ 364 glue(address_space_stl_internal, SUFFIX)(ARG1, addr, val, attrs, 365 result, DEVICE_BIG_ENDIAN); 366} 367 368void glue(address_space_stb, SUFFIX)(ARG1_DECL, 369 hwaddr addr, uint8_t val, MemTxAttrs attrs, MemTxResult *result) 370{ 371 uint8_t *ptr; 372 MemoryRegion *mr; 373 hwaddr l = 1; 374 hwaddr addr1; 375 MemTxResult r; 376 bool release_lock = false; 377 378 RCU_READ_LOCK(); 379 mr = TRANSLATE(addr, &addr1, &l, true, attrs); 380 if (!memory_access_is_direct(mr, true)) { 381 release_lock |= prepare_mmio_access(mr); 382 r = memory_region_dispatch_write(mr, addr1, val, MO_8, attrs); 383 } else { 384 /* RAM case */ 385 ptr = qemu_map_ram_ptr(mr->ram_block, addr1); 386 stb_p(ptr, val); 387 invalidate_and_set_dirty(mr, addr1, 1); 388 r = MEMTX_OK; 389 } 390 if (result) { 391 *result = r; 392 } 393 if (release_lock) { 394 bql_unlock(); 395 } 396 RCU_READ_UNLOCK(); 397} 398 399/* warning: addr must be aligned */ 400static inline void glue(address_space_stw_internal, SUFFIX)(ARG1_DECL, 401 hwaddr addr, uint16_t val, MemTxAttrs attrs, 402 MemTxResult *result, enum device_endian endian) 403{ 404 uint8_t *ptr; 405 MemoryRegion *mr; 406 hwaddr l = 2; 407 hwaddr addr1; 408 MemTxResult r; 409 bool release_lock = false; 410 411 RCU_READ_LOCK(); 412 mr = TRANSLATE(addr, &addr1, &l, true, attrs); 413 if (l < 2 || !memory_access_is_direct(mr, true)) { 414 release_lock |= prepare_mmio_access(mr); 415 r = memory_region_dispatch_write(mr, addr1, val, 416 MO_16 | devend_memop(endian), attrs); 417 } else { 418 /* RAM case */ 419 ptr = qemu_map_ram_ptr(mr->ram_block, addr1); 420 switch (endian) { 421 case DEVICE_LITTLE_ENDIAN: 422 stw_le_p(ptr, val); 423 break; 424 case DEVICE_BIG_ENDIAN: 425 stw_be_p(ptr, val); 426 break; 427 default: 428 stw_p(ptr, val); 429 break; 430 } 431 invalidate_and_set_dirty(mr, addr1, 2); 432 r = MEMTX_OK; 433 } 434 if (result) { 435 *result = r; 436 } 437 if (release_lock) { 438 bql_unlock(); 439 } 440 RCU_READ_UNLOCK(); 441} 442 443void glue(address_space_stw, SUFFIX)(ARG1_DECL, 444 hwaddr addr, uint16_t val, MemTxAttrs attrs, MemTxResult *result) 445{ 446 glue(address_space_stw_internal, SUFFIX)(ARG1, addr, val, attrs, result, 447 DEVICE_NATIVE_ENDIAN); 448} 449 450void glue(address_space_stw_le, SUFFIX)(ARG1_DECL, 451 hwaddr addr, uint16_t val, MemTxAttrs attrs, MemTxResult *result) 452{ 453 glue(address_space_stw_internal, SUFFIX)(ARG1, addr, val, attrs, result, 454 DEVICE_LITTLE_ENDIAN); 455} 456 457void glue(address_space_stw_be, SUFFIX)(ARG1_DECL, 458 hwaddr addr, uint16_t val, MemTxAttrs attrs, MemTxResult *result) 459{ 460 glue(address_space_stw_internal, SUFFIX)(ARG1, addr, val, attrs, result, 461 DEVICE_BIG_ENDIAN); 462} 463 464static void glue(address_space_stq_internal, SUFFIX)(ARG1_DECL, 465 hwaddr addr, uint64_t val, MemTxAttrs attrs, 466 MemTxResult *result, enum device_endian endian) 467{ 468 uint8_t *ptr; 469 MemoryRegion *mr; 470 hwaddr l = 8; 471 hwaddr addr1; 472 MemTxResult r; 473 bool release_lock = false; 474 475 RCU_READ_LOCK(); 476 mr = TRANSLATE(addr, &addr1, &l, true, attrs); 477 if (l < 8 || !memory_access_is_direct(mr, true)) { 478 release_lock |= prepare_mmio_access(mr); 479 r = memory_region_dispatch_write(mr, addr1, val, 480 MO_64 | devend_memop(endian), attrs); 481 } else { 482 /* RAM case */ 483 ptr = qemu_map_ram_ptr(mr->ram_block, addr1); 484 switch (endian) { 485 case DEVICE_LITTLE_ENDIAN: 486 stq_le_p(ptr, val); 487 break; 488 case DEVICE_BIG_ENDIAN: 489 stq_be_p(ptr, val); 490 break; 491 default: 492 stq_p(ptr, val); 493 break; 494 } 495 invalidate_and_set_dirty(mr, addr1, 8); 496 r = MEMTX_OK; 497 } 498 if (result) { 499 *result = r; 500 } 501 if (release_lock) { 502 bql_unlock(); 503 } 504 RCU_READ_UNLOCK(); 505} 506 507void glue(address_space_stq, SUFFIX)(ARG1_DECL, 508 hwaddr addr, uint64_t val, MemTxAttrs attrs, MemTxResult *result) 509{ 510 glue(address_space_stq_internal, SUFFIX)(ARG1, addr, val, attrs, result, 511 DEVICE_NATIVE_ENDIAN); 512} 513 514void glue(address_space_stq_le, SUFFIX)(ARG1_DECL, 515 hwaddr addr, uint64_t val, MemTxAttrs attrs, MemTxResult *result) 516{ 517 glue(address_space_stq_internal, SUFFIX)(ARG1, addr, val, attrs, result, 518 DEVICE_LITTLE_ENDIAN); 519} 520 521void glue(address_space_stq_be, SUFFIX)(ARG1_DECL, 522 hwaddr addr, uint64_t val, MemTxAttrs attrs, MemTxResult *result) 523{ 524 glue(address_space_stq_internal, SUFFIX)(ARG1, addr, val, attrs, result, 525 DEVICE_BIG_ENDIAN); 526} 527 528#undef ARG1_DECL 529#undef ARG1 530#undef SUFFIX 531#undef TRANSLATE 532#undef RCU_READ_LOCK 533#undef RCU_READ_UNLOCK 534