target-arm queue:

* connect SPI devices in Xilinx Zynq platforms
  * multiple-address-space support
  * use multiple-address-space support for ARM TrustZone
  * arm_gic: return correct ID registers for 11MPCore/v1/v2 GICs
  * various fixes for (currently disabled) AArch64 EL2 and EL3 support
  * add 'always-on' property to the virt board timer DT entry
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABCAAGBQJWoPFAAAoJEDwlJe0UNgzeKKAP/jpTj6yfwXxkbU3BT+SmiJDe
 J9vSUkPnVLABxy0TGtnGTvgVZrgJfhKcEkk4i/uswsV7U8Vxxpa5XDir0ZNPo7VG
 3KqQBM3ZKZgMD+QuxMIr76ar9+FukfSFI/9yfmZZOthON9P3Tu9BtXAbjLuezdXt
 jQHI5FDsNhgxvXSRa0qY8fTayKRBCirHzzkpLsaaS2Frj9HUUnrHQtOjEWAyb10N
 QxQkuFLzqIbzTynKtVkrFbQknuIFF/h6tMe5Oj/J07A/nl1GmLJQtvmy4M7sFG4Z
 uAqJNxtO36CYGg/RdRYNmW89k5iRqAMHqJNlNYLlAz9q2cB59MPXrTWqgUOQq3UI
 QOOkINqubd62le0QarnZofGp+YJwUj1Uv+URD4kRnOFMjIvuF3rH6S+PCnDPD53a
 rCrkNZM2YKYMe7CSgqy5cz2rnrnYhl+ubpo/yz5Gs4g+iqcK7BLyY1QK72oZAy0U
 9bUNrMFUCFQrJioel34m9kM3QZFOz14kbR4NTaxovUMATimi+qveLdYp9rLi9WMc
 tpyEDHL3KYbJv/siUtC9da0A1hWe/WlMqvC/6Fm55xC75+ihQEJhoJvxs4auDqQx
 GafvkFasjpPZ/2ZpgCj+kwZZvqjU0mzncj+FKF6fflAfxJmdikHIXUQ+L83eYAgd
 QQC+zYjyWa343GwdO3yl
 =IB51
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20160121' into staging

target-arm queue:
 * connect SPI devices in Xilinx Zynq platforms
 * multiple-address-space support
 * use multiple-address-space support for ARM TrustZone
 * arm_gic: return correct ID registers for 11MPCore/v1/v2 GICs
 * various fixes for (currently disabled) AArch64 EL2 and EL3 support
 * add 'always-on' property to the virt board timer DT entry

# gpg: Signature made Thu 21 Jan 2016 14:54:56 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-20160121: (36 commits)
  target-arm: Implement FPEXC32_EL2 system register
  target-arm: ignore ELR_ELx[1] for exception return to 32-bit ARM mode
  target-arm: Implement remaining illegal return event checks
  target-arm: Handle exception return from AArch64 to non-EL0 AArch32
  target-arm: Fix wrong AArch64 entry offset for EL2/EL3 target
  target-arm: Pull semihosting handling out to arm_cpu_do_interrupt()
  target-arm: Use a single entry point for AArch64 and AArch32 exceptions
  target-arm: Move aarch64_cpu_do_interrupt() to helper.c
  target-arm: Properly support EL2 and EL3 in arm_el_is_aa64()
  arm_gic: Update ID registers based on revision
  hw/arm/virt: Add always-on property to the virt board timer
  hw/arm/virt: add secure memory region and UART
  hw/arm/virt: Wire up memory region to CPUs explicitly
  target-arm: Support multiple address spaces in page table walks
  target-arm: Implement cpu_get_phys_page_attrs_debug
  target-arm: Implement asidx_from_attrs
  target-arm: Add QOM property for Secure memory region
  qom/cpu: Add MemoryRegion property
  memory: Add address_space_init_shareable()
  exec.c: Use correct AddressSpace in watch_mem_read and watch_mem_write
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2016-01-21 15:00:39 +00:00
commit 1a4f446f81
43 changed files with 909 additions and 315 deletions

13
cpus.c
View File

