mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
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:
@@ -1310,8 +1310,6 @@ static void qemu_tcg_init_vcpu(CPUState *cpu)
|
||||
static QemuCond *tcg_halt_cond;
|
||||
static QemuThread *tcg_cpu_thread;
|
||||
|
||||
tcg_cpu_address_space_init(cpu, cpu->as);
|
||||
|
||||
/* share a single thread for all cpus with TCG */
|
||||
if (!tcg_cpu_thread) {
|
||||
cpu->thread = g_malloc0(sizeof(QemuThread));
|
||||
@@ -1372,6 +1370,17 @@ void qemu_init_vcpu(CPUState *cpu)
|
||||
cpu->nr_cores = smp_cores;
|
||||
cpu->nr_threads = smp_threads;
|
||||
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()) {
|
||||
qemu_kvm_start_vcpu(cpu);
|
||||
} else if (tcg_enabled()) {
|
||||
|
||||
@@ -356,6 +356,7 @@ void tlb_set_page_with_attrs(CPUState *cpu, target_ulong vaddr,
|
||||
CPUTLBEntry *te;
|
||||
hwaddr iotlb, xlat, sz;
|
||||
unsigned vidx = env->vtlb_index++ % CPU_VTLB_SIZE;
|
||||
int asidx = cpu_asidx_from_attrs(cpu, attrs);
|
||||
|
||||
assert(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;
|
||||
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);
|
||||
|
||||
#if defined(DEBUG_TLB)
|
||||
@@ -448,6 +449,7 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr)
|
||||
void *p;
|
||||
MemoryRegion *mr;
|
||||
CPUState *cpu = ENV_GET_CPU(env1);
|
||||
CPUIOTLBEntry *iotlbentry;
|
||||
|
||||
page_index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
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))) {
|
||||
cpu_ldub_code(env1, addr);
|
||||
}
|
||||
pd = env1->iotlb[mmu_idx][page_index].addr & ~TARGET_PAGE_MASK;
|
||||
mr = iotlb_to_region(cpu, pd);
|
||||
iotlbentry = &env1->iotlb[mmu_idx][page_index];
|
||||
pd = iotlbentry->addr & ~TARGET_PAGE_MASK;
|
||||
mr = iotlb_to_region(cpu, pd, iotlbentry->attrs);
|
||||
if (memory_region_is_unassigned(mr)) {
|
||||
CPUClass *cc = CPU_GET_CLASS(cpu);
|
||||
|
||||
|
||||
@@ -431,12 +431,13 @@ MemoryRegion *address_space_translate(AddressSpace *as, hwaddr addr,
|
||||
|
||||
/* Called from RCU critical section */
|
||||
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)
|
||||
{
|
||||
MemoryRegionSection *section;
|
||||
section = address_space_translate_internal(cpu->cpu_ases[0].memory_dispatch,
|
||||
addr, xlat, plen, false);
|
||||
AddressSpaceDispatch *d = cpu->cpu_ases[asidx].memory_dispatch;
|
||||
|
||||
section = address_space_translate_internal(d, addr, xlat, plen, false);
|
||||
|
||||
assert(!section->mr->iommu_ops);
|
||||
return section;
|
||||
@@ -536,21 +537,38 @@ CPUState *qemu_get_cpu(int index)
|
||||
}
|
||||
|
||||
#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. */
|
||||
assert(cpu->as == as);
|
||||
CPUAddressSpace *newas;
|
||||
|
||||
if (cpu->cpu_ases) {
|
||||
/* We've already registered the listener for our only AS */
|
||||
return;
|
||||
/* Target code should have set num_ases before calling us */
|
||||
assert(asidx < cpu->num_ases);
|
||||
|
||||
if (asidx == 0) {
|
||||
/* address space 0 gets the convenience alias */
|
||||
cpu->as = as;
|
||||
}
|
||||
|
||||
cpu->cpu_ases = g_new0(CPUAddressSpace, 1);
|
||||
cpu->cpu_ases[0].cpu = cpu;
|
||||
cpu->cpu_ases[0].as = as;
|
||||
cpu->cpu_ases[0].tcg_as_listener.commit = tcg_commit;
|
||||
memory_listener_register(&cpu->cpu_ases[0].tcg_as_listener, as);
|
||||
/* KVM cannot currently support multiple address spaces. */
|
||||
assert(asidx == 0 || !kvm_enabled());
|
||||
|
||||
if (!cpu->cpu_ases) {
|
||||
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
|
||||
|
||||
@@ -605,9 +623,25 @@ void cpu_exec_init(CPUState *cpu, Error **errp)
|
||||
int cpu_index;
|
||||
Error *local_err = NULL;
|
||||
|
||||
cpu->as = NULL;
|
||||
cpu->num_ases = 0;
|
||||
|
||||
#ifndef CONFIG_USER_ONLY
|
||||
cpu->as = &address_space_memory;
|
||||
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
|
||||
|
||||
#if defined(CONFIG_USER_ONLY)
|
||||
@@ -647,9 +681,11 @@ static void breakpoint_invalidate(CPUState *cpu, target_ulong pc)
|
||||
#else
|
||||
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) {
|
||||
tb_invalidate_phys_addr(cpu->as,
|
||||
tb_invalidate_phys_addr(cpu->cpu_ases[asidx].as,
|
||||
phys | (pc & ~TARGET_PAGE_MASK));
|
||||
}
|
||||
}
|
||||
@@ -2034,17 +2070,19 @@ static MemTxResult watch_mem_read(void *opaque, hwaddr addr, uint64_t *pdata,
|
||||
{
|
||||
MemTxResult res;
|
||||
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);
|
||||
switch (size) {
|
||||
case 1:
|
||||
data = address_space_ldub(&address_space_memory, addr, attrs, &res);
|
||||
data = address_space_ldub(as, addr, attrs, &res);
|
||||
break;
|
||||
case 2:
|
||||
data = address_space_lduw(&address_space_memory, addr, attrs, &res);
|
||||
data = address_space_lduw(as, addr, attrs, &res);
|
||||
break;
|
||||
case 4:
|
||||
data = address_space_ldl(&address_space_memory, addr, attrs, &res);
|
||||
data = address_space_ldl(as, addr, attrs, &res);
|
||||
break;
|
||||
default: abort();
|
||||
}
|
||||
@@ -2057,17 +2095,19 @@ static MemTxResult watch_mem_write(void *opaque, hwaddr addr,
|
||||
MemTxAttrs attrs)
|
||||
{
|
||||
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);
|
||||
switch (size) {
|
||||
case 1:
|
||||
address_space_stb(&address_space_memory, addr, val, attrs, &res);
|
||||
address_space_stb(as, addr, val, attrs, &res);
|
||||
break;
|
||||
case 2:
|
||||
address_space_stw(&address_space_memory, addr, val, attrs, &res);
|
||||
address_space_stw(as, addr, val, attrs, &res);
|
||||
break;
|
||||
case 4:
|
||||
address_space_stl(&address_space_memory, addr, val, attrs, &res);
|
||||
address_space_stl(as, addr, val, attrs, &res);
|
||||
break;
|
||||
default: abort();
|
||||
}
|
||||
@@ -2224,9 +2264,10 @@ static uint16_t dummy_section(PhysPageMap *map, AddressSpace *as,
|
||||
return phys_section_add(map, §ion);
|
||||
}
|
||||
|
||||
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);
|
||||
MemoryRegionSection *sections = d->map.sections;
|
||||
|
||||
@@ -3565,8 +3606,12 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
|
||||
target_ulong page;
|
||||
|
||||
while (len > 0) {
|
||||
int asidx;
|
||||
MemTxAttrs attrs;
|
||||
|
||||
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 (phys_addr == -1)
|
||||
return -1;
|
||||
@@ -3575,9 +3620,11 @@ int cpu_memory_rw_debug(CPUState *cpu, target_ulong addr,
|
||||
l = len;
|
||||
phys_addr += (addr & ~TARGET_PAGE_MASK);
|
||||
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 {
|
||||
address_space_rw(cpu->as, phys_addr, MEMTXATTRS_UNSPECIFIED,
|
||||
address_space_rw(cpu->cpu_ases[asidx].as, phys_addr,
|
||||
MEMTXATTRS_UNSPECIFIED,
|
||||
buf, l, 0);
|
||||
}
|
||||
len -= l;
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "hw/i2c/i2c.h"
|
||||
#include "hw/ssi.h"
|
||||
#include "hw/ssi/ssi.h"
|
||||
#include "sysemu/char.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/pcmcia.h"
|
||||
#include "hw/i2c/i2c.h"
|
||||
#include "hw/ssi.h"
|
||||
#include "hw/ssi/ssi.h"
|
||||
#include "hw/block/flash.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "hw/devices.h"
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/ssi.h"
|
||||
#include "hw/ssi/ssi.h"
|
||||
#include "hw/arm/arm.h"
|
||||
#include "hw/devices.h"
|
||||
#include "qemu/timer.h"
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@
|
||||
#include "hw/arm/arm.h"
|
||||
#include "sysemu/char.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/ssi.h"
|
||||
#include "hw/ssi/ssi.h"
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@
|
||||
#include "hw/pcmcia.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/i2c/i2c.h"
|
||||
#include "hw/ssi.h"
|
||||
#include "hw/ssi/ssi.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "exec/address-spaces.h"
|
||||
|
||||
+52
-7
@@ -123,6 +123,7 @@ static const MemMapEntry a15memmap[] = {
|
||||
[VIRT_RTC] = { 0x09010000, 0x00001000 },
|
||||
[VIRT_FW_CFG] = { 0x09020000, 0x00000018 },
|
||||
[VIRT_GPIO] = { 0x09030000, 0x00001000 },
|
||||
[VIRT_SECURE_UART] = { 0x09040000, 0x00001000 },
|
||||
[VIRT_MMIO] = { 0x0a000000, 0x00000200 },
|
||||
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
|
||||
[VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 },
|
||||
@@ -139,6 +140,7 @@ static const int a15irqmap[] = {
|
||||
[VIRT_RTC] = 2,
|
||||
[VIRT_PCIE] = 3, /* ... to 6 */
|
||||
[VIRT_GPIO] = 7,
|
||||
[VIRT_SECURE_UART] = 8,
|
||||
[VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */
|
||||
[VIRT_GIC_V2M] = 48, /* ...to 48 + NUM_GICV2M_SPIS - 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",
|
||||
"arm,armv7-timer");
|
||||
}
|
||||
qemu_fdt_setprop(vbi->fdt, "/timer", "always-on", NULL, 0);
|
||||
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_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;
|
||||
hwaddr base = vbi->memmap[VIRT_UART].base;
|
||||
hwaddr size = vbi->memmap[VIRT_UART].size;
|
||||
int irq = vbi->irqmap[VIRT_UART];
|
||||
hwaddr base = vbi->memmap[uart].base;
|
||||
hwaddr size = vbi->memmap[uart].size;
|
||||
int irq = vbi->irqmap[uart];
|
||||
const char compat[] = "arm,pl011\0arm,primecell";
|
||||
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);
|
||||
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",
|
||||
clocknames, sizeof(clocknames));
|
||||
|
||||
qemu_fdt_setprop_string(vbi->fdt, "/chosen", "stdout-path", nodename);
|
||||
if (uart == VIRT_UART) {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -995,6 +1011,7 @@ static void machvirt_init(MachineState *machine)
|
||||
VirtMachineState *vms = VIRT_MACHINE(machine);
|
||||
qemu_irq pic[NUM_IRQS];
|
||||
MemoryRegion *sysmem = get_system_memory();
|
||||
MemoryRegion *secure_sysmem = NULL;
|
||||
int gic_version = vms->gic_version;
|
||||
int n, max_cpus;
|
||||
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||
@@ -1053,6 +1070,23 @@ static void machvirt_init(MachineState *machine)
|
||||
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);
|
||||
|
||||
for (n = 0; n < smp_cpus; n++) {
|
||||
@@ -1093,6 +1127,13 @@ static void machvirt_init(MachineState *machine)
|
||||
"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);
|
||||
}
|
||||
g_strfreev(cpustr);
|
||||
@@ -1108,7 +1149,11 @@ static void machvirt_init(MachineState *machine)
|
||||
|
||||
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);
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/loader.h"
|
||||
#include "hw/misc/zynq-xadc.h"
|
||||
#include "hw/ssi.h"
|
||||
#include "hw/ssi/ssi.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
||||
#define NUM_SPI_FLASHES 4
|
||||
|
||||
@@ -31,6 +31,7 @@ static struct arm_boot_info xlnx_ep108_binfo;
|
||||
static void xlnx_ep108_init(MachineState *machine)
|
||||
{
|
||||
XlnxEP108 *s = g_new0(XlnxEP108, 1);
|
||||
int i;
|
||||
Error *err = NULL;
|
||||
uint64_t ram_size = machine->ram_size;
|
||||
|
||||
@@ -63,6 +64,21 @@ static void xlnx_ep108_init(MachineState *machine)
|
||||
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.kernel_filename = machine->kernel_filename;
|
||||
xlnx_ep108_binfo.kernel_cmdline = machine->kernel_cmdline;
|
||||
|
||||
@@ -57,6 +57,14 @@ static const int sdhci_intr[XLNX_ZYNQMP_NUM_SDHCI] = {
|
||||
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 {
|
||||
int region_index;
|
||||
uint32_t address;
|
||||
@@ -118,6 +126,12 @@ static void xlnx_zynqmp_init(Object *obj)
|
||||
qdev_set_parent_bus(DEVICE(&s->sdhci[i]),
|
||||
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)
|
||||
@@ -324,6 +338,23 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci[i]), 0,
|
||||
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[] = {
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
#include "hw/arm/arm.h"
|
||||
#include "hw/devices.h"
|
||||
#include "hw/i2c/i2c.h"
|
||||
#include "hw/ssi.h"
|
||||
#include "hw/ssi/ssi.h"
|
||||
#include "hw/boards.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/block/flash.h"
|
||||
|
||||
+2
-1
@@ -25,7 +25,7 @@
|
||||
#include "hw/hw.h"
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "sysemu/blockdev.h"
|
||||
#include "hw/ssi.h"
|
||||
#include "hw/ssi/ssi.h"
|
||||
|
||||
#ifndef M25P80_ERR_DEBUG
|
||||
#define M25P80_ERR_DEBUG 0
|
||||
@@ -164,6 +164,7 @@ static const FlashPartInfo known_devices[] = {
|
||||
{ INFO("sst25wf010", 0xbf2502, 0, 64 << 10, 2, ER_4K) },
|
||||
{ INFO("sst25wf020", 0xbf2503, 0, 64 << 10, 4, 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 */
|
||||
{ INFO("m25p05", 0x202010, 0, 32 << 10, 2, 0) },
|
||||
|
||||
@@ -580,6 +580,12 @@ void qdev_pass_gpios(DeviceState *dev, DeviceState *container,
|
||||
BusState *qdev_get_child_bus(DeviceState *dev, const char *name)
|
||||
{
|
||||
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) {
|
||||
if (strcmp(name, bus->name) == 0) {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "hw/ssi.h"
|
||||
#include "hw/ssi/ssi.h"
|
||||
#include "ui/console.h"
|
||||
|
||||
typedef struct {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
/* The controller can support a variety of different displays, but we only
|
||||
implement one. Most of the commends relating to brightness and geometry
|
||||
setup are ignored. */
|
||||
#include "hw/ssi.h"
|
||||
#include "hw/ssi/ssi.h"
|
||||
#include "ui/console.h"
|
||||
|
||||
//#define DEBUG_SSD0323 1
|
||||
|
||||
+30
-5
@@ -31,8 +31,16 @@ do { fprintf(stderr, "arm_gic: " fmt , ## __VA_ARGS__); } while (0)
|
||||
#define DPRINTF(fmt, ...) do {} while(0)
|
||||
#endif
|
||||
|
||||
static const uint8_t gic_id[] = {
|
||||
0x90, 0x13, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1
|
||||
static const uint8_t gic_id_11mpcore[] = {
|
||||
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)
|
||||
@@ -683,14 +691,31 @@ static uint32_t gic_dist_readb(void *opaque, hwaddr offset, MemTxAttrs attrs)
|
||||
}
|
||||
|
||||
res = s->sgi_pending[irq][cpu];
|
||||
} else if (offset < 0xfe0) {
|
||||
} else if (offset < 0xfd0) {
|
||||
goto bad_reg;
|
||||
} else /* offset >= 0xfe0 */ {
|
||||
} else if (offset < 0x1000) {
|
||||
if (offset & 3) {
|
||||
res = 0;
|
||||
} 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;
|
||||
bad_reg:
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
#include "sysemu/block-backend.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "exec/address-spaces.h"
|
||||
#include "hw/ssi.h"
|
||||
#include "hw/ssi/ssi.h"
|
||||
|
||||
#include "boot.h"
|
||||
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "hw/ssi.h"
|
||||
#include "hw/ssi/ssi.h"
|
||||
|
||||
typedef struct {
|
||||
SSISlave parent_obj;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user