target-arm queue:
* Correct handling of writes to CPSR from gdbstub in user mode * virt: lift maximum RAM limit to 255GB * sdhci: implement reset * virt: if booting in Secure mode, provide secure-only RAM, make first flash device secure-only, and assume the EL3 boot rom will handle PSCI * bcm2835: use explicit endianness accessors rather than ldl/stl_phys * support big-endian in system mode for ARM * implement SETEND instruction * arm_gic: implement the GICv2 GICC_DIR register * fix SRS bug: only trap from S-EL1 to EL3 if specified mode is Mon -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABCAAGBQJW2XPNAAoJEDwlJe0UNgze3qgQAJI5tMud+PtKDF3B7hihlKAe Ffwn+OO/Pl3U7O2IcKw4qqRbze88e4rFHWtsPmKhId8iwvQ1xQ/bXUDE39F4zVFT p0Xp0hHpvM2DzUuuX1Y5wmypUAAuSdFe+6BiHa1AY93qzdTbx/5kmzJ2B0ML38pW c/igiOQZSQ3piKhHm6LvYNv5APMKq11+8qGlBqNootoUplnhEvEEgiqtiqat1KPI 7fBzObFGu0OnMaD83yAUYS4+/dSke7Wxl2IW+sAkVZM0mylY8GmxdLFw1nnUh3UW HNCbKzaC3v2GwbtD7Ewc9ubD2vN6leSyYfzVJYWyCkT8awQdZp0f+3kIKlWg30uc VStrFNtzqhd5B/jJkynR7i2uJ7kXEcRdZi/FXF8jo+9RuxI6iJ0agVk5/rzznShz jscr2oIIw90lybDm7TQsWDXjpxo3khUBMYvGQ0iZ+IDHSbj2FGLB1W/V06Lxm4xM NU4FjHCXB2H501WAaglo6JKXMWLXhE1TprJwh4g9KYYSjsFNSxPw9fOOiecysZ2e FEJ8MbACV8IlGtG1AeNjM3ml2JMvKlBq/zifKYzXim8pAcgHgxSAaRMNGIUdN7DO I4lAHmqqOLLRaERzGQjemBOVvXpDHPqlocfzo9awqAouz3K3tv1NKRaRatd4P4kw opE0lOV70ecHMcjelg12 =6cP7 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20160304' into staging target-arm queue: * Correct handling of writes to CPSR from gdbstub in user mode * virt: lift maximum RAM limit to 255GB * sdhci: implement reset * virt: if booting in Secure mode, provide secure-only RAM, make first flash device secure-only, and assume the EL3 boot rom will handle PSCI * bcm2835: use explicit endianness accessors rather than ldl/stl_phys * support big-endian in system mode for ARM * implement SETEND instruction * arm_gic: implement the GICv2 GICC_DIR register * fix SRS bug: only trap from S-EL1 to EL3 if specified mode is Mon # gpg: Signature made Fri 04 Mar 2016 11:38:53 GMT using RSA key ID 14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" # gpg: aka "Peter Maydell <pmaydell@gmail.com>" # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" * remotes/pmaydell/tags/pull-target-arm-20160304: (30 commits) target-arm: Only trap SRS from S-EL1 if specified mode is MON hw/intc/arm_gic.c: Implement GICv2 GICC_DIR arm: boot: Support big-endian elfs loader: Add data swap option to load-elf loader: load_elf(): Add doc comment loader: add API to load elf header target-arm: implement BE32 mode in system emulation target-arm: implement setend target-arm: introduce tbflag for endianness target-arm: a64: Add endianness support target-arm: introduce disas flag for endianness target-arm: pass DisasContext to gen_aa32_ld*/st* target-arm: implement SCTLR.EE linux-user: arm: handle CPSR.E correctly in strex emulation linux-user: arm: set CPSR.E/SCTLR.E0E correctly for BE mode arm: cpu: handle BE32 user-mode as BE target-arm: cpu: Move cpu_is_big_endian to header target-arm: implement SCTLR.B, drop bswap_code linux-user: arm: pass env to get_user_code_* linux-user: arm: fix coding style for some linux-user signal functions ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
3c0f12df65
@ -111,7 +111,7 @@ static void clipper_init(MachineState *machine)
|
||||
}
|
||||
size = load_elf(palcode_filename, cpu_alpha_superpage_to_phys,
|
||||
NULL, &palcode_entry, &palcode_low, &palcode_high,
|
||||
0, EM_ALPHA, 0);
|
||||
0, EM_ALPHA, 0, 0);
|
||||
if (size < 0) {
|
||||
error_report("could not load palcode '%s'", palcode_filename);
|
||||
exit(1);
|
||||
@ -131,7 +131,7 @@ static void clipper_init(MachineState *machine)
|
||||
|
||||
size = load_elf(kernel_filename, cpu_alpha_superpage_to_phys,
|
||||
NULL, &kernel_entry, &kernel_low, &kernel_high,
|
||||
0, EM_ALPHA, 0);
|
||||
0, EM_ALPHA, 0, 0);
|
||||
if (size < 0) {
|
||||
error_report("could not load kernel '%s'", kernel_filename);
|
||||
exit(1);
|
||||
|
@ -211,7 +211,7 @@ DeviceState *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq,
|
||||
|
||||
if (kernel_filename) {
|
||||
image_size = load_elf(kernel_filename, NULL, NULL, &entry, &lowaddr,
|
||||
NULL, big_endian, EM_ARM, 1);
|
||||
NULL, big_endian, EM_ARM, 1, 0);
|
||||
if (image_size < 0) {
|
||||
image_size = load_image_targphys(kernel_filename, 0, mem_size);
|
||||
lowaddr = 0;
|
||||
|
@ -518,9 +518,34 @@ static void do_cpu_reset(void *opaque)
|
||||
cpu_reset(cs);
|
||||
if (info) {
|
||||
if (!info->is_linux) {
|
||||
int i;
|
||||
/* Jump to the entry point. */
|
||||
uint64_t entry = info->entry;
|
||||
|
||||
switch (info->endianness) {
|
||||
case ARM_ENDIANNESS_LE:
|
||||
env->cp15.sctlr_el[1] &= ~SCTLR_E0E;
|
||||
for (i = 1; i < 4; ++i) {
|
||||
env->cp15.sctlr_el[i] &= ~SCTLR_EE;
|
||||
}
|
||||
env->uncached_cpsr &= ~CPSR_E;
|
||||
break;
|
||||
case ARM_ENDIANNESS_BE8:
|
||||
env->cp15.sctlr_el[1] |= SCTLR_E0E;
|
||||
for (i = 1; i < 4; ++i) {
|
||||
env->cp15.sctlr_el[i] |= SCTLR_EE;
|
||||
}
|
||||
env->uncached_cpsr |= CPSR_E;
|
||||
break;
|
||||
case ARM_ENDIANNESS_BE32:
|
||||
env->cp15.sctlr_el[1] |= SCTLR_B;
|
||||
break;
|
||||
case ARM_ENDIANNESS_UNKNOWN:
|
||||
break; /* Board's decision */
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
|
||||
if (!env->aarch64) {
|
||||
env->thumb = info->entry & 1;
|
||||
entry &= 0xfffffffe;
|
||||
@ -638,6 +663,62 @@ static int do_arm_linux_init(Object *obj, void *opaque)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t arm_load_elf(struct arm_boot_info *info, uint64_t *pentry,
|
||||
uint64_t *lowaddr, uint64_t *highaddr,
|
||||
int elf_machine)
|
||||
{
|
||||
bool elf_is64;
|
||||
union {
|
||||
Elf32_Ehdr h32;
|
||||
Elf64_Ehdr h64;
|
||||
} elf_header;
|
||||
int data_swab = 0;
|
||||
bool big_endian;
|
||||
uint64_t ret = -1;
|
||||
Error *err = NULL;
|
||||
|
||||
|
||||
load_elf_hdr(info->kernel_filename, &elf_header, &elf_is64, &err);
|
||||
if (err) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (elf_is64) {
|
||||
big_endian = elf_header.h64.e_ident[EI_DATA] == ELFDATA2MSB;
|
||||
info->endianness = big_endian ? ARM_ENDIANNESS_BE8
|
||||
: ARM_ENDIANNESS_LE;
|
||||
} else {
|
||||
big_endian = elf_header.h32.e_ident[EI_DATA] == ELFDATA2MSB;
|
||||
if (big_endian) {
|
||||
if (bswap32(elf_header.h32.e_flags) & EF_ARM_BE8) {
|
||||
info->endianness = ARM_ENDIANNESS_BE8;
|
||||
} else {
|
||||
info->endianness = ARM_ENDIANNESS_BE32;
|
||||
/* In BE32, the CPU has a different view of the per-byte
|
||||
* address map than the rest of the system. BE32 ELF files
|
||||
* are organised such that they can be programmed through
|
||||
* the CPU's per-word byte-reversed view of the world. QEMU
|
||||
* however loads ELF files independently of the CPU. So
|
||||
* tell the ELF loader to byte reverse the data for us.
|
||||
*/
|
||||
data_swab = 2;
|
||||
}
|
||||
} else {
|
||||
info->endianness = ARM_ENDIANNESS_LE;
|
||||
}
|
||||
}
|
||||
|
||||
ret = load_elf(info->kernel_filename, NULL, NULL,
|
||||
pentry, lowaddr, highaddr, big_endian, elf_machine,
|
||||
1, data_swab);
|
||||
if (ret <= 0) {
|
||||
/* The header loaded but the image didn't */
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void arm_load_kernel_notify(Notifier *notifier, void *data)
|
||||
{
|
||||
CPUState *cs;
|
||||
@ -647,7 +728,6 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data)
|
||||
uint64_t elf_entry, elf_low_addr, elf_high_addr;
|
||||
int elf_machine;
|
||||
hwaddr entry, kernel_load_offset;
|
||||
int big_endian;
|
||||
static const ARMInsnFixup *primary_loader;
|
||||
ArmLoadKernelNotifier *n = DO_UPCAST(ArmLoadKernelNotifier,
|
||||
notifier, notifier);
|
||||
@ -733,12 +813,6 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data)
|
||||
if (info->nb_cpus == 0)
|
||||
info->nb_cpus = 1;
|
||||
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
big_endian = 1;
|
||||
#else
|
||||
big_endian = 0;
|
||||
#endif
|
||||
|
||||
/* We want to put the initrd far enough into RAM that when the
|
||||
* kernel is uncompressed it will not clobber the initrd. However
|
||||
* on boards without much RAM we must ensure that we still leave
|
||||
@ -753,9 +827,8 @@ static void arm_load_kernel_notify(Notifier *notifier, void *data)
|
||||
MIN(info->ram_size / 2, 128 * 1024 * 1024);
|
||||
|
||||
/* Assume that raw images are linux kernels, and ELF images are not. */
|
||||
kernel_size = load_elf(info->kernel_filename, NULL, NULL, &elf_entry,
|
||||
&elf_low_addr, &elf_high_addr, big_endian,
|
||||
elf_machine, 1);
|
||||
kernel_size = arm_load_elf(info, &elf_entry, &elf_low_addr,
|
||||
&elf_high_addr, elf_machine);
|
||||
if (kernel_size > 0 && have_dtb(info)) {
|
||||
/* If there is still some room left at the base of RAM, try and put
|
||||
* the DTB there like we do for images loaded with -bios or -pflash.
|
||||
|
168
hw/arm/virt.c
168
hw/arm/virt.c
@ -73,6 +73,7 @@ typedef struct VirtBoardInfo {
|
||||
uint32_t clock_phandle;
|
||||
uint32_t gic_phandle;
|
||||
uint32_t v2m_phandle;
|
||||
bool using_psci;
|
||||
} VirtBoardInfo;
|
||||
|
||||
typedef struct {
|
||||
@ -95,6 +96,23 @@ typedef struct {
|
||||
#define VIRT_MACHINE_CLASS(klass) \
|
||||
OBJECT_CLASS_CHECK(VirtMachineClass, klass, TYPE_VIRT_MACHINE)
|
||||
|
||||
/* RAM limit in GB. Since VIRT_MEM starts at the 1GB mark, this means
|
||||
* RAM can go up to the 256GB mark, leaving 256GB of the physical
|
||||
* address space unallocated and free for future use between 256G and 512G.
|
||||
* If we need to provide more RAM to VMs in the future then we need to:
|
||||
* * allocate a second bank of RAM starting at 2TB and working up
|
||||
* * fix the DT and ACPI table generation code in QEMU to correctly
|
||||
* report two split lumps of RAM to the guest
|
||||
* * fix KVM in the host kernel to allow guests with >40 bit address spaces
|
||||
* (We don't want to fill all the way up to 512GB with RAM because
|
||||
* we might want it for non-RAM purposes later. Conversely it seems
|
||||
* reasonable to assume that anybody configuring a VM with a quarter
|
||||
* of a terabyte of RAM will be doing it on a host with more than a
|
||||
* terabyte of physical address space.)
|
||||
*/
|
||||
#define RAMLIMIT_GB 255
|
||||
#define RAMLIMIT_BYTES (RAMLIMIT_GB * 1024ULL * 1024 * 1024)
|
||||
|
||||
/* Addresses and sizes of our components.
|
||||
* 0..128MB is space for a flash device so we can run bootrom code such as UEFI.
|
||||
* 128MB..256MB is used for miscellaneous device I/O.
|
||||
@ -127,10 +145,11 @@ static const MemMapEntry a15memmap[] = {
|
||||
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
|
||||
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
|
||||
[VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 },
|
||||
[VIRT_SECURE_MEM] = { 0x0e000000, 0x01000000 },
|
||||
[VIRT_PCIE_MMIO] = { 0x10000000, 0x2eff0000 },
|
||||
[VIRT_PCIE_PIO] = { 0x3eff0000, 0x00010000 },
|
||||
[VIRT_PCIE_ECAM] = { 0x3f000000, 0x01000000 },
|
||||
[VIRT_MEM] = { 0x40000000, 30ULL * 1024 * 1024 * 1024 },
|
||||
[VIRT_MEM] = { 0x40000000, RAMLIMIT_BYTES },
|
||||
/* Second PCIe window, 512GB wide at the 512GB boundary */
|
||||
[VIRT_PCIE_MMIO_HIGH] = { 0x8000000000ULL, 0x8000000000ULL },
|
||||
};
|
||||
@ -230,6 +249,10 @@ static void fdt_add_psci_node(const VirtBoardInfo *vbi)
|
||||
void *fdt = vbi->fdt;
|
||||
ARMCPU *armcpu = ARM_CPU(qemu_get_cpu(0));
|
||||
|
||||
if (!vbi->using_psci) {
|
||||
return;
|
||||
}
|
||||
|
||||
qemu_fdt_add_subnode(fdt, "/psci");
|
||||
if (armcpu->psci_version == 2) {
|
||||
const char comp[] = "arm,psci-0.2\0arm,psci";
|
||||
@ -341,7 +364,7 @@ static void fdt_add_cpu_nodes(const VirtBoardInfo *vbi)
|
||||
qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible",
|
||||
armcpu->dtb_compatible);
|
||||
|
||||
if (vbi->smp_cpus > 1) {
|
||||
if (vbi->using_psci && vbi->smp_cpus > 1) {
|
||||
qemu_fdt_setprop_string(vbi->fdt, nodename,
|
||||
"enable-method", "psci");
|
||||
}
|
||||
@ -678,13 +701,15 @@ static void create_virtio_devices(const VirtBoardInfo *vbi, qemu_irq *pic)
|
||||
}
|
||||
|
||||
static void create_one_flash(const char *name, hwaddr flashbase,
|
||||
hwaddr flashsize)
|
||||
hwaddr flashsize, const char *file,
|
||||
MemoryRegion *sysmem)
|
||||
{
|
||||
/* Create and map a single flash device. We use the same
|
||||
* parameters as the flash devices on the Versatile Express board.
|
||||
*/
|
||||
DriveInfo *dinfo = drive_get_next(IF_PFLASH);
|
||||
DeviceState *dev = qdev_create(NULL, "cfi.pflash01");
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
const uint64_t sectorlength = 256 * 1024;
|
||||
|
||||
if (dinfo) {
|
||||
@ -704,19 +729,10 @@ static void create_one_flash(const char *name, hwaddr flashbase,
|
||||
qdev_prop_set_string(dev, "name", name);
|
||||
qdev_init_nofail(dev);
|
||||
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, flashbase);
|
||||
}
|
||||
memory_region_add_subregion(sysmem, flashbase,
|
||||
sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0));
|
||||
|
||||
static void create_flash(const VirtBoardInfo *vbi)
|
||||
{
|
||||
/* Create two flash devices to fill the VIRT_FLASH space in the memmap.
|
||||
* Any file passed via -bios goes in the first of these.
|
||||
*/
|
||||
hwaddr flashsize = vbi->memmap[VIRT_FLASH].size / 2;
|
||||
hwaddr flashbase = vbi->memmap[VIRT_FLASH].base;
|
||||
char *nodename;
|
||||
|
||||
if (bios_name) {
|
||||
if (file) {
|
||||
char *fn;
|
||||
int image_size;
|
||||
|
||||
@ -726,30 +742,73 @@ static void create_flash(const VirtBoardInfo *vbi)
|
||||
"but you cannot use both options at once");
|
||||
exit(1);
|
||||
}
|
||||
fn = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
|
||||
fn = qemu_find_file(QEMU_FILE_TYPE_BIOS, file);
|
||||
if (!fn) {
|
||||
error_report("Could not find ROM image '%s'", bios_name);
|
||||
error_report("Could not find ROM image '%s'", file);
|
||||
exit(1);
|
||||
}
|
||||
image_size = load_image_targphys(fn, flashbase, flashsize);
|
||||
image_size = load_image_mr(fn, sysbus_mmio_get_region(sbd, 0));
|
||||
g_free(fn);
|
||||
if (image_size < 0) {
|
||||
error_report("Could not load ROM image '%s'", bios_name);
|
||||
error_report("Could not load ROM image '%s'", file);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
create_one_flash("virt.flash0", flashbase, flashsize);
|
||||
create_one_flash("virt.flash1", flashbase + flashsize, flashsize);
|
||||
static void create_flash(const VirtBoardInfo *vbi,
|
||||
MemoryRegion *sysmem,
|
||||
MemoryRegion *secure_sysmem)
|
||||
{
|
||||
/* Create two flash devices to fill the VIRT_FLASH space in the memmap.
|
||||
* Any file passed via -bios goes in the first of these.
|
||||
* sysmem is the system memory space. secure_sysmem is the secure view
|
||||
* of the system, and the first flash device should be made visible only
|
||||
* there. The second flash device is visible to both secure and nonsecure.
|
||||
* If sysmem == secure_sysmem this means there is no separate Secure
|
||||
* address space and both flash devices are generally visible.
|
||||
*/
|
||||
hwaddr flashsize = vbi->memmap[VIRT_FLASH].size / 2;
|
||||
hwaddr flashbase = vbi->memmap[VIRT_FLASH].base;
|
||||
char *nodename;
|
||||
|
||||
nodename = g_strdup_printf("/flash@%" PRIx64, flashbase);
|
||||
qemu_fdt_add_subnode(vbi->fdt, nodename);
|
||||
qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible", "cfi-flash");
|
||||
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
|
||||
2, flashbase, 2, flashsize,
|
||||
2, flashbase + flashsize, 2, flashsize);
|
||||
qemu_fdt_setprop_cell(vbi->fdt, nodename, "bank-width", 4);
|
||||
g_free(nodename);
|
||||
create_one_flash("virt.flash0", flashbase, flashsize,
|
||||
bios_name, secure_sysmem);
|
||||
create_one_flash("virt.flash1", flashbase + flashsize, flashsize,
|
||||
NULL, sysmem);
|
||||
|
||||
if (sysmem == secure_sysmem) {
|
||||
/* Report both flash devices as a single node in the DT */
|
||||
nodename = g_strdup_printf("/flash@%" PRIx64, flashbase);
|
||||
qemu_fdt_add_subnode(vbi->fdt, nodename);
|
||||
qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible", "cfi-flash");
|
||||
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
|
||||
2, flashbase, 2, flashsize,
|
||||
2, flashbase + flashsize, 2, flashsize);
|
||||
qemu_fdt_setprop_cell(vbi->fdt, nodename, "bank-width", 4);
|
||||
g_free(nodename);
|
||||
} else {
|
||||
/* Report the devices as separate nodes so we can mark one as
|
||||
* only visible to the secure world.
|
||||
*/
|
||||
nodename = g_strdup_printf("/secflash@%" PRIx64, flashbase);
|
||||
qemu_fdt_add_subnode(vbi->fdt, nodename);
|
||||
qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible", "cfi-flash");
|
||||
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
|
||||
2, flashbase, 2, flashsize);
|
||||
qemu_fdt_setprop_cell(vbi->fdt, nodename, "bank-width", 4);
|
||||
qemu_fdt_setprop_string(vbi->fdt, nodename, "status", "disabled");
|
||||
qemu_fdt_setprop_string(vbi->fdt, nodename, "secure-status", "okay");
|
||||
g_free(nodename);
|
||||
|
||||
nodename = g_strdup_printf("/flash@%" PRIx64, flashbase);
|
||||
qemu_fdt_add_subnode(vbi->fdt, nodename);
|
||||
qemu_fdt_setprop_string(vbi->fdt, nodename, "compatible", "cfi-flash");
|
||||
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg",
|
||||
2, flashbase + flashsize, 2, flashsize);
|
||||
qemu_fdt_setprop_cell(vbi->fdt, nodename, "bank-width", 4);
|
||||
g_free(nodename);
|
||||
}
|
||||
}
|
||||
|
||||
static void create_fw_cfg(const VirtBoardInfo *vbi, AddressSpace *as)
|
||||
@ -960,6 +1019,27 @@ static void create_platform_bus(VirtBoardInfo *vbi, qemu_irq *pic)
|
||||
sysbus_mmio_get_region(s, 0));
|
||||
}
|
||||
|
||||
static void create_secure_ram(VirtBoardInfo *vbi, MemoryRegion *secure_sysmem)
|
||||
{
|
||||
MemoryRegion *secram = g_new(MemoryRegion, 1);
|
||||
char *nodename;
|
||||
hwaddr base = vbi->memmap[VIRT_SECURE_MEM].base;
|
||||
hwaddr size = vbi->memmap[VIRT_SECURE_MEM].size;
|
||||
|
||||
memory_region_init_ram(secram, NULL, "virt.secure-ram", size, &error_fatal);
|
||||
vmstate_register_ram_global(secram);
|
||||
memory_region_add_subregion(secure_sysmem, base, secram);
|
||||
|
||||
nodename = g_strdup_printf("/secram@%" PRIx64, base);
|
||||
qemu_fdt_add_subnode(vbi->fdt, nodename);
|
||||
qemu_fdt_setprop_string(vbi->fdt, nodename, "device_type", "memory");
|
||||
qemu_fdt_setprop_sized_cells(vbi->fdt, nodename, "reg", 2, base, 2, size);
|
||||
qemu_fdt_setprop_string(vbi->fdt, nodename, "status", "disabled");
|
||||
qemu_fdt_setprop_string(vbi->fdt, nodename, "secure-status", "okay");
|
||||
|
||||
g_free(nodename);
|
||||
}
|
||||
|
||||
static void *machvirt_dtb(const struct arm_boot_info *binfo, int *fdt_size)
|
||||
{
|
||||
const VirtBoardInfo *board = (const VirtBoardInfo *)binfo;
|
||||
@ -1020,6 +1100,7 @@ static void machvirt_init(MachineState *machine)
|
||||
VirtGuestInfoState *guest_info_state = g_malloc0(sizeof *guest_info_state);
|
||||
VirtGuestInfo *guest_info = &guest_info_state->info;
|
||||
char **cpustr;
|
||||
bool firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);
|
||||
|
||||
if (!cpu_model) {
|
||||
cpu_model = "cortex-a15";
|
||||
@ -1047,6 +1128,15 @@ static void machvirt_init(MachineState *machine)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* If we have an EL3 boot ROM then the assumption is that it will
|
||||
* implement PSCI itself, so disable QEMU's internal implementation
|
||||
* so it doesn't get in the way. Instead of starting secondary
|
||||
* CPUs in PSCI powerdown state we will start them all running and
|
||||
* let the boot ROM sort them out.
|
||||
* The usual case is that we do use QEMU's PSCI implementation.
|
||||
*/
|
||||
vbi->using_psci = !(vms->secure && firmware_loaded);
|
||||
|
||||
/* The maximum number of CPUs depends on the GIC version, or on how
|
||||
* many redistributors we can fit into the memory map.
|
||||
*/
|
||||
@ -1066,7 +1156,7 @@ static void machvirt_init(MachineState *machine)
|
||||
vbi->smp_cpus = smp_cpus;
|
||||
|
||||
if (machine->ram_size > vbi->memmap[VIRT_MEM].size) {
|
||||
error_report("mach-virt: cannot model more than 30GB RAM");
|
||||
error_report("mach-virt: cannot model more than %dGB RAM", RAMLIMIT_GB);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
@ -1114,12 +1204,15 @@ static void machvirt_init(MachineState *machine)
|
||||
object_property_set_bool(cpuobj, false, "has_el3", NULL);
|
||||
}
|
||||
|
||||
object_property_set_int(cpuobj, QEMU_PSCI_CONDUIT_HVC, "psci-conduit",
|
||||
NULL);
|
||||
if (vbi->using_psci) {
|
||||
object_property_set_int(cpuobj, QEMU_PSCI_CONDUIT_HVC,
|
||||
"psci-conduit", NULL);
|
||||
|
||||
/* Secondary CPUs start in PSCI powered-down state */
|
||||
if (n > 0) {
|
||||
object_property_set_bool(cpuobj, true, "start-powered-off", NULL);
|
||||
/* Secondary CPUs start in PSCI powered-down state */
|
||||
if (n > 0) {
|
||||
object_property_set_bool(cpuobj, true,
|
||||
"start-powered-off", NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (object_property_find(cpuobj, "reset-cbar", NULL)) {
|
||||
@ -1145,13 +1238,14 @@ static void machvirt_init(MachineState *machine)
|
||||
machine->ram_size);
|
||||
memory_region_add_subregion(sysmem, vbi->memmap[VIRT_MEM].base, ram);
|
||||
|
||||
create_flash(vbi);
|
||||
create_flash(vbi, sysmem, secure_sysmem ? secure_sysmem : sysmem);
|
||||
|
||||
create_gic(vbi, pic, gic_version, vms->secure);
|
||||
|
||||
create_uart(vbi, pic, VIRT_UART, sysmem);
|
||||
|
||||
if (vms->secure) {
|
||||
create_secure_ram(vbi, secure_sysmem);
|
||||
create_uart(vbi, pic, VIRT_SECURE_UART, secure_sysmem);
|
||||
}
|
||||
|
||||
@ -1187,7 +1281,7 @@ static void machvirt_init(MachineState *machine)
|
||||
vbi->bootinfo.board_id = -1;
|
||||
vbi->bootinfo.loader_start = vbi->memmap[VIRT_MEM].base;
|
||||
vbi->bootinfo.get_dtb = machvirt_dtb;
|
||||
vbi->bootinfo.firmware_loaded = bios_name || drive_get(IF_PFLASH, 0, 0);
|
||||
vbi->bootinfo.firmware_loaded = firmware_loaded;
|
||||
arm_load_kernel(ARM_CPU(first_cpu), &vbi->bootinfo);
|
||||
|
||||
/*
|
||||
|
@ -147,6 +147,28 @@ int load_image_targphys(const char *filename,
|
||||
return size;
|
||||
}
|
||||
|
||||
int load_image_mr(const char *filename, MemoryRegion *mr)
|
||||
{
|
||||
int size;
|
||||
|
||||
if (!memory_access_is_direct(mr, false)) {
|
||||
/* Can only load an image into RAM or ROM */
|
||||
return -1;
|
||||
}
|
||||
|
||||
size = get_image_size(filename);
|
||||
|
||||
if (size > memory_region_size(mr)) {
|
||||
return -1;
|
||||
}
|
||||
if (size > 0) {
|
||||
if (rom_add_file_mr(filename, mr, -1) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void pstrcpy_targphys(const char *name, hwaddr dest, int buf_size,
|
||||
const char *source)
|
||||
{
|
||||
@ -332,10 +354,66 @@ const char *load_elf_strerror(int error)
|
||||
}
|
||||
}
|
||||
|
||||
void load_elf_hdr(const char *filename, void *hdr, bool *is64, Error **errp)
|
||||
{
|
||||
int fd;
|
||||
uint8_t e_ident_local[EI_NIDENT];
|
||||
uint8_t *e_ident;
|
||||
size_t hdr_size, off;
|
||||
bool is64l;
|
||||
|
||||
if (!hdr) {
|
||||
hdr = e_ident_local;
|
||||
}
|
||||
e_ident = hdr;
|
||||
|
||||
fd = open(filename, O_RDONLY | O_BINARY);
|
||||
if (fd < 0) {
|
||||
error_setg_errno(errp, errno, "Failed to open file: %s", filename);
|
||||
return;
|
||||
}
|
||||
if (read(fd, hdr, EI_NIDENT) != EI_NIDENT) {
|
||||
error_setg_errno(errp, errno, "Failed to read file: %s", filename);
|
||||
goto fail;
|
||||
}
|
||||
if (e_ident[0] != ELFMAG0 ||
|
||||
e_ident[1] != ELFMAG1 ||
|
||||
e_ident[2] != ELFMAG2 ||
|
||||
e_ident[3] != ELFMAG3) {
|
||||
error_setg(errp, "Bad ELF magic");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
is64l = e_ident[EI_CLASS] == ELFCLASS64;
|
||||
hdr_size = is64l ? sizeof(Elf64_Ehdr) : sizeof(Elf32_Ehdr);
|
||||
if (is64) {
|
||||
*is64 = is64l;
|
||||
}
|
||||
|
||||
off = EI_NIDENT;
|
||||
while (hdr != e_ident_local && off < hdr_size) {
|
||||
size_t br = read(fd, hdr + off, hdr_size - off);
|
||||
switch (br) {
|
||||
case 0:
|
||||
error_setg(errp, "File too short: %s", filename);
|
||||
goto fail;
|
||||
case -1:
|
||||
error_setg_errno(errp, errno, "Failed to read file: %s",
|
||||
filename);
|
||||
goto fail;
|
||||
}
|
||||
off += br;
|
||||
}
|
||||
|
||||
fail:
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/* return < 0 if error, otherwise the number of bytes loaded in memory */
|
||||
int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
|
||||
void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr,
|
||||
uint64_t *highaddr, int big_endian, int elf_machine, int clear_lsb)
|
||||
uint64_t *highaddr, int big_endian, int elf_machine,
|
||||
int clear_lsb, int data_swab)
|
||||
{
|
||||
int fd, data_order, target_data_order, must_swab, ret = ELF_LOAD_FAILED;
|
||||
uint8_t e_ident[EI_NIDENT];
|
||||
@ -374,10 +452,12 @@ int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
if (e_ident[EI_CLASS] == ELFCLASS64) {
|
||||
ret = load_elf64(filename, fd, translate_fn, translate_opaque, must_swab,
|
||||
pentry, lowaddr, highaddr, elf_machine, clear_lsb);
|
||||
pentry, lowaddr, highaddr, elf_machine, clear_lsb,
|
||||
data_swab);
|
||||
} else {
|
||||
ret = load_elf32(filename, fd, translate_fn, translate_opaque, must_swab,
|
||||
pentry, lowaddr, highaddr, elf_machine, clear_lsb);
|
||||
pentry, lowaddr, highaddr, elf_machine, clear_lsb,
|
||||
data_swab);
|
||||
}
|
||||
|
||||
fail:
|
||||
@ -751,7 +831,7 @@ static void *rom_set_mr(Rom *rom, Object *owner, const char *name)
|
||||
|
||||
int rom_add_file(const char *file, const char *fw_dir,
|
||||
hwaddr addr, int32_t bootindex,
|
||||
bool option_rom)
|
||||
bool option_rom, MemoryRegion *mr)
|
||||
{
|
||||
MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
|
||||
Rom *rom;
|
||||
@ -818,7 +898,12 @@ int rom_add_file(const char *file, const char *fw_dir,
|
||||
|
||||
fw_cfg_add_file(fw_cfg, fw_file_name, data, rom->romsize);
|
||||
} else {
|
||||
snprintf(devpath, sizeof(devpath), "/rom@" TARGET_FMT_plx, addr);
|
||||
if (mr) {
|
||||
rom->mr = mr;
|
||||
snprintf(devpath, sizeof(devpath), "/rom@%s", file);
|
||||
} else {
|
||||
snprintf(devpath, sizeof(devpath), "/rom@" TARGET_FMT_plx, addr);
|
||||
}
|
||||
}
|
||||
|
||||
add_boot_device_path(bootindex, NULL, devpath);
|
||||
@ -892,12 +977,12 @@ int rom_add_elf_program(const char *name, void *data, size_t datasize,
|
||||
|
||||
int rom_add_vga(const char *file)
|
||||
{
|
||||
return rom_add_file(file, "vgaroms", 0, -1, true);
|
||||
return rom_add_file(file, "vgaroms", 0, -1, true, NULL);
|
||||
}
|
||||
|
||||
int rom_add_option(const char *file, int32_t bootindex)
|
||||
{
|
||||
return rom_add_file(file, "genroms", 0, bootindex, true);
|
||||
return rom_add_file(file, "genroms", 0, bootindex, true, NULL);
|
||||
}
|
||||
|
||||
static void rom_reset(void *unused)
|
||||
|
@ -109,7 +109,7 @@ static void a15mp_priv_realize(DeviceState *dev, Error **errp)
|
||||
/* Memory map (addresses are offsets from PERIPHBASE):
|
||||
* 0x0000-0x0fff -- reserved
|
||||
* 0x1000-0x1fff -- GIC Distributor
|
||||
* 0x2000-0x2fff -- GIC CPU interface
|
||||
* 0x2000-0x3fff -- GIC CPU interface
|
||||
* 0x4000-0x4fff -- GIC virtual interface control (not modelled)
|
||||
* 0x5000-0x5fff -- GIC virtual interface control (not modelled)
|
||||
* 0x6000-0x7fff -- GIC virtual CPU interface (not modelled)
|
||||
|
@ -73,7 +73,7 @@ void cris_load_image(CRISCPU *cpu, struct cris_load_info *li)
|
||||
/* Boots a kernel elf binary, os/linux-2.6/vmlinux from the axis
|
||||
devboard SDK. */
|
||||
image_size = load_elf(li->image_filename, translate_kernel_address, NULL,
|
||||
&entry, NULL, &high, 0, EM_CRIS, 0);
|
||||
&entry, NULL, &high, 0, EM_CRIS, 0, 0);
|
||||
li->entry = entry;
|
||||
if (image_size < 0) {
|
||||
/* Takes a kimage from the axis devboard SDK. */
|
||||
|
@ -196,7 +196,8 @@ int load_multiboot(FWCfgState *fw_cfg,
|
||||
}
|
||||
|
||||
kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
|
||||
&elf_low, &elf_high, 0, I386_ELF_MACHINE, 0);
|
||||
&elf_low, &elf_high, 0, I386_ELF_MACHINE,
|
||||
0, 0);
|
||||
if (kernel_size < 0) {
|
||||
fprintf(stderr, "Error while loading elf kernel\n");
|
||||
exit(1);
|
||||
|
@ -500,6 +500,41 @@ static uint8_t gic_get_running_priority(GICState *s, int cpu, MemTxAttrs attrs)
|
||||
}
|
||||
}
|
||||
|
||||
/* Return true if we should split priority drop and interrupt deactivation,
|
||||
* ie whether the relevant EOIMode bit is set.
|
||||
*/
|
||||
static bool gic_eoi_split(GICState *s, int cpu, MemTxAttrs attrs)
|
||||
{
|
||||
if (s->revision != 2) {
|
||||
/* Before GICv2 prio-drop and deactivate are not separable */
|
||||
return false;
|
||||
}
|
||||
if (s->security_extn && !attrs.secure) {
|
||||
return s->cpu_ctlr[cpu] & GICC_CTLR_EOIMODE_NS;
|
||||
}
|
||||
return s->cpu_ctlr[cpu] & GICC_CTLR_EOIMODE;
|
||||
}
|
||||
|
||||
static void gic_deactivate_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs)
|
||||
{
|
||||
int cm = 1 << cpu;
|
||||
int group = gic_has_groups(s) && GIC_TEST_GROUP(irq, cm);
|
||||
|
||||
if (!gic_eoi_split(s, cpu, attrs)) {
|
||||
/* This is UNPREDICTABLE; we choose to ignore it */
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"gic_deactivate_irq: GICC_DIR write when EOIMode clear");
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->security_extn && !attrs.secure && !group) {
|
||||
DPRINTF("Non-secure DI for Group0 interrupt %d ignored\n", irq);
|
||||
return;
|
||||
}
|
||||
|
||||
GIC_CLEAR_ACTIVE(irq, cm);
|
||||
}
|
||||
|
||||
void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs)
|
||||
{
|
||||
int cm = 1 << cpu;
|
||||
@ -544,7 +579,11 @@ void gic_complete_irq(GICState *s, int cpu, int irq, MemTxAttrs attrs)
|
||||
*/
|
||||
|
||||
gic_drop_prio(s, cpu, group);
|
||||
GIC_CLEAR_ACTIVE(irq, cm);
|
||||
|
||||
/* In GICv2 the guest can choose to split priority-drop and deactivate */
|
||||
if (!gic_eoi_split(s, cpu, attrs)) {
|
||||
GIC_CLEAR_ACTIVE(irq, cm);
|
||||
}
|
||||
gic_update(s);
|
||||
}
|
||||
|
||||
@ -1210,6 +1249,10 @@ static MemTxResult gic_cpu_write(GICState *s, int cpu, int offset,
|
||||
s->nsapr[regno][cpu] = value;
|
||||
break;
|
||||
}
|
||||
case 0x1000:
|
||||
/* GICC_DIR */
|
||||
gic_deactivate_irq(s, cpu, value & 0x3ff, attrs);
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"gic_cpu_write: Bad offset %x\n", (int)offset);
|
||||
|
@ -121,7 +121,7 @@ void gic_init_irqs_and_mmio(GICState *s, qemu_irq_handler handler,
|
||||
* neither it can use KVM.
|
||||
*/
|
||||
memory_region_init_io(&s->cpuiomem[0], OBJECT(s), ops ? &ops[1] : NULL,
|
||||
s, "gic_cpu", s->revision == 2 ? 0x1000 : 0x100);
|
||||
s, "gic_cpu", s->revision == 2 ? 0x2000 : 0x100);
|
||||
sysbus_init_mmio(sbd, &s->cpuiomem[0]);
|
||||
}
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ static void lm32_evr_init(MachineState *machine)
|
||||
int kernel_size;
|
||||
|
||||
kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
|
||||
1, EM_LATTICEMICO32, 0);
|
||||
1, EM_LATTICEMICO32, 0, 0);
|
||||
reset_info->bootstrap_pc = entry;
|
||||
|
||||
if (kernel_size < 0) {
|
||||
@ -245,7 +245,7 @@ static void lm32_uclinux_init(MachineState *machine)
|
||||
int kernel_size;
|
||||
|
||||
kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
|
||||
1, EM_LATTICEMICO32, 0);
|
||||
1, EM_LATTICEMICO32, 0, 0);
|
||||
reset_info->bootstrap_pc = entry;
|
||||
|
||||
if (kernel_size < 0) {
|
||||
|
@ -177,7 +177,7 @@ milkymist_init(MachineState *machine)
|
||||
|
||||
/* Boots a kernel elf binary. */
|
||||
kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
|
||||
1, EM_LATTICEMICO32, 0);
|
||||
1, EM_LATTICEMICO32, 0, 0);
|
||||
reset_info->bootstrap_pc = entry;
|
||||
|
||||
if (kernel_size < 0) {
|
||||
|
@ -73,7 +73,7 @@ static void an5206_init(MachineState *machine)
|
||||
}
|
||||
|
||||
kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
|
||||
NULL, NULL, 1, EM_68K, 0);
|
||||
NULL, NULL, 1, EM_68K, 0, 0);
|
||||
entry = elf_entry;
|
||||
if (kernel_size < 0) {
|
||||
kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL,
|
||||
|
@ -50,7 +50,7 @@ static void dummy_m68k_init(MachineState *machine)
|
||||
/* Load kernel. */
|
||||
if (kernel_filename) {
|
||||
kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
|
||||
NULL, NULL, 1, EM_68K, 0);
|
||||
NULL, NULL, 1, EM_68K, 0, 0);
|
||||
entry = elf_entry;
|
||||
if (kernel_size < 0) {
|
||||
kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL,
|
||||
|
@ -276,7 +276,7 @@ static void mcf5208evb_init(MachineState *machine)
|
||||
}
|
||||
|
||||
kernel_size = load_elf(kernel_filename, NULL, NULL, &elf_entry,
|
||||
NULL, NULL, 1, EM_68K, 0);
|
||||
NULL, NULL, 1, EM_68K, 0, 0);
|
||||
entry = elf_entry;
|
||||
if (kernel_size < 0) {
|
||||
kernel_size = load_uimage(kernel_filename, &entry, NULL, NULL,
|
||||
|
@ -142,12 +142,12 @@ void microblaze_load_kernel(MicroBlazeCPU *cpu, hwaddr ddr_base,
|
||||
/* Boots a kernel elf binary. */
|
||||
kernel_size = load_elf(kernel_filename, NULL, NULL,
|
||||
&entry, &low, &high,
|
||||
big_endian, EM_MICROBLAZE, 0);
|
||||
big_endian, EM_MICROBLAZE, 0, 0);
|
||||
base32 = entry;
|
||||
if (base32 == 0xc0000000) {
|
||||
kernel_size = load_elf(kernel_filename, translate_kernel_address,
|
||||
NULL, &entry, NULL, NULL,
|
||||
big_endian, EM_MICROBLAZE, 0);
|
||||
big_endian, EM_MICROBLAZE, 0, 0);
|
||||
}
|
||||
/* Always boot into physical ram. */
|
||||
boot_info.bootstrap_pc = (uint32_t)entry;
|
||||
|
@ -117,7 +117,7 @@ static int64_t load_kernel (CPUMIPSState *env)
|
||||
|
||||
if (load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys, NULL,
|
||||
(uint64_t *)&kernel_entry, (uint64_t *)&kernel_low,
|
||||
(uint64_t *)&kernel_high, 0, EM_MIPS, 1) < 0) {
|
||||
(uint64_t *)&kernel_high, 0, EM_MIPS, 1, 0) < 0) {
|
||||
fprintf(stderr, "qemu: could not load kernel '%s'\n",
|
||||
loaderparams.kernel_filename);
|
||||
exit(1);
|
||||
|
@ -796,7 +796,7 @@ static int64_t load_kernel (void)
|
||||
|
||||
if (load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys, NULL,
|
||||
(uint64_t *)&kernel_entry, NULL, (uint64_t *)&kernel_high,
|
||||
big_endian, EM_MIPS, 1) < 0) {
|
||||
big_endian, EM_MIPS, 1, 0) < 0) {
|
||||
fprintf(stderr, "qemu: could not load kernel '%s'\n",
|
||||
loaderparams.kernel_filename);
|
||||
exit(1);
|
||||
|
@ -70,7 +70,7 @@ static int64_t load_kernel(void)
|
||||
kernel_size = load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys,
|
||||
NULL, (uint64_t *)&entry, NULL,
|
||||
(uint64_t *)&kernel_high, big_endian,
|
||||
EM_MIPS, 1);
|
||||
EM_MIPS, 1, 0);
|
||||
if (kernel_size >= 0) {
|
||||
if ((entry & ~0x7fffffffULL) == 0x80000000)
|
||||
entry = (int32_t)entry;
|
||||
|
@ -88,7 +88,7 @@ static int64_t load_kernel(void)
|
||||
kernel_size = load_elf(loaderparams.kernel_filename, cpu_mips_kseg0_to_phys,
|
||||
NULL, (uint64_t *)&entry, NULL,
|
||||
(uint64_t *)&kernel_high, big_endian,
|
||||
EM_MIPS, 1);
|
||||
EM_MIPS, 1, 0);
|
||||
if (kernel_size >= 0) {
|
||||
if ((entry & ~0x7fffffffULL) == 0x80000000)
|
||||
entry = (int32_t)entry;
|
||||
|
@ -98,7 +98,7 @@ static void bcm2835_mbox_update(BCM2835MboxState *s)
|
||||
*/
|
||||
for (n = 0; n < MBOX_CHAN_COUNT; n++) {
|
||||
while (s->available[n] && !(s->mbox[0].status & ARM_MS_FULL)) {
|
||||
value = ldl_phys(&s->mbox_as, n << MBOX_AS_CHAN_SHIFT);
|
||||
value = ldl_le_phys(&s->mbox_as, n << MBOX_AS_CHAN_SHIFT);
|
||||
assert(value != MBOX_INVALID_DATA); /* Pending interrupt but no data */
|
||||
mbox_push(&s->mbox[0], value);
|
||||
}
|
||||
@ -207,12 +207,12 @@ static void bcm2835_mbox_write(void *opaque, hwaddr offset,
|
||||
ch = value & 0xf;
|
||||
if (ch < MBOX_CHAN_COUNT) {
|
||||
childaddr = ch << MBOX_AS_CHAN_SHIFT;
|
||||
if (ldl_phys(&s->mbox_as, childaddr + MBOX_AS_PENDING)) {
|
||||
if (ldl_le_phys(&s->mbox_as, childaddr + MBOX_AS_PENDING)) {
|
||||
/* Child busy, push delayed. Push it in the arm->vc mbox */
|
||||
mbox_push(&s->mbox[1], value);
|
||||
} else {
|
||||
/* Push it directly to the child device */
|
||||
stl_phys(&s->mbox_as, childaddr, value);
|
||||
stl_le_phys(&s->mbox_as, childaddr, value);
|
||||
}
|
||||
} else {
|
||||
/* Invalid channel number */
|
||||
|
@ -22,20 +22,20 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
|
||||
|
||||
s->addr = value;
|
||||
|
||||
tot_len = ldl_phys(&s->dma_as, value);
|
||||
tot_len = ldl_le_phys(&s->dma_as, value);
|
||||
|
||||
/* @(addr + 4) : Buffer response code */
|
||||
value = s->addr + 8;
|
||||
while (value + 8 <= s->addr + tot_len) {
|
||||
tag = ldl_phys(&s->dma_as, value);
|
||||
bufsize = ldl_phys(&s->dma_as, value + 4);
|
||||
tag = ldl_le_phys(&s->dma_as, value);
|
||||
bufsize = ldl_le_phys(&s->dma_as, value + 4);
|
||||
/* @(value + 8) : Request/response indicator */
|
||||
resplen = 0;
|
||||
switch (tag) {
|
||||
case 0x00000000: /* End tag */
|
||||
break;
|
||||
case 0x00000001: /* Get firmware revision */
|
||||
stl_phys(&s->dma_as, value + 12, 346337);
|
||||
stl_le_phys(&s->dma_as, value + 12, 346337);
|
||||
resplen = 4;
|
||||
break;
|
||||
case 0x00010001: /* Get board model */
|
||||
@ -44,7 +44,7 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
|
||||
resplen = 4;
|
||||
break;
|
||||
case 0x00010002: /* Get board revision */
|
||||
stl_phys(&s->dma_as, value + 12, s->board_rev);
|
||||
stl_le_phys(&s->dma_as, value + 12, s->board_rev);
|
||||
resplen = 4;
|
||||
break;
|
||||
case 0x00010003: /* Get board MAC address */
|
||||
@ -58,24 +58,24 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
|
||||
break;
|
||||
case 0x00010005: /* Get ARM memory */
|
||||
/* base */
|
||||
stl_phys(&s->dma_as, value + 12, 0);
|
||||
stl_le_phys(&s->dma_as, value + 12, 0);
|
||||
/* size */
|
||||
stl_phys(&s->dma_as, value + 16, s->ram_size);
|
||||
stl_le_phys(&s->dma_as, value + 16, s->ram_size);
|
||||
resplen = 8;
|
||||
break;
|
||||
case 0x00028001: /* Set power state */
|
||||
/* Assume that whatever device they asked for exists,
|
||||
* and we'll just claim we set it to the desired state
|
||||
*/
|
||||
tmp = ldl_phys(&s->dma_as, value + 16);
|
||||
stl_phys(&s->dma_as, value + 16, (tmp & 1));
|
||||
tmp = ldl_le_phys(&s->dma_as, value + 16);
|
||||
stl_le_phys(&s->dma_as, value + 16, (tmp & 1));
|
||||
resplen = 8;
|
||||
break;
|
||||
|
||||
/* Clocks */
|
||||
|
||||
case 0x00030001: /* Get clock state */
|
||||
stl_phys(&s->dma_as, value + 16, 0x1);
|
||||
stl_le_phys(&s->dma_as, value + 16, 0x1);
|
||||
resplen = 8;
|
||||
break;
|
||||
|
||||
@ -88,15 +88,15 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
|
||||
case 0x00030002: /* Get clock rate */
|
||||
case 0x00030004: /* Get max clock rate */
|
||||
case 0x00030007: /* Get min clock rate */
|
||||
switch (ldl_phys(&s->dma_as, value + 12)) {
|
||||
switch (ldl_le_phys(&s->dma_as, value + 12)) {
|
||||
case 1: /* EMMC */
|
||||
stl_phys(&s->dma_as, value + 16, 50000000);
|
||||
stl_le_phys(&s->dma_as, value + 16, 50000000);
|
||||
break;
|
||||
case 2: /* UART */
|
||||
stl_phys(&s->dma_as, value + 16, 3000000);
|
||||
stl_le_phys(&s->dma_as, value + 16, 3000000);
|
||||
break;
|
||||
default:
|
||||
stl_phys(&s->dma_as, value + 16, 700000000);
|
||||
stl_le_phys(&s->dma_as, value + 16, 700000000);
|
||||
break;
|
||||
}
|
||||
resplen = 8;
|
||||
@ -113,19 +113,19 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
|
||||
/* Temperature */
|
||||
|
||||
case 0x00030006: /* Get temperature */
|
||||
stl_phys(&s->dma_as, value + 16, 25000);
|
||||
stl_le_phys(&s->dma_as, value + 16, 25000);
|
||||
resplen = 8;
|
||||
break;
|
||||
|
||||
case 0x0003000A: /* Get max temperature */
|
||||
stl_phys(&s->dma_as, value + 16, 99000);
|
||||
stl_le_phys(&s->dma_as, value + 16, 99000);
|
||||
resplen = 8;
|
||||
break;
|
||||
|
||||
|
||||
case 0x00060001: /* Get DMA channels */
|
||||
/* channels 2-5 */
|
||||
stl_phys(&s->dma_as, value + 12, 0x003C);
|
||||
stl_le_phys(&s->dma_as, value + 12, 0x003C);
|
||||
resplen = 4;
|
||||
break;
|
||||
|
||||
@ -143,12 +143,12 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value)
|
||||
break;
|
||||
}
|
||||
|
||||
stl_phys(&s->dma_as, value + 8, (1 << 31) | resplen);
|
||||
stl_le_phys(&s->dma_as, value + 8, (1 << 31) | resplen);
|
||||
value += bufsize + 12;
|
||||
}
|
||||
|
||||
/* Buffer response code */
|
||||
stl_phys(&s->dma_as, s->addr + 4, (1 << 31));
|
||||
stl_le_phys(&s->dma_as, s->addr + 4, (1 << 31));
|
||||
}
|
||||
|
||||
static uint64_t bcm2835_property_read(void *opaque, hwaddr offset,
|
||||
|
@ -54,7 +54,8 @@ static void load_kernel(MoxieCPU *cpu, LoaderParams *loader_params)
|
||||
ram_addr_t initrd_offset;
|
||||
|
||||
kernel_size = load_elf(loader_params->kernel_filename, NULL, NULL,
|
||||
&entry, &kernel_low, &kernel_high, 1, EM_MOXIE, 0);
|
||||
&entry, &kernel_low, &kernel_high, 1, EM_MOXIE,
|
||||
0, 0);
|
||||
|
||||
if (kernel_size <= 0) {
|
||||
fprintf(stderr, "qemu: could not load kernel '%s'\n",
|
||||
|
@ -69,7 +69,8 @@ static void cpu_openrisc_load_kernel(ram_addr_t ram_size,
|
||||
|
||||
if (kernel_filename && !qtest_enabled()) {
|
||||
kernel_size = load_elf(kernel_filename, NULL, NULL,
|
||||
&elf_entry, NULL, NULL, 1, EM_OPENRISC, 1);
|
||||
&elf_entry, NULL, NULL, 1, EM_OPENRISC,
|
||||
1, 0);
|
||||
entry = elf_entry;
|
||||
if (kernel_size < 0) {
|
||||
kernel_size = load_uimage(kernel_filename,
|
||||
|
@ -313,7 +313,7 @@ static void raven_realize(PCIDevice *d, Error **errp)
|
||||
if (filename) {
|
||||
if (s->elf_machine != EM_NONE) {
|
||||
bios_size = load_elf(filename, NULL, NULL, NULL,
|
||||
NULL, NULL, 1, s->elf_machine, 0);
|
||||
NULL, NULL, 1, s->elf_machine, 0, 0);
|
||||
}
|
||||
if (bios_size < 0) {
|
||||
bios_size = get_image_size(filename);
|
||||
|
@ -1017,7 +1017,7 @@ void ppce500_init(MachineState *machine, PPCE500Params *params)
|
||||
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
|
||||
|
||||
bios_size = load_elf(filename, NULL, NULL, &bios_entry, &loadaddr, NULL,
|
||||
1, PPC_ELF_MACHINE, 0);
|
||||
1, PPC_ELF_MACHINE, 0, 0);
|
||||
if (bios_size < 0) {
|
||||
/*
|
||||
* Hrm. No ELF image? Try a uImage, maybe someone is giving us an
|
||||
|
@ -221,7 +221,7 @@ static void ppc_core99_init(MachineState *machine)
|
||||
/* Load OpenBIOS (ELF) */
|
||||
if (filename) {
|
||||
bios_size = load_elf(filename, NULL, NULL, NULL,
|
||||
NULL, NULL, 1, PPC_ELF_MACHINE, 0);
|
||||
NULL, NULL, 1, PPC_ELF_MACHINE, 0, 0);
|
||||
|
||||
g_free(filename);
|
||||
} else {
|
||||
@ -244,7 +244,8 @@ static void ppc_core99_init(MachineState *machine)
|
||||
kernel_base = KERNEL_LOAD_ADDR;
|
||||
|
||||
kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
|
||||
NULL, &lowaddr, NULL, 1, PPC_ELF_MACHINE, 0);
|
||||
NULL, &lowaddr, NULL, 1, PPC_ELF_MACHINE,
|
||||
0, 0);
|
||||
if (kernel_size < 0)
|
||||
kernel_size = load_aout(kernel_filename, kernel_base,
|
||||
ram_size - kernel_base, bswap_needed,
|
||||
|
@ -149,7 +149,7 @@ static void ppc_heathrow_init(MachineState *machine)
|
||||
/* Load OpenBIOS (ELF) */
|
||||
if (filename) {
|
||||
bios_size = load_elf(filename, 0, NULL, NULL, NULL, NULL,
|
||||
1, PPC_ELF_MACHINE, 0);
|
||||
1, PPC_ELF_MACHINE, 0, 0);
|
||||
g_free(filename);
|
||||
} else {
|
||||
bios_size = -1;
|
||||
@ -170,7 +170,8 @@ static void ppc_heathrow_init(MachineState *machine)
|
||||
#endif
|
||||
kernel_base = KERNEL_LOAD_ADDR;
|
||||
kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
|
||||
NULL, &lowaddr, NULL, 1, PPC_ELF_MACHINE, 0);
|
||||
NULL, &lowaddr, NULL, 1, PPC_ELF_MACHINE,
|
||||
0, 0);
|
||||
if (kernel_size < 0)
|
||||
kernel_size = load_aout(kernel_filename, kernel_base,
|
||||
ram_size - kernel_base, bswap_needed,
|
||||
|
@ -256,7 +256,8 @@ static void bamboo_init(MachineState *machine)
|
||||
NULL, NULL);
|
||||
if (success < 0) {
|
||||
success = load_elf(kernel_filename, NULL, NULL, &elf_entry,
|
||||
&elf_lowaddr, NULL, 1, PPC_ELF_MACHINE, 0);
|
||||
&elf_lowaddr, NULL, 1, PPC_ELF_MACHINE,
|
||||
0, 0);
|
||||
entry = elf_entry;
|
||||
loadaddr = elf_lowaddr;
|
||||
}
|
||||
|
@ -1942,11 +1942,13 @@ static void ppc_spapr_init(MachineState *machine)
|
||||
uint64_t lowaddr = 0;
|
||||
|
||||
kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
|
||||
NULL, &lowaddr, NULL, 1, PPC_ELF_MACHINE, 0);
|
||||
NULL, &lowaddr, NULL, 1, PPC_ELF_MACHINE,
|
||||
0, 0);
|
||||
if (kernel_size == ELF_LOAD_WRONG_ENDIAN) {
|
||||
kernel_size = load_elf(kernel_filename,
|
||||
translate_kernel_address, NULL,
|
||||
NULL, &lowaddr, NULL, 0, PPC_ELF_MACHINE, 0);
|
||||
NULL, &lowaddr, NULL, 0, PPC_ELF_MACHINE,
|
||||
0, 0);
|
||||
kernel_le = kernel_size > 0;
|
||||
}
|
||||
if (kernel_size < 0) {
|
||||
|
@ -258,7 +258,8 @@ static void virtex_init(MachineState *machine)
|
||||
|
||||
/* Boots a kernel elf binary. */
|
||||
kernel_size = load_elf(kernel_filename, NULL, NULL,
|
||||
&entry, &low, &high, 1, PPC_ELF_MACHINE, 0);
|
||||
&entry, &low, &high, 1, PPC_ELF_MACHINE,
|
||||
0, 0);
|
||||
boot_info.bootstrap_pc = entry & 0x00ffffff;
|
||||
|
||||
if (kernel_size < 0) {
|
||||
|
@ -101,7 +101,7 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
|
||||
|
||||
bios_size = load_elf(bios_filename, bios_translate_addr, &fwbase,
|
||||
&ipl->bios_start_addr, NULL, NULL, 1,
|
||||
EM_S390, 0);
|
||||
EM_S390, 0, 0);
|
||||
if (bios_size > 0) {
|
||||
/* Adjust ELF start address to final location */
|
||||
ipl->bios_start_addr += fwbase;
|
||||
@ -124,7 +124,7 @@ static void s390_ipl_realize(DeviceState *dev, Error **errp)
|
||||
|
||||
if (ipl->kernel) {
|
||||
kernel_size = load_elf(ipl->kernel, NULL, NULL, &pentry, NULL,
|
||||
NULL, 1, EM_S390, 0);
|
||||
NULL, 1, EM_S390, 0, 0);
|
||||
if (kernel_size < 0) {
|
||||
kernel_size = load_image_targphys(ipl->kernel, 0, ram_size);
|
||||
}
|
||||
|
@ -449,7 +449,7 @@ static void sd_reset(DeviceState *dev)
|
||||
|
||||
static bool sd_get_inserted(SDState *sd)
|
||||
{
|
||||
return blk_is_inserted(sd->blk);
|
||||
return sd->blk && blk_is_inserted(sd->blk);
|
||||
}
|
||||
|
||||
static bool sd_get_readonly(SDState *sd)
|
||||
|
@ -207,6 +207,21 @@ static void sdhci_reset(SDHCIState *s)
|
||||
s->pending_insert_state = false;
|
||||
}
|
||||
|
||||
static void sdhci_poweron_reset(DeviceState *dev)
|
||||
{
|
||||
/* QOM (ie power-on) reset. This is identical to reset
|
||||
* commanded via device register apart from handling of the
|
||||
* 'pending insert on powerup' quirk.
|
||||
*/
|
||||
SDHCIState *s = (SDHCIState *)dev;
|
||||
|
||||
sdhci_reset(s);
|
||||
|
||||
if (s->pending_insert_quirk) {
|
||||
s->pending_insert_state = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void sdhci_data_transfer(void *opaque);
|
||||
|
||||
static void sdhci_send_command(SDHCIState *s)
|
||||
@ -1290,6 +1305,7 @@ static void sdhci_pci_class_init(ObjectClass *klass, void *data)
|
||||
set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
|
||||
dc->vmsd = &sdhci_vmstate;
|
||||
dc->props = sdhci_pci_properties;
|
||||
dc->reset = sdhci_poweron_reset;
|
||||
}
|
||||
|
||||
static const TypeInfo sdhci_pci_info = {
|
||||
@ -1332,10 +1348,6 @@ static void sdhci_sysbus_realize(DeviceState *dev, Error ** errp)
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &sdhci_mmio_ops, s, "sdhci",
|
||||
SDHC_REGISTERS_MAP_SIZE);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
|
||||
if (s->pending_insert_quirk) {
|
||||
s->pending_insert_state = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void sdhci_sysbus_class_init(ObjectClass *klass, void *data)
|
||||
@ -1345,6 +1357,7 @@ static void sdhci_sysbus_class_init(ObjectClass *klass, void *data)
|
||||
dc->vmsd = &sdhci_vmstate;
|
||||
dc->props = sdhci_sysbus_properties;
|
||||
dc->realize = sdhci_sysbus_realize;
|
||||
dc->reset = sdhci_poweron_reset;
|
||||
}
|
||||
|
||||
static const TypeInfo sdhci_sysbus_info = {
|
||||
|
@ -194,7 +194,7 @@ static void leon3_generic_hw_init(MachineState *machine)
|
||||
uint64_t entry;
|
||||
|
||||
kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
|
||||
1 /* big endian */, EM_SPARC, 0);
|
||||
1 /* big endian */, EM_SPARC, 0, 0);
|
||||
if (kernel_size < 0) {
|
||||
fprintf(stderr, "qemu: could not load kernel '%s'\n",
|
||||
kernel_filename);
|
||||
|
@ -279,7 +279,7 @@ static unsigned long sun4m_load_kernel(const char *kernel_filename,
|
||||
bswap_needed = 0;
|
||||
#endif
|
||||
kernel_size = load_elf(kernel_filename, translate_kernel_address, NULL,
|
||||
NULL, NULL, NULL, 1, EM_SPARC, 0);
|
||||
NULL, NULL, NULL, 1, EM_SPARC, 0, 0);
|
||||
if (kernel_size < 0)
|
||||
kernel_size = load_aout(kernel_filename, KERNEL_LOAD_ADDR,
|
||||
RAM_size - KERNEL_LOAD_ADDR, bswap_needed,
|
||||
@ -723,7 +723,7 @@ static void prom_init(hwaddr addr, const char *bios_name)
|
||||
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
|
||||
if (filename) {
|
||||
ret = load_elf(filename, translate_prom_address, &addr, NULL,
|
||||
NULL, NULL, 1, EM_SPARC, 0);
|
||||
NULL, NULL, 1, EM_SPARC, 0, 0);
|
||||
if (ret < 0 || ret > PROM_SIZE_MAX) {
|
||||
ret = load_image_targphys(filename, addr, PROM_SIZE_MAX);
|
||||
}
|
||||
|
@ -187,7 +187,7 @@ static uint64_t sun4u_load_kernel(const char *kernel_filename,
|
||||
bswap_needed = 0;
|
||||
#endif
|
||||
kernel_size = load_elf(kernel_filename, NULL, NULL, kernel_entry,
|
||||
kernel_addr, &kernel_top, 1, EM_SPARCV9, 0);
|
||||
kernel_addr, &kernel_top, 1, EM_SPARCV9, 0, 0);
|
||||
if (kernel_size < 0) {
|
||||
*kernel_addr = KERNEL_LOAD_ADDR;
|
||||
*kernel_entry = KERNEL_LOAD_ADDR;
|
||||
@ -633,7 +633,7 @@ static void prom_init(hwaddr addr, const char *bios_name)
|
||||
filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
|
||||
if (filename) {
|
||||
ret = load_elf(filename, translate_prom_address, &addr,
|
||||
NULL, NULL, NULL, 1, EM_SPARCV9, 0);
|
||||
NULL, NULL, NULL, 1, EM_SPARCV9, 0, 0);
|
||||
if (ret < 0 || ret > PROM_SIZE_MAX) {
|
||||
ret = load_image_targphys(filename, addr, PROM_SIZE_MAX);
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ static void tricore_load_kernel(CPUTriCoreState *env)
|
||||
kernel_size = load_elf(tricoretb_binfo.kernel_filename, NULL,
|
||||
NULL, (uint64_t *)&entry, NULL,
|
||||
NULL, 0,
|
||||
EM_TRICORE, 1);
|
||||
EM_TRICORE, 1, 0);
|
||||
if (kernel_size <= 0) {
|
||||
error_report("qemu: no kernel file '%s'",
|
||||
tricoretb_binfo.kernel_filename);
|
||||
|
@ -94,10 +94,10 @@ static void xtensa_sim_init(MachineState *machine)
|
||||
uint64_t elf_lowaddr;
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
int success = load_elf(kernel_filename, translate_phys_addr, cpu,
|
||||
&elf_entry, &elf_lowaddr, NULL, 1, EM_XTENSA, 0);
|
||||
&elf_entry, &elf_lowaddr, NULL, 1, EM_XTENSA, 0, 0);
|
||||
#else
|
||||
int success = load_elf(kernel_filename, translate_phys_addr, cpu,
|
||||
&elf_entry, &elf_lowaddr, NULL, 0, EM_XTENSA, 0);
|
||||
&elf_entry, &elf_lowaddr, NULL, 0, EM_XTENSA, 0, 0);
|
||||
#endif
|
||||
if (success > 0) {
|
||||
env->pc = elf_entry;
|
||||
|
@ -355,7 +355,7 @@ static void lx_init(const LxBoardDesc *board, MachineState *machine)
|
||||
uint64_t elf_entry;
|
||||
uint64_t elf_lowaddr;
|
||||
int success = load_elf(kernel_filename, translate_phys_addr, cpu,
|
||||
&elf_entry, &elf_lowaddr, NULL, be, EM_XTENSA, 0);
|
||||
&elf_entry, &elf_lowaddr, NULL, be, EM_XTENSA, 0, 0);
|
||||
if (success > 0) {
|
||||
entry_point = elf_entry;
|
||||
} else {
|
||||
|
@ -16,6 +16,13 @@
|
||||
#include "qemu/notify.h"
|
||||
#include "cpu.h"
|
||||
|
||||
typedef enum {
|
||||
ARM_ENDIANNESS_UNKNOWN = 0,
|
||||
ARM_ENDIANNESS_LE,
|
||||
ARM_ENDIANNESS_BE8,
|
||||
ARM_ENDIANNESS_BE32,
|
||||
} arm_endianness;
|
||||
|
||||
/* armv7m.c */
|
||||
DeviceState *armv7m_init(MemoryRegion *system_memory, int mem_size, int num_irq,
|
||||
const char *kernel_filename, const char *cpu_model);
|
||||
@ -103,6 +110,8 @@ struct arm_boot_info {
|
||||
* changing to non-secure state if implementing a non-secure boot
|
||||
*/
|
||||
bool secure_board_setup;
|
||||
|
||||
arm_endianness endianness;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -61,6 +61,7 @@ enum {
|
||||
VIRT_PCIE_MMIO_HIGH,
|
||||
VIRT_GPIO,
|
||||
VIRT_SECURE_UART,
|
||||
VIRT_SECURE_MEM,
|
||||
};
|
||||
|
||||
typedef struct MemMapEntry {
|
||||
|
@ -263,7 +263,7 @@ static int glue(load_elf, SZ)(const char *name, int fd,
|
||||
void *translate_opaque,
|
||||
int must_swab, uint64_t *pentry,
|
||||
uint64_t *lowaddr, uint64_t *highaddr,
|
||||
int elf_machine, int clear_lsb)
|
||||
int elf_machine, int clear_lsb, int data_swab)
|
||||
{
|
||||
struct elfhdr ehdr;
|
||||
struct elf_phdr *phdr = NULL, *ph;
|
||||
@ -366,6 +366,26 @@ static int glue(load_elf, SZ)(const char *name, int fd,
|
||||
addr = ph->p_paddr;
|
||||
}
|
||||
|
||||
if (data_swab) {
|
||||
int j;
|
||||
for (j = 0; j < file_size; j += (1 << data_swab)) {
|
||||
uint8_t *dp = data + j;
|
||||
switch (data_swab) {
|
||||
case (1):
|
||||
*(uint16_t *)dp = bswap16(*(uint16_t *)dp);
|
||||
break;
|
||||
case (2):
|
||||
*(uint32_t *)dp = bswap32(*(uint32_t *)dp);
|
||||
break;
|
||||
case (3):
|
||||
*(uint64_t *)dp = bswap64(*(uint64_t *)dp);
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* the entry pointer in the ELF header is a virtual
|
||||
* address, if the text segments paddr and vaddr differ
|
||||
* we need to adjust the entry */
|
||||
|
@ -16,6 +16,18 @@ int load_image(const char *filename, uint8_t *addr); /* deprecated */
|
||||
ssize_t load_image_size(const char *filename, void *addr, size_t size);
|
||||
int load_image_targphys(const char *filename, hwaddr,
|
||||
uint64_t max_sz);
|
||||
/**
|
||||
* load_image_mr: load an image into a memory region
|
||||
* @filename: Path to the image file
|
||||
* @mr: Memory Region to load into
|
||||
*
|
||||
* Load the specified file into the memory region.
|
||||
* The file loaded is registered as a ROM, so its contents will be
|
||||
* reinstated whenever the system is reset.
|
||||
* If the file is larger than the memory region's size the call will fail.
|
||||
* Returns -1 on failure, or the size of the file.
|
||||
*/
|
||||
int load_image_mr(const char *filename, MemoryRegion *mr);
|
||||
|
||||
/* This is the limit on the maximum uncompressed image size that
|
||||
* load_image_gzipped_buffer() and load_image_gzipped() will read. It prevents
|
||||
@ -32,10 +44,49 @@ int load_image_gzipped(const char *filename, hwaddr addr, uint64_t max_sz);
|
||||
#define ELF_LOAD_WRONG_ARCH -3
|
||||
#define ELF_LOAD_WRONG_ENDIAN -4
|
||||
const char *load_elf_strerror(int error);
|
||||
|
||||
/** load_elf:
|
||||
* @filename: Path of ELF file
|
||||
* @translate_fn: optional function to translate load addresses
|
||||
* @translate_opaque: opaque data passed to @translate_fn
|
||||
* @pentry: Populated with program entry point. Ignored if NULL.
|
||||
* @lowaddr: Populated with lowest loaded address. Ignored if NULL.
|
||||
* @highaddr: Populated with highest loaded address. Ignored if NULL.
|
||||
* @bigendian: Expected ELF endianness. 0 for LE otherwise BE
|
||||
* @elf_machine: Expected ELF machine type
|
||||
* @clear_lsb: Set to mask off LSB of addresses (Some architectures use
|
||||
* this for non-address data)
|
||||
* @data_swab: Set to order of byte swapping for data. 0 for no swap, 1
|
||||
* for swapping bytes within halfwords, 2 for bytes within
|
||||
* words and 3 for within doublewords.
|
||||
*
|
||||
* Load an ELF file's contents to the emulated system's address space.
|
||||
* Clients may optionally specify a callback to perform address
|
||||
* translations. @pentry, @lowaddr and @highaddr are optional pointers
|
||||
* which will be populated with various load information. @bigendian and
|
||||
* @elf_machine give the expected endianness and machine for the ELF the
|
||||
* load will fail if the target ELF does not match. Some architectures
|
||||
* have some architecture-specific behaviours that come into effect when
|
||||
* their particular values for @elf_machine are set.
|
||||
*/
|
||||
|
||||
int load_elf(const char *filename, uint64_t (*translate_fn)(void *, uint64_t),
|
||||
void *translate_opaque, uint64_t *pentry, uint64_t *lowaddr,
|
||||
uint64_t *highaddr, int big_endian, int elf_machine,
|
||||
int clear_lsb);
|
||||
int clear_lsb, int data_swab);
|
||||
|
||||
/** load_elf_hdr:
|
||||
* @filename: Path of ELF file
|
||||
* @hdr: Buffer to populate with header data. Header data will not be
|
||||
* filled if set to NULL.
|
||||
* @is64: Set to true if the ELF is 64bit. Ignored if set to NULL
|
||||
* @errp: Populated with an error in failure cases
|
||||
*
|
||||
* Inspect an ELF file's header. Read its full header contents into a
|
||||
* buffer and/or determine if the ELF is 64bit.
|
||||
*/
|
||||
void load_elf_hdr(const char *filename, void *hdr, bool *is64, Error **errp);
|
||||
|
||||
int load_aout(const char *filename, hwaddr addr, int max_sz,
|
||||
int bswap_needed, hwaddr target_page_size);
|
||||
int load_uimage(const char *filename, hwaddr *ep,
|
||||
@ -67,7 +118,7 @@ extern bool rom_file_has_mr;
|
||||
|
||||
int rom_add_file(const char *file, const char *fw_dir,
|
||||
hwaddr addr, int32_t bootindex,
|
||||
bool option_rom);
|
||||
bool option_rom, MemoryRegion *mr);
|
||||
MemoryRegion *rom_add_blob(const char *name, const void *blob, size_t len,
|
||||
size_t max_len, hwaddr addr,
|
||||
const char *fw_file_name,
|
||||
@ -82,9 +133,11 @@ void *rom_ptr(hwaddr addr);
|
||||
void hmp_info_roms(Monitor *mon, const QDict *qdict);
|
||||
|
||||
#define rom_add_file_fixed(_f, _a, _i) \
|
||||
rom_add_file(_f, NULL, _a, _i, false)
|
||||
rom_add_file(_f, NULL, _a, _i, false, NULL)
|
||||
#define rom_add_blob_fixed(_f, _b, _l, _a) \
|
||||
rom_add_blob(_f, _b, _l, _l, _a, NULL, NULL, NULL)
|
||||
#define rom_add_file_mr(_f, _mr, _i) \
|
||||
rom_add_file(_f, NULL, 0, _i, false, mr)
|
||||
|
||||
#define PC_ROM_MIN_VGA 0xc0000
|
||||
#define PC_ROM_MIN_OPTION 0xc8000
|
||||
|
@ -435,22 +435,54 @@ void cpu_loop(CPUX86State *env)
|
||||
|
||||
#ifdef TARGET_ARM
|
||||
|
||||
#define get_user_code_u32(x, gaddr, doswap) \
|
||||
#define get_user_code_u32(x, gaddr, env) \
|
||||
({ abi_long __r = get_user_u32((x), (gaddr)); \
|
||||
if (!__r && (doswap)) { \
|
||||
if (!__r && bswap_code(arm_sctlr_b(env))) { \
|
||||
(x) = bswap32(x); \
|
||||
} \
|
||||
__r; \
|
||||
})
|
||||
|
||||
#define get_user_code_u16(x, gaddr, doswap) \
|
||||
#define get_user_code_u16(x, gaddr, env) \
|
||||
({ abi_long __r = get_user_u16((x), (gaddr)); \
|
||||
if (!__r && (doswap)) { \
|
||||
if (!__r && bswap_code(arm_sctlr_b(env))) { \
|
||||
(x) = bswap16(x); \
|
||||
} \
|
||||
__r; \
|
||||
})
|
||||
|
||||
#define get_user_data_u32(x, gaddr, env) \
|
||||
({ abi_long __r = get_user_u32((x), (gaddr)); \
|
||||
if (!__r && arm_cpu_bswap_data(env)) { \
|
||||
(x) = bswap32(x); \
|
||||
} \
|
||||
__r; \
|
||||
})
|
||||
|
||||
#define get_user_data_u16(x, gaddr, env) \
|
||||
({ abi_long __r = get_user_u16((x), (gaddr)); \
|
||||
if (!__r && arm_cpu_bswap_data(env)) { \
|
||||
(x) = bswap16(x); \
|
||||
} \
|
||||
__r; \
|
||||
})
|
||||
|
||||
#define put_user_data_u32(x, gaddr, env) \
|
||||
({ typeof(x) __x = (x); \
|
||||
if (arm_cpu_bswap_data(env)) { \
|
||||
__x = bswap32(__x); \
|
||||
} \
|
||||
put_user_u32(__x, (gaddr)); \
|
||||
})
|
||||
|
||||
#define put_user_data_u16(x, gaddr, env) \
|
||||
({ typeof(x) __x = (x); \
|
||||
if (arm_cpu_bswap_data(env)) { \
|
||||
__x = bswap16(__x); \
|
||||
} \
|
||||
put_user_u16(__x, (gaddr)); \
|
||||
})
|
||||
|
||||
#ifdef TARGET_ABI32
|
||||
/* Commpage handling -- there is no commpage for AArch64 */
|
||||
|
||||
@ -610,11 +642,11 @@ static int do_strex(CPUARMState *env)
|
||||
segv = get_user_u8(val, addr);
|
||||
break;
|
||||
case 1:
|
||||
segv = get_user_u16(val, addr);
|
||||
segv = get_user_data_u16(val, addr, env);
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
segv = get_user_u32(val, addr);
|
||||
segv = get_user_data_u32(val, addr, env);
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
@ -625,12 +657,16 @@ static int do_strex(CPUARMState *env)
|
||||
}
|
||||
if (size == 3) {
|
||||
uint32_t valhi;
|
||||
segv = get_user_u32(valhi, addr + 4);
|
||||
segv = get_user_data_u32(valhi, addr + 4, env);
|
||||
if (segv) {
|
||||
env->exception.vaddress = addr + 4;
|
||||
goto done;
|
||||
}
|
||||
val = deposit64(val, 32, 32, valhi);
|
||||
if (arm_cpu_bswap_data(env)) {
|
||||
val = deposit64((uint64_t)valhi, 32, 32, val);
|
||||
} else {
|
||||
val = deposit64(val, 32, 32, valhi);
|
||||
}
|
||||
}
|
||||
if (val != env->exclusive_val) {
|
||||
goto fail;
|
||||
@ -642,11 +678,11 @@ static int do_strex(CPUARMState *env)
|
||||
segv = put_user_u8(val, addr);
|
||||
break;
|
||||
case 1:
|
||||
segv = put_user_u16(val, addr);
|
||||
segv = put_user_data_u16(val, addr, env);
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
segv = put_user_u32(val, addr);
|
||||
segv = put_user_data_u32(val, addr, env);
|
||||
break;
|
||||
}
|
||||
if (segv) {
|
||||
@ -655,7 +691,7 @@ static int do_strex(CPUARMState *env)
|
||||
}
|
||||
if (size == 3) {
|
||||
val = env->regs[(env->exclusive_info >> 12) & 0xf];
|
||||
segv = put_user_u32(val, addr + 4);
|
||||
segv = put_user_data_u32(val, addr + 4, env);
|
||||
if (segv) {
|
||||
env->exception.vaddress = addr + 4;
|
||||
goto done;
|
||||
@ -692,7 +728,7 @@ void cpu_loop(CPUARMState *env)
|
||||
/* we handle the FPU emulation here, as Linux */
|
||||
/* we get the opcode */
|
||||
/* FIXME - what to do if get_user() fails? */
|
||||
get_user_code_u32(opcode, env->regs[15], env->bswap_code);
|
||||
get_user_code_u32(opcode, env->regs[15], env);
|
||||
|
||||
rc = EmulateAll(opcode, &ts->fpa, env);
|
||||
if (rc == 0) { /* illegal instruction */
|
||||
@ -762,25 +798,23 @@ void cpu_loop(CPUARMState *env)
|
||||
if (trapnr == EXCP_BKPT) {
|
||||
if (env->thumb) {
|
||||
/* FIXME - what to do if get_user() fails? */
|
||||
get_user_code_u16(insn, env->regs[15], env->bswap_code);
|
||||
get_user_code_u16(insn, env->regs[15], env);
|
||||
n = insn & 0xff;
|
||||
env->regs[15] += 2;
|
||||
} else {
|
||||
/* FIXME - what to do if get_user() fails? */
|
||||
get_user_code_u32(insn, env->regs[15], env->bswap_code);
|
||||
get_user_code_u32(insn, env->regs[15], env);
|
||||
n = (insn & 0xf) | ((insn >> 4) & 0xff0);
|
||||
env->regs[15] += 4;
|
||||
}
|
||||
} else {
|
||||
if (env->thumb) {
|
||||
/* FIXME - what to do if get_user() fails? */
|
||||
get_user_code_u16(insn, env->regs[15] - 2,
|
||||
env->bswap_code);
|
||||
get_user_code_u16(insn, env->regs[15] - 2, env);
|
||||
n = insn & 0xff;
|
||||
} else {
|
||||
/* FIXME - what to do if get_user() fails? */
|
||||
get_user_code_u32(insn, env->regs[15] - 4,
|
||||
env->bswap_code);
|
||||
get_user_code_u32(insn, env->regs[15] - 4, env);
|
||||
n = insn & 0xffffff;
|
||||
}
|
||||
}
|
||||
@ -4451,11 +4485,16 @@ int main(int argc, char **argv, char **envp)
|
||||
for(i = 0; i < 16; i++) {
|
||||
env->regs[i] = regs->uregs[i];
|
||||
}
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
/* Enable BE8. */
|
||||
if (EF_ARM_EABI_VERSION(info->elf_flags) >= EF_ARM_EABI_VER4
|
||||
&& (info->elf_flags & EF_ARM_BE8)) {
|
||||
env->bswap_code = 1;
|
||||
env->uncached_cpsr |= CPSR_E;
|
||||
env->cp15.sctlr_el[1] |= SCTLR_E0E;
|
||||
} else {
|
||||
env->cp15.sctlr_el[1] |= SCTLR_B;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#elif defined(TARGET_UNICORE32)
|
||||
{
|
||||
|
@ -1536,82 +1536,84 @@ static void
|
||||
setup_sigcontext(struct target_sigcontext *sc, /*struct _fpstate *fpstate,*/
|
||||
CPUARMState *env, abi_ulong mask)
|
||||
{
|
||||
__put_user(env->regs[0], &sc->arm_r0);
|
||||
__put_user(env->regs[1], &sc->arm_r1);
|
||||
__put_user(env->regs[2], &sc->arm_r2);
|
||||
__put_user(env->regs[3], &sc->arm_r3);
|
||||
__put_user(env->regs[4], &sc->arm_r4);
|
||||
__put_user(env->regs[5], &sc->arm_r5);
|
||||
__put_user(env->regs[6], &sc->arm_r6);
|
||||
__put_user(env->regs[7], &sc->arm_r7);
|
||||
__put_user(env->regs[8], &sc->arm_r8);
|
||||
__put_user(env->regs[9], &sc->arm_r9);
|
||||
__put_user(env->regs[10], &sc->arm_r10);
|
||||
__put_user(env->regs[11], &sc->arm_fp);
|
||||
__put_user(env->regs[12], &sc->arm_ip);
|
||||
__put_user(env->regs[13], &sc->arm_sp);
|
||||
__put_user(env->regs[14], &sc->arm_lr);
|
||||
__put_user(env->regs[15], &sc->arm_pc);
|
||||
__put_user(env->regs[0], &sc->arm_r0);
|
||||
__put_user(env->regs[1], &sc->arm_r1);
|
||||
__put_user(env->regs[2], &sc->arm_r2);
|
||||
__put_user(env->regs[3], &sc->arm_r3);
|
||||
__put_user(env->regs[4], &sc->arm_r4);
|
||||
__put_user(env->regs[5], &sc->arm_r5);
|
||||
__put_user(env->regs[6], &sc->arm_r6);
|
||||
__put_user(env->regs[7], &sc->arm_r7);
|
||||
__put_user(env->regs[8], &sc->arm_r8);
|
||||
__put_user(env->regs[9], &sc->arm_r9);
|
||||
__put_user(env->regs[10], &sc->arm_r10);
|
||||
__put_user(env->regs[11], &sc->arm_fp);
|
||||
__put_user(env->regs[12], &sc->arm_ip);
|
||||
__put_user(env->regs[13], &sc->arm_sp);
|
||||
__put_user(env->regs[14], &sc->arm_lr);
|
||||
__put_user(env->regs[15], &sc->arm_pc);
|
||||
#ifdef TARGET_CONFIG_CPU_32
|
||||
__put_user(cpsr_read(env), &sc->arm_cpsr);
|
||||
__put_user(cpsr_read(env), &sc->arm_cpsr);
|
||||
#endif
|
||||
|
||||
__put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
|
||||
__put_user(/* current->thread.error_code */ 0, &sc->error_code);
|
||||
__put_user(/* current->thread.address */ 0, &sc->fault_address);
|
||||
__put_user(mask, &sc->oldmask);
|
||||
__put_user(/* current->thread.trap_no */ 0, &sc->trap_no);
|
||||
__put_user(/* current->thread.error_code */ 0, &sc->error_code);
|
||||
__put_user(/* current->thread.address */ 0, &sc->fault_address);
|
||||
__put_user(mask, &sc->oldmask);
|
||||
}
|
||||
|
||||
static inline abi_ulong
|
||||
get_sigframe(struct target_sigaction *ka, CPUARMState *regs, int framesize)
|
||||
{
|
||||
unsigned long sp = regs->regs[13];
|
||||
unsigned long sp = regs->regs[13];
|
||||
|
||||
/*
|
||||
* This is the X/Open sanctioned signal stack switching.
|
||||
*/
|
||||
if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp))
|
||||
sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
|
||||
/*
|
||||
* ATPCS B01 mandates 8-byte alignment
|
||||
*/
|
||||
return (sp - framesize) & ~7;
|
||||
/*
|
||||
* This is the X/Open sanctioned signal stack switching.
|
||||
*/
|
||||
if ((ka->sa_flags & TARGET_SA_ONSTACK) && !sas_ss_flags(sp)) {
|
||||
sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size;
|
||||
}
|
||||
/*
|
||||
* ATPCS B01 mandates 8-byte alignment
|
||||
*/
|
||||
return (sp - framesize) & ~7;
|
||||
}
|
||||
|
||||
static void
|
||||
setup_return(CPUARMState *env, struct target_sigaction *ka,
|
||||
abi_ulong *rc, abi_ulong frame_addr, int usig, abi_ulong rc_addr)
|
||||
{
|
||||
abi_ulong handler = ka->_sa_handler;
|
||||
abi_ulong retcode;
|
||||
int thumb = handler & 1;
|
||||
uint32_t cpsr = cpsr_read(env);
|
||||
abi_ulong handler = ka->_sa_handler;
|
||||
abi_ulong retcode;
|
||||
int thumb = handler & 1;
|
||||
uint32_t cpsr = cpsr_read(env);
|
||||
|
||||
cpsr &= ~CPSR_IT;
|
||||
if (thumb) {
|
||||
cpsr |= CPSR_T;
|
||||
} else {
|
||||
cpsr &= ~CPSR_T;
|
||||
}
|
||||
cpsr &= ~CPSR_IT;
|
||||
if (thumb) {
|
||||
cpsr |= CPSR_T;
|
||||
} else {
|
||||
cpsr &= ~CPSR_T;
|
||||
}
|
||||
|
||||
if (ka->sa_flags & TARGET_SA_RESTORER) {
|
||||
retcode = ka->sa_restorer;
|
||||
} else {
|
||||
unsigned int idx = thumb;
|
||||
if (ka->sa_flags & TARGET_SA_RESTORER) {
|
||||
retcode = ka->sa_restorer;
|
||||
} else {
|
||||
unsigned int idx = thumb;
|
||||
|
||||
if (ka->sa_flags & TARGET_SA_SIGINFO)
|
||||
idx += 2;
|
||||
if (ka->sa_flags & TARGET_SA_SIGINFO) {
|
||||
idx += 2;
|
||||
}
|
||||
|
||||
__put_user(retcodes[idx], rc);
|
||||
|
||||
retcode = rc_addr + thumb;
|
||||
}
|
||||
retcode = rc_addr + thumb;
|
||||
}
|
||||
|
||||
env->regs[0] = usig;
|
||||
env->regs[13] = frame_addr;
|
||||
env->regs[14] = retcode;
|
||||
env->regs[15] = handler & (thumb ? ~1 : ~3);
|
||||
cpsr_write(env, cpsr, CPSR_IT | CPSR_T, CPSRWriteByInstr);
|
||||
env->regs[0] = usig;
|
||||
env->regs[13] = frame_addr;
|
||||
env->regs[14] = retcode;
|
||||
env->regs[15] = handler & (thumb ? ~1 : ~3);
|
||||
cpsr_write(env, cpsr, CPSR_IT | CPSR_T, CPSRWriteByInstr);
|
||||
}
|
||||
|
||||
static abi_ulong *setup_sigframe_v2_vfp(abi_ulong *regspace, CPUARMState *env)
|
||||
|
@ -25,10 +25,10 @@
|
||||
|
||||
/* Load an instruction and return it in the standard little-endian order */
|
||||
static inline uint32_t arm_ldl_code(CPUARMState *env, target_ulong addr,
|
||||
bool do_swap)
|
||||
bool sctlr_b)
|
||||
{
|
||||
uint32_t insn = cpu_ldl_code(env, addr);
|
||||
if (do_swap) {
|
||||
if (bswap_code(sctlr_b)) {
|
||||
return bswap32(insn);
|
||||
}
|
||||
return insn;
|
||||
@ -36,10 +36,10 @@ static inline uint32_t arm_ldl_code(CPUARMState *env, target_ulong addr,
|
||||
|
||||
/* Ditto, for a halfword (Thumb) instruction */
|
||||
static inline uint16_t arm_lduw_code(CPUARMState *env, target_ulong addr,
|
||||
bool do_swap)
|
||||
bool sctlr_b)
|
||||
{
|
||||
uint16_t insn = cpu_lduw_code(env, addr);
|
||||
if (do_swap) {
|
||||
if (bswap_code(sctlr_b)) {
|
||||
return bswap16(insn);
|
||||
}
|
||||
return insn;
|
||||
|
@ -369,26 +369,13 @@ static void arm_cpu_kvm_set_irq(void *opaque, int irq, int level)
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool arm_cpu_is_big_endian(CPUState *cs)
|
||||
static bool arm_cpu_virtio_is_big_endian(CPUState *cs)
|
||||
{
|
||||
ARMCPU *cpu = ARM_CPU(cs);
|
||||
CPUARMState *env = &cpu->env;
|
||||
int cur_el;
|
||||
|
||||
cpu_synchronize_state(cs);
|
||||
|
||||
/* In 32bit guest endianness is determined by looking at CPSR's E bit */
|
||||
if (!is_a64(env)) {
|
||||
return (env->uncached_cpsr & CPSR_E) ? 1 : 0;
|
||||
}
|
||||
|
||||
cur_el = arm_current_el(env);
|
||||
|
||||
if (cur_el == 0) {
|
||||
return (env->cp15.sctlr_el[1] & SCTLR_E0E) != 0;
|
||||
}
|
||||
|
||||
return (env->cp15.sctlr_el[cur_el] & SCTLR_EE) != 0;
|
||||
return arm_cpu_data_is_big_endian(env);
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -427,7 +414,7 @@ static void arm_disas_set_info(CPUState *cpu, disassemble_info *info)
|
||||
} else {
|
||||
info->print_insn = print_insn_arm;
|
||||
}
|
||||
if (env->bswap_code) {
|
||||
if (bswap_code(arm_sctlr_b(env))) {
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
info->endian = BFD_ENDIAN_LITTLE;
|
||||
#else
|
||||
@ -1476,7 +1463,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
|
||||
cc->get_phys_page_attrs_debug = arm_cpu_get_phys_page_attrs_debug;
|
||||
cc->asidx_from_attrs = arm_asidx_from_attrs;
|
||||
cc->vmsd = &vmstate_arm_cpu;
|
||||
cc->virtio_is_big_endian = arm_cpu_is_big_endian;
|
||||
cc->virtio_is_big_endian = arm_cpu_virtio_is_big_endian;
|
||||
cc->write_elf64_note = arm_cpu_write_elf64_note;
|
||||
cc->write_elf32_note = arm_cpu_write_elf32_note;
|
||||
#endif
|
||||
|
@ -478,9 +478,6 @@ typedef struct CPUARMState {
|
||||
uint32_t cregs[16];
|
||||
} iwmmxt;
|
||||
|
||||
/* For mixed endian mode. */
|
||||
bool bswap_code;
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
/* For usermode syscall translation. */
|
||||
int eabi;
|
||||
@ -1898,6 +1895,53 @@ static inline bool arm_singlestep_active(CPUARMState *env)
|
||||
&& arm_generate_debug_exceptions(env);
|
||||
}
|
||||
|
||||
static inline bool arm_sctlr_b(CPUARMState *env)
|
||||
{
|
||||
return
|
||||
/* We need not implement SCTLR.ITD in user-mode emulation, so
|
||||
* let linux-user ignore the fact that it conflicts with SCTLR_B.
|
||||
* This lets people run BE32 binaries with "-cpu any".
|
||||
*/
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
!arm_feature(env, ARM_FEATURE_V7) &&
|
||||
#endif
|
||||
(env->cp15.sctlr_el[1] & SCTLR_B) != 0;
|
||||
}
|
||||
|
||||
/* Return true if the processor is in big-endian mode. */
|
||||
static inline bool arm_cpu_data_is_big_endian(CPUARMState *env)
|
||||
{
|
||||
int cur_el;
|
||||
|
||||
/* In 32bit endianness is determined by looking at CPSR's E bit */
|
||||
if (!is_a64(env)) {
|
||||
return
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/* In system mode, BE32 is modelled in line with the
|
||||
* architecture (as word-invariant big-endianness), where loads
|
||||
* and stores are done little endian but from addresses which
|
||||
* are adjusted by XORing with the appropriate constant. So the
|
||||
* endianness to use for the raw data access is not affected by
|
||||
* SCTLR.B.
|
||||
* In user mode, however, we model BE32 as byte-invariant
|
||||
* big-endianness (because user-only code cannot tell the
|
||||
* difference), and so we need to use a data access endianness
|
||||
* that depends on SCTLR.B.
|
||||
*/
|
||||
arm_sctlr_b(env) ||
|
||||
#endif
|
||||
((env->uncached_cpsr & CPSR_E) ? 1 : 0);
|
||||
}
|
||||
|
||||
cur_el = arm_current_el(env);
|
||||
|
||||
if (cur_el == 0) {
|
||||
return (env->cp15.sctlr_el[1] & SCTLR_E0E) != 0;
|
||||
}
|
||||
|
||||
return (env->cp15.sctlr_el[cur_el] & SCTLR_EE) != 0;
|
||||
}
|
||||
|
||||
#include "exec/cpu-all.h"
|
||||
|
||||
/* Bit usage in the TB flags field: bit 31 indicates whether we are
|
||||
@ -1928,8 +1972,8 @@ static inline bool arm_singlestep_active(CPUARMState *env)
|
||||
#define ARM_TBFLAG_VFPEN_MASK (1 << ARM_TBFLAG_VFPEN_SHIFT)
|
||||
#define ARM_TBFLAG_CONDEXEC_SHIFT 8
|
||||
#define ARM_TBFLAG_CONDEXEC_MASK (0xff << ARM_TBFLAG_CONDEXEC_SHIFT)
|
||||
#define ARM_TBFLAG_BSWAP_CODE_SHIFT 16
|
||||
#define ARM_TBFLAG_BSWAP_CODE_MASK (1 << ARM_TBFLAG_BSWAP_CODE_SHIFT)
|
||||
#define ARM_TBFLAG_SCTLR_B_SHIFT 16
|
||||
#define ARM_TBFLAG_SCTLR_B_MASK (1 << ARM_TBFLAG_SCTLR_B_SHIFT)
|
||||
/* We store the bottom two bits of the CPAR as TB flags and handle
|
||||
* checks on the other bits at runtime
|
||||
*/
|
||||
@ -1941,6 +1985,8 @@ static inline bool arm_singlestep_active(CPUARMState *env)
|
||||
*/
|
||||
#define ARM_TBFLAG_NS_SHIFT 19
|
||||
#define ARM_TBFLAG_NS_MASK (1 << ARM_TBFLAG_NS_SHIFT)
|
||||
#define ARM_TBFLAG_BE_DATA_SHIFT 20
|
||||
#define ARM_TBFLAG_BE_DATA_MASK (1 << ARM_TBFLAG_BE_DATA_SHIFT)
|
||||
|
||||
/* Bit usage when in AArch64 state: currently we have no A64 specific bits */
|
||||
|
||||
@ -1965,12 +2011,34 @@ static inline bool arm_singlestep_active(CPUARMState *env)
|
||||
(((F) & ARM_TBFLAG_VFPEN_MASK) >> ARM_TBFLAG_VFPEN_SHIFT)
|
||||
#define ARM_TBFLAG_CONDEXEC(F) \
|
||||
(((F) & ARM_TBFLAG_CONDEXEC_MASK) >> ARM_TBFLAG_CONDEXEC_SHIFT)
|
||||
#define ARM_TBFLAG_BSWAP_CODE(F) \
|
||||
(((F) & ARM_TBFLAG_BSWAP_CODE_MASK) >> ARM_TBFLAG_BSWAP_CODE_SHIFT)
|
||||
#define ARM_TBFLAG_SCTLR_B(F) \
|
||||
(((F) & ARM_TBFLAG_SCTLR_B_MASK) >> ARM_TBFLAG_SCTLR_B_SHIFT)
|
||||
#define ARM_TBFLAG_XSCALE_CPAR(F) \
|
||||
(((F) & ARM_TBFLAG_XSCALE_CPAR_MASK) >> ARM_TBFLAG_XSCALE_CPAR_SHIFT)
|
||||
#define ARM_TBFLAG_NS(F) \
|
||||
(((F) & ARM_TBFLAG_NS_MASK) >> ARM_TBFLAG_NS_SHIFT)
|
||||
#define ARM_TBFLAG_BE_DATA(F) \
|
||||
(((F) & ARM_TBFLAG_BE_DATA_MASK) >> ARM_TBFLAG_BE_DATA_SHIFT)
|
||||
|
||||
static inline bool bswap_code(bool sctlr_b)
|
||||
{
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
/* BE8 (SCTLR.B = 0, TARGET_WORDS_BIGENDIAN = 1) is mixed endian.
|
||||
* The invalid combination SCTLR.B=1/CPSR.E=1/TARGET_WORDS_BIGENDIAN=0
|
||||
* would also end up as a mixed-endian mode with BE code, LE data.
|
||||
*/
|
||||
return
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
1 ^
|
||||
#endif
|
||||
sctlr_b;
|
||||
#else
|
||||
/* All code access in ARM is little endian, and there are no loaders
|
||||
* doing swaps that need to be reversed
|
||||
*/
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Return the exception level to which FP-disabled exceptions should
|
||||
* be taken, or 0 if FP is enabled.
|
||||
@ -2037,6 +2105,17 @@ static inline int fp_exception_el(CPUARMState *env)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
static inline bool arm_cpu_bswap_data(CPUARMState *env)
|
||||
{
|
||||
return
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
1 ^
|
||||
#endif
|
||||
arm_cpu_data_is_big_endian(env);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
|
||||
target_ulong *cs_base, int *flags)
|
||||
{
|
||||
@ -2049,7 +2128,7 @@ static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
|
||||
| (env->vfp.vec_len << ARM_TBFLAG_VECLEN_SHIFT)
|
||||
| (env->vfp.vec_stride << ARM_TBFLAG_VECSTRIDE_SHIFT)
|
||||
| (env->condexec_bits << ARM_TBFLAG_CONDEXEC_SHIFT)
|
||||
| (env->bswap_code << ARM_TBFLAG_BSWAP_CODE_SHIFT);
|
||||
| (arm_sctlr_b(env) << ARM_TBFLAG_SCTLR_B_SHIFT);
|
||||
if (!(access_secure_reg(env))) {
|
||||
*flags |= ARM_TBFLAG_NS_MASK;
|
||||
}
|
||||
@ -2081,6 +2160,9 @@ static inline void cpu_get_tb_cpu_state(CPUARMState *env, target_ulong *pc,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (arm_cpu_data_is_big_endian(env)) {
|
||||
*flags |= ARM_TBFLAG_BE_DATA_MASK;
|
||||
}
|
||||
*flags |= fp_exception_el(env) << ARM_TBFLAG_FPEXC_EL_SHIFT;
|
||||
|
||||
*cs_base = 0;
|
||||
|
@ -5490,9 +5490,16 @@ void cpsr_write(CPUARMState *env, uint32_t val, uint32_t mask,
|
||||
env->daif |= val & CPSR_AIF & mask;
|
||||
|
||||
if (write_type != CPSRWriteRaw &&
|
||||
(env->uncached_cpsr & CPSR_M) != CPSR_USER &&
|
||||
((env->uncached_cpsr ^ val) & mask & CPSR_M)) {
|
||||
if (bad_mode_switch(env, val & CPSR_M, write_type)) {
|
||||
if ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR) {
|
||||
/* Note that we can only get here in USR mode if this is a
|
||||
* gdb stub write; for this case we follow the architectural
|
||||
* behaviour for guest writes in USR mode of ignoring an attempt
|
||||
* to switch mode. (Those are caught by translate.c for writes
|
||||
* triggered by guest instructions.)
|
||||
*/
|
||||
mask &= ~CPSR_M;
|
||||
} else if (bad_mode_switch(env, val & CPSR_M, write_type)) {
|
||||
/* Attempt to switch to an invalid mode: this is UNPREDICTABLE in
|
||||
* v7, and has defined behaviour in v8:
|
||||
* + leave CPSR.M untouched
|
||||
@ -5841,7 +5848,7 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs)
|
||||
case EXCP_BKPT:
|
||||
if (semihosting_enabled()) {
|
||||
int nr;
|
||||
nr = arm_lduw_code(env, env->regs[15], env->bswap_code) & 0xff;
|
||||
nr = arm_lduw_code(env, env->regs[15], arm_sctlr_b(env)) & 0xff;
|
||||
if (nr == 0xab) {
|
||||
env->regs[15] += 2;
|
||||
qemu_log_mask(CPU_LOG_INT,
|
||||
@ -6234,6 +6241,11 @@ static void arm_cpu_do_interrupt_aarch32(CPUState *cs)
|
||||
env->condexec_bits = 0;
|
||||
/* Switch to the new mode, and to the correct instruction set. */
|
||||
env->uncached_cpsr = (env->uncached_cpsr & ~CPSR_M) | new_mode;
|
||||
/* Set new mode endianness */
|
||||
env->uncached_cpsr &= ~CPSR_E;
|
||||
if (env->cp15.sctlr_el[arm_current_el(env)] & SCTLR_EE) {
|
||||
env->uncached_cpsr |= ~CPSR_E;
|
||||
}
|
||||
env->daif |= mask;
|
||||
/* this is a lie, as the was no c1_sys on V4T/V5, but who cares
|
||||
* and we should just guard the thumb mode on V4 */
|
||||
@ -6379,13 +6391,13 @@ static inline bool check_for_semihosting(CPUState *cs)
|
||||
case EXCP_SWI:
|
||||
/* Check for semihosting interrupt. */
|
||||
if (env->thumb) {
|
||||
imm = arm_lduw_code(env, env->regs[15] - 2, env->bswap_code)
|
||||
imm = arm_lduw_code(env, env->regs[15] - 2, arm_sctlr_b(env))
|
||||
& 0xff;
|
||||
if (imm == 0xab) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
imm = arm_ldl_code(env, env->regs[15] - 4, env->bswap_code)
|
||||
imm = arm_ldl_code(env, env->regs[15] - 4, arm_sctlr_b(env))
|
||||
& 0xffffff;
|
||||
if (imm == 0x123456) {
|
||||
break;
|
||||
@ -6395,7 +6407,7 @@ static inline bool check_for_semihosting(CPUState *cs)
|
||||
case EXCP_BKPT:
|
||||
/* See if this is a semihosting syscall. */
|
||||
if (env->thumb) {
|
||||
imm = arm_lduw_code(env, env->regs[15], env->bswap_code)
|
||||
imm = arm_lduw_code(env, env->regs[15], arm_sctlr_b(env))
|
||||
& 0xff;
|
||||
if (imm == 0xab) {
|
||||
env->regs[15] += 2;
|
||||
@ -6520,6 +6532,12 @@ static inline bool regime_translation_disabled(CPUARMState *env,
|
||||
return (regime_sctlr(env, mmu_idx) & SCTLR_M) == 0;
|
||||
}
|
||||
|
||||
static inline bool regime_translation_big_endian(CPUARMState *env,
|
||||
ARMMMUIdx mmu_idx)
|
||||
{
|
||||
return (regime_sctlr(env, mmu_idx) & SCTLR_EE) != 0;
|
||||
}
|
||||
|
||||
/* Return the TCR controlling this translation regime */
|
||||
static inline TCR *regime_tcr(CPUARMState *env, ARMMMUIdx mmu_idx)
|
||||
{
|
||||
@ -6842,7 +6860,11 @@ static uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure,
|
||||
if (fi->s1ptw) {
|
||||
return 0;
|
||||
}
|
||||
return address_space_ldl(as, addr, attrs, NULL);
|
||||
if (regime_translation_big_endian(env, mmu_idx)) {
|
||||
return address_space_ldl_be(as, addr, attrs, NULL);
|
||||
} else {
|
||||
return address_space_ldl_le(as, addr, attrs, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure,
|
||||
@ -6860,7 +6882,11 @@ static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure,
|
||||
if (fi->s1ptw) {
|
||||
return 0;
|
||||
}
|
||||
return address_space_ldq(as, addr, attrs, NULL);
|
||||
if (regime_translation_big_endian(env, mmu_idx)) {
|
||||
return address_space_ldq_be(as, addr, attrs, NULL);
|
||||
} else {
|
||||
return address_space_ldq_le(as, addr, attrs, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static bool get_phys_addr_v5(CPUARMState *env, uint32_t address,
|
||||
|
@ -48,6 +48,7 @@ DEF_HELPER_FLAGS_3(sel_flags, TCG_CALL_NO_RWG_SE,
|
||||
i32, i32, i32, i32)
|
||||
DEF_HELPER_2(exception_internal, void, env, i32)
|
||||
DEF_HELPER_4(exception_with_syndrome, void, env, i32, i32, i32)
|
||||
DEF_HELPER_1(setend, void, env)
|
||||
DEF_HELPER_1(wfi, void, env)
|
||||
DEF_HELPER_1(wfe, void, env)
|
||||
DEF_HELPER_1(yield, void, env)
|
||||
|
@ -296,6 +296,11 @@ uint32_t HELPER(usat16)(CPUARMState *env, uint32_t x, uint32_t shift)
|
||||
return res;
|
||||
}
|
||||
|
||||
void HELPER(setend)(CPUARMState *env)
|
||||
{
|
||||
env->uncached_cpsr ^= CPSR_E;
|
||||
}
|
||||
|
||||
/* Function checks whether WFx (WFI/WFE) instructions are set up to be trapped.
|
||||
* The function returns the target EL (1-3) if the instruction is to be trapped;
|
||||
* otherwise it returns 0 indicating it is not trapped.
|
||||
|
@ -723,7 +723,7 @@ static void do_gpr_st_memidx(DisasContext *s, TCGv_i64 source,
|
||||
TCGv_i64 tcg_addr, int size, int memidx)
|
||||
{
|
||||
g_assert(size <= 3);
|
||||
tcg_gen_qemu_st_i64(source, tcg_addr, memidx, MO_TE + size);
|
||||
tcg_gen_qemu_st_i64(source, tcg_addr, memidx, s->be_data + size);
|
||||
}
|
||||
|
||||
static void do_gpr_st(DisasContext *s, TCGv_i64 source,
|
||||
@ -738,7 +738,7 @@ static void do_gpr_st(DisasContext *s, TCGv_i64 source,
|
||||
static void do_gpr_ld_memidx(DisasContext *s, TCGv_i64 dest, TCGv_i64 tcg_addr,
|
||||
int size, bool is_signed, bool extend, int memidx)
|
||||
{
|
||||
TCGMemOp memop = MO_TE + size;
|
||||
TCGMemOp memop = s->be_data + size;
|
||||
|
||||
g_assert(size <= 3);
|
||||
|
||||
@ -770,13 +770,18 @@ static void do_fp_st(DisasContext *s, int srcidx, TCGv_i64 tcg_addr, int size)
|
||||
TCGv_i64 tmp = tcg_temp_new_i64();
|
||||
tcg_gen_ld_i64(tmp, cpu_env, fp_reg_offset(s, srcidx, MO_64));
|
||||
if (size < 4) {
|
||||
tcg_gen_qemu_st_i64(tmp, tcg_addr, get_mem_index(s), MO_TE + size);
|
||||
tcg_gen_qemu_st_i64(tmp, tcg_addr, get_mem_index(s),
|
||||
s->be_data + size);
|
||||
} else {
|
||||
bool be = s->be_data == MO_BE;
|
||||
TCGv_i64 tcg_hiaddr = tcg_temp_new_i64();
|
||||
tcg_gen_qemu_st_i64(tmp, tcg_addr, get_mem_index(s), MO_TEQ);
|
||||
tcg_gen_ld_i64(tmp, cpu_env, fp_reg_hi_offset(s, srcidx));
|
||||
|
||||
tcg_gen_addi_i64(tcg_hiaddr, tcg_addr, 8);
|
||||
tcg_gen_qemu_st_i64(tmp, tcg_hiaddr, get_mem_index(s), MO_TEQ);
|
||||
tcg_gen_qemu_st_i64(tmp, be ? tcg_hiaddr : tcg_addr, get_mem_index(s),
|
||||
s->be_data | MO_Q);
|
||||
tcg_gen_ld_i64(tmp, cpu_env, fp_reg_hi_offset(s, srcidx));
|
||||
tcg_gen_qemu_st_i64(tmp, be ? tcg_addr : tcg_hiaddr, get_mem_index(s),
|
||||
s->be_data | MO_Q);
|
||||
tcg_temp_free_i64(tcg_hiaddr);
|
||||
}
|
||||
|
||||
@ -793,17 +798,21 @@ static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size)
|
||||
TCGv_i64 tmphi;
|
||||
|
||||
if (size < 4) {
|
||||
TCGMemOp memop = MO_TE + size;
|
||||
TCGMemOp memop = s->be_data + size;
|
||||
tmphi = tcg_const_i64(0);
|
||||
tcg_gen_qemu_ld_i64(tmplo, tcg_addr, get_mem_index(s), memop);
|
||||
} else {
|
||||
bool be = s->be_data == MO_BE;
|
||||
TCGv_i64 tcg_hiaddr;
|
||||
|
||||
tmphi = tcg_temp_new_i64();
|
||||
tcg_hiaddr = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_qemu_ld_i64(tmplo, tcg_addr, get_mem_index(s), MO_TEQ);
|
||||
tcg_gen_addi_i64(tcg_hiaddr, tcg_addr, 8);
|
||||
tcg_gen_qemu_ld_i64(tmphi, tcg_hiaddr, get_mem_index(s), MO_TEQ);
|
||||
tcg_gen_qemu_ld_i64(tmplo, be ? tcg_hiaddr : tcg_addr, get_mem_index(s),
|
||||
s->be_data | MO_Q);
|
||||
tcg_gen_qemu_ld_i64(tmphi, be ? tcg_addr : tcg_hiaddr, get_mem_index(s),
|
||||
s->be_data | MO_Q);
|
||||
tcg_temp_free_i64(tcg_hiaddr);
|
||||
}
|
||||
|
||||
@ -942,7 +951,7 @@ static void clear_vec_high(DisasContext *s, int rd)
|
||||
static void do_vec_st(DisasContext *s, int srcidx, int element,
|
||||
TCGv_i64 tcg_addr, int size)
|
||||
{
|
||||
TCGMemOp memop = MO_TE + size;
|
||||
TCGMemOp memop = s->be_data + size;
|
||||
TCGv_i64 tcg_tmp = tcg_temp_new_i64();
|
||||
|
||||
read_vec_element(s, tcg_tmp, srcidx, element, size);
|
||||
@ -955,7 +964,7 @@ static void do_vec_st(DisasContext *s, int srcidx, int element,
|
||||
static void do_vec_ld(DisasContext *s, int destidx, int element,
|
||||
TCGv_i64 tcg_addr, int size)
|
||||
{
|
||||
TCGMemOp memop = MO_TE + size;
|
||||
TCGMemOp memop = s->be_data + size;
|
||||
TCGv_i64 tcg_tmp = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_qemu_ld_i64(tcg_tmp, tcg_addr, get_mem_index(s), memop);
|
||||
@ -1702,7 +1711,7 @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
|
||||
TCGv_i64 addr, int size, bool is_pair)
|
||||
{
|
||||
TCGv_i64 tmp = tcg_temp_new_i64();
|
||||
TCGMemOp memop = MO_TE + size;
|
||||
TCGMemOp memop = s->be_data + size;
|
||||
|
||||
g_assert(size <= 3);
|
||||
tcg_gen_qemu_ld_i64(tmp, addr, get_mem_index(s), memop);
|
||||
@ -1764,7 +1773,7 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
|
||||
tcg_gen_brcond_i64(TCG_COND_NE, addr, cpu_exclusive_addr, fail_label);
|
||||
|
||||
tmp = tcg_temp_new_i64();
|
||||
tcg_gen_qemu_ld_i64(tmp, addr, get_mem_index(s), MO_TE + size);
|
||||
tcg_gen_qemu_ld_i64(tmp, addr, get_mem_index(s), s->be_data + size);
|
||||
tcg_gen_brcond_i64(TCG_COND_NE, tmp, cpu_exclusive_val, fail_label);
|
||||
tcg_temp_free_i64(tmp);
|
||||
|
||||
@ -1773,7 +1782,8 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
|
||||
TCGv_i64 tmphi = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_addi_i64(addrhi, addr, 1 << size);
|
||||
tcg_gen_qemu_ld_i64(tmphi, addrhi, get_mem_index(s), MO_TE + size);
|
||||
tcg_gen_qemu_ld_i64(tmphi, addrhi, get_mem_index(s),
|
||||
s->be_data + size);
|
||||
tcg_gen_brcond_i64(TCG_COND_NE, tmphi, cpu_exclusive_high, fail_label);
|
||||
|
||||
tcg_temp_free_i64(tmphi);
|
||||
@ -1781,13 +1791,14 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
|
||||
}
|
||||
|
||||
/* We seem to still have the exclusive monitor, so do the store */
|
||||
tcg_gen_qemu_st_i64(cpu_reg(s, rt), addr, get_mem_index(s), MO_TE + size);
|
||||
tcg_gen_qemu_st_i64(cpu_reg(s, rt), addr, get_mem_index(s),
|
||||
s->be_data + size);
|
||||
if (is_pair) {
|
||||
TCGv_i64 addrhi = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_addi_i64(addrhi, addr, 1 << size);
|
||||
tcg_gen_qemu_st_i64(cpu_reg(s, rt2), addrhi,
|
||||
get_mem_index(s), MO_TE + size);
|
||||
get_mem_index(s), s->be_data + size);
|
||||
tcg_temp_free_i64(addrhi);
|
||||
}
|
||||
|
||||
@ -2602,7 +2613,7 @@ static void disas_ldst_single_struct(DisasContext *s, uint32_t insn)
|
||||
TCGv_i64 tcg_tmp = tcg_temp_new_i64();
|
||||
|
||||
tcg_gen_qemu_ld_i64(tcg_tmp, tcg_addr,
|
||||
get_mem_index(s), MO_TE + scale);
|
||||
get_mem_index(s), s->be_data + scale);
|
||||
switch (scale) {
|
||||
case 0:
|
||||
mulconst = 0x0101010101010101ULL;
|
||||
@ -2632,9 +2643,9 @@ static void disas_ldst_single_struct(DisasContext *s, uint32_t insn)
|
||||
} else {
|
||||
/* Load/store one element per register */
|
||||
if (is_load) {
|
||||
do_vec_ld(s, rt, index, tcg_addr, MO_TE + scale);
|
||||
do_vec_ld(s, rt, index, tcg_addr, s->be_data + scale);
|
||||
} else {
|
||||
do_vec_st(s, rt, index, tcg_addr, MO_TE + scale);
|
||||
do_vec_st(s, rt, index, tcg_addr, s->be_data + scale);
|
||||
}
|
||||
}
|
||||
tcg_gen_addi_i64(tcg_addr, tcg_addr, ebytes);
|
||||
@ -10966,7 +10977,7 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s)
|
||||
{
|
||||
uint32_t insn;
|
||||
|
||||
insn = arm_ldl_code(env, s->pc, s->bswap_code);
|
||||
insn = arm_ldl_code(env, s->pc, s->sctlr_b);
|
||||
s->insn = insn;
|
||||
s->pc += 4;
|
||||
|
||||
@ -11031,7 +11042,8 @@ void gen_intermediate_code_a64(ARMCPU *cpu, TranslationBlock *tb)
|
||||
dc->secure_routed_to_el3 = arm_feature(env, ARM_FEATURE_EL3) &&
|
||||
!arm_el_is_aa64(env, 3);
|
||||
dc->thumb = 0;
|
||||
dc->bswap_code = 0;
|
||||
dc->sctlr_b = 0;
|
||||
dc->be_data = ARM_TBFLAG_BE_DATA(tb->flags) ? MO_BE : MO_LE;
|
||||
dc->condexec_mask = 0;
|
||||
dc->condexec_cond = 0;
|
||||
dc->mmu_idx = ARM_TBFLAG_MMUIDX(tb->flags);
|
||||
@ -11217,7 +11229,7 @@ done_generating:
|
||||
qemu_log("----------------\n");
|
||||
qemu_log("IN: %s\n", lookup_symbol(pc_start));
|
||||
log_target_disas(cs, pc_start, dc->pc - pc_start,
|
||||
4 | (dc->bswap_code << 1));
|
||||
4 | (bswap_code(dc->sctlr_b) ? 2 : 0));
|
||||
qemu_log("\n");
|
||||
}
|
||||
#endif
|
||||
|
@ -911,6 +911,12 @@ static inline void store_reg_from_load(DisasContext *s, int reg, TCGv_i32 var)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_USER_ONLY
|
||||
#define IS_USER_ONLY 1
|
||||
#else
|
||||
#define IS_USER_ONLY 0
|
||||
#endif
|
||||
|
||||
/* Abstractions of "generate code to do a guest load/store for
|
||||
* AArch32", where a vaddr is always 32 bits (and is zero
|
||||
* extended if we're a 64 bit core) and data is also
|
||||
@ -920,77 +926,143 @@ static inline void store_reg_from_load(DisasContext *s, int reg, TCGv_i32 var)
|
||||
*/
|
||||
#if TARGET_LONG_BITS == 32
|
||||
|
||||
#define DO_GEN_LD(SUFF, OPC) \
|
||||
static inline void gen_aa32_ld##SUFF(TCGv_i32 val, TCGv_i32 addr, int index) \
|
||||
#define DO_GEN_LD(SUFF, OPC, BE32_XOR) \
|
||||
static inline void gen_aa32_ld##SUFF(DisasContext *s, TCGv_i32 val, \
|
||||
TCGv_i32 addr, int index) \
|
||||
{ \
|
||||
tcg_gen_qemu_ld_i32(val, addr, index, (OPC)); \
|
||||
TCGMemOp opc = (OPC) | s->be_data; \
|
||||
/* Not needed for user-mode BE32, where we use MO_BE instead. */ \
|
||||
if (!IS_USER_ONLY && s->sctlr_b && BE32_XOR) { \
|
||||
TCGv addr_be = tcg_temp_new(); \
|
||||
tcg_gen_xori_i32(addr_be, addr, BE32_XOR); \
|
||||
tcg_gen_qemu_ld_i32(val, addr_be, index, opc); \
|
||||
tcg_temp_free(addr_be); \
|
||||
return; \
|
||||
} \
|
||||
tcg_gen_qemu_ld_i32(val, addr, index, opc); \
|
||||
}
|
||||
|
||||
#define DO_GEN_ST(SUFF, OPC) \
|
||||
static inline void gen_aa32_st##SUFF(TCGv_i32 val, TCGv_i32 addr, int index) \
|
||||
#define DO_GEN_ST(SUFF, OPC, BE32_XOR) \
|
||||
static inline void gen_aa32_st##SUFF(DisasContext *s, TCGv_i32 val, \
|
||||
TCGv_i32 addr, int index) \
|
||||
{ \
|
||||
tcg_gen_qemu_st_i32(val, addr, index, (OPC)); \
|
||||
TCGMemOp opc = (OPC) | s->be_data; \
|
||||
/* Not needed for user-mode BE32, where we use MO_BE instead. */ \
|
||||
if (!IS_USER_ONLY && s->sctlr_b && BE32_XOR) { \
|
||||
TCGv addr_be = tcg_temp_new(); \
|
||||
tcg_gen_xori_i32(addr_be, addr, BE32_XOR); \
|
||||
tcg_gen_qemu_st_i32(val, addr_be, index, opc); \
|
||||
tcg_temp_free(addr_be); \
|
||||
return; \
|
||||
} \
|
||||
tcg_gen_qemu_st_i32(val, addr, index, opc); \
|
||||
}
|
||||
|
||||
static inline void gen_aa32_ld64(TCGv_i64 val, TCGv_i32 addr, int index)
|
||||
static inline void gen_aa32_ld64(DisasContext *s, TCGv_i64 val,
|
||||
TCGv_i32 addr, int index)
|
||||
{
|
||||
tcg_gen_qemu_ld_i64(val, addr, index, MO_TEQ);
|
||||
TCGMemOp opc = MO_Q | s->be_data;
|
||||
tcg_gen_qemu_ld_i64(val, addr, index, opc);
|
||||
/* Not needed for user-mode BE32, where we use MO_BE instead. */
|
||||
if (!IS_USER_ONLY && s->sctlr_b) {
|
||||
tcg_gen_rotri_i64(val, val, 32);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void gen_aa32_st64(TCGv_i64 val, TCGv_i32 addr, int index)
|
||||
static inline void gen_aa32_st64(DisasContext *s, TCGv_i64 val,
|
||||
TCGv_i32 addr, int index)
|
||||
{
|
||||
tcg_gen_qemu_st_i64(val, addr, index, MO_TEQ);
|
||||
TCGMemOp opc = MO_Q | s->be_data;
|
||||
/* Not needed for user-mode BE32, where we use MO_BE instead. */
|
||||
if (!IS_USER_ONLY && s->sctlr_b) {
|
||||
TCGv_i64 tmp = tcg_temp_new_i64();
|
||||
tcg_gen_rotri_i64(tmp, val, 32);
|
||||
tcg_gen_qemu_st_i64(tmp, addr, index, opc);
|
||||
tcg_temp_free_i64(tmp);
|
||||
return;
|
||||
}
|
||||
tcg_gen_qemu_st_i64(val, addr, index, opc);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define DO_GEN_LD(SUFF, OPC) \
|
||||
static inline void gen_aa32_ld##SUFF(TCGv_i32 val, TCGv_i32 addr, int index) \
|
||||
#define DO_GEN_LD(SUFF, OPC, BE32_XOR) \
|
||||
static inline void gen_aa32_ld##SUFF(DisasContext *s, TCGv_i32 val, \
|
||||
TCGv_i32 addr, int index) \
|
||||
{ \
|
||||
TCGMemOp opc = (OPC) | s->be_data; \
|
||||
TCGv addr64 = tcg_temp_new(); \
|
||||
tcg_gen_extu_i32_i64(addr64, addr); \
|
||||
tcg_gen_qemu_ld_i32(val, addr64, index, OPC); \
|
||||
/* Not needed for user-mode BE32, where we use MO_BE instead. */ \
|
||||
if (!IS_USER_ONLY && s->sctlr_b && BE32_XOR) { \
|
||||
tcg_gen_xori_i64(addr64, addr64, BE32_XOR); \
|
||||
} \
|
||||
tcg_gen_qemu_ld_i32(val, addr64, index, opc); \
|
||||
tcg_temp_free(addr64); \
|
||||
}
|
||||
|
||||
#define DO_GEN_ST(SUFF, OPC) \
|
||||
static inline void gen_aa32_st##SUFF(TCGv_i32 val, TCGv_i32 addr, int index) \
|
||||
#define DO_GEN_ST(SUFF, OPC, BE32_XOR) \
|
||||
static inline void gen_aa32_st##SUFF(DisasContext *s, TCGv_i32 val, \
|
||||
TCGv_i32 addr, int index) \
|
||||
{ \
|
||||
TCGMemOp opc = (OPC) | s->be_data; \
|
||||
TCGv addr64 = tcg_temp_new(); \
|
||||
tcg_gen_extu_i32_i64(addr64, addr); \
|
||||
tcg_gen_qemu_st_i32(val, addr64, index, OPC); \
|
||||
/* Not needed for user-mode BE32, where we use MO_BE instead. */ \
|
||||
if (!IS_USER_ONLY && s->sctlr_b && BE32_XOR) { \
|
||||
tcg_gen_xori_i64(addr64, addr64, BE32_XOR); \
|
||||
} \
|
||||
tcg_gen_qemu_st_i32(val, addr64, index, opc); \
|
||||
tcg_temp_free(addr64); \
|
||||
}
|
||||
|
||||
static inline void gen_aa32_ld64(TCGv_i64 val, TCGv_i32 addr, int index)
|
||||
static inline void gen_aa32_ld64(DisasContext *s, TCGv_i64 val,
|
||||
TCGv_i32 addr, int index)
|
||||
{
|
||||
TCGMemOp opc = MO_Q | s->be_data;
|
||||
TCGv addr64 = tcg_temp_new();
|
||||
tcg_gen_extu_i32_i64(addr64, addr);
|
||||
tcg_gen_qemu_ld_i64(val, addr64, index, MO_TEQ);
|
||||
tcg_gen_qemu_ld_i64(val, addr64, index, opc);
|
||||
|
||||
/* Not needed for user-mode BE32, where we use MO_BE instead. */
|
||||
if (!IS_USER_ONLY && s->sctlr_b) {
|
||||
tcg_gen_rotri_i64(val, val, 32);
|
||||
}
|
||||
tcg_temp_free(addr64);
|
||||
}
|
||||
|
||||
static inline void gen_aa32_st64(TCGv_i64 val, TCGv_i32 addr, int index)
|
||||
static inline void gen_aa32_st64(DisasContext *s, TCGv_i64 val,
|
||||
TCGv_i32 addr, int index)
|
||||
{
|
||||
TCGMemOp opc = MO_Q | s->be_data;
|
||||
TCGv addr64 = tcg_temp_new();
|
||||
tcg_gen_extu_i32_i64(addr64, addr);
|
||||
tcg_gen_qemu_st_i64(val, addr64, index, MO_TEQ);
|
||||
|
||||
/* Not needed for user-mode BE32, where we use MO_BE instead. */
|
||||
if (!IS_USER_ONLY && s->sctlr_b) {
|
||||
TCGv tmp = tcg_temp_new();
|
||||
tcg_gen_rotri_i64(tmp, val, 32);
|
||||
tcg_gen_qemu_st_i64(tmp, addr64, index, opc);
|
||||
tcg_temp_free(tmp);
|
||||
} else {
|
||||
tcg_gen_qemu_st_i64(val, addr64, index, opc);
|
||||
}
|
||||
tcg_temp_free(addr64);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
DO_GEN_LD(8s, MO_SB)
|
||||
DO_GEN_LD(8u, MO_UB)
|
||||
DO_GEN_LD(16s, MO_TESW)
|
||||
DO_GEN_LD(16u, MO_TEUW)
|
||||
DO_GEN_LD(32u, MO_TEUL)
|
||||
DO_GEN_LD(8s, MO_SB, 3)
|
||||
DO_GEN_LD(8u, MO_UB, 3)
|
||||
DO_GEN_LD(16s, MO_SW, 2)
|
||||
DO_GEN_LD(16u, MO_UW, 2)
|
||||
DO_GEN_LD(32u, MO_UL, 0)
|
||||
/* 'a' variants include an alignment check */
|
||||
DO_GEN_LD(16ua, MO_TEUW | MO_ALIGN)
|
||||
DO_GEN_LD(32ua, MO_TEUL | MO_ALIGN)
|
||||
DO_GEN_ST(8, MO_UB)
|
||||
DO_GEN_ST(16, MO_TEUW)
|
||||
DO_GEN_ST(32, MO_TEUL)
|
||||
DO_GEN_LD(16ua, MO_UW | MO_ALIGN, 2)
|
||||
DO_GEN_LD(32ua, MO_UL | MO_ALIGN, 0)
|
||||
DO_GEN_ST(8, MO_UB, 3)
|
||||
DO_GEN_ST(16, MO_UW, 2)
|
||||
DO_GEN_ST(32, MO_UL, 0)
|
||||
|
||||
static inline void gen_set_pc_im(DisasContext *s, target_ulong val)
|
||||
{
|
||||
@ -1285,18 +1357,18 @@ VFP_GEN_FIX(ulto, )
|
||||
static inline void gen_vfp_ld(DisasContext *s, int dp, TCGv_i32 addr)
|
||||
{
|
||||
if (dp) {
|
||||
gen_aa32_ld64(cpu_F0d, addr, get_mem_index(s));
|
||||
gen_aa32_ld64(s, cpu_F0d, addr, get_mem_index(s));
|
||||
} else {
|
||||
gen_aa32_ld32u(cpu_F0s, addr, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, cpu_F0s, addr, get_mem_index(s));
|
||||
}
|
||||
}
|
||||
|
||||
static inline void gen_vfp_st(DisasContext *s, int dp, TCGv_i32 addr)
|
||||
{
|
||||
if (dp) {
|
||||
gen_aa32_st64(cpu_F0d, addr, get_mem_index(s));
|
||||
gen_aa32_st64(s, cpu_F0d, addr, get_mem_index(s));
|
||||
} else {
|
||||
gen_aa32_st32(cpu_F0s, addr, get_mem_index(s));
|
||||
gen_aa32_st32(s, cpu_F0s, addr, get_mem_index(s));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1632,24 +1704,24 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
|
||||
if (insn & ARM_CP_RW_BIT) {
|
||||
if ((insn >> 28) == 0xf) { /* WLDRW wCx */
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
|
||||
iwmmxt_store_creg(wrd, tmp);
|
||||
} else {
|
||||
i = 1;
|
||||
if (insn & (1 << 8)) {
|
||||
if (insn & (1 << 22)) { /* WLDRD */
|
||||
gen_aa32_ld64(cpu_M0, addr, get_mem_index(s));
|
||||
gen_aa32_ld64(s, cpu_M0, addr, get_mem_index(s));
|
||||
i = 0;
|
||||
} else { /* WLDRW wRd */
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
|
||||
}
|
||||
} else {
|
||||
tmp = tcg_temp_new_i32();
|
||||
if (insn & (1 << 22)) { /* WLDRH */
|
||||
gen_aa32_ld16u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
|
||||
} else { /* WLDRB */
|
||||
gen_aa32_ld8u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
|
||||
}
|
||||
}
|
||||
if (i) {
|
||||
@ -1661,24 +1733,24 @@ static int disas_iwmmxt_insn(DisasContext *s, uint32_t insn)
|
||||
} else {
|
||||
if ((insn >> 28) == 0xf) { /* WSTRW wCx */
|
||||
tmp = iwmmxt_load_creg(wrd);
|
||||
gen_aa32_st32(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
|
||||
} else {
|
||||
gen_op_iwmmxt_movq_M0_wRn(wrd);
|
||||
tmp = tcg_temp_new_i32();
|
||||
if (insn & (1 << 8)) {
|
||||
if (insn & (1 << 22)) { /* WSTRD */
|
||||
gen_aa32_st64(cpu_M0, addr, get_mem_index(s));
|
||||
gen_aa32_st64(s, cpu_M0, addr, get_mem_index(s));
|
||||
} else { /* WSTRW wRd */
|
||||
tcg_gen_extrl_i64_i32(tmp, cpu_M0);
|
||||
gen_aa32_st32(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
|
||||
}
|
||||
} else {
|
||||
if (insn & (1 << 22)) { /* WSTRH */
|
||||
tcg_gen_extrl_i64_i32(tmp, cpu_M0);
|
||||
gen_aa32_st16(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st16(s, tmp, addr, get_mem_index(s));
|
||||
} else { /* WSTRB */
|
||||
tcg_gen_extrl_i64_i32(tmp, cpu_M0);
|
||||
gen_aa32_st8(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st8(s, tmp, addr, get_mem_index(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2743,15 +2815,15 @@ static TCGv_i32 gen_load_and_replicate(DisasContext *s, TCGv_i32 addr, int size)
|
||||
TCGv_i32 tmp = tcg_temp_new_i32();
|
||||
switch (size) {
|
||||
case 0:
|
||||
gen_aa32_ld8u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
|
||||
gen_neon_dup_u8(tmp, 0);
|
||||
break;
|
||||
case 1:
|
||||
gen_aa32_ld16u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
|
||||
gen_neon_dup_low16(tmp);
|
||||
break;
|
||||
case 2:
|
||||
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
default: /* Avoid compiler warnings. */
|
||||
abort();
|
||||
@ -4449,11 +4521,11 @@ static int disas_neon_ls_insn(DisasContext *s, uint32_t insn)
|
||||
if (size == 3) {
|
||||
tmp64 = tcg_temp_new_i64();
|
||||
if (load) {
|
||||
gen_aa32_ld64(tmp64, addr, get_mem_index(s));
|
||||
gen_aa32_ld64(s, tmp64, addr, get_mem_index(s));
|
||||
neon_store_reg64(tmp64, rd);
|
||||
} else {
|
||||
neon_load_reg64(tmp64, rd);
|
||||
gen_aa32_st64(tmp64, addr, get_mem_index(s));
|
||||
gen_aa32_st64(s, tmp64, addr, get_mem_index(s));
|
||||
}
|
||||
tcg_temp_free_i64(tmp64);
|
||||
tcg_gen_addi_i32(addr, addr, stride);
|
||||
@ -4462,21 +4534,21 @@ static int disas_neon_ls_insn(DisasContext *s, uint32_t insn)
|
||||
if (size == 2) {
|
||||
if (load) {
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
|
||||
neon_store_reg(rd, pass, tmp);
|
||||
} else {
|
||||
tmp = neon_load_reg(rd, pass);
|
||||
gen_aa32_st32(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp);
|
||||
}
|
||||
tcg_gen_addi_i32(addr, addr, stride);
|
||||
} else if (size == 1) {
|
||||
if (load) {
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld16u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
|
||||
tcg_gen_addi_i32(addr, addr, stride);
|
||||
tmp2 = tcg_temp_new_i32();
|
||||
gen_aa32_ld16u(tmp2, addr, get_mem_index(s));
|
||||
gen_aa32_ld16u(s, tmp2, addr, get_mem_index(s));
|
||||
tcg_gen_addi_i32(addr, addr, stride);
|
||||
tcg_gen_shli_i32(tmp2, tmp2, 16);
|
||||
tcg_gen_or_i32(tmp, tmp, tmp2);
|
||||
@ -4486,10 +4558,10 @@ static int disas_neon_ls_insn(DisasContext *s, uint32_t insn)
|
||||
tmp = neon_load_reg(rd, pass);
|
||||
tmp2 = tcg_temp_new_i32();
|
||||
tcg_gen_shri_i32(tmp2, tmp, 16);
|
||||
gen_aa32_st16(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st16(s, tmp, addr, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp);
|
||||
tcg_gen_addi_i32(addr, addr, stride);
|
||||
gen_aa32_st16(tmp2, addr, get_mem_index(s));
|
||||
gen_aa32_st16(s, tmp2, addr, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp2);
|
||||
tcg_gen_addi_i32(addr, addr, stride);
|
||||
}
|
||||
@ -4498,7 +4570,7 @@ static int disas_neon_ls_insn(DisasContext *s, uint32_t insn)
|
||||
TCGV_UNUSED_I32(tmp2);
|
||||
for (n = 0; n < 4; n++) {
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld8u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
|
||||
tcg_gen_addi_i32(addr, addr, stride);
|
||||
if (n == 0) {
|
||||
tmp2 = tmp;
|
||||
@ -4518,7 +4590,7 @@ static int disas_neon_ls_insn(DisasContext *s, uint32_t insn)
|
||||
} else {
|
||||
tcg_gen_shri_i32(tmp, tmp2, n * 8);
|
||||
}
|
||||
gen_aa32_st8(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st8(s, tmp, addr, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp);
|
||||
tcg_gen_addi_i32(addr, addr, stride);
|
||||
}
|
||||
@ -4642,13 +4714,13 @@ static int disas_neon_ls_insn(DisasContext *s, uint32_t insn)
|
||||
tmp = tcg_temp_new_i32();
|
||||
switch (size) {
|
||||
case 0:
|
||||
gen_aa32_ld8u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
case 1:
|
||||
gen_aa32_ld16u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
case 2:
|
||||
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
default: /* Avoid compiler warnings. */
|
||||
abort();
|
||||
@ -4666,13 +4738,13 @@ static int disas_neon_ls_insn(DisasContext *s, uint32_t insn)
|
||||
tcg_gen_shri_i32(tmp, tmp, shift);
|
||||
switch (size) {
|
||||
case 0:
|
||||
gen_aa32_st8(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st8(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
case 1:
|
||||
gen_aa32_st16(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st16(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
case 2:
|
||||
gen_aa32_st32(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
}
|
||||
tcg_temp_free_i32(tmp);
|
||||
@ -7435,14 +7507,14 @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
|
||||
|
||||
switch (size) {
|
||||
case 0:
|
||||
gen_aa32_ld8u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
case 1:
|
||||
gen_aa32_ld16ua(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld16ua(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
gen_aa32_ld32ua(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld32ua(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
@ -7453,7 +7525,7 @@ static void gen_load_exclusive(DisasContext *s, int rt, int rt2,
|
||||
TCGv_i32 tmp3 = tcg_temp_new_i32();
|
||||
|
||||
tcg_gen_addi_i32(tmp2, addr, 4);
|
||||
gen_aa32_ld32u(tmp3, tmp2, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp3, tmp2, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp2);
|
||||
tcg_gen_concat_i32_i64(cpu_exclusive_val, tmp, tmp3);
|
||||
store_reg(s, rt2, tmp3);
|
||||
@ -7504,14 +7576,14 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
|
||||
tmp = tcg_temp_new_i32();
|
||||
switch (size) {
|
||||
case 0:
|
||||
gen_aa32_ld8u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
case 1:
|
||||
gen_aa32_ld16u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
@ -7522,7 +7594,7 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
|
||||
TCGv_i32 tmp2 = tcg_temp_new_i32();
|
||||
TCGv_i32 tmp3 = tcg_temp_new_i32();
|
||||
tcg_gen_addi_i32(tmp2, addr, 4);
|
||||
gen_aa32_ld32u(tmp3, tmp2, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp3, tmp2, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp2);
|
||||
tcg_gen_concat_i32_i64(val64, tmp, tmp3);
|
||||
tcg_temp_free_i32(tmp3);
|
||||
@ -7537,14 +7609,14 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
|
||||
tmp = load_reg(s, rt);
|
||||
switch (size) {
|
||||
case 0:
|
||||
gen_aa32_st8(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st8(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
case 1:
|
||||
gen_aa32_st16(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st16(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
gen_aa32_st32(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
@ -7553,7 +7625,7 @@ static void gen_store_exclusive(DisasContext *s, int rd, int rt, int rt2,
|
||||
if (size == 3) {
|
||||
tcg_gen_addi_i32(addr, addr, 4);
|
||||
tmp = load_reg(s, rt2);
|
||||
gen_aa32_st32(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp);
|
||||
}
|
||||
tcg_gen_movi_i32(cpu_R[rd], 0);
|
||||
@ -7583,6 +7655,7 @@ static void gen_srs(DisasContext *s,
|
||||
|
||||
/* SRS is:
|
||||
* - trapped to EL3 if EL3 is AArch64 and we are at Secure EL1
|
||||
* and specified mode is monitor mode
|
||||
* - UNDEFINED in Hyp mode
|
||||
* - UNPREDICTABLE in User or System mode
|
||||
* - UNPREDICTABLE if the specified mode is:
|
||||
@ -7592,7 +7665,7 @@ static void gen_srs(DisasContext *s,
|
||||
* -- Monitor, if we are Non-secure
|
||||
* For the UNPREDICTABLE cases we choose to UNDEF.
|
||||
*/
|
||||
if (s->current_el == 1 && !s->ns) {
|
||||
if (s->current_el == 1 && !s->ns && mode == ARM_CPU_MODE_MON) {
|
||||
gen_exception_insn(s, 4, EXCP_UDEF, syn_uncategorized(), 3);
|
||||
return;
|
||||
}
|
||||
@ -7659,11 +7732,11 @@ static void gen_srs(DisasContext *s,
|
||||
}
|
||||
tcg_gen_addi_i32(addr, addr, offset);
|
||||
tmp = load_reg(s, 14);
|
||||
gen_aa32_st32(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp);
|
||||
tmp = load_cpu_field(spsr);
|
||||
tcg_gen_addi_i32(addr, addr, 4);
|
||||
gen_aa32_st32(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp);
|
||||
if (writeback) {
|
||||
switch (amode) {
|
||||
@ -7770,10 +7843,9 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
||||
if ((insn & 0x0ffffdff) == 0x01010000) {
|
||||
ARCH(6);
|
||||
/* setend */
|
||||
if (((insn >> 9) & 1) != s->bswap_code) {
|
||||
/* Dynamic endianness switching not implemented. */
|
||||
qemu_log_mask(LOG_UNIMP, "arm: unimplemented setend\n");
|
||||
goto illegal_op;
|
||||
if (((insn >> 9) & 1) != !!(s->be_data == MO_BE)) {
|
||||
gen_helper_setend(cpu_env);
|
||||
s->is_jmp = DISAS_UPDATE;
|
||||
}
|
||||
return;
|
||||
} else if ((insn & 0x0fffff00) == 0x057ff000) {
|
||||
@ -7822,10 +7894,10 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
||||
tcg_gen_addi_i32(addr, addr, offset);
|
||||
/* Load PC into tmp and CPSR into tmp2. */
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
|
||||
tcg_gen_addi_i32(addr, addr, 4);
|
||||
tmp2 = tcg_temp_new_i32();
|
||||
gen_aa32_ld32u(tmp2, addr, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp2, addr, get_mem_index(s));
|
||||
if (insn & (1 << 21)) {
|
||||
/* Base writeback. */
|
||||
switch (i) {
|
||||
@ -8441,13 +8513,16 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
||||
tmp = tcg_temp_new_i32();
|
||||
switch (op1) {
|
||||
case 0: /* lda */
|
||||
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp, addr,
|
||||
get_mem_index(s));
|
||||
break;
|
||||
case 2: /* ldab */
|
||||
gen_aa32_ld8u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld8u(s, tmp, addr,
|
||||
get_mem_index(s));
|
||||
break;
|
||||
case 3: /* ldah */
|
||||
gen_aa32_ld16u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld16u(s, tmp, addr,
|
||||
get_mem_index(s));
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
@ -8458,13 +8533,16 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
||||
tmp = load_reg(s, rm);
|
||||
switch (op1) {
|
||||
case 0: /* stl */
|
||||
gen_aa32_st32(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st32(s, tmp, addr,
|
||||
get_mem_index(s));
|
||||
break;
|
||||
case 2: /* stlb */
|
||||
gen_aa32_st8(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st8(s, tmp, addr,
|
||||
get_mem_index(s));
|
||||
break;
|
||||
case 3: /* stlh */
|
||||
gen_aa32_st16(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st16(s, tmp, addr,
|
||||
get_mem_index(s));
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
@ -8519,11 +8597,11 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
||||
tmp = load_reg(s, rm);
|
||||
tmp2 = tcg_temp_new_i32();
|
||||
if (insn & (1 << 22)) {
|
||||
gen_aa32_ld8u(tmp2, addr, get_mem_index(s));
|
||||
gen_aa32_st8(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld8u(s, tmp2, addr, get_mem_index(s));
|
||||
gen_aa32_st8(s, tmp, addr, get_mem_index(s));
|
||||
} else {
|
||||
gen_aa32_ld32u(tmp2, addr, get_mem_index(s));
|
||||
gen_aa32_st32(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp2, addr, get_mem_index(s));
|
||||
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
|
||||
}
|
||||
tcg_temp_free_i32(tmp);
|
||||
tcg_temp_free_i32(addr);
|
||||
@ -8558,20 +8636,20 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
||||
if (!load) {
|
||||
/* store */
|
||||
tmp = load_reg(s, rd);
|
||||
gen_aa32_st32(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp);
|
||||
tcg_gen_addi_i32(addr, addr, 4);
|
||||
tmp = load_reg(s, rd + 1);
|
||||
gen_aa32_st32(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp);
|
||||
} else {
|
||||
/* load */
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
|
||||
store_reg(s, rd, tmp);
|
||||
tcg_gen_addi_i32(addr, addr, 4);
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
|
||||
rd++;
|
||||
}
|
||||
address_offset = -4;
|
||||
@ -8580,20 +8658,20 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
||||
tmp = tcg_temp_new_i32();
|
||||
switch (sh) {
|
||||
case 1:
|
||||
gen_aa32_ld16u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
case 2:
|
||||
gen_aa32_ld8s(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld8s(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
default:
|
||||
case 3:
|
||||
gen_aa32_ld16s(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld16s(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* store */
|
||||
tmp = load_reg(s, rd);
|
||||
gen_aa32_st16(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st16(s, tmp, addr, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp);
|
||||
}
|
||||
/* Perform base writeback before the loaded value to
|
||||
@ -8946,17 +9024,17 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
||||
/* load */
|
||||
tmp = tcg_temp_new_i32();
|
||||
if (insn & (1 << 22)) {
|
||||
gen_aa32_ld8u(tmp, tmp2, i);
|
||||
gen_aa32_ld8u(s, tmp, tmp2, i);
|
||||
} else {
|
||||
gen_aa32_ld32u(tmp, tmp2, i);
|
||||
gen_aa32_ld32u(s, tmp, tmp2, i);
|
||||
}
|
||||
} else {
|
||||
/* store */
|
||||
tmp = load_reg(s, rd);
|
||||
if (insn & (1 << 22)) {
|
||||
gen_aa32_st8(tmp, tmp2, i);
|
||||
gen_aa32_st8(s, tmp, tmp2, i);
|
||||
} else {
|
||||
gen_aa32_st32(tmp, tmp2, i);
|
||||
gen_aa32_st32(s, tmp, tmp2, i);
|
||||
}
|
||||
tcg_temp_free_i32(tmp);
|
||||
}
|
||||
@ -9029,7 +9107,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
||||
if (is_load) {
|
||||
/* load */
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
|
||||
if (user) {
|
||||
tmp2 = tcg_const_i32(i);
|
||||
gen_helper_set_user_reg(cpu_env, tmp2, tmp);
|
||||
@ -9056,7 +9134,7 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
|
||||
} else {
|
||||
tmp = load_reg(s, i);
|
||||
}
|
||||
gen_aa32_st32(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp);
|
||||
}
|
||||
j++;
|
||||
@ -9286,7 +9364,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
|
||||
/* Fall through to 32-bit decode. */
|
||||
}
|
||||
|
||||
insn = arm_lduw_code(env, s->pc, s->bswap_code);
|
||||
insn = arm_lduw_code(env, s->pc, s->sctlr_b);
|
||||
s->pc += 2;
|
||||
insn |= (uint32_t)insn_hw1 << 16;
|
||||
|
||||
@ -9323,20 +9401,20 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
|
||||
if (insn & (1 << 20)) {
|
||||
/* ldrd */
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
|
||||
store_reg(s, rs, tmp);
|
||||
tcg_gen_addi_i32(addr, addr, 4);
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
|
||||
store_reg(s, rd, tmp);
|
||||
} else {
|
||||
/* strd */
|
||||
tmp = load_reg(s, rs);
|
||||
gen_aa32_st32(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp);
|
||||
tcg_gen_addi_i32(addr, addr, 4);
|
||||
tmp = load_reg(s, rd);
|
||||
gen_aa32_st32(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp);
|
||||
}
|
||||
if (insn & (1 << 21)) {
|
||||
@ -9374,11 +9452,11 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
|
||||
tcg_gen_add_i32(addr, addr, tmp);
|
||||
tcg_temp_free_i32(tmp);
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld16u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
|
||||
} else { /* tbb */
|
||||
tcg_temp_free_i32(tmp);
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld8u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
|
||||
}
|
||||
tcg_temp_free_i32(addr);
|
||||
tcg_gen_shli_i32(tmp, tmp, 1);
|
||||
@ -9415,13 +9493,13 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
|
||||
tmp = tcg_temp_new_i32();
|
||||
switch (op) {
|
||||
case 0: /* ldab */
|
||||
gen_aa32_ld8u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
case 1: /* ldah */
|
||||
gen_aa32_ld16u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
case 2: /* lda */
|
||||
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
@ -9431,13 +9509,13 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
|
||||
tmp = load_reg(s, rs);
|
||||
switch (op) {
|
||||
case 0: /* stlb */
|
||||
gen_aa32_st8(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st8(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
case 1: /* stlh */
|
||||
gen_aa32_st16(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st16(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
case 2: /* stl */
|
||||
gen_aa32_st32(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
@ -9465,10 +9543,10 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
|
||||
tcg_gen_addi_i32(addr, addr, -8);
|
||||
/* Load PC into tmp and CPSR into tmp2. */
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
|
||||
tcg_gen_addi_i32(addr, addr, 4);
|
||||
tmp2 = tcg_temp_new_i32();
|
||||
gen_aa32_ld32u(tmp2, addr, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp2, addr, get_mem_index(s));
|
||||
if (insn & (1 << 21)) {
|
||||
/* Base writeback. */
|
||||
if (insn & (1 << 24)) {
|
||||
@ -9507,7 +9585,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
|
||||
if (insn & (1 << 20)) {
|
||||
/* Load. */
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
|
||||
if (i == 15) {
|
||||
gen_bx(s, tmp);
|
||||
} else if (i == rn) {
|
||||
@ -9519,7 +9597,7 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
|
||||
} else {
|
||||
/* Store. */
|
||||
tmp = load_reg(s, i);
|
||||
gen_aa32_st32(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp);
|
||||
}
|
||||
tcg_gen_addi_i32(addr, addr, 4);
|
||||
@ -10449,19 +10527,19 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
|
||||
tmp = tcg_temp_new_i32();
|
||||
switch (op) {
|
||||
case 0:
|
||||
gen_aa32_ld8u(tmp, addr, memidx);
|
||||
gen_aa32_ld8u(s, tmp, addr, memidx);
|
||||
break;
|
||||
case 4:
|
||||
gen_aa32_ld8s(tmp, addr, memidx);
|
||||
gen_aa32_ld8s(s, tmp, addr, memidx);
|
||||
break;
|
||||
case 1:
|
||||
gen_aa32_ld16u(tmp, addr, memidx);
|
||||
gen_aa32_ld16u(s, tmp, addr, memidx);
|
||||
break;
|
||||
case 5:
|
||||
gen_aa32_ld16s(tmp, addr, memidx);
|
||||
gen_aa32_ld16s(s, tmp, addr, memidx);
|
||||
break;
|
||||
case 2:
|
||||
gen_aa32_ld32u(tmp, addr, memidx);
|
||||
gen_aa32_ld32u(s, tmp, addr, memidx);
|
||||
break;
|
||||
default:
|
||||
tcg_temp_free_i32(tmp);
|
||||
@ -10478,13 +10556,13 @@ static int disas_thumb2_insn(CPUARMState *env, DisasContext *s, uint16_t insn_hw
|
||||
tmp = load_reg(s, rs);
|
||||
switch (op) {
|
||||
case 0:
|
||||
gen_aa32_st8(tmp, addr, memidx);
|
||||
gen_aa32_st8(s, tmp, addr, memidx);
|
||||
break;
|
||||
case 1:
|
||||
gen_aa32_st16(tmp, addr, memidx);
|
||||
gen_aa32_st16(s, tmp, addr, memidx);
|
||||
break;
|
||||
case 2:
|
||||
gen_aa32_st32(tmp, addr, memidx);
|
||||
gen_aa32_st32(s, tmp, addr, memidx);
|
||||
break;
|
||||
default:
|
||||
tcg_temp_free_i32(tmp);
|
||||
@ -10528,7 +10606,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
|
||||
}
|
||||
}
|
||||
|
||||
insn = arm_lduw_code(env, s->pc, s->bswap_code);
|
||||
insn = arm_lduw_code(env, s->pc, s->sctlr_b);
|
||||
s->pc += 2;
|
||||
|
||||
switch (insn >> 12) {
|
||||
@ -10621,7 +10699,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
|
||||
addr = tcg_temp_new_i32();
|
||||
tcg_gen_movi_i32(addr, val);
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
|
||||
tcg_temp_free_i32(addr);
|
||||
store_reg(s, rd, tmp);
|
||||
break;
|
||||
@ -10824,28 +10902,28 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
|
||||
|
||||
switch (op) {
|
||||
case 0: /* str */
|
||||
gen_aa32_st32(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
case 1: /* strh */
|
||||
gen_aa32_st16(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st16(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
case 2: /* strb */
|
||||
gen_aa32_st8(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st8(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
case 3: /* ldrsb */
|
||||
gen_aa32_ld8s(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld8s(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
case 4: /* ldr */
|
||||
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
case 5: /* ldrh */
|
||||
gen_aa32_ld16u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
case 6: /* ldrb */
|
||||
gen_aa32_ld8u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
case 7: /* ldrsh */
|
||||
gen_aa32_ld16s(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld16s(s, tmp, addr, get_mem_index(s));
|
||||
break;
|
||||
}
|
||||
if (op >= 3) { /* load */
|
||||
@ -10867,12 +10945,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
|
||||
if (insn & (1 << 11)) {
|
||||
/* load */
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
|
||||
store_reg(s, rd, tmp);
|
||||
} else {
|
||||
/* store */
|
||||
tmp = load_reg(s, rd);
|
||||
gen_aa32_st32(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp);
|
||||
}
|
||||
tcg_temp_free_i32(addr);
|
||||
@ -10889,12 +10967,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
|
||||
if (insn & (1 << 11)) {
|
||||
/* load */
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld8u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld8u(s, tmp, addr, get_mem_index(s));
|
||||
store_reg(s, rd, tmp);
|
||||
} else {
|
||||
/* store */
|
||||
tmp = load_reg(s, rd);
|
||||
gen_aa32_st8(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st8(s, tmp, addr, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp);
|
||||
}
|
||||
tcg_temp_free_i32(addr);
|
||||
@ -10911,12 +10989,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
|
||||
if (insn & (1 << 11)) {
|
||||
/* load */
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld16u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld16u(s, tmp, addr, get_mem_index(s));
|
||||
store_reg(s, rd, tmp);
|
||||
} else {
|
||||
/* store */
|
||||
tmp = load_reg(s, rd);
|
||||
gen_aa32_st16(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st16(s, tmp, addr, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp);
|
||||
}
|
||||
tcg_temp_free_i32(addr);
|
||||
@ -10932,12 +11010,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
|
||||
if (insn & (1 << 11)) {
|
||||
/* load */
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
|
||||
store_reg(s, rd, tmp);
|
||||
} else {
|
||||
/* store */
|
||||
tmp = load_reg(s, rd);
|
||||
gen_aa32_st32(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp);
|
||||
}
|
||||
tcg_temp_free_i32(addr);
|
||||
@ -11005,12 +11083,12 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
|
||||
if (insn & (1 << 11)) {
|
||||
/* pop */
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
|
||||
store_reg(s, i, tmp);
|
||||
} else {
|
||||
/* push */
|
||||
tmp = load_reg(s, i);
|
||||
gen_aa32_st32(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp);
|
||||
}
|
||||
/* advance to the next address. */
|
||||
@ -11022,13 +11100,13 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
|
||||
if (insn & (1 << 11)) {
|
||||
/* pop pc */
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
|
||||
/* don't set the pc until the rest of the instruction
|
||||
has completed */
|
||||
} else {
|
||||
/* push lr */
|
||||
tmp = load_reg(s, 14);
|
||||
gen_aa32_st32(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp);
|
||||
}
|
||||
tcg_gen_addi_i32(addr, addr, 4);
|
||||
@ -11099,10 +11177,9 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
|
||||
case 2:
|
||||
/* setend */
|
||||
ARCH(6);
|
||||
if (((insn >> 3) & 1) != s->bswap_code) {
|
||||
/* Dynamic endianness switching not implemented. */
|
||||
qemu_log_mask(LOG_UNIMP, "arm: unimplemented setend\n");
|
||||
goto illegal_op;
|
||||
if (((insn >> 3) & 1) != !!(s->be_data == MO_BE)) {
|
||||
gen_helper_setend(cpu_env);
|
||||
s->is_jmp = DISAS_UPDATE;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
@ -11158,7 +11235,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
|
||||
if (insn & (1 << 11)) {
|
||||
/* load */
|
||||
tmp = tcg_temp_new_i32();
|
||||
gen_aa32_ld32u(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
|
||||
if (i == rn) {
|
||||
loaded_var = tmp;
|
||||
} else {
|
||||
@ -11167,7 +11244,7 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s)
|
||||
} else {
|
||||
/* store */
|
||||
tmp = load_reg(s, i);
|
||||
gen_aa32_st32(tmp, addr, get_mem_index(s));
|
||||
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
|
||||
tcg_temp_free_i32(tmp);
|
||||
}
|
||||
/* advance to the next address */
|
||||
@ -11253,7 +11330,7 @@ static bool insn_crosses_page(CPUARMState *env, DisasContext *s)
|
||||
}
|
||||
|
||||
/* This must be a Thumb insn */
|
||||
insn = arm_lduw_code(env, s->pc, s->bswap_code);
|
||||
insn = arm_lduw_code(env, s->pc, s->sctlr_b);
|
||||
|
||||
if ((insn >> 11) >= 0x1d) {
|
||||
/* Top five bits 0b11101 / 0b11110 / 0b11111 : this is the
|
||||
@ -11307,7 +11384,8 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
|
||||
dc->secure_routed_to_el3 = arm_feature(env, ARM_FEATURE_EL3) &&
|
||||
!arm_el_is_aa64(env, 3);
|
||||
dc->thumb = ARM_TBFLAG_THUMB(tb->flags);
|
||||
dc->bswap_code = ARM_TBFLAG_BSWAP_CODE(tb->flags);
|
||||
dc->sctlr_b = ARM_TBFLAG_SCTLR_B(tb->flags);
|
||||
dc->be_data = ARM_TBFLAG_BE_DATA(tb->flags) ? MO_BE : MO_LE;
|
||||
dc->condexec_mask = (ARM_TBFLAG_CONDEXEC(tb->flags) & 0xf) << 1;
|
||||
dc->condexec_cond = ARM_TBFLAG_CONDEXEC(tb->flags) >> 4;
|
||||
dc->mmu_idx = ARM_TBFLAG_MMUIDX(tb->flags);
|
||||
@ -11487,7 +11565,7 @@ void gen_intermediate_code(CPUARMState *env, TranslationBlock *tb)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unsigned int insn = arm_ldl_code(env, dc->pc, dc->bswap_code);
|
||||
unsigned int insn = arm_ldl_code(env, dc->pc, dc->sctlr_b);
|
||||
dc->pc += 4;
|
||||
disas_arm_insn(dc, insn);
|
||||
}
|
||||
@ -11644,7 +11722,7 @@ done_generating:
|
||||
qemu_log("----------------\n");
|
||||
qemu_log("IN: %s\n", lookup_symbol(pc_start));
|
||||
log_target_disas(cs, pc_start, dc->pc - pc_start,
|
||||
dc->thumb | (dc->bswap_code << 1));
|
||||
dc->thumb | (dc->sctlr_b << 1));
|
||||
qemu_log("\n");
|
||||
}
|
||||
#endif
|
||||
|
@ -16,7 +16,8 @@ typedef struct DisasContext {
|
||||
struct TranslationBlock *tb;
|
||||
int singlestep_enabled;
|
||||
int thumb;
|
||||
int bswap_code;
|
||||
int sctlr_b;
|
||||
TCGMemOp be_data;
|
||||
#if !defined(CONFIG_USER_ONLY)
|
||||
int user;
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user