@ -1310,8 +1310,6 @@ static void qemu_tcg_init_vcpu(CPUState *cpu)
static QemuCond *tcg_halt_cond; static QemuCond *tcg_halt_cond;
static QemuThread *tcg_cpu_thread; static QemuThread *tcg_cpu_thread;
tcg_cpu_address_space_init(cpu, cpu->as);
/* share a single thread for all cpus with TCG */ /* share a single thread for all cpus with TCG */
if (!tcg_cpu_thread) { if (!tcg_cpu_thread) {
cpu->thread = g_malloc0(sizeof(QemuThread)); cpu->thread = g_malloc0(sizeof(QemuThread));
@ -1372,6 +1370,17 @@ void qemu_init_vcpu(CPUState *cpu)
cpu->nr_cores = smp_cores; cpu->nr_cores = smp_cores;
cpu->nr_threads = smp_threads; cpu->nr_threads = smp_threads;
cpu->stopped = true; cpu->stopped = true;
if (!cpu->as) {
/* If the target cpu hasn't set up any address spaces itself,
* give it the default one.
*/
AddressSpace *as = address_space_init_shareable(cpu->memory,
"cpu-memory");
cpu->num_ases = 1;
cpu_address_space_init(cpu, as, 0);
}
if (kvm_enabled()) { if (kvm_enabled()) {
qemu_kvm_start_vcpu(cpu); qemu_kvm_start_vcpu(cpu);
} else if (tcg_enabled()) { } else if (tcg_enabled()) {

View File

@ -356,6 +356,7 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr,
CPUTLBEntry *te; CPUTLBEntry *te;
hwaddr iotlb, xlat, sz; hwaddr iotlb, xlat, sz;
unsigned vidx = env->vtlb_index++ % CPU_VTLB_SIZE; unsigned vidx = env->vtlb_index++ % CPU_VTLB_SIZE;
int asidx = cpu_asidx_from_attrs(cpu, attrs);
assert(size >= TARGET_PAGE_SIZE); assert(size >= TARGET_PAGE_SIZE);
if (size != TARGET_PAGE_SIZE) { if (size != TARGET_PAGE_SIZE) {
@ -363,7 +364,7 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr,
} }
sz = size; sz = size;
section = address_space_translate_for_iotlb(cpu, paddr, &xlat, &sz); section = address_space_translate_for_iotlb(cpu, asidx, paddr, &xlat, &sz);
assert(sz >= TARGET_PAGE_SIZE); assert(sz >= TARGET_PAGE_SIZE);
#if defined(DEBUG_TLB) #if defined(DEBUG_TLB)
@ -448,6 +449,7 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr)
void *p; void *p;
MemoryRegion *mr; MemoryRegion *mr;
CPUState *cpu = ENV_GET_CPU(env1); CPUState *cpu = ENV_GET_CPU(env1);
CPUIOTLBEntry *iotlbentry;
page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1); page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
mmu_idx = cpu_mmu_index(env1, true); mmu_idx = cpu_mmu_index(env1, true);
@ -455,8 +457,9 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr)
(addr & TARGET_PAGE_MASK))) { (addr & TARGET_PAGE_MASK))) {
cpu_ldub_code(env1, addr); cpu_ldub_code(env1, addr);
} }
pd = env1->iotlb[mmu_idx][page_index].addr & ~TARGET_PAGE_MASK; iotlbentry = &env1->iotlb[mmu_idx][page_index];
mr = iotlb_to_region(cpu, pd); pd = iotlbentry->addr & ~TARGET_PAGE_MASK;
mr = iotlb_to_region(cpu, pd, iotlbentry->attrs);
if (memory_region_is_unassigned(mr)) { if (memory_region_is_unassigned(mr)) {
CPUClass *cc = CPU_GET_CLASS(cpu); CPUClass *cc = CPU_GET_CLASS(cpu);

103
exec.c
View File

@ -431,12 +431,13 @@ MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
/* Called from RCU critical section */ /* Called from RCU critical section */
MemoryRegionSection * MemoryRegionSection *
address_space_translate_for_iotlb(CPUState *cpu, hwaddr addr, address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr,
hwaddr *xlat, hwaddr *plen) hwaddr *xlat, hwaddr *plen)
{ {
MemoryRegionSection *section; MemoryRegionSection *section;
section = address_space_translate_internal(cpu->cpu_ases[0].memory_dispatch, AddressSpaceDispatch *d = cpu->cpu_ases[asidx].memory_dispatch;
addr, xlat, plen, false);
section = address_space_translate_internal(d, addr, xlat, plen, false);
assert(!section->mr->iommu_ops); assert(!section->mr->iommu_ops);
return section; return section;
@ -536,21 +537,38 @@ CPUState *qemu_get_cpu(int index)
} }
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
void tcg_cpu_address_space_init(CPUState *cpu, AddressSpace *as) void cpu_address_space_init(CPUState *cpu, AddressSpace *as, int asidx)
{ {
/* We only support one address space per cpu at the moment. */ CPUAddressSpace *newas;
assert(cpu->as == as);
if (cpu->cpu_ases) { /* Target code should have set num_ases before calling us */
/* We've already registered the listener for our only AS */ assert(asidx < cpu->num_ases);
return;
if (asidx == 0) {
/* address space 0 gets the convenience alias */
cpu->as = as;
} }
cpu->cpu_ases = g_new0(CPUAddressSpace, 1); /* KVM cannot currently support multiple address spaces. */
cpu->cpu_ases[0].cpu = cpu; assert(asidx == 0 || !kvm_enabled());
cpu->cpu_ases[0].as = as;
cpu->cpu_ases[0].tcg_as_listener.commit = tcg_commit; if (!cpu->cpu_ases) {
memory_listener_register(&cpu->cpu_ases[0].tcg_as_listener, as); cpu->cpu_ases = g_new0(CPUAddressSpace, cpu->num_ases);
}
newas = &cpu->cpu_ases[asidx];
newas->cpu = cpu;
newas->as = as;
if (tcg_enabled()) {
newas->tcg_as_listener.commit = tcg_commit;
memory_listener_register(&newas->tcg_as_listener, as);
}
}
AddressSpace *cpu_get_address_space(CPUState *cpu, int asidx)
{
/* Return the AddressSpace corresponding to the specified index */
return cpu->cpu_ases[asidx].as;
} }
#endif #endif
@ -605,9 +623,25 @@ void cpu_exec_init(CPUState *cpu, Error **errp)
int cpu_index; int cpu_index;
Error *local_err = NULL; Error *local_err = NULL;
cpu->as = NULL;
cpu->num_ases = 0;
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
cpu->as = &address_space_memory;
cpu->thread_id = qemu_get_thread_id(); cpu->thread_id = qemu_get_thread_id();
/* This is a softmmu CPU object, so create a property for it
* so users can wire up its memory. (This can't go in qom/cpu.c
* because that file is compiled only once for both user-mode
* and system builds.) The default if no link is set up is to use
* the system address space.
*/
object_property_add_link(OBJECT(cpu), "memory", TYPE_MEMORY_REGION,
(Object **)&cpu->memory,
qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_UNREF_ON_RELEASE,
&error_abort);
cpu->memory = system_memory;
object_ref(OBJECT(cpu->memory));
#endif #endif
#if defined(CONFIG_USER_ONLY) #if defined(CONFIG_USER_ONLY)
@ -647,9 +681,11 @@ static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
#else #else
static void breakpoint_invalidate(CPUState *cpu, target_ulong pc) static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
{ {
hwaddr phys = cpu_get_phys_page_debug(cpu, pc); MemTxAttrs attrs;
hwaddr phys = cpu_get_phys_page_attrs_debug(cpu, pc, &attrs);
int asidx = cpu_asidx_from_attrs(cpu, attrs);
if (phys != -1) { if (phys != -1) {
tb_invalidate_phys_addr(cpu->as, tb_invalidate_phys_addr(cpu->cpu_ases[asidx].as,
phys | (pc & ~TARGET_PAGE_MASK)); phys | (pc & ~TARGET_PAGE_MASK));
} }
} }
@ -2034,17 +2070,19 @@ static MemTxResult watch_mem_read(void *opaque, hwaddr addr, uint64_t *pdata,
{ {
MemTxResult res; MemTxResult res;
uint64_t data; uint64_t data;
int asidx = cpu_asidx_from_attrs(current_cpu, attrs);
AddressSpace *as = current_cpu->cpu_ases[asidx].as;
check_watchpoint(addr & ~TARGET_PAGE_MASK, size, attrs, BP_MEM_READ); check_watchpoint(addr & ~TARGET_PAGE_MASK, size, attrs, BP_MEM_READ);
switch (size) { switch (size) {
case 1: case 1:
data = address_space_ldub(&address_space_memory, addr, attrs, &res); data = address_space_ldub(as, addr, attrs, &res);
break; break;
case 2: case 2:
data = address_space_lduw(&address_space_memory, addr, attrs, &res); data = address_space_lduw(as, addr, attrs, &res);
break; break;
case 4: case 4:
data = address_space_ldl(&address_space_memory, addr, attrs, &res); data = address_space_ldl(as, addr, attrs, &res);
break; break;
default: abort(); default: abort();
} }
@ -2057,17 +2095,19 @@ static MemTxResult watch_mem_write(void *opaque, hwaddr addr,
MemTxAttrs attrs) MemTxAttrs attrs)
{ {
MemTxResult res; MemTxResult res;
int asidx = cpu_asidx_from_attrs(current_cpu, attrs);
AddressSpace *as = current_cpu->cpu_ases[asidx].as;
check_watchpoint(addr & ~TARGET_PAGE_MASK, size, attrs, BP_MEM_WRITE); check_watchpoint(addr & ~TARGET_PAGE_MASK, size, attrs, BP_MEM_WRITE);
switch (size) { switch (size) {
case 1: case 1:
address_space_stb(&address_space_memory, addr, val, attrs, &res); address_space_stb(as, addr, val, attrs, &res);
break; break;
case 2: case 2:
address_space_stw(&address_space_memory, addr, val, attrs, &res); address_space_stw(as, addr, val, attrs, &res);
break; break;
case 4: case 4:
address_space_stl(&address_space_memory, addr, val, attrs, &res); address_space_stl(as, addr, val, attrs, &res);
break; break;
default: abort(); default: abort();
} }
@ -2224,9 +2264,10 @@ static uint16_t dummy_section(PhysPageMap *map, AddressSpace *as,
return phys_section_add(map, &section); return phys_section_add(map, &section);
} }
MemoryRegion *iotlb_to_region(CPUState *cpu, hwaddr index) MemoryRegion *iotlb_to_region(CPUState *cpu, hwaddr index, MemTxAttrs attrs)
{ {
CPUAddressSpace *cpuas = &cpu->cpu_ases[0]; int asidx = cpu_asidx_from_attrs(cpu, attrs);
CPUAddressSpace *cpuas = &cpu->cpu_ases[asidx];
AddressSpaceDispatch *d = atomic_rcu_read(&cpuas->memory_dispatch); AddressSpaceDispatch *d = atomic_rcu_read(&cpuas->memory_dispatch);
MemoryRegionSection *sections = d->map.sections; MemoryRegionSection *sections = d->map.sections;
@ -3565,8 +3606,12 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
target_ulong page; target_ulong page;
while (len > 0) { while (len > 0) {
int asidx;
MemTxAttrs attrs;
page = addr & TARGET_PAGE_MASK; page = addr & TARGET_PAGE_MASK;
phys_addr = cpu_get_phys_page_debug(cpu, page); phys_addr = cpu_get_phys_page_attrs_debug(cpu, page, &attrs);
asidx = cpu_asidx_from_attrs(cpu, attrs);
/* if no physical page mapped, return an error */ /* if no physical page mapped, return an error */
if (phys_addr == -1) if (phys_addr == -1)
return -1; return -1;
@ -3575,9 +3620,11 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
l = len; l = len;
phys_addr += (addr & ~TARGET_PAGE_MASK); phys_addr += (addr & ~TARGET_PAGE_MASK);
if (is_write) { if (is_write) {
cpu_physical_memory_write_rom(cpu->as, phys_addr, buf, l); cpu_physical_memory_write_rom(cpu->cpu_ases[asidx].as,
phys_addr, buf, l);
} else { } else {
address_space_rw(cpu->as, phys_addr, MEMTXATTRS_UNSPECIFIED, address_space_rw(cpu->cpu_ases[asidx].as, phys_addr,
MEMTXATTRS_UNSPECIFIED,
buf, l, 0); buf, l, 0);
} }
len -= l; len -= l;

View File

@ -13,7 +13,7 @@
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "hw/char/serial.h" #include "hw/char/serial.h"
#include "hw/i2c/i2c.h" #include "hw/i2c/i2c.h"
#include "hw/ssi.h" #include "hw/ssi/ssi.h"
#include "sysemu/char.h" #include "sysemu/char.h"
#include "sysemu/block-backend.h" #include "sysemu/block-backend.h"
#include "sysemu/blockdev.h" #include "sysemu/blockdev.h"

View File

@ -17,7 +17,7 @@
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "hw/pcmcia.h" #include "hw/pcmcia.h"
#include "hw/i2c/i2c.h" #include "hw/i2c/i2c.h"
#include "hw/ssi.h" #include "hw/ssi/ssi.h"
#include "hw/block/flash.h" #include "hw/block/flash.h"
#include "qemu/timer.h" #include "qemu/timer.h"
#include "hw/devices.h" #include "hw/devices.h"

View File

@ -9,7 +9,7 @@
#include "qemu/osdep.h" #include "qemu/osdep.h"
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "hw/ssi.h" #include "hw/ssi/ssi.h"
#include "hw/arm/arm.h" #include "hw/arm/arm.h"
#include "hw/devices.h" #include "hw/devices.h"
#include "qemu/timer.h" #include "qemu/timer.h"

View File

@ -35,7 +35,7 @@
#include "hw/arm/arm.h" #include "hw/arm/arm.h"
#include "sysemu/char.h" #include "sysemu/char.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "hw/ssi.h" #include "hw/ssi/ssi.h"
//#define DEBUG //#define DEBUG

View File

@ -20,7 +20,7 @@
#include "hw/pcmcia.h" #include "hw/pcmcia.h"
#include "hw/boards.h" #include "hw/boards.h"
#include "hw/i2c/i2c.h" #include "hw/i2c/i2c.h"
#include "hw/ssi.h" #include "hw/ssi/ssi.h"
#include "sysemu/block-backend.h" #include "sysemu/block-backend.h"
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "exec/address-spaces.h" #include "exec/address-spaces.h"

View File

@ -123,6 +123,7 @@ static const MemMapEntry a15memmap[] = {
[VIRT_RTC] = { 0x09010000, 0x00001000 }, [VIRT_RTC] = { 0x09010000, 0x00001000 },
[VIRT_FW_CFG] = { 0x09020000, 0x00000018 }, [VIRT_FW_CFG] = { 0x09020000, 0x00000018 },
[VIRT_GPIO] = { 0x09030000, 0x00001000 }, [VIRT_GPIO] = { 0x09030000, 0x00001000 },
[VIRT_SECURE_UART] = { 0x09040000, 0x00001000 },
[VIRT_MMIO] = { 0x0a000000, 0x00000200 }, [VIRT_MMIO] = { 0x0a000000, 0x00000200 },
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */ /* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
[VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 }, [VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 },
@ -139,6 +140,7 @@ static const int a15irqmap[] = {
[VIRT_RTC] = 2, [VIRT_RTC] = 2,
[VIRT_PCIE] = 3, /* ... to 6 */ [VIRT_PCIE] = 3, /* ... to 6 */
[VIRT_GPIO] = 7, [VIRT_GPIO] = 7,
[VIRT_SECURE_UART] = 8,
[VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */ [VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */
[VIRT_GIC_V2M] = 48, /* ...to 48 + NUM_GICV2M_SPIS - 1 */ [VIRT_GIC_V2M] = 48, /* ...to 48 + NUM_GICV2M_SPIS - 1 */
[VIRT_PLATFORM_BUS] = 112, /* ...to 112 + PLATFORM_BUS_NUM_IRQS -1 */ [VIRT_PLATFORM_BUS] = 112, /* ...to 112 + PLATFORM_BUS_NUM_IRQS -1 */
@ -291,6 +293,7 @@ static void fdt_add_timer_nodes(const VirtBoardInfo *vbi, int gictype)
qemu_fdt_setprop_string(vbi->fdt, "/timer", "compatible", qemu_fdt_setprop_string(vbi->fdt, "/timer", "compatible",
"arm,armv7-timer"); "arm,armv7-timer");
} }
qemu_fdt_setprop(vbi->fdt, "/timer", "always-on", NULL, 0);
qemu_fdt_setprop_cells(vbi->fdt, "/timer", "interrupts", qemu_fdt_setprop_cells(vbi->fdt, "/timer", "interrupts",
GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_S_EL1_IRQ, irqflags, GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_S_EL1_IRQ, irqflags,
GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_NS_EL1_IRQ, irqflags, GIC_FDT_IRQ_TYPE_PPI, ARCH_TIMER_NS_EL1_IRQ, irqflags,
@ -489,16 +492,22 @@ static void create_gic(VirtBoardInfo *vbi, qemu_irq *pic, int type, bool secure)
} }
} }
static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic) static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic, int uart,
MemoryRegion *mem)
{ {
char *nodename; char *nodename;
hwaddr base = vbi->memmap[VIRT_UART].base; hwaddr base = vbi->memmap[uart].base;
hwaddr size = vbi->memmap[VIRT_UART].size; hwaddr size = vbi->memmap[uart].size;
int irq = vbi->irqmap[VIRT_UART]; int irq = vbi->irqmap[uart];
const char compat[] = "arm,pl011\0arm,primecell"; const char compat[] = "arm,pl011\0arm,primecell";
const char clocknames[] = "uartclk\0apb_pclk"; const char clocknames[] = "uartclk\0apb_pclk";
DeviceState *dev = qdev_create(NULL, "pl011");
SysBusDevice *s = SYS_BUS_DEVICE(dev);
sysbus_create_simple("pl011", base, pic[irq]); qdev_init_nofail(dev);
memory_region_add_subregion(mem, base,
sysbus_mmio_get_region(s, 0));
sysbus_connect_irq(s, 0, pic[irq]);
nodename = g_strdup_printf("/pl011@%" PRIx64, base); nodename = g_strdup_printf("/pl011@%" PRIx64, base);
qemu_fdt_add_subnode(vbi->fdt, nodename); qemu_fdt_add_subnode(vbi->fdt, nodename);
@ -515,7 +524,14 @@ static void create_uart(const VirtBoardInfo *vbi, qemu_irq *pic)
qemu_fdt_setprop(vbi->fdt, nodename, "clock-names", qemu_fdt_setprop(vbi->fdt, nodename, "clock-names",
clocknames, sizeof(clocknames)); clocknames, sizeof(clocknames));
if (uart == VIRT_UART) {
qemu_fdt_setprop_string(vbi->fdt, "/chosen", "stdout-path", nodename); qemu_fdt_setprop_string(vbi->fdt, "/chosen", "stdout-path", nodename);
} else {
/* Mark as not usable by the normal world */
qemu_fdt_setprop_string(vbi->fdt, nodename, "status", "disabled");
qemu_fdt_setprop_string(vbi->fdt, nodename, "secure-status", "okay");
}
g_free(nodename); g_free(nodename);
} }
@ -995,6 +1011,7 @@ static void machvirt_init(MachineState *machine)
VirtMachineState *vms = VIRT_MACHINE(machine); VirtMachineState *vms = VIRT_MACHINE(machine);
qemu_irq pic[NUM_IRQS]; qemu_irq pic[NUM_IRQS];
MemoryRegion *sysmem = get_system_memory(); MemoryRegion *sysmem = get_system_memory();
MemoryRegion *secure_sysmem = NULL;
int gic_version = vms->gic_version; int gic_version = vms->gic_version;
int n, max_cpus; int n, max_cpus;
MemoryRegion *ram = g_new(MemoryRegion, 1); MemoryRegion *ram = g_new(MemoryRegion, 1);
@ -1053,6 +1070,23 @@ static void machvirt_init(MachineState *machine)
exit(1); exit(1);
} }
if (vms->secure) {
if (kvm_enabled()) {
error_report("mach-virt: KVM does not support Security extensions");
exit(1);
}
/* The Secure view of the world is the same as the NonSecure,
* but with a few extra devices. Create it as a container region
* containing the system memory at low priority; any secure-only
* devices go in at higher priority and take precedence.
*/
secure_sysmem = g_new(MemoryRegion, 1);
memory_region_init(secure_sysmem, OBJECT(machine), "secure-memory",
UINT64_MAX);
memory_region_add_subregion_overlap(secure_sysmem, 0, sysmem, -1);
}
create_fdt(vbi); create_fdt(vbi);
for (n = 0; n < smp_cpus; n++) { for (n = 0; n < smp_cpus; n++) {
@ -1093,6 +1127,13 @@ static void machvirt_init(MachineState *machine)
"reset-cbar", &error_abort); "reset-cbar", &error_abort);
} }
object_property_set_link(cpuobj, OBJECT(sysmem), "memory",
&error_abort);
if (vms->secure) {
object_property_set_link(cpuobj, OBJECT(secure_sysmem),
"secure-memory", &error_abort);
}
object_property_set_bool(cpuobj, true, "realized", NULL); object_property_set_bool(cpuobj, true, "realized", NULL);
} }
g_strfreev(cpustr); g_strfreev(cpustr);
@ -1108,7 +1149,11 @@ static void machvirt_init(MachineState *machine)
create_gic(vbi, pic, gic_version, vms->secure); create_gic(vbi, pic, gic_version, vms->secure);
create_uart(vbi, pic); create_uart(vbi, pic, VIRT_UART, sysmem);
if (vms->secure) {
create_uart(vbi, pic, VIRT_SECURE_UART, secure_sysmem);
}
create_rtc(vbi, pic); create_rtc(vbi, pic);

