mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-11-05 20:35:44 +00:00
exec: add endian specific phys ld/st functions
Device code some times needs to access physical memory and does that through the ld./st._phys functions. However, these are the exact same functions that the CPU uses to access memory, which means they will be endianness swapped depending on the target CPU. However, devices don't know about the CPU's endianness, but instead access memory directly using their own interface to the memory bus, so they need some way to read data with their native endianness. This patch adds _le and _be functions to ld./st._phys. Signed-off-by: Alexander Graf <agraf@suse.de> Signed-off-by: Blue Swirl <blauwirbel@gmail.com>
This commit is contained in:
parent
c925400ba8
commit
1e78bcc19c
2 changed files with 203 additions and 10 deletions
12
cpu-common.h
12
cpu-common.h
|
@ -135,14 +135,26 @@ void qemu_flush_coalesced_mmio_buffer(void);
|
|||
|
||||
uint32_t ldub_phys(target_phys_addr_t addr);
|
||||
uint32_t lduw_phys(target_phys_addr_t addr);
|
||||
uint32_t lduw_le_phys(target_phys_addr_t addr);
|
||||
uint32_t lduw_be_phys(target_phys_addr_t addr);
|
||||
uint32_t ldl_phys(target_phys_addr_t addr);
|
||||
uint32_t ldl_le_phys(target_phys_addr_t addr);
|
||||
uint32_t ldl_be_phys(target_phys_addr_t addr);
|
||||
uint64_t ldq_phys(target_phys_addr_t addr);
|
||||
uint64_t ldq_le_phys(target_phys_addr_t addr);
|
||||
uint64_t ldq_be_phys(target_phys_addr_t addr);
|
||||
void stl_phys_notdirty(target_phys_addr_t addr, uint32_t val);
|
||||
void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val);
|
||||
void stb_phys(target_phys_addr_t addr, uint32_t val);
|
||||
void stw_phys(target_phys_addr_t addr, uint32_t val);
|
||||
void stw_le_phys(target_phys_addr_t addr, uint32_t val);
|
||||
void stw_be_phys(target_phys_addr_t addr, uint32_t val);
|
||||
void stl_phys(target_phys_addr_t addr, uint32_t val);
|
||||
void stl_le_phys(target_phys_addr_t addr, uint32_t val);
|
||||
void stl_be_phys(target_phys_addr_t addr, uint32_t val);
|
||||
void stq_phys(target_phys_addr_t addr, uint64_t val);
|
||||
void stq_le_phys(target_phys_addr_t addr, uint64_t val);
|
||||
void stq_be_phys(target_phys_addr_t addr, uint64_t val);
|
||||
|
||||
void cpu_physical_memory_write_rom(target_phys_addr_t addr,
|
||||
const uint8_t *buf, int len);
|
||||
|
|
201
exec.c
201
exec.c
|
@ -4127,7 +4127,8 @@ void cpu_physical_memory_unmap(void *buffer, target_phys_addr_t len,
|
|||
}
|
||||
|
||||
/* warning: addr must be aligned */
|
||||
uint32_t ldl_phys(target_phys_addr_t addr)
|
||||
static inline uint32_t ldl_phys_internal(target_phys_addr_t addr,
|
||||
enum device_endian endian)
|
||||
{
|
||||
int io_index;
|
||||
uint8_t *ptr;
|
||||
|
@ -4149,17 +4150,52 @@ uint32_t ldl_phys(target_phys_addr_t addr)
|
|||
if (p)
|
||||
addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
|
||||
val = io_mem_read[io_index][2](io_mem_opaque[io_index], addr);
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
if (endian == DEVICE_LITTLE_ENDIAN) {
|
||||
val = bswap32(val);
|
||||
}
|
||||
#else
|
||||
if (endian == DEVICE_BIG_ENDIAN) {
|
||||
val = bswap32(val);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
/* RAM case */
|
||||
ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
|
||||
(addr & ~TARGET_PAGE_MASK);
|
||||
val = ldl_p(ptr);
|
||||
switch (endian) {
|
||||
case DEVICE_LITTLE_ENDIAN:
|
||||
val = ldl_le_p(ptr);
|
||||
break;
|
||||
case DEVICE_BIG_ENDIAN:
|
||||
val = ldl_be_p(ptr);
|
||||
break;
|
||||
default:
|
||||
val = ldl_p(ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
uint32_t ldl_phys(target_phys_addr_t addr)
|
||||
{
|
||||
return ldl_phys_internal(addr, DEVICE_NATIVE_ENDIAN);
|
||||
}
|
||||
|
||||
uint32_t ldl_le_phys(target_phys_addr_t addr)
|
||||
{
|
||||
return ldl_phys_internal(addr, DEVICE_LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
uint32_t ldl_be_phys(target_phys_addr_t addr)
|
||||
{
|
||||
return ldl_phys_internal(addr, DEVICE_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
/* warning: addr must be aligned */
|
||||
uint64_t ldq_phys(target_phys_addr_t addr)
|
||||
static inline uint64_t ldq_phys_internal(target_phys_addr_t addr,
|
||||
enum device_endian endian)
|
||||
{
|
||||
int io_index;
|
||||
uint8_t *ptr;
|
||||
|
@ -4180,6 +4216,9 @@ uint64_t ldq_phys(target_phys_addr_t addr)
|
|||
io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
|
||||
if (p)
|
||||
addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
|
||||
|
||||
/* XXX This is broken when device endian != cpu endian.
|
||||
Fix and add "endian" variable check */
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
val = (uint64_t)io_mem_read[io_index][2](io_mem_opaque[io_index], addr) << 32;
|
||||
val |= io_mem_read[io_index][2](io_mem_opaque[io_index], addr + 4);
|
||||
|
@ -4191,11 +4230,36 @@ uint64_t ldq_phys(target_phys_addr_t addr)
|
|||
/* RAM case */
|
||||
ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
|
||||
(addr & ~TARGET_PAGE_MASK);
|
||||
val = ldq_p(ptr);
|
||||
switch (endian) {
|
||||
case DEVICE_LITTLE_ENDIAN:
|
||||
val = ldq_le_p(ptr);
|
||||
break;
|
||||
case DEVICE_BIG_ENDIAN:
|
||||
val = ldq_be_p(ptr);
|
||||
break;
|
||||
default:
|
||||
val = ldq_p(ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
uint64_t ldq_phys(target_phys_addr_t addr)
|
||||
{
|
||||
return ldq_phys_internal(addr, DEVICE_NATIVE_ENDIAN);
|
||||
}
|
||||
|
||||
uint64_t ldq_le_phys(target_phys_addr_t addr)
|
||||
{
|
||||
return ldq_phys_internal(addr, DEVICE_LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
uint64_t ldq_be_phys(target_phys_addr_t addr)
|
||||
{
|
||||
return ldq_phys_internal(addr, DEVICE_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
/* XXX: optimize */
|
||||
uint32_t ldub_phys(target_phys_addr_t addr)
|
||||
{
|
||||
|
@ -4205,7 +4269,8 @@ uint32_t ldub_phys(target_phys_addr_t addr)
|
|||
}
|
||||
|
||||
/* warning: addr must be aligned */
|
||||
uint32_t lduw_phys(target_phys_addr_t addr)
|
||||
static inline uint32_t lduw_phys_internal(target_phys_addr_t addr,
|
||||
enum device_endian endian)
|
||||
{
|
||||
int io_index;
|
||||
uint8_t *ptr;
|
||||
|
@ -4227,15 +4292,49 @@ uint32_t lduw_phys(target_phys_addr_t addr)
|
|||
if (p)
|
||||
addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
|
||||
val = io_mem_read[io_index][1](io_mem_opaque[io_index], addr);
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
if (endian == DEVICE_LITTLE_ENDIAN) {
|
||||
val = bswap16(val);
|
||||
}
|
||||
#else
|
||||
if (endian == DEVICE_BIG_ENDIAN) {
|
||||
val = bswap16(val);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
/* RAM case */
|
||||
ptr = qemu_get_ram_ptr(pd & TARGET_PAGE_MASK) +
|
||||
(addr & ~TARGET_PAGE_MASK);
|
||||
val = lduw_p(ptr);
|
||||
switch (endian) {
|
||||
case DEVICE_LITTLE_ENDIAN:
|
||||
val = lduw_le_p(ptr);
|
||||
break;
|
||||
case DEVICE_BIG_ENDIAN:
|
||||
val = lduw_be_p(ptr);
|
||||
break;
|
||||
default:
|
||||
val = lduw_p(ptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
uint32_t lduw_phys(target_phys_addr_t addr)
|
||||
{
|
||||
return lduw_phys_internal(addr, DEVICE_NATIVE_ENDIAN);
|
||||
}
|
||||
|
||||
uint32_t lduw_le_phys(target_phys_addr_t addr)
|
||||
{
|
||||
return lduw_phys_internal(addr, DEVICE_LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
uint32_t lduw_be_phys(target_phys_addr_t addr)
|
||||
{
|
||||
return lduw_phys_internal(addr, DEVICE_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
/* warning: addr must be aligned. The ram page is not masked as dirty
|
||||
and the code inside is not invalidated. It is useful if the dirty
|
||||
bits are used to track modified PTEs */
|
||||
|
@ -4308,7 +4407,8 @@ void stq_phys_notdirty(target_phys_addr_t addr, uint64_t val)
|
|||
}
|
||||
|
||||
/* warning: addr must be aligned */
|
||||
void stl_phys(target_phys_addr_t addr, uint32_t val)
|
||||
static inline void stl_phys_internal(target_phys_addr_t addr, uint32_t val,
|
||||
enum device_endian endian)
|
||||
{
|
||||
int io_index;
|
||||
uint8_t *ptr;
|
||||
|
@ -4326,13 +4426,32 @@ void stl_phys(target_phys_addr_t addr, uint32_t val)
|
|||
io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
|
||||
if (p)
|
||||
addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
if (endian == DEVICE_LITTLE_ENDIAN) {
|
||||
val = bswap32(val);
|
||||
}
|
||||
#else
|
||||
if (endian == DEVICE_BIG_ENDIAN) {
|
||||
val = bswap32(val);
|
||||
}
|
||||
#endif
|
||||
io_mem_write[io_index][2](io_mem_opaque[io_index], addr, val);
|
||||
} else {
|
||||
unsigned long addr1;
|
||||
addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
|
||||
/* RAM case */
|
||||
ptr = qemu_get_ram_ptr(addr1);
|
||||
stl_p(ptr, val);
|
||||
switch (endian) {
|
||||
case DEVICE_LITTLE_ENDIAN:
|
||||
stl_le_p(ptr, val);
|
||||
break;
|
||||
case DEVICE_BIG_ENDIAN:
|
||||
stl_be_p(ptr, val);
|
||||
break;
|
||||
default:
|
||||
stl_p(ptr, val);
|
||||
break;
|
||||
}
|
||||
if (!cpu_physical_memory_is_dirty(addr1)) {
|
||||
/* invalidate code */
|
||||
tb_invalidate_phys_page_range(addr1, addr1 + 4, 0);
|
||||
|
@ -4343,6 +4462,21 @@ void stl_phys(target_phys_addr_t addr, uint32_t val)
|
|||
}
|
||||
}
|
||||
|
||||
void stl_phys(target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
stl_phys_internal(addr, val, DEVICE_NATIVE_ENDIAN);
|
||||
}
|
||||
|
||||
void stl_le_phys(target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
stl_phys_internal(addr, val, DEVICE_LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
void stl_be_phys(target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
stl_phys_internal(addr, val, DEVICE_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
/* XXX: optimize */
|
||||
void stb_phys(target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
|
@ -4351,7 +4485,8 @@ void stb_phys(target_phys_addr_t addr, uint32_t val)
|
|||
}
|
||||
|
||||
/* warning: addr must be aligned */
|
||||
void stw_phys(target_phys_addr_t addr, uint32_t val)
|
||||
static inline void stw_phys_internal(target_phys_addr_t addr, uint32_t val,
|
||||
enum device_endian endian)
|
||||
{
|
||||
int io_index;
|
||||
uint8_t *ptr;
|
||||
|
@ -4369,13 +4504,32 @@ void stw_phys(target_phys_addr_t addr, uint32_t val)
|
|||
io_index = (pd >> IO_MEM_SHIFT) & (IO_MEM_NB_ENTRIES - 1);
|
||||
if (p)
|
||||
addr = (addr & ~TARGET_PAGE_MASK) + p->region_offset;
|
||||
#if defined(TARGET_WORDS_BIGENDIAN)
|
||||
if (endian == DEVICE_LITTLE_ENDIAN) {
|
||||
val = bswap16(val);
|
||||
}
|
||||
#else
|
||||
if (endian == DEVICE_BIG_ENDIAN) {
|
||||
val = bswap16(val);
|
||||
}
|
||||
#endif
|
||||
io_mem_write[io_index][1](io_mem_opaque[io_index], addr, val);
|
||||
} else {
|
||||
unsigned long addr1;
|
||||
addr1 = (pd & TARGET_PAGE_MASK) + (addr & ~TARGET_PAGE_MASK);
|
||||
/* RAM case */
|
||||
ptr = qemu_get_ram_ptr(addr1);
|
||||
stw_p(ptr, val);
|
||||
switch (endian) {
|
||||
case DEVICE_LITTLE_ENDIAN:
|
||||
stw_le_p(ptr, val);
|
||||
break;
|
||||
case DEVICE_BIG_ENDIAN:
|
||||
stw_be_p(ptr, val);
|
||||
break;
|
||||
default:
|
||||
stw_p(ptr, val);
|
||||
break;
|
||||
}
|
||||
if (!cpu_physical_memory_is_dirty(addr1)) {
|
||||
/* invalidate code */
|
||||
tb_invalidate_phys_page_range(addr1, addr1 + 2, 0);
|
||||
|
@ -4386,6 +4540,21 @@ void stw_phys(target_phys_addr_t addr, uint32_t val)
|
|||
}
|
||||
}
|
||||
|
||||
void stw_phys(target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
stw_phys_internal(addr, val, DEVICE_NATIVE_ENDIAN);
|
||||
}
|
||||
|
||||
void stw_le_phys(target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
stw_phys_internal(addr, val, DEVICE_LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
void stw_be_phys(target_phys_addr_t addr, uint32_t val)
|
||||
{
|
||||
stw_phys_internal(addr, val, DEVICE_BIG_ENDIAN);
|
||||
}
|
||||
|
||||
/* XXX: optimize */
|
||||
void stq_phys(target_phys_addr_t addr, uint64_t val)
|
||||
{
|
||||
|
@ -4393,6 +4562,18 @@ void stq_phys(target_phys_addr_t addr, uint64_t val)
|
|||
cpu_physical_memory_write(addr, &val, 8);
|
||||
}
|
||||
|
||||
void stq_le_phys(target_phys_addr_t addr, uint64_t val)
|
||||
{
|
||||
val = cpu_to_le64(val);
|
||||
cpu_physical_memory_write(addr, &val, 8);
|
||||
}
|
||||
|
||||
void stq_be_phys(target_phys_addr_t addr, uint64_t val)
|
||||
{
|
||||
val = cpu_to_be64(val);
|
||||
cpu_physical_memory_write(addr, &val, 8);
|
||||
}
|
||||
|
||||
/* virtual memory access for debug (includes writing to ROM) */
|
||||
int cpu_memory_rw_debug(CPUState *env, target_ulong addr,
|
||||
uint8_t *buf, int len, int is_write)
|
||||
|
|
Loading…
Reference in a new issue