memory: move endianness compensation to memory core

Instead of doing device endianness compensation in cpu_register_io_memory(),
do it in the memory core.

Signed-off-by: Avi Kivity <avi@redhat.com>
Reviewed-by: Richard Henderson <rth@twiddle.net>
This commit is contained in:
Avi Kivity 2011-11-20 16:22:55 +02:00
parent 7638e0d220
commit be675c9720
3 changed files with 41 additions and 140 deletions

View File

@ -33,7 +33,7 @@ void qemu_ram_free_from_ptr(ram_addr_t addr);
int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read, int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
CPUWriteMemoryFunc * const *mem_write, CPUWriteMemoryFunc * const *mem_write,
void *opaque, enum device_endian endian); void *opaque);
void cpu_unregister_io_memory(int table_address); void cpu_unregister_io_memory(int table_address);
void cpu_register_physical_memory_log(target_phys_addr_t start_addr, void cpu_register_physical_memory_log(target_phys_addr_t start_addr,

142
exec.c
View File

@ -3507,8 +3507,7 @@ static subpage_t *subpage_init (target_phys_addr_t base, ram_addr_t *phys,
mmio = g_malloc0(sizeof(subpage_t)); mmio = g_malloc0(sizeof(subpage_t));
mmio->base = base; mmio->base = base;
subpage_memory = cpu_register_io_memory(subpage_read, subpage_write, mmio, subpage_memory = cpu_register_io_memory(subpage_read, subpage_write, mmio);
DEVICE_NATIVE_ENDIAN);
#if defined(DEBUG_SUBPAGE) #if defined(DEBUG_SUBPAGE)
printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__, printf("%s: %p base " TARGET_FMT_plx " len %08x %d\n", __func__,
mmio, base, TARGET_PAGE_SIZE, subpage_memory); mmio, base, TARGET_PAGE_SIZE, subpage_memory);
@ -3532,106 +3531,6 @@ static int get_free_io_mem_idx(void)
return -1; return -1;
} }
/*
* Usually, devices operate in little endian mode. There are devices out
* there that operate in big endian too. Each device gets byte swapped
* mmio if plugged onto a CPU that does the other endianness.
*
* CPU Device swap?
*
* little little no
* little big yes
* big little yes
* big big no
*/
typedef struct SwapEndianContainer {
CPUReadMemoryFunc *read[3];
CPUWriteMemoryFunc *write[3];
void *opaque;
} SwapEndianContainer;
static uint32_t swapendian_mem_readb (void *opaque, target_phys_addr_t addr)
{
uint32_t val;
SwapEndianContainer *c = opaque;
val = c->read[0](c->opaque, addr);
return val;
}
static uint32_t swapendian_mem_readw(void *opaque, target_phys_addr_t addr)
{
uint32_t val;
SwapEndianContainer *c = opaque;
val = bswap16(c->read[1](c->opaque, addr));
return val;
}
static uint32_t swapendian_mem_readl(void *opaque, target_phys_addr_t addr)
{
uint32_t val;
SwapEndianContainer *c = opaque;
val = bswap32(c->read[2](c->opaque, addr));
return val;
}
static CPUReadMemoryFunc * const swapendian_readfn[3]={
swapendian_mem_readb,
swapendian_mem_readw,
swapendian_mem_readl
};
static void swapendian_mem_writeb(void *opaque, target_phys_addr_t addr,
uint32_t val)
{
SwapEndianContainer *c = opaque;
c->write[0](c->opaque, addr, val);
}
static void swapendian_mem_writew(void *opaque, target_phys_addr_t addr,
uint32_t val)
{
SwapEndianContainer *c = opaque;
c->write[1](c->opaque, addr, bswap16(val));
}
static void swapendian_mem_writel(void *opaque, target_phys_addr_t addr,
uint32_t val)
{
SwapEndianContainer *c = opaque;
c->write[2](c->opaque, addr, bswap32(val));
}
static CPUWriteMemoryFunc * const swapendian_writefn[3]={
swapendian_mem_writeb,
swapendian_mem_writew,
swapendian_mem_writel
};
static void swapendian_init(int io_index)
{
SwapEndianContainer *c = g_malloc(sizeof(SwapEndianContainer));
int i;
/* Swap mmio for big endian targets */
c->opaque = io_mem_opaque[io_index];
for (i = 0; i < 3; i++) {
c->read[i] = io_mem_read[io_index][i];
c->write[i] = io_mem_write[io_index][i];
io_mem_read[io_index][i] = swapendian_readfn[i];
io_mem_write[io_index][i] = swapendian_writefn[i];
}
io_mem_opaque[io_index] = c;
}
static void swapendian_del(int io_index)
{
if (io_mem_read[io_index][0] == swapendian_readfn[0]) {
g_free(io_mem_opaque[io_index]);
}
}
/* mem_read and mem_write are arrays of functions containing the /* mem_read and mem_write are arrays of functions containing the
function to access byte (index 0), word (index 1) and dword (index function to access byte (index 0), word (index 1) and dword (index
2). Functions can be omitted with a NULL function pointer. 2). Functions can be omitted with a NULL function pointer.
@ -3642,7 +3541,7 @@ static void swapendian_del(int io_index)
static int cpu_register_io_memory_fixed(int io_index, static int cpu_register_io_memory_fixed(int io_index,
CPUReadMemoryFunc * const *mem_read, CPUReadMemoryFunc * const *mem_read,
CPUWriteMemoryFunc * const *mem_write, CPUWriteMemoryFunc * const *mem_write,
void *opaque, enum device_endian endian) void *opaque)
{ {
int i; int i;
@ -3666,30 +3565,14 @@ static int cpu_register_io_memory_fixed(int io_index,
} }
io_mem_opaque[io_index] = opaque; io_mem_opaque[io_index] = opaque;
switch (endian) {
case DEVICE_BIG_ENDIAN:
#ifndef TARGET_WORDS_BIGENDIAN
swapendian_init(io_index);
#endif
break;
case DEVICE_LITTLE_ENDIAN:
#ifdef TARGET_WORDS_BIGENDIAN
swapendian_init(io_index);
#endif
break;
case DEVICE_NATIVE_ENDIAN:
default:
break;
}
return (io_index << IO_MEM_SHIFT); return (io_index << IO_MEM_SHIFT);
} }
int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read, int cpu_register_io_memory(CPUReadMemoryFunc * const *mem_read,
CPUWriteMemoryFunc * const *mem_write, CPUWriteMemoryFunc * const *mem_write,
void *opaque, enum device_endian endian) void *opaque)
{ {
return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque, endian); return cpu_register_io_memory_fixed(0, mem_read, mem_write, opaque);
} }
void cpu_unregister_io_memory(int io_table_address) void cpu_unregister_io_memory(int io_table_address)
@ -3697,8 +3580,6 @@ void cpu_unregister_io_memory(int io_table_address)
int i; int i;
int io_index = io_table_address >> IO_MEM_SHIFT; int io_index = io_table_address >> IO_MEM_SHIFT;
swapendian_del(io_index);
for (i=0;i < 3; i++) { for (i=0;i < 3; i++) {
io_mem_read[io_index][i] = unassigned_mem_read[i]; io_mem_read[io_index][i] = unassigned_mem_read[i];
io_mem_write[io_index][i] = unassigned_mem_write[i]; io_mem_write[io_index][i] = unassigned_mem_write[i];
@ -3712,23 +3593,18 @@ static void io_mem_init(void)
int i; int i;
cpu_register_io_memory_fixed(IO_MEM_ROM, error_mem_read, cpu_register_io_memory_fixed(IO_MEM_ROM, error_mem_read,
unassigned_mem_write, NULL, unassigned_mem_write, NULL);
DEVICE_NATIVE_ENDIAN);
cpu_register_io_memory_fixed(IO_MEM_UNASSIGNED, unassigned_mem_read, cpu_register_io_memory_fixed(IO_MEM_UNASSIGNED, unassigned_mem_read,
unassigned_mem_write, NULL, unassigned_mem_write, NULL);
DEVICE_NATIVE_ENDIAN);
cpu_register_io_memory_fixed(IO_MEM_NOTDIRTY, error_mem_read, cpu_register_io_memory_fixed(IO_MEM_NOTDIRTY, error_mem_read,
notdirty_mem_write, NULL, notdirty_mem_write, NULL);
DEVICE_NATIVE_ENDIAN);
cpu_register_io_memory_fixed(IO_MEM_SUBPAGE_RAM, subpage_ram_read, cpu_register_io_memory_fixed(IO_MEM_SUBPAGE_RAM, subpage_ram_read,
subpage_ram_write, NULL, subpage_ram_write, NULL);
DEVICE_NATIVE_ENDIAN);
for (i=0; i<5; i++) for (i=0; i<5; i++)
io_mem_used[i] = 1; io_mem_used[i] = 1;
io_mem_watch = cpu_register_io_memory(watch_mem_read, io_mem_watch = cpu_register_io_memory(watch_mem_read,
watch_mem_write, NULL, watch_mem_write, NULL);
DEVICE_NATIVE_ENDIAN);
} }
static void memory_map_init(void) static void memory_map_init(void)

View File

@ -857,6 +857,15 @@ static void memory_region_destructor_rom_device(MemoryRegion *mr)
cpu_unregister_io_memory(mr->ram_addr & ~(TARGET_PAGE_MASK | IO_MEM_ROMD)); cpu_unregister_io_memory(mr->ram_addr & ~(TARGET_PAGE_MASK | IO_MEM_ROMD));
} }
static bool memory_region_wrong_endianness(MemoryRegion *mr)
{
#ifdef TARGET_BIG_ENDIAN
return mr->ops->endianness == DEVICE_LITTLE_ENDIAN;
#else
return mr->ops->endianness == DEVICE_BIG_ENDIAN;
#endif
}
void memory_region_init(MemoryRegion *mr, void memory_region_init(MemoryRegion *mr,
const char *name, const char *name,
uint64_t size) uint64_t size)
@ -967,12 +976,24 @@ static uint32_t memory_region_read_thunk_b(void *mr, target_phys_addr_t addr)
static uint32_t memory_region_read_thunk_w(void *mr, target_phys_addr_t addr) static uint32_t memory_region_read_thunk_w(void *mr, target_phys_addr_t addr)
{ {
return memory_region_read_thunk_n(mr, addr, 2); uint32_t data;
data = memory_region_read_thunk_n(mr, addr, 2);
if (memory_region_wrong_endianness(mr)) {
data = bswap16(data);
}
return data;
} }
static uint32_t memory_region_read_thunk_l(void *mr, target_phys_addr_t addr) static uint32_t memory_region_read_thunk_l(void *mr, target_phys_addr_t addr)
{ {
return memory_region_read_thunk_n(mr, addr, 4); uint32_t data;
data = memory_region_read_thunk_n(mr, addr, 4);
if (memory_region_wrong_endianness(mr)) {
data = bswap32(data);
}
return data;
} }
static void memory_region_write_thunk_b(void *mr, target_phys_addr_t addr, static void memory_region_write_thunk_b(void *mr, target_phys_addr_t addr,
@ -984,12 +1005,18 @@ static void memory_region_write_thunk_b(void *mr, target_phys_addr_t addr,
static void memory_region_write_thunk_w(void *mr, target_phys_addr_t addr, static void memory_region_write_thunk_w(void *mr, target_phys_addr_t addr,
uint32_t data) uint32_t data)
{ {
if (memory_region_wrong_endianness(mr)) {
data = bswap16(data);
}
memory_region_write_thunk_n(mr, addr, 2, data); memory_region_write_thunk_n(mr, addr, 2, data);
} }
static void memory_region_write_thunk_l(void *mr, target_phys_addr_t addr, static void memory_region_write_thunk_l(void *mr, target_phys_addr_t addr,
uint32_t data) uint32_t data)
{ {
if (memory_region_wrong_endianness(mr)) {
data = bswap32(data);
}
memory_region_write_thunk_n(mr, addr, 4, data); memory_region_write_thunk_n(mr, addr, 4, data);
} }
@ -1014,8 +1041,7 @@ static void memory_region_prepare_ram_addr(MemoryRegion *mr)
mr->destructor = memory_region_destructor_iomem; mr->destructor = memory_region_destructor_iomem;
mr->ram_addr = cpu_register_io_memory(memory_region_read_thunk, mr->ram_addr = cpu_register_io_memory(memory_region_read_thunk,
memory_region_write_thunk, memory_region_write_thunk,
mr, mr);
mr->ops->endianness);
mr->backend_registered = true; mr->backend_registered = true;
} }
@ -1082,8 +1108,7 @@ void memory_region_init_rom_device(MemoryRegion *mr,
mr->ram_addr = qemu_ram_alloc(size, mr); mr->ram_addr = qemu_ram_alloc(size, mr);
mr->ram_addr |= cpu_register_io_memory(memory_region_read_thunk, mr->ram_addr |= cpu_register_io_memory(memory_region_read_thunk,
memory_region_write_thunk, memory_region_write_thunk,
mr, mr);
mr->ops->endianness);
mr->ram_addr |= IO_MEM_ROMD; mr->ram_addr |= IO_MEM_ROMD;
mr->backend_registered = true; mr->backend_registered = true;
} }