View File

@ -26,7 +26,7 @@
#include "sysemu/block-backend.h" #include "sysemu/block-backend.h"
#include "hw/loader.h" #include "hw/loader.h"
#include "hw/misc/zynq-xadc.h" #include "hw/misc/zynq-xadc.h"
#include "hw/ssi.h" #include "hw/ssi/ssi.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"
#define NUM_SPI_FLASHES 4 #define NUM_SPI_FLASHES 4

View File

@ -31,6 +31,7 @@ static struct arm_boot_info xlnx_ep108_binfo;
static void xlnx_ep108_init(MachineState *machine) static void xlnx_ep108_init(MachineState *machine)
{ {
XlnxEP108 *s = g_new0(XlnxEP108, 1); XlnxEP108 *s = g_new0(XlnxEP108, 1);
int i;
Error *err = NULL; Error *err = NULL;
uint64_t ram_size = machine->ram_size; uint64_t ram_size = machine->ram_size;
@ -63,6 +64,21 @@ static void xlnx_ep108_init(MachineState *machine)
exit(1); exit(1);
} }
for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) {
SSIBus *spi_bus;
DeviceState *flash_dev;
qemu_irq cs_line;
gchar *bus_name = g_strdup_printf("spi%d", i);
spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(&s->soc), bus_name);
g_free(bus_name);
flash_dev = ssi_create_slave(spi_bus, "sst25wf080");
cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.spi[i]), 1, cs_line);
}
xlnx_ep108_binfo.ram_size = ram_size; xlnx_ep108_binfo.ram_size = ram_size;
xlnx_ep108_binfo.kernel_filename = machine->kernel_filename; xlnx_ep108_binfo.kernel_filename = machine->kernel_filename;
xlnx_ep108_binfo.kernel_cmdline = machine->kernel_cmdline; xlnx_ep108_binfo.kernel_cmdline = machine->kernel_cmdline;

View File

@ -57,6 +57,14 @@ static const int sdhci_intr[XLNX_ZYNQMP_NUM_SDHCI] = {
48, 49, 48, 49,
}; };
static const uint64_t spi_addr[XLNX_ZYNQMP_NUM_SPIS] = {
0xFF040000, 0xFF050000,
};
static const int spi_intr[XLNX_ZYNQMP_NUM_SPIS] = {
19, 20,
};
typedef struct XlnxZynqMPGICRegion { typedef struct XlnxZynqMPGICRegion {
int region_index; int region_index;
uint32_t address; uint32_t address;
@ -118,6 +126,12 @@ static void xlnx_zynqmp_init(Object *obj)
qdev_set_parent_bus(DEVICE(&s->sdhci[i]), qdev_set_parent_bus(DEVICE(&s->sdhci[i]),
sysbus_get_default()); sysbus_get_default());
} }
for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) {
object_initialize(&s->spi[i], sizeof(s->spi[i]),
TYPE_XILINX_SPIPS);
qdev_set_parent_bus(DEVICE(&s->spi[i]), sysbus_get_default());
}
} }
static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp) static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
@ -324,6 +338,23 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci[i]), 0, sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci[i]), 0,
gic_spi[sdhci_intr[i]]); gic_spi[sdhci_intr[i]]);
} }
for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) {
gchar *bus_name;
object_property_set_bool(OBJECT(&s->spi[i]), true, "realized", &err);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0, spi_addr[i]);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->spi[i]), 0,
gic_spi[spi_intr[i]]);
/* Alias controller SPI bus to the SoC itself */
bus_name = g_strdup_printf("spi%d", i);
object_property_add_alias(OBJECT(s), bus_name,
OBJECT(&s->spi[i]), "spi0",
&error_abort);
g_free(bus_name);
}
} }
static Property xlnx_zynqmp_props[] = { static Property xlnx_zynqmp_props[] = {

View File

@ -17,7 +17,7 @@
#include "hw/arm/arm.h" #include "hw/arm/arm.h"
#include "hw/devices.h" #include "hw/devices.h"
#include "hw/i2c/i2c.h" #include "hw/i2c/i2c.h"
#include "hw/ssi.h" #include "hw/ssi/ssi.h"
#include "hw/boards.h" #include "hw/boards.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "hw/block/flash.h" #include "hw/block/flash.h"

View File

@ -25,7 +25,7 @@
#include "hw/hw.h" #include "hw/hw.h"
#include "sysemu/block-backend.h" #include "sysemu/block-backend.h"
#include "sysemu/blockdev.h" #include "sysemu/blockdev.h"
#include "hw/ssi.h" #include "hw/ssi/ssi.h"
#ifndef M25P80_ERR_DEBUG #ifndef M25P80_ERR_DEBUG
#define M25P80_ERR_DEBUG 0 #define M25P80_ERR_DEBUG 0
@ -164,6 +164,7 @@ static const FlashPartInfo known_devices[] = {
{ INFO("sst25wf010", 0xbf2502, 0, 64 << 10, 2, ER_4K) }, { INFO("sst25wf010", 0xbf2502, 0, 64 << 10, 2, ER_4K) },
{ INFO("sst25wf020", 0xbf2503, 0, 64 << 10, 4, ER_4K) }, { INFO("sst25wf020", 0xbf2503, 0, 64 << 10, 4, ER_4K) },
{ INFO("sst25wf040", 0xbf2504, 0, 64 << 10, 8, ER_4K) }, { INFO("sst25wf040", 0xbf2504, 0, 64 << 10, 8, ER_4K) },
{ INFO("sst25wf080", 0xbf2505, 0, 64 << 10, 16, ER_4K) },
/* ST Microelectronics -- newer production may have feature updates */ /* ST Microelectronics -- newer production may have feature updates */
{ INFO("m25p05", 0x202010, 0, 32 << 10, 2, 0) }, { INFO("m25p05", 0x202010, 0, 32 << 10, 2, 0) },

View File

@ -580,6 +580,12 @@ void qdev_pass_gpios(DeviceState *dev, DeviceState *container,
BusState *qdev_get_child_bus(DeviceState *dev, const char *name) BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
{ {
BusState *bus; BusState *bus;
Object *child = object_resolve_path_component(OBJECT(dev), name);
bus = (BusState *)object_dynamic_cast(child, TYPE_BUS);
if (bus) {
return bus;
}
QLIST_FOREACH(bus, &dev->child_bus, sibling) { QLIST_FOREACH(bus, &dev->child_bus, sibling) {
if (strcmp(name, bus->name) == 0) { if (strcmp(name, bus->name) == 0) {

View File

@ -10,7 +10,7 @@
* GNU GPL, version 2 or (at your option) any later version. * GNU GPL, version 2 or (at your option) any later version.
*/ */
#include "hw/ssi.h" #include "hw/ssi/ssi.h"
#include "ui/console.h" #include "ui/console.h"
typedef struct { typedef struct {

View File

@ -10,7 +10,7 @@
/* The controller can support a variety of different displays, but we only /* The controller can support a variety of different displays, but we only
implement one. Most of the commends relating to brightness and geometry implement one. Most of the commends relating to brightness and geometry
setup are ignored. */ setup are ignored. */
#include "hw/ssi.h" #include "hw/ssi/ssi.h"
#include "ui/console.h" #include "ui/console.h"
//#define DEBUG_SSD0323 1 //#define DEBUG_SSD0323 1

View File

@ -31,8 +31,16 @@ do { fprintf(stderr, "arm_gic: " fmt , ## __VA_ARGS__); } while (0)
#define DPRINTF(fmt, ...) do {} while(0) #define DPRINTF(fmt, ...) do {} while(0)
#endif #endif
static const uint8_t gic_id[] = { static const uint8_t gic_id_11mpcore[] = {
0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 0x00, 0x00, 0x00, 0x00, 0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1
};
static const uint8_t gic_id_gicv1[] = {
0x04, 0x00, 0x00, 0x00, 0x90, 0xb3, 0x1b, 0x00, 0x0d, 0xf0, 0x05, 0xb1
};
static const uint8_t gic_id_gicv2[] = {
0x04, 0x00, 0x00, 0x00, 0x90, 0xb4, 0x2b, 0x00, 0x0d, 0xf0, 0x05, 0xb1
}; };
static inline int gic_get_current_cpu(GICState *s) static inline int gic_get_current_cpu(GICState *s)
@ -683,15 +691,32 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs)
} }
res = s->sgi_pending[irq][cpu]; res = s->sgi_pending[irq][cpu];
} else if (offset < 0xfe0) { } else if (offset < 0xfd0) {
goto bad_reg; goto bad_reg;
} else /* offset >= 0xfe0 */ { } else if (offset < 0x1000) {
if (offset & 3) { if (offset & 3) {
res = 0; res = 0;
} else { } else {
res = gic_id[(offset - 0xfe0) >> 2]; switch (s->revision) {
case REV_11MPCORE:
res = gic_id_11mpcore[(offset - 0xfd0) >> 2];
break;
case 1:
res = gic_id_gicv1[(offset - 0xfd0) >> 2];
break;
case 2:
res = gic_id_gicv2[(offset - 0xfd0) >> 2];
break;
case REV_NVIC:
/* Shouldn't be able to get here */
abort();
default:
res = 0;
} }
} }
} else {
g_assert_not_reached();
}
return res; return res;
bad_reg: bad_reg:
qemu_log_mask(LOG_GUEST_ERROR, qemu_log_mask(LOG_GUEST_ERROR,

View File

@ -35,7 +35,7 @@
#include "sysemu/block-backend.h" #include "sysemu/block-backend.h"
#include "hw/char/serial.h" #include "hw/char/serial.h"
#include "exec/address-spaces.h" #include "exec/address-spaces.h"
#include "hw/ssi.h" #include "hw/ssi/ssi.h"
#include "boot.h" #include "boot.h"

View File

@ -10,7 +10,7 @@
* GNU GPL, version 2 or (at your option) any later version. * GNU GPL, version 2 or (at your option) any later version.
*/ */
#include "hw/ssi.h" #include "hw/ssi/ssi.h"
typedef struct { typedef struct {
SSISlave parent_obj; SSISlave parent_obj;

View File

@ -220,7 +220,7 @@ static void zynq_xadc_write(void *opaque, hwaddr offset, uint64_t val,
break; break;
} }
if (xadc_reg > ZYNQ_XADC_NUM_ADC_REGS && xadc_cmd != CMD_NOP) { if (xadc_reg >= ZYNQ_XADC_NUM_ADC_REGS && xadc_cmd != CMD_NOP) {
qemu_log_mask(LOG_GUEST_ERROR, "read/write op to invalid xadc " qemu_log_mask(LOG_GUEST_ERROR, "read/write op to invalid xadc "
"reg 0x%x\n", xadc_reg); "reg 0x%x\n", xadc_reg);
break; break;

View File

@ -12,7 +12,7 @@
#include "sysemu/block-backend.h" #include "sysemu/block-backend.h"
#include "sysemu/blockdev.h" #include "sysemu/blockdev.h"
#include "hw/ssi.h" #include "hw/ssi/ssi.h"
#include "hw/sd/sd.h" #include "hw/sd/sd.h"
//#define DEBUG_SSI_SD 1 //#define DEBUG_SSI_SD 1

View File

@ -8,7 +8,7 @@
*/ */
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "hw/ssi.h" #include "hw/ssi/ssi.h"
//#define DEBUG_PL022 1 //#define DEBUG_PL022 1

View File

@ -12,7 +12,7 @@
* GNU GPL, version 2 or (at your option) any later version. * GNU GPL, version 2 or (at your option) any later version.
*/ */
#include "hw/ssi.h" #include "hw/ssi/ssi.h"
struct SSIBus { struct SSIBus {
BusState parent_obj; BusState parent_obj;

View File

@ -29,7 +29,7 @@
#include "qemu/log.h" #include "qemu/log.h"
#include "qemu/fifo8.h" #include "qemu/fifo8.h"
#include "hw/ssi.h" #include "hw/ssi/ssi.h"
#ifdef XILINX_SPI_ERR_DEBUG #ifdef XILINX_SPI_ERR_DEBUG
#define DB_PRINT(...) do { \ #define DB_PRINT(...) do { \

View File

@ -27,8 +27,9 @@
#include "hw/ptimer.h" #include "hw/ptimer.h"
#include "qemu/log.h" #include "qemu/log.h"
#include "qemu/fifo8.h" #include "qemu/fifo8.h"
#include "hw/ssi.h" #include "hw/ssi/ssi.h"
#include "qemu/bitops.h" #include "qemu/bitops.h"
#include "hw/ssi/xilinx_spips.h"
#ifndef XILINX_SPIPS_ERR_DEBUG #ifndef XILINX_SPIPS_ERR_DEBUG
#define XILINX_SPIPS_ERR_DEBUG 0 #define XILINX_SPIPS_ERR_DEBUG 0
@ -103,8 +104,6 @@
#define R_MOD_ID (0xFC / 4) #define R_MOD_ID (0xFC / 4)
#define R_MAX (R_MOD_ID+1)
/* size of TXRX FIFOs */ /* size of TXRX FIFOs */
#define RXFF_A 32 #define RXFF_A 32
#define TXFF_A 32 #define TXFF_A 32
@ -134,30 +133,6 @@ typedef enum {
QPP = 0x32, QPP = 0x32,
} FlashCMD; } FlashCMD;
typedef struct {
SysBusDevice parent_obj;
MemoryRegion iomem;
MemoryRegion mmlqspi;
qemu_irq irq;
int irqline;
uint8_t num_cs;
uint8_t num_busses;
uint8_t snoop_state;
qemu_irq *cs_lines;
SSIBus **spi;
Fifo8 rx_fifo;
Fifo8 tx_fifo;
uint8_t num_txrx_bytes;
uint32_t regs[R_MAX];
} XilinxSPIPS;
typedef struct { typedef struct {
XilinxSPIPS parent_obj; XilinxSPIPS parent_obj;
@ -174,19 +149,6 @@ typedef struct XilinxSPIPSClass {
uint32_t tx_fifo_size; uint32_t tx_fifo_size;
} XilinxSPIPSClass; } XilinxSPIPSClass;
#define TYPE_XILINX_SPIPS "xlnx.ps7-spi"
#define TYPE_XILINX_QSPIPS "xlnx.ps7-qspi"
#define XILINX_SPIPS(obj) \
OBJECT_CHECK(XilinxSPIPS, (obj), TYPE_XILINX_SPIPS)
#define XILINX_SPIPS_CLASS(klass) \
OBJECT_CLASS_CHECK(XilinxSPIPSClass, (klass), TYPE_XILINX_SPIPS)
#define XILINX_SPIPS_GET_CLASS(obj) \
OBJECT_GET_CLASS(XilinxSPIPSClass, (obj), TYPE_XILINX_SPIPS)
#define XILINX_QSPIPS(obj) \
OBJECT_CHECK(XilinxQSPIPS, (obj), TYPE_XILINX_QSPIPS)
static inline int num_effective_busses(XilinxSPIPS *s) static inline int num_effective_busses(XilinxSPIPS *s)
{ {
return (s->regs[R_LQSPI_CFG] & LQSPI_CFG_SEP_BUS && return (s->regs[R_LQSPI_CFG] & LQSPI_CFG_SEP_BUS &&
@ -257,7 +219,7 @@ static void xilinx_spips_reset(DeviceState *d)
XilinxSPIPS *s = XILINX_SPIPS(d); XilinxSPIPS *s = XILINX_SPIPS(d);
int i; int i;
for (i = 0; i < R_MAX; i++) { for (i = 0; i < XLNX_SPIPS_R_MAX; i++) {
s->regs[i] = 0; s->regs[i] = 0;
} }
@ -664,7 +626,7 @@ static void xilinx_spips_realize(DeviceState *dev, Error **errp)
} }
memory_region_init_io(&s->iomem, OBJECT(s), xsc->reg_ops, s, memory_region_init_io(&s->iomem, OBJECT(s), xsc->reg_ops, s,
"spi", R_MAX*4); "spi", XLNX_SPIPS_R_MAX * 4);
sysbus_init_mmio(sbd, &s->iomem); sysbus_init_mmio(sbd, &s->iomem);
s->irqline = -1; s->irqline = -1;
@ -708,7 +670,7 @@ static const VMStateDescription vmstate_xilinx_spips = {
.fields = (VMStateField[]) { .fields = (VMStateField[]) {
VMSTATE_FIFO8(tx_fifo, XilinxSPIPS), VMSTATE_FIFO8(tx_fifo, XilinxSPIPS),
VMSTATE_FIFO8(rx_fifo, XilinxSPIPS), VMSTATE_FIFO8(rx_fifo, XilinxSPIPS),
VMSTATE_UINT32_ARRAY(regs, XilinxSPIPS, R_MAX), VMSTATE_UINT32_ARRAY(regs, XilinxSPIPS, XLNX_SPIPS_R_MAX),
VMSTATE_UINT8(snoop_state, XilinxSPIPS), VMSTATE_UINT8(snoop_state, XilinxSPIPS),
VMSTATE_END_OF_LIST() VMSTATE_END_OF_LIST()
} }

View File

@ -84,7 +84,34 @@ void QEMU_NORETURN cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc);
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
void cpu_reloading_memory_map(void); void cpu_reloading_memory_map(void);
void tcg_cpu_address_space_init(CPUState *cpu, AddressSpace *as); /**
* cpu_address_space_init:
* @cpu: CPU to add this address space to
* @as: address space to add
* @asidx: integer index of this address space
*
* Add the specified address space to the CPU's cpu_ases list.
* The address space added with @asidx 0 is the one used for the
* convenience pointer cpu->as.
* The target-specific code which registers ASes is responsible
* for defining what semantics address space 0, 1, 2, etc have.
*
* Before the first call to this function, the caller must set
* cpu->num_ases to the total number of address spaces it needs
* to support.
*
* Note that with KVM only one address space is supported.
*/
void cpu_address_space_init(CPUState *cpu, AddressSpace *as, int asidx);
/**
* cpu_get_address_space:
* @cpu: CPU to get address space from
* @asidx: index identifying which address space to get
*
* Return the requested address space of this CPU. @asidx
* specifies which address space to read.
*/
AddressSpace *cpu_get_address_space(CPUState *cpu, int asidx);
/* cputlb.c */ /* cputlb.c */
/** /**
* tlb_flush_page: * tlb_flush_page:
@ -126,12 +153,40 @@ void tlb_flush_page_by_mmuidx(CPUState *cpu, target_ulong addr, ...);
* MMU indexes. * MMU indexes.
*/ */
void tlb_flush_by_mmuidx(CPUState *cpu, ...); void tlb_flush_by_mmuidx(CPUState *cpu, ...);
void tlb_set_page(CPUState *cpu, target_ulong vaddr, /**
hwaddr paddr, int prot, * tlb_set_page_with_attrs:
int mmu_idx, target_ulong size); * @cpu: CPU to add this TLB entry for
* @vaddr: virtual address of page to add entry for
* @paddr: physical address of the page
* @attrs: memory transaction attributes
* @prot: access permissions (PAGE_READ/PAGE_WRITE/PAGE_EXEC bits)
* @mmu_idx: MMU index to insert TLB entry for
* @size: size of the page in bytes
*
* Add an entry to this CPU's TLB (a mapping from virtual address
* @vaddr to physical address @paddr) with the specified memory
* transaction attributes. This is generally called by the target CPU
* specific code after it has been called through the tlb_fill()
* entry point and performed a successful page table walk to find
* the physical address and attributes for the virtual address
* which provoked the TLB miss.
*
* At most one entry for a given virtual address is permitted. Only a
* single TARGET_PAGE_SIZE region is mapped; the supplied @size is only
* used by tlb_flush_page.
*/
void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr, void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr,
hwaddr paddr, MemTxAttrs attrs, hwaddr paddr, MemTxAttrs attrs,
int prot, int mmu_idx, target_ulong size); int prot, int mmu_idx, target_ulong size);
/* tlb_set_page:
*
* This function is equivalent to calling tlb_set_page_with_attrs()
* with an @attrs argument of MEMTXATTRS_UNSPECIFIED. It's provided
* as a convenience for CPUs which don't use memory transaction attributes.
*/
void tlb_set_page(CPUState *cpu, target_ulong vaddr,
hwaddr paddr, int prot,
int mmu_idx, target_ulong size);
void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr); void tb_invalidate_phys_addr(AddressSpace *as, hwaddr addr);
void probe_write(CPUArchState *env, target_ulong addr, int mmu_idx, void probe_write(CPUArchState *env, target_ulong addr, int mmu_idx,
uintptr_t retaddr); uintptr_t retaddr);
@ -357,7 +412,7 @@ extern uintptr_t tci_tb_ptr;
#if !defined(CONFIG_USER_ONLY) #if !defined(CONFIG_USER_ONLY)
struct MemoryRegion *iotlb_to_region(CPUState *cpu, struct MemoryRegion *iotlb_to_region(CPUState *cpu,
hwaddr index); hwaddr index, MemTxAttrs attrs);
void tlb_fill(CPUState *cpu, target_ulong addr, int is_write, int mmu_idx, void tlb_fill(CPUState *cpu, target_ulong addr, int is_write, int mmu_idx,
uintptr_t retaddr); uintptr_t retaddr);
@ -386,8 +441,8 @@ void tlb_set_dirty(CPUState *cpu, target_ulong vaddr);
void tb_flush_jmp_cache(CPUState *cpu, target_ulong addr); void tb_flush_jmp_cache(CPUState *cpu, target_ulong addr);
MemoryRegionSection * MemoryRegionSection *
address_space_translate_for_iotlb(CPUState *cpu, hwaddr addr, hwaddr *xlat, address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr,
hwaddr *plen); hwaddr *xlat, hwaddr *plen);
hwaddr memory_region_section_get_iotlb(CPUState *cpu, hwaddr memory_region_section_get_iotlb(CPUState *cpu,
MemoryRegionSection *section, MemoryRegionSection *section,
target_ulong vaddr, target_ulong vaddr,

View File

@ -241,6 +241,8 @@ struct AddressSpace {
struct rcu_head rcu; struct rcu_head rcu;
char *name; char *name;
MemoryRegion *root; MemoryRegion *root;
int ref_count;
bool malloced;
/* Accessed via RCU. */ /* Accessed via RCU. */
struct FlatView *current_map; struct FlatView *current_map;
@ -1189,6 +1191,22 @@ MemTxResult memory_region_dispatch_write(MemoryRegion *mr,
*/ */
void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name); void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name);
/**
* address_space_init_shareable: return an address space for a memory region,
* creating it if it does not already exist
*
* @root: a #MemoryRegion that routes addresses for the address space
* @name: an address space name. The name is only used for debugging
* output.
*
* This function will return a pointer to an existing AddressSpace
* which was initialized with the specified MemoryRegion, or it will
* create and initialize one if it does not already exist. The ASes
* are reference-counted, so the memory will be freed automatically
* when the AddressSpace is destroyed via address_space_destroy.
*/
AddressSpace *address_space_init_shareable(MemoryRegion *root,
const char *name);
/** /**
* address_space_destroy: destroy an address space * address_space_destroy: destroy an address space

View File

@ -60,6 +60,7 @@ enum {
VIRT_PLATFORM_BUS, VIRT_PLATFORM_BUS,
VIRT_PCIE_MMIO_HIGH, VIRT_PCIE_MMIO_HIGH,
VIRT_GPIO, VIRT_GPIO,
VIRT_SECURE_UART,
}; };
typedef struct MemMapEntry { typedef struct MemMapEntry {

View File

@ -25,6 +25,7 @@
#include "hw/ide/pci.h" #include "hw/ide/pci.h"
#include "hw/ide/ahci.h" #include "hw/ide/ahci.h"
#include "hw/sd/sdhci.h" #include "hw/sd/sdhci.h"
#include "hw/ssi/xilinx_spips.h"
#define TYPE_XLNX_ZYNQMP "xlnx,zynqmp" #define TYPE_XLNX_ZYNQMP "xlnx,zynqmp"
#define XLNX_ZYNQMP(obj) OBJECT_CHECK(XlnxZynqMPState, (obj), \ #define XLNX_ZYNQMP(obj) OBJECT_CHECK(XlnxZynqMPState, (obj), \
@ -35,6 +36,7 @@
#define XLNX_ZYNQMP_NUM_GEMS 4 #define XLNX_ZYNQMP_NUM_GEMS 4
#define XLNX_ZYNQMP_NUM_UARTS 2 #define XLNX_ZYNQMP_NUM_UARTS 2
#define XLNX_ZYNQMP_NUM_SDHCI 2 #define XLNX_ZYNQMP_NUM_SDHCI 2
#define XLNX_ZYNQMP_NUM_SPIS 2
#define XLNX_ZYNQMP_NUM_OCM_BANKS 4 #define XLNX_ZYNQMP_NUM_OCM_BANKS 4
#define XLNX_ZYNQMP_OCM_RAM_0_ADDRESS 0xFFFC0000 #define XLNX_ZYNQMP_OCM_RAM_0_ADDRESS 0xFFFC0000
@ -78,6 +80,7 @@ typedef struct XlnxZynqMPState {
CadenceUARTState uart[XLNX_ZYNQMP_NUM_UARTS]; CadenceUARTState uart[XLNX_ZYNQMP_NUM_UARTS];
SysbusAHCIState sata; SysbusAHCIState sata;
SDHCIState sdhci[XLNX_ZYNQMP_NUM_SDHCI]; SDHCIState sdhci[XLNX_ZYNQMP_NUM_SDHCI];
XilinxSPIPS spi[XLNX_ZYNQMP_NUM_SPIS];
char *boot_cpu; char *boot_cpu;
ARMCPU *boot_cpu_ptr; ARMCPU *boot_cpu_ptr;

View File

@ -14,6 +14,8 @@
#include "hw/qdev.h" #include "hw/qdev.h"
typedef struct SSISlave SSISlave; typedef struct SSISlave SSISlave;
typedef struct SSISlaveClass SSISlaveClass;
typedef enum SSICSMode SSICSMode;
#define TYPE_SSI_SLAVE "ssi-slave" #define TYPE_SSI_SLAVE "ssi-slave"
#define SSI_SLAVE(obj) \ #define SSI_SLAVE(obj) \
@ -25,14 +27,14 @@ typedef struct SSISlave SSISlave;
#define SSI_GPIO_CS "ssi-gpio-cs" #define SSI_GPIO_CS "ssi-gpio-cs"
typedef enum { enum SSICSMode {
SSI_CS_NONE = 0, SSI_CS_NONE = 0,
SSI_CS_LOW, SSI_CS_LOW,
SSI_CS_HIGH, SSI_CS_HIGH,
} SSICSMode; };
/* Slave devices. */ /* Slave devices. */
typedef struct SSISlaveClass { struct SSISlaveClass {
DeviceClass parent_class; DeviceClass parent_class;
int (*init)(SSISlave *dev); int (*init)(SSISlave *dev);
@ -55,7 +57,7 @@ typedef struct SSISlaveClass {
* always be called for the device for every txrx access to the parent bus * always be called for the device for every txrx access to the parent bus
*/ */
uint32_t (*transfer_raw)(SSISlave *dev, uint32_t val); uint32_t (*transfer_raw)(SSISlave *dev, uint32_t val);
} SSISlaveClass; };
struct SSISlave { struct SSISlave {
DeviceState parent_obj; DeviceState parent_obj;

View File

@ -0,0 +1,72 @@
/*
* Header file for the Xilinx Zynq SPI controller
*
* Copyright (C) 2015 Xilinx Inc
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef XLNX_SPIPS_H
#define XLNX_SPIPS_H
#include "hw/ssi/ssi.h"
#include "qemu/fifo8.h"
typedef struct XilinxSPIPS XilinxSPIPS;
#define XLNX_SPIPS_R_MAX (0x100 / 4)
struct XilinxSPIPS {
SysBusDevice parent_obj;
MemoryRegion iomem;
MemoryRegion mmlqspi;
qemu_irq irq;
int irqline;
uint8_t num_cs;
uint8_t num_busses;
uint8_t snoop_state;
qemu_irq *cs_lines;
SSIBus **spi;
Fifo8 rx_fifo;
Fifo8 tx_fifo;
uint8_t num_txrx_bytes;
uint32_t regs[XLNX_SPIPS_R_MAX];
};
#define TYPE_XILINX_SPIPS "xlnx.ps7-spi"
#define TYPE_XILINX_QSPIPS "xlnx.ps7-qspi"
#define XILINX_SPIPS(obj) \
OBJECT_CHECK(XilinxSPIPS, (obj), TYPE_XILINX_SPIPS)
#define XILINX_SPIPS_CLASS(klass) \
OBJECT_CLASS_CHECK(XilinxSPIPSClass, (klass), TYPE_XILINX_SPIPS)
#define XILINX_SPIPS_GET_CLASS(obj) \
OBJECT_GET_CLASS(XilinxSPIPSClass, (obj), TYPE_XILINX_SPIPS)
#define XILINX_QSPIPS(obj) \
OBJECT_CHECK(XilinxQSPIPS, (obj), TYPE_XILINX_QSPIPS)
#endif /* XLNX_SPIPS_H */

View File

@ -98,6 +98,12 @@ struct TranslationBlock;
* #TranslationBlock. * #TranslationBlock.
* @handle_mmu_fault: Callback for handling an MMU fault. * @handle_mmu_fault: Callback for handling an MMU fault.
* @get_phys_page_debug: Callback for obtaining a physical address. * @get_phys_page_debug: Callback for obtaining a physical address.
* @get_phys_page_attrs_debug: Callback for obtaining a physical address and the
* associated memory transaction attributes to use for the access.
* CPUs which use memory transaction attributes should implement this
* instead of get_phys_page_debug.
* @asidx_from_attrs: Callback to return the CPU AddressSpace to use for
* a memory access with the specified memory transaction attributes.
* @gdb_read_register: Callback for letting GDB read a register. * @gdb_read_register: Callback for letting GDB read a register.
* @gdb_write_register: Callback for letting GDB write a register. * @gdb_write_register: Callback for letting GDB write a register.
* @debug_excp_handler: Callback for handling debug exceptions. * @debug_excp_handler: Callback for handling debug exceptions.
@ -152,6 +158,9 @@ typedef struct CPUClass {
int (*handle_mmu_fault)(CPUState *cpu, vaddr address, int rw, int (*handle_mmu_fault)(CPUState *cpu, vaddr address, int rw,
int mmu_index); int mmu_index);
hwaddr (*get_phys_page_debug)(CPUState *cpu, vaddr addr); hwaddr (*get_phys_page_debug)(CPUState *cpu, vaddr addr);
hwaddr (*get_phys_page_attrs_debug)(CPUState *cpu, vaddr addr,
MemTxAttrs *attrs);
int (*asidx_from_attrs)(CPUState *cpu, MemTxAttrs attrs);
int (*gdb_read_register)(CPUState *cpu, uint8_t *buf, int reg); int (*gdb_read_register)(CPUState *cpu, uint8_t *buf, int reg);
int (*gdb_write_register)(CPUState *cpu, uint8_t *buf, int reg); int (*gdb_write_register)(CPUState *cpu, uint8_t *buf, int reg);
void (*debug_excp_handler)(CPUState *cpu); void (*debug_excp_handler)(CPUState *cpu);
@ -236,6 +245,7 @@ struct kvm_run;
* so that interrupts take effect immediately. * so that interrupts take effect immediately.
* @cpu_ases: Pointer to array of CPUAddressSpaces (which define the * @cpu_ases: Pointer to array of CPUAddressSpaces (which define the
* AddressSpaces this CPU has) * AddressSpaces this CPU has)
* @num_ases: number of CPUAddressSpaces in @cpu_ases
* @as: Pointer to the first AddressSpace, for the convenience of targets which * @as: Pointer to the first AddressSpace, for the convenience of targets which
* only have a single AddressSpace * only have a single AddressSpace
* @env_ptr: Pointer to subclass-specific CPUArchState field. * @env_ptr: Pointer to subclass-specific CPUArchState field.
@ -285,7 +295,9 @@ struct CPUState {
struct qemu_work_item *queued_work_first, *queued_work_last; struct qemu_work_item *queued_work_first, *queued_work_last;
CPUAddressSpace *cpu_ases; CPUAddressSpace *cpu_ases;
int num_ases;
AddressSpace *as; AddressSpace *as;
MemoryRegion *memory;
void *env_ptr; /* CPUArchState */ void *env_ptr; /* CPUArchState */
struct TranslationBlock *current_tb; struct TranslationBlock *current_tb;
@ -442,6 +454,32 @@ void cpu_dump_statistics(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
int flags); int flags);
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
/**
* cpu_get_phys_page_attrs_debug:
* @cpu: The CPU to obtain the physical page address for.
* @addr: The virtual address.
* @attrs: Updated on return with the memory transaction attributes to use
* for this access.
*
* Obtains the physical page corresponding to a virtual one, together
* with the corresponding memory transaction attributes to use for the access.
* Use it only for debugging because no protection checks are done.
*
* Returns: Corresponding physical page address or -1 if no page found.
*/
static inline hwaddr cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr,
MemTxAttrs *attrs)
{
CPUClass *cc = CPU_GET_CLASS(cpu);
if (cc->get_phys_page_attrs_debug) {
return cc->get_phys_page_attrs_debug(cpu, addr, attrs);
}
/* Fallback for CPUs which don't implement the _attrs_ hook */
*attrs = MEMTXATTRS_UNSPECIFIED;
return cc->get_phys_page_debug(cpu, addr);
}
/** /**
* cpu_get_phys_page_debug: * cpu_get_phys_page_debug:
* @cpu: The CPU to obtain the physical page address for. * @cpu: The CPU to obtain the physical page address for.
@ -453,10 +491,27 @@ void cpu_dump_statistics(CPUState *cpu, FILE *f, fprintf_function cpu_fprintf,
* Returns: Corresponding physical page address or -1 if no page found. * Returns: Corresponding physical page address or -1 if no page found.
*/ */
static inline hwaddr cpu_get_phys_page_debug(CPUState *cpu, vaddr addr) static inline hwaddr cpu_get_phys_page_debug(CPUState *cpu, vaddr addr)
{
MemTxAttrs attrs = {};
return cpu_get_phys_page_attrs_debug(cpu, addr, &attrs);
}
/** cpu_asidx_from_attrs:
* @cpu: CPU
* @attrs: memory transaction attributes
*
* Returns the address space index specifying the CPU AddressSpace
* to use for a memory access with the given transaction attributes.
*/
static inline int cpu_asidx_from_attrs(CPUState *cpu, MemTxAttrs attrs)
{ {
CPUClass *cc = CPU_GET_CLASS(cpu); CPUClass *cc = CPU_GET_CLASS(cpu);
return cc->get_phys_page_debug(cpu, addr); if (cc->asidx_from_attrs) {
return cc->asidx_from_attrs(cpu, attrs);
}
return 0;
} }
#endif #endif

View File

@ -2124,7 +2124,9 @@ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name)
{ {
memory_region_ref(root); memory_region_ref(root);
memory_region_transaction_begin(); memory_region_transaction_begin();
as->ref_count = 1;
as->root = root; as->root = root;
as->malloced = false;
as->current_map = g_new(FlatView, 1); as->current_map = g_new(FlatView, 1);
flatview_init(as->current_map); flatview_init(as->current_map);
as->ioeventfd_nb = 0; as->ioeventfd_nb = 0;
@ -2139,6 +2141,7 @@ void address_space_init(AddressSpace *as, MemoryRegion *root, const char *name)
static void do_address_space_destroy(AddressSpace *as) static void do_address_space_destroy(AddressSpace *as)
{ {
MemoryListener *listener; MemoryListener *listener;
bool do_free = as->malloced;
address_space_destroy_dispatch(as); address_space_destroy_dispatch(as);
@ -2150,12 +2153,36 @@ static void do_address_space_destroy(AddressSpace *as)
g_free(as->name); g_free(as->name);
g_free(as->ioeventfds); g_free(as->ioeventfds);
memory_region_unref(as->root); memory_region_unref(as->root);
if (do_free) {
g_free(as);
}
}
AddressSpace *address_space_init_shareable(MemoryRegion *root, const char *name)
{
AddressSpace *as;
QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) {
if (root == as->root && as->malloced) {
as->ref_count++;
return as;
}
}
as = g_malloc0(sizeof *as);
address_space_init(as, root, name);
as->malloced = true;
return as;
} }
void address_space_destroy(AddressSpace *as) void address_space_destroy(AddressSpace *as)
{ {
MemoryRegion *root = as->root; MemoryRegion *root = as->root;
as->ref_count--;
if (as->ref_count) {
return;
}
/* Flush out anything from MemoryListeners listening in on this */ /* Flush out anything from MemoryListeners listening in on this */
memory_region_transaction_begin(); memory_region_transaction_begin();
as->root = NULL; as->root = NULL;

View File

@ -150,7 +150,7 @@ static inline DATA_TYPE glue(io_read, SUFFIX)(CPUArchState *env,
uint64_t val; uint64_t val;
CPUState *cpu = ENV_GET_CPU(env); CPUState *cpu = ENV_GET_CPU(env);
hwaddr physaddr = iotlbentry->addr; hwaddr physaddr = iotlbentry->addr;
MemoryRegion *mr = iotlb_to_region(cpu, physaddr); MemoryRegion *mr = iotlb_to_region(cpu, physaddr, iotlbentry->attrs);
physaddr = (physaddr & TARGET_PAGE_MASK) + addr; physaddr = (physaddr & TARGET_PAGE_MASK) + addr;
cpu->mem_io_pc = retaddr; cpu->mem_io_pc = retaddr;
@ -357,7 +357,7 @@ static inline void glue(io_write, SUFFIX)(CPUArchState *env,
{ {
CPUState *cpu = ENV_GET_CPU(env); CPUState *cpu = ENV_GET_CPU(env);
hwaddr physaddr = iotlbentry->addr; hwaddr physaddr = iotlbentry->addr;
MemoryRegion *mr = iotlb_to_region(cpu, physaddr); MemoryRegion *mr = iotlb_to_region(cpu, physaddr, iotlbentry->attrs);
physaddr = (physaddr & TARGET_PAGE_MASK) + addr; physaddr = (physaddr & TARGET_PAGE_MASK) + addr;
if (mr != &io_mem_rom && mr != &io_mem_notdirty && !cpu->can_do_io) { if (mr != &io_mem_rom && mr != &io_mem_notdirty && !cpu->can_do_io) {

View File

@ -87,6 +87,9 @@ typedef struct ARMCPU {
/* GPIO outputs for generic timer */ /* GPIO outputs for generic timer */
qemu_irq gt_timer_outputs[NUM_GTIMERS]; qemu_irq gt_timer_outputs[NUM_GTIMERS];
/* MemoryRegion to use for secure physical accesses */
MemoryRegion *secure_memory;
/* 'compatible' string for this CPU for Linux device trees */ /* 'compatible' string for this CPU for Linux device trees */
const char *dtb_compatible; const char *dtb_compatible;
@ -216,7 +219,8 @@ bool arm_cpu_exec_interrupt(CPUState *cpu, int int_req);
void arm_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, void arm_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
int flags); int flags);
hwaddr arm_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cpu, vaddr addr,
MemTxAttrs *attrs);
int arm_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); int arm_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); int arm_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
@ -248,8 +252,6 @@ void arm_gt_stimer_cb(void *opaque);
#ifdef TARGET_AARCH64 #ifdef TARGET_AARCH64
int aarch64_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); int aarch64_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg);
int aarch64_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); int aarch64_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
void aarch64_cpu_do_interrupt(CPUState *cs);
#endif #endif
#endif #endif

View File

@ -543,6 +543,15 @@ static void arm_cpu_post_init(Object *obj)
*/ */
qdev_property_add_static(DEVICE(obj), &arm_cpu_has_el3_property, qdev_property_add_static(DEVICE(obj), &arm_cpu_has_el3_property,
&error_abort); &error_abort);
#ifndef CONFIG_USER_ONLY
object_property_add_link(obj, "secure-memory",
TYPE_MEMORY_REGION,
(Object **)&cpu->secure_memory,
qdev_prop_allow_set_link_before_realize,
OBJ_PROP_LINK_UNREF_ON_RELEASE,
&error_abort);
#endif
} }
if (arm_feature(&cpu->env, ARM_FEATURE_MPU)) { if (arm_feature(&cpu->env, ARM_FEATURE_MPU)) {
@ -666,6 +675,29 @@ static void arm_cpu_realizefn(DeviceState *dev, Error **errp)
init_cpreg_list(cpu); init_cpreg_list(cpu);
#ifndef CONFIG_USER_ONLY
if (cpu->has_el3) {
cs->num_ases = 2;
} else {
cs->num_ases = 1;
}
if (cpu->has_el3) {
AddressSpace *as;
if (!cpu->secure_memory) {
cpu->secure_memory = cs->memory;
}
as = address_space_init_shareable(cpu->secure_memory,
"cpu-secure-memory");
cpu_address_space_init(cs, as, ARMASIdx_S);
}
cpu_address_space_init(cs,
address_space_init_shareable(cs->memory,
"cpu-memory"),
ARMASIdx_NS);
#endif
qemu_init_vcpu(cs); qemu_init_vcpu(cs);
cpu_reset(cs); cpu_reset(cs);
@ -1419,7 +1451,8 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data)
#else #else
cc->do_interrupt = arm_cpu_do_interrupt; cc->do_interrupt = arm_cpu_do_interrupt;
cc->do_unaligned_access = arm_cpu_do_unaligned_access; cc->do_unaligned_access = arm_cpu_do_unaligned_access;
cc->get_phys_page_debug = arm_cpu_get_phys_page_debug; 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->vmsd = &vmstate_arm_cpu;
cc->virtio_is_big_endian = arm_cpu_is_big_endian; cc->virtio_is_big_endian = arm_cpu_is_big_endian;
cc->write_elf64_note = arm_cpu_write_elf64_note; cc->write_elf64_note = arm_cpu_write_elf64_note;

View File

@ -969,18 +969,33 @@ static inline bool arm_is_secure(CPUARMState *env)
/* Return true if the specified exception level is running in AArch64 state. */ /* Return true if the specified exception level is running in AArch64 state. */
static inline bool arm_el_is_aa64(CPUARMState *env, int el) static inline bool arm_el_is_aa64(CPUARMState *env, int el)
{ {
/* We don't currently support EL2, and this isn't valid for EL0 /* This isn't valid for EL0 (if we're in EL0, is_a64() is what you want,
* (if we're in EL0, is_a64() is what you want, and if we're not in EL0 * and if we're not in EL0 then the state of EL0 isn't well defined.)
* then the state of EL0 isn't well defined.)
*/ */
assert(el == 1 || el == 3); assert(el >= 1 && el <= 3);
bool aa64 = arm_feature(env, ARM_FEATURE_AARCH64);
/* AArch64-capable CPUs always run with EL1 in AArch64 mode. This /* The highest exception level is always at the maximum supported
* is a QEMU-imposed simplification which we may wish to change later. * register width, and then lower levels have a register width controlled
* If we in future support EL2 and/or EL3, then the state of lower * by bits in the SCR or HCR registers.
* exception levels is controlled by the HCR.RW and SCR.RW bits.
*/ */
return arm_feature(env, ARM_FEATURE_AARCH64); if (el == 3) {
return aa64;
}
if (arm_feature(env, ARM_FEATURE_EL3)) {
aa64 = aa64 && (env->cp15.scr_el3 & SCR_RW);
}
if (el == 2) {
return aa64;
}
if (arm_feature(env, ARM_FEATURE_EL2) && !arm_is_secure_below_el3(env)) {
aa64 = aa64 && (env->cp15.hcr_el2 & HCR_RW);
}
return aa64;
} }
/* Function for determing whether guest cp register reads and writes should /* Function for determing whether guest cp register reads and writes should
@ -1720,6 +1735,12 @@ static inline int cpu_mmu_index(CPUARMState *env, bool ifetch)
return el; return el;
} }
/* Indexes used when registering address spaces with cpu_address_space_init */
typedef enum ARMASIdx {
ARMASIdx_NS = 0,
ARMASIdx_S = 1,
} ARMASIdx;
/* Return the Exception Level targeted by debug exceptions; /* Return the Exception Level targeted by debug exceptions;
* currently always EL1 since we don't implement EL2 or EL3. * currently always EL1 since we don't implement EL2 or EL3.
*/ */
@ -1991,4 +2012,21 @@ enum {
QEMU_PSCI_CONDUIT_HVC = 2, QEMU_PSCI_CONDUIT_HVC = 2,
}; };
#ifndef CONFIG_USER_ONLY
/* Return the address space index to use for a memory access */
static inline int arm_asidx_from_attrs(CPUState *cs, MemTxAttrs attrs)
{
return attrs.secure ? ARMASIdx_S : ARMASIdx_NS;
}
/* Return the AddressSpace to use for a memory access
* (which depends on whether the access is S or NS, and whether
* the board gave us a separate AddressSpace for S accesses).
*/
static inline AddressSpace *arm_addressspace(CPUState *cs, MemTxAttrs attrs)
{
return cpu_get_address_space(cs, arm_asidx_from_attrs(cs, attrs));
}
#endif
#endif #endif

View File

@ -291,9 +291,6 @@ static void aarch64_cpu_class_init(ObjectClass *oc, void *data)
{ {
CPUClass *cc = CPU_CLASS(oc); CPUClass *cc = CPU_CLASS(oc);
#if !defined(CONFIG_USER_ONLY)
cc->do_interrupt = aarch64_cpu_do_interrupt;
#endif
cc->cpu_exec_interrupt = arm_cpu_exec_interrupt; cc->cpu_exec_interrupt = arm_cpu_exec_interrupt;
cc->set_pc = aarch64_cpu_set_pc; cc->set_pc = aarch64_cpu_set_pc;
cc->gdb_read_register = aarch64_cpu_gdb_read_register; cc->gdb_read_register = aarch64_cpu_gdb_read_register;

View File

@ -26,7 +26,6 @@
#include "qemu/bitops.h" #include "qemu/bitops.h"
#include "internals.h" #include "internals.h"
#include "qemu/crc32c.h" #include "qemu/crc32c.h"
#include "sysemu/kvm.h"
#include <zlib.h> /* For crc32 */ #include <zlib.h> /* For crc32 */
/* C2.4.7 Multiply and divide */ /* C2.4.7 Multiply and divide */
@ -444,106 +443,3 @@ uint64_t HELPER(crc32c_64)(uint64_t acc, uint64_t val, uint32_t bytes)
/* Linux crc32c converts the output to one's complement. */ /* Linux crc32c converts the output to one's complement. */
return crc32c(acc, buf, bytes) ^ 0xffffffff; return crc32c(acc, buf, bytes) ^ 0xffffffff;
} }
#if !defined(CONFIG_USER_ONLY)
/* Handle a CPU exception. */
void aarch64_cpu_do_interrupt(CPUState *cs)
{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
unsigned int new_el = env->exception.target_el;
target_ulong addr = env->cp15.vbar_el[new_el];
unsigned int new_mode = aarch64_pstate_mode(new_el, true);
if (arm_current_el(env) < new_el) {
if (env->aarch64) {
addr += 0x400;
} else {
addr += 0x600;
}
} else if (pstate_read(env) & PSTATE_SP) {
addr += 0x200;
}
arm_log_exception(cs->exception_index);
qemu_log_mask(CPU_LOG_INT, "...from EL%d to EL%d\n", arm_current_el(env),
new_el);
if (qemu_loglevel_mask(CPU_LOG_INT)
&& !excp_is_internal(cs->exception_index)) {
qemu_log_mask(CPU_LOG_INT, "...with ESR %x/0x%" PRIx32 "\n",
env->exception.syndrome >> ARM_EL_EC_SHIFT,
env->exception.syndrome);
}
if (arm_is_psci_call(cpu, cs->exception_index)) {
arm_handle_psci_call(cpu);
qemu_log_mask(CPU_LOG_INT, "...handled as PSCI call\n");
return;
}
switch (cs->exception_index) {
case EXCP_PREFETCH_ABORT:
case EXCP_DATA_ABORT:
env->cp15.far_el[new_el] = env->exception.vaddress;
qemu_log_mask(CPU_LOG_INT, "...with FAR 0x%" PRIx64 "\n",
env->cp15.far_el[new_el]);
/* fall through */
case EXCP_BKPT:
case EXCP_UDEF:
case EXCP_SWI:
case EXCP_HVC:
case EXCP_HYP_TRAP:
case EXCP_SMC:
env->cp15.esr_el[new_el] = env->exception.syndrome;
break;
case EXCP_IRQ:
case EXCP_VIRQ:
addr += 0x80;
break;
case EXCP_FIQ:
case EXCP_VFIQ:
addr += 0x100;
break;
case EXCP_SEMIHOST:
qemu_log_mask(CPU_LOG_INT,
"...handling as semihosting call 0x%" PRIx64 "\n",
env->xregs[0]);
env->xregs[0] = do_arm_semihosting(env);
return;
default:
cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index);
}
if (is_a64(env)) {
env->banked_spsr[aarch64_banked_spsr_index(new_el)] = pstate_read(env);
aarch64_save_sp(env, arm_current_el(env));
env->elr_el[new_el] = env->pc;
} else {
env->banked_spsr[aarch64_banked_spsr_index(new_el)] = cpsr_read(env);
if (!env->thumb) {
env->cp15.esr_el[new_el] |= 1 << 25;
}
env->elr_el[new_el] = env->regs[15];
aarch64_sync_32_to_64(env);
env->condexec_bits = 0;
}
qemu_log_mask(CPU_LOG_INT, "...with ELR 0x%" PRIx64 "\n",
env->elr_el[new_el]);
pstate_write(env, PSTATE_DAIF | new_mode);
env->aarch64 = 1;
aarch64_restore_sp(env, new_el);
env->pc = addr;
qemu_log_mask(CPU_LOG_INT, "...to EL%d PC 0x%" PRIx64 " PSTATE 0x%x\n",
new_el, env->pc, pstate_read(env));
if (!kvm_enabled()) {
cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
}
}
#endif

View File

@ -12,6 +12,7 @@
#include "arm_ldst.h" #include "arm_ldst.h"
#include <zlib.h> /* For crc32 */ #include <zlib.h> /* For crc32 */
#include "exec/semihost.h" #include "exec/semihost.h"
#include "sysemu/kvm.h"
#define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */ #define ARM_CPU_FREQ 1000000000 /* FIXME: 1 GHz, should be configurable */
@ -2890,6 +2891,17 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri,
tlb_flush(CPU(cpu), 1); tlb_flush(CPU(cpu), 1);
} }
static CPAccessResult fpexc32_access(CPUARMState *env, const ARMCPRegInfo *ri)
{
if ((env->cp15.cptr_el[2] & CPTR_TFP) && arm_current_el(env) == 2) {
return CP_ACCESS_TRAP_EL2;
}
if (env->cp15.cptr_el[3] & CPTR_TFP) {
return CP_ACCESS_TRAP_EL3;
}
return CP_ACCESS_OK;
}
static const ARMCPRegInfo v8_cp_reginfo[] = { static const ARMCPRegInfo v8_cp_reginfo[] = {
/* Minimal set of EL0-visible registers. This will need to be expanded /* Minimal set of EL0-visible registers. This will need to be expanded
* significantly for system emulation of AArch64 CPUs. * significantly for system emulation of AArch64 CPUs.
@ -3150,6 +3162,11 @@ static const ARMCPRegInfo v8_cp_reginfo[] = {
.opc0 = 3, .opc1 = 0, .crn = 4, .crm = 2, .opc2 = 0, .opc0 = 3, .opc1 = 0, .crn = 4, .crm = 2, .opc2 = 0,
.type = ARM_CP_NO_RAW, .type = ARM_CP_NO_RAW,
.access = PL1_RW, .readfn = spsel_read, .writefn = spsel_write }, .access = PL1_RW, .readfn = spsel_read, .writefn = spsel_write },
{ .name = "FPEXC32_EL2", .state = ARM_CP_STATE_AA64,
.opc0 = 3, .opc1 = 4, .crn = 5, .crm = 3, .opc2 = 0,
.type = ARM_CP_ALIAS,
.fieldoffset = offsetof(CPUARMState, vfp.xregs[ARM_VFP_FPEXC]),
.access = PL2_RW, .accessfn = fpexc32_access },
REGINFO_SENTINEL REGINFO_SENTINEL
}; };
@ -5707,8 +5724,7 @@ void aarch64_sync_64_to_32(CPUARMState *env)
env->regs[15] = env->pc; env->regs[15] = env->pc;
} }
/* Handle a CPU exception. */ static void arm_cpu_do_interrupt_aarch32(CPUState *cs)
void arm_cpu_do_interrupt(CPUState *cs)
{ {
ARMCPU *cpu = ARM_CPU(cs); ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env; CPUARMState *env = &cpu->env;
@ -5718,16 +5734,6 @@ void arm_cpu_do_interrupt(CPUState *cs)
uint32_t offset; uint32_t offset;
uint32_t moe; uint32_t moe;
assert(!IS_M(env));
arm_log_exception(cs->exception_index);
if (arm_is_psci_call(cpu, cs->exception_index)) {
arm_handle_psci_call(cpu);
qemu_log_mask(CPU_LOG_INT, "...handled as PSCI call\n");
return;
}
/* If this is a debug exception we must update the DBGDSCR.MOE bits */ /* If this is a debug exception we must update the DBGDSCR.MOE bits */
switch (env->exception.syndrome >> ARM_EL_EC_SHIFT) { switch (env->exception.syndrome >> ARM_EL_EC_SHIFT) {
case EC_BREAKPOINT: case EC_BREAKPOINT:
@ -5765,27 +5771,6 @@ void arm_cpu_do_interrupt(CPUState *cs)
offset = 4; offset = 4;
break; break;
case EXCP_SWI: case EXCP_SWI:
if (semihosting_enabled()) {
/* Check for semihosting interrupt. */
if (env->thumb) {
mask = arm_lduw_code(env, env->regs[15] - 2, env->bswap_code)
& 0xff;
} else {
mask = arm_ldl_code(env, env->regs[15] - 4, env->bswap_code)
& 0xffffff;
}
/* Only intercept calls from privileged modes, to provide some
semblance of security. */
if (((mask == 0x123456 && !env->thumb)
|| (mask == 0xab && env->thumb))
&& (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) {
qemu_log_mask(CPU_LOG_INT,
"...handling as semihosting call 0x%x\n",
env->regs[0]);
env->regs[0] = do_arm_semihosting(env);
return;
}
}
new_mode = ARM_CPU_MODE_SVC; new_mode = ARM_CPU_MODE_SVC;
addr = 0x08; addr = 0x08;
mask = CPSR_I; mask = CPSR_I;
@ -5793,19 +5778,6 @@ void arm_cpu_do_interrupt(CPUState *cs)
offset = 0; offset = 0;
break; break;
case EXCP_BKPT: case EXCP_BKPT:
/* See if this is a semihosting syscall. */
if (env->thumb && semihosting_enabled()) {
mask = arm_lduw_code(env, env->regs[15], env->bswap_code) & 0xff;
if (mask == 0xab
&& (env->uncached_cpsr & CPSR_M) != ARM_CPU_MODE_USR) {
env->regs[15] += 2;
qemu_log_mask(CPU_LOG_INT,
"...handling as semihosting call 0x%x\n",
env->regs[0]);
env->regs[0] = do_arm_semihosting(env);
return;
}
}
env->exception.fsr = 2; env->exception.fsr = 2;
/* Fall through to prefetch abort. */ /* Fall through to prefetch abort. */
case EXCP_PREFETCH_ABORT: case EXCP_PREFETCH_ABORT:
@ -5899,9 +5871,227 @@ void arm_cpu_do_interrupt(CPUState *cs)
} }
env->regs[14] = env->regs[15] + offset; env->regs[14] = env->regs[15] + offset;
env->regs[15] = addr; env->regs[15] = addr;
cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
} }
/* Handle exception entry to a target EL which is using AArch64 */
static void arm_cpu_do_interrupt_aarch64(CPUState *cs)
{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
unsigned int new_el = env->exception.target_el;
target_ulong addr = env->cp15.vbar_el[new_el];
unsigned int new_mode = aarch64_pstate_mode(new_el, true);
if (arm_current_el(env) < new_el) {
/* Entry vector offset depends on whether the implemented EL
* immediately lower than the target level is using AArch32 or AArch64
*/
bool is_aa64;
switch (new_el) {
case 3:
is_aa64 = (env->cp15.scr_el3 & SCR_RW) != 0;
break;
case 2:
is_aa64 = (env->cp15.hcr_el2 & HCR_RW) != 0;
break;
case 1:
is_aa64 = is_a64(env);
break;
default:
g_assert_not_reached();
}
if (is_aa64) {
addr += 0x400;
} else {
addr += 0x600;
}
} else if (pstate_read(env) & PSTATE_SP) {
addr += 0x200;
}
switch (cs->exception_index) {
case EXCP_PREFETCH_ABORT:
case EXCP_DATA_ABORT:
env->cp15.far_el[new_el] = env->exception.vaddress;
qemu_log_mask(CPU_LOG_INT, "...with FAR 0x%" PRIx64 "\n",
env->cp15.far_el[new_el]);
/* fall through */
case EXCP_BKPT:
case EXCP_UDEF:
case EXCP_SWI:
case EXCP_HVC:
case EXCP_HYP_TRAP:
case EXCP_SMC:
env->cp15.esr_el[new_el] = env->exception.syndrome;
break;
case EXCP_IRQ:
case EXCP_VIRQ:
addr += 0x80;
break;
case EXCP_FIQ:
case EXCP_VFIQ:
addr += 0x100;
break;
case EXCP_SEMIHOST:
qemu_log_mask(CPU_LOG_INT,
"...handling as semihosting call 0x%" PRIx64 "\n",
env->xregs[0]);
env->xregs[0] = do_arm_semihosting(env);
return;
default:
cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index);
}
if (is_a64(env)) {
env->banked_spsr[aarch64_banked_spsr_index(new_el)] = pstate_read(env);
aarch64_save_sp(env, arm_current_el(env));
env->elr_el[new_el] = env->pc;
} else {
env->banked_spsr[aarch64_banked_spsr_index(new_el)] = cpsr_read(env);
if (!env->thumb) {
env->cp15.esr_el[new_el] |= 1 << 25;
}
env->elr_el[new_el] = env->regs[15];
aarch64_sync_32_to_64(env);
env->condexec_bits = 0;
}
qemu_log_mask(CPU_LOG_INT, "...with ELR 0x%" PRIx64 "\n",
env->elr_el[new_el]);
pstate_write(env, PSTATE_DAIF | new_mode);
env->aarch64 = 1;
aarch64_restore_sp(env, new_el);
env->pc = addr;
qemu_log_mask(CPU_LOG_INT, "...to EL%d PC 0x%" PRIx64 " PSTATE 0x%x\n",
new_el, env->pc, pstate_read(env));
}
static inline bool check_for_semihosting(CPUState *cs)
{
/* Check whether this exception is a semihosting call; if so
* then handle it and return true; otherwise return false.
*/
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
if (is_a64(env)) {
if (cs->exception_index == EXCP_SEMIHOST) {
/* This is always the 64-bit semihosting exception.
* The "is this usermode" and "is semihosting enabled"
* checks have been done at translate time.
*/
qemu_log_mask(CPU_LOG_INT,
"...handling as semihosting call 0x%" PRIx64 "\n",
env->xregs[0]);
env->xregs[0] = do_arm_semihosting(env);
return true;
}
return false;
} else {
uint32_t imm;
/* Only intercept calls from privileged modes, to provide some
* semblance of security.
*/
if (!semihosting_enabled() ||
((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR)) {
return false;
}
switch (cs->exception_index) {
case EXCP_SWI:
/* Check for semihosting interrupt. */
if (env->thumb) {
imm = arm_lduw_code(env, env->regs[15] - 2, env->bswap_code)
& 0xff;
if (imm == 0xab) {
break;
}
} else {
imm = arm_ldl_code(env, env->regs[15] - 4, env->bswap_code)
& 0xffffff;
if (imm == 0x123456) {
break;
}
}
return false;
case EXCP_BKPT:
/* See if this is a semihosting syscall. */
if (env->thumb) {
imm = arm_lduw_code(env, env->regs[15], env->bswap_code)
& 0xff;
if (imm == 0xab) {
env->regs[15] += 2;
break;
}
}
return false;
default:
return false;
}
qemu_log_mask(CPU_LOG_INT,
"...handling as semihosting call 0x%x\n",
env->regs[0]);
env->regs[0] = do_arm_semihosting(env);
return true;
}
}
/* Handle a CPU exception for A and R profile CPUs.
* Do any appropriate logging, handle PSCI calls, and then hand off
* to the AArch64-entry or AArch32-entry function depending on the
* target exception level's register width.
*/
void arm_cpu_do_interrupt(CPUState *cs)
{
ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env;
unsigned int new_el = env->exception.target_el;
assert(!IS_M(env));
arm_log_exception(cs->exception_index);
qemu_log_mask(CPU_LOG_INT, "...from EL%d to EL%d\n", arm_current_el(env),
new_el);
if (qemu_loglevel_mask(CPU_LOG_INT)
&& !excp_is_internal(cs->exception_index)) {
qemu_log_mask(CPU_LOG_INT, "...with ESR %x/0x%" PRIx32 "\n",
env->exception.syndrome >> ARM_EL_EC_SHIFT,
env->exception.syndrome);
}
if (arm_is_psci_call(cpu, cs->exception_index)) {
arm_handle_psci_call(cpu);
qemu_log_mask(CPU_LOG_INT, "...handled as PSCI call\n");
return;
}
/* Semihosting semantics depend on the register width of the
* code that caused the exception, not the target exception level,
* so must be handled here.
*/
if (check_for_semihosting(cs)) {
return;
}
assert(!excp_is_internal(cs->exception_index));
if (arm_el_is_aa64(env, new_el)) {
arm_cpu_do_interrupt_aarch64(cs);
} else {
arm_cpu_do_interrupt_aarch32(cs);
}
if (!kvm_enabled()) {
cs->interrupt_request |= CPU_INTERRUPT_EXITTB;
}
}
/* Return the exception level which controls this address translation regime */ /* Return the exception level which controls this address translation regime */
static inline uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx) static inline uint32_t regime_el(CPUARMState *env, ARMMMUIdx mmu_idx)
@ -6273,13 +6463,15 @@ static uint32_t arm_ldl_ptw(CPUState *cs, hwaddr addr, bool is_secure,
ARMCPU *cpu = ARM_CPU(cs); ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env; CPUARMState *env = &cpu->env;
MemTxAttrs attrs = {}; MemTxAttrs attrs = {};
AddressSpace *as;
attrs.secure = is_secure; attrs.secure = is_secure;
as = arm_addressspace(cs, attrs);
addr = S1_ptw_translate(env, mmu_idx, addr, attrs, fsr, fi); addr = S1_ptw_translate(env, mmu_idx, addr, attrs, fsr, fi);
if (fi->s1ptw) { if (fi->s1ptw) {
return 0; return 0;
} }
return address_space_ldl(cs->as, addr, attrs, NULL); return address_space_ldl(as, addr, attrs, NULL);
} }
static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure, static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure,
@ -6289,13 +6481,15 @@ static uint64_t arm_ldq_ptw(CPUState *cs, hwaddr addr, bool is_secure,
ARMCPU *cpu = ARM_CPU(cs); ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env; CPUARMState *env = &cpu->env;
MemTxAttrs attrs = {}; MemTxAttrs attrs = {};
AddressSpace *as;
attrs.secure = is_secure; attrs.secure = is_secure;
as = arm_addressspace(cs, attrs);
addr = S1_ptw_translate(env, mmu_idx, addr, attrs, fsr, fi); addr = S1_ptw_translate(env, mmu_idx, addr, attrs, fsr, fi);
if (fi->s1ptw) { if (fi->s1ptw) {
return 0; return 0;
} }
return address_space_ldq(cs->as, addr, attrs, NULL); return address_space_ldq(as, addr, attrs, NULL);
} }
static bool get_phys_addr_v5(CPUARMState *env, uint32_t address, static bool get_phys_addr_v5(CPUARMState *env, uint32_t address,
@ -7346,7 +7540,8 @@ bool arm_tlb_fill(CPUState *cs, vaddr address,
return ret; return ret;
} }
hwaddr arm_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) hwaddr arm_cpu_get_phys_page_attrs_debug(CPUState *cs, vaddr addr,
MemTxAttrs *attrs)
{ {
ARMCPU *cpu = ARM_CPU(cs); ARMCPU *cpu = ARM_CPU(cs);
CPUARMState *env = &cpu->env; CPUARMState *env = &cpu->env;
@ -7355,16 +7550,16 @@ hwaddr arm_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
int prot; int prot;
bool ret; bool ret;
uint32_t fsr; uint32_t fsr;
MemTxAttrs attrs = {};
ARMMMUFaultInfo fi = {}; ARMMMUFaultInfo fi = {};
*attrs = (MemTxAttrs) {};
ret = get_phys_addr(env, addr, 0, cpu_mmu_index(env, false), &phys_addr, ret = get_phys_addr(env, addr, 0, cpu_mmu_index(env, false), &phys_addr,
&attrs, &prot, &page_size, &fsr, &fi); attrs, &prot, &page_size, &fsr, &fi);
if (ret) { if (ret) {
return -1; return -1;
} }
return phys_addr; return phys_addr;
} }

View File

@ -641,12 +641,51 @@ void HELPER(pre_smc)(CPUARMState *env, uint32_t syndrome)
} }
} }
static int el_from_spsr(uint32_t spsr)
{
/* Return the exception level that this SPSR is requesting a return to,
* or -1 if it is invalid (an illegal return)
*/
if (spsr & PSTATE_nRW) {
switch (spsr & CPSR_M) {
case ARM_CPU_MODE_USR:
return 0;
case ARM_CPU_MODE_HYP:
return 2;
case ARM_CPU_MODE_FIQ:
case ARM_CPU_MODE_IRQ:
case ARM_CPU_MODE_SVC:
case ARM_CPU_MODE_ABT:
case ARM_CPU_MODE_UND:
case ARM_CPU_MODE_SYS:
return 1;
case ARM_CPU_MODE_MON:
/* Returning to Mon from AArch64 is never possible,
* so this is an illegal return.
*/
default:
return -1;
}
} else {
if (extract32(spsr, 1, 1)) {
/* Return with reserved M[1] bit set */
return -1;
}
if (extract32(spsr, 0, 4) == 1) {
/* return to EL0 with M[0] bit set */
return -1;
}
return extract32(spsr, 2, 2);
}
}
void HELPER(exception_return)(CPUARMState *env) void HELPER(exception_return)(CPUARMState *env)
{ {
int cur_el = arm_current_el(env); int cur_el = arm_current_el(env);
unsigned int spsr_idx = aarch64_banked_spsr_index(cur_el); unsigned int spsr_idx = aarch64_banked_spsr_index(cur_el);
uint32_t spsr = env->banked_spsr[spsr_idx]; uint32_t spsr = env->banked_spsr[spsr_idx];
int new_el; int new_el;
bool return_to_aa64 = (spsr & PSTATE_nRW) == 0;
aarch64_save_sp(env, cur_el); aarch64_save_sp(env, cur_el);
@ -663,20 +702,10 @@ void HELPER(exception_return)(CPUARMState *env)
spsr &= ~PSTATE_SS; spsr &= ~PSTATE_SS;
} }
if (spsr & PSTATE_nRW) { new_el = el_from_spsr(spsr);
/* TODO: We currently assume EL1/2/3 are running in AArch64. */ if (new_el == -1) {
env->aarch64 = 0; goto illegal_return;
new_el = 0;
env->uncached_cpsr = 0x10;
cpsr_write(env, spsr, ~0);
if (!arm_singlestep_active(env)) {
env->uncached_cpsr &= ~PSTATE_SS;
} }
aarch64_sync_64_to_32(env);
env->regs[15] = env->elr_el[1] & ~0x1;
} else {
new_el = extract32(spsr, 2, 2);
if (new_el > cur_el if (new_el > cur_el
|| (new_el == 2 && !arm_feature(env, ARM_FEATURE_EL2))) { || (new_el == 2 && !arm_feature(env, ARM_FEATURE_EL2))) {
/* Disallow return to an EL which is unimplemented or higher /* Disallow return to an EL which is unimplemented or higher
@ -684,14 +713,37 @@ void HELPER(exception_return)(CPUARMState *env)
*/ */
goto illegal_return; goto illegal_return;
} }
if (extract32(spsr, 1, 1)) {
/* Return with reserved M[1] bit set */ if (new_el != 0 && arm_el_is_aa64(env, new_el) != return_to_aa64) {
/* Return to an EL which is configured for a different register width */
goto illegal_return; goto illegal_return;
} }
if (new_el == 0 && (spsr & PSTATE_SP)) {
/* Return to EL0 with M[0] bit set */ if (new_el == 2 && arm_is_secure_below_el3(env)) {
/* Return to the non-existent secure-EL2 */
goto illegal_return; goto illegal_return;
} }
if (new_el == 1 && (env->cp15.hcr_el2 & HCR_TGE)
&& !arm_is_secure_below_el3(env)) {
goto illegal_return;
}
if (!return_to_aa64) {
env->aarch64 = 0;
env->uncached_cpsr = spsr & CPSR_M;
cpsr_write(env, spsr, ~0);
if (!arm_singlestep_active(env)) {
env->uncached_cpsr &= ~PSTATE_SS;
}
aarch64_sync_64_to_32(env);
if (spsr & CPSR_T) {
env->regs[15] = env->elr_el[cur_el] & ~0x1;
} else {
env->regs[15] = env->elr_el[cur_el] & ~0x3;
}
} else {
env->aarch64 = 1; env->aarch64 = 1;
pstate_write(env, spsr); pstate_write(env, spsr);
if (!arm_singlestep_active(env)) { if (!arm_singlestep_active(env)) {

View File

@ -2861,9 +2861,10 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
#ifndef CONFIG_USER_ONLY #ifndef CONFIG_USER_ONLY
if (tcg_enabled()) { if (tcg_enabled()) {
AddressSpace *newas = g_new(AddressSpace, 1);
cpu->cpu_as_mem = g_new(MemoryRegion, 1); cpu->cpu_as_mem = g_new(MemoryRegion, 1);
cpu->cpu_as_root = g_new(MemoryRegion, 1); cpu->cpu_as_root = g_new(MemoryRegion, 1);
cs->as = g_new(AddressSpace, 1);
/* Outer container... */ /* Outer container... */
memory_region_init(cpu->cpu_as_root, OBJECT(cpu), "memory", ~0ull); memory_region_init(cpu->cpu_as_root, OBJECT(cpu), "memory", ~0ull);
@ -2876,7 +2877,9 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp)
get_system_memory(), 0, ~0ull); get_system_memory(), 0, ~0ull);
memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, cpu->cpu_as_mem, 0); memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, cpu->cpu_as_mem, 0);
memory_region_set_enabled(cpu->cpu_as_mem, true); memory_region_set_enabled(cpu->cpu_as_mem, true);
address_space_init(cs->as, cpu->cpu_as_root, "CPU"); address_space_init(newas, cpu->cpu_as_root, "CPU");
cs->num_ases = 1;
cpu_address_space_init(cs, newas, 0);
/* ... SMRAM with higher priority, linked from /machine/smram. */ /* ... SMRAM with higher priority, linked from /machine/smram. */
cpu->machine_done.notify = x86_cpu_machine_done; cpu->machine_done.notify = x86_cpu_machine_done;