From 56943e8cc14b7eeeab67d1942fa5d8bcafe3e53f Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 21 Jan 2016 14:15:04 +0000 Subject: exec.c: Don't set cpu->as until cpu_address_space_init Rather than setting cpu->as unconditionally in cpu_exec_init (and then having target-i386 override this later), don't set it until the first call to cpu_address_space_init. This requires us to initialise the address space for both TCG and KVM (KVM doesn't need the AS listener but it does require cpu->as to be set). For target CPUs which don't set up any address spaces (currently everything except i386), add the default address_space_memory in qemu_init_vcpu(). Signed-off-by: Peter Maydell Reviewed-by: Edgar E. Iglesias Acked-by: Edgar E. Iglesias --- include/exec/exec-all.h | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'include/exec/exec-all.h') diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index d900b0d078..eb3890a389 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -84,7 +84,21 @@ void QEMU_NORETURN cpu_loop_exit_restore(CPUState *cpu, uintptr_t pc); #if !defined(CONFIG_USER_ONLY) 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. + * + * Note that with KVM only one address space is supported. + */ +void cpu_address_space_init(CPUState *cpu, AddressSpace *as, int asidx); /* cputlb.c */ /** * tlb_flush_page: -- cgit 1.4.1 From 12ebc9a76dd7702aef0a3618717a826c19c34ef4 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 21 Jan 2016 14:15:04 +0000 Subject: exec.c: Allow target CPUs to define multiple AddressSpaces Allow multiple calls to cpu_address_space_init(); each call adds an entry to the cpu->ases array at the specified index. It is up to the target-specific CPU code to actually use these extra address spaces. Since this multiple AddressSpace support won't work with KVM, add an assertion to avoid confusing failures. Signed-off-by: Peter Maydell Acked-by: Edgar E. Iglesias --- cpus.c | 1 + exec.c | 25 +++++++++++++++---------- include/exec/exec-all.h | 4 ++++ include/qom/cpu.h | 2 ++ target-i386/cpu.c | 1 + 5 files changed, 23 insertions(+), 10 deletions(-) (limited to 'include/exec/exec-all.h') diff --git a/cpus.c b/cpus.c index 787877aa24..725a51dac9 100644 --- a/cpus.c +++ b/cpus.c @@ -1375,6 +1375,7 @@ void qemu_init_vcpu(CPUState *cpu) /* If the target cpu hasn't set up any address spaces itself, * give it the default one. */ + cpu->num_ases = 1; cpu_address_space_init(cpu, &address_space_memory, 0); } diff --git a/exec.c b/exec.c index f34d55698b..8bc3288105 100644 --- a/exec.c +++ b/exec.c @@ -538,25 +538,29 @@ CPUState *qemu_get_cpu(int index) #if !defined(CONFIG_USER_ONLY) void cpu_address_space_init(CPUState *cpu, AddressSpace *as, int asidx) { + CPUAddressSpace *newas; + + /* 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; } - /* We only support one address space per cpu at the moment. */ - assert(cpu->as == as); + /* KVM cannot currently support multiple address spaces. */ + assert(asidx == 0 || !kvm_enabled()); - if (cpu->cpu_ases) { - /* We've already registered the listener for our only AS */ - return; + if (!cpu->cpu_ases) { + cpu->cpu_ases = g_new0(CPUAddressSpace, cpu->num_ases); } - cpu->cpu_ases = g_new0(CPUAddressSpace, 1); - cpu->cpu_ases[0].cpu = cpu; - cpu->cpu_ases[0].as = as; + newas = &cpu->cpu_ases[asidx]; + newas->cpu = cpu; + newas->as = as; if (tcg_enabled()) { - cpu->cpu_ases[0].tcg_as_listener.commit = tcg_commit; - memory_listener_register(&cpu->cpu_ases[0].tcg_as_listener, as); + newas->tcg_as_listener.commit = tcg_commit; + memory_listener_register(&newas->tcg_as_listener, as); } } #endif @@ -613,6 +617,7 @@ void cpu_exec_init(CPUState *cpu, Error **errp) Error *local_err = NULL; cpu->as = NULL; + cpu->num_ases = 0; #ifndef CONFIG_USER_ONLY cpu->thread_id = qemu_get_thread_id(); diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index eb3890a389..9be0165e80 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -96,6 +96,10 @@ void cpu_reloading_memory_map(void); * 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); diff --git a/include/qom/cpu.h b/include/qom/cpu.h index 51a1323ead..ae1793219b 100644 --- a/include/qom/cpu.h +++ b/include/qom/cpu.h @@ -236,6 +236,7 @@ struct kvm_run; * so that interrupts take effect immediately. * @cpu_ases: Pointer to array of CPUAddressSpaces (which define the * AddressSpaces this CPU has) + * @num_ases: number of CPUAddressSpaces in @cpu_ases * @as: Pointer to the first AddressSpace, for the convenience of targets which * only have a single AddressSpace * @env_ptr: Pointer to subclass-specific CPUArchState field. @@ -285,6 +286,7 @@ struct CPUState { struct qemu_work_item *queued_work_first, *queued_work_last; CPUAddressSpace *cpu_ases; + int num_ases; AddressSpace *as; void *env_ptr; /* CPUArchState */ diff --git a/target-i386/cpu.c b/target-i386/cpu.c index 36fae2dc26..4430494085 100644 --- a/target-i386/cpu.c +++ b/target-i386/cpu.c @@ -2878,6 +2878,7 @@ static void x86_cpu_realizefn(DeviceState *dev, Error **errp) memory_region_add_subregion_overlap(cpu->cpu_as_root, 0, cpu->cpu_as_mem, 0); memory_region_set_enabled(cpu->cpu_as_mem, true); 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. */ -- cgit 1.4.1 From 1787cc8ee55143b6071c87e59f08d56e7c22c1eb Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 21 Jan 2016 14:15:04 +0000 Subject: exec-all.h: Document tlb_set_page_with_attrs, tlb_set_page Add documentation comments for tlb_set_page_with_attrs() and tlb_set_page(). Signed-off-by: Peter Maydell Acked-by: Edgar E. Iglesias --- include/exec/exec-all.h | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) (limited to 'include/exec/exec-all.h') diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 9be0165e80..caa78a952b 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -144,12 +144,40 @@ void tlb_flush_page_by_mmuidx(CPUState *cpu, target_ulong addr, ...); * MMU indexes. */ void tlb_flush_by_mmuidx(CPUState *cpu, ...); -void tlb_set_page(CPUState *cpu, target_ulong vaddr, - hwaddr paddr, int prot, - int mmu_idx, target_ulong size); +/** + * tlb_set_page_with_attrs: + * @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, hwaddr paddr, MemTxAttrs attrs, 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 probe_write(CPUArchState *env, target_ulong addr, int mmu_idx, uintptr_t retaddr); -- cgit 1.4.1 From d7898cda81b6efa6b2d7a749882695cdcf280eaa Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 21 Jan 2016 14:15:05 +0000 Subject: cputlb.c: Use correct address space when looking up MemoryRegionSection When looking up the MemoryRegionSection for the new TLB entry in tlb_set_page_with_attrs(), use cpu_asidx_from_attrs() to determine the correct address space index for the lookup, and pass it into address_space_translate_for_iotlb(). Signed-off-by: Peter Maydell Acked-by: Edgar E. Iglesias --- cputlb.c | 3 ++- exec.c | 7 ++++--- include/exec/exec-all.h | 4 ++-- 3 files changed, 8 insertions(+), 6 deletions(-) (limited to 'include/exec/exec-all.h') diff --git a/cputlb.c b/cputlb.c index bf1d50adde..f1c1082069 100644 --- a/cputlb.c +++ b/cputlb.c @@ -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) diff --git a/exec.c b/exec.c index 8bc3288105..884586ad2f 100644 --- a/exec.c +++ b/exec.c @@ -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; diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index caa78a952b..ee9757f60d 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -432,8 +432,8 @@ void tlb_set_dirty(CPUState *cpu, target_ulong vaddr); void tb_flush_jmp_cache(CPUState *cpu, target_ulong addr); MemoryRegionSection * -address_space_translate_for_iotlb(CPUState *cpu, hwaddr addr, hwaddr *xlat, - hwaddr *plen); +address_space_translate_for_iotlb(CPUState *cpu, int asidx, hwaddr addr, + hwaddr *xlat, hwaddr *plen); hwaddr memory_region_section_get_iotlb(CPUState *cpu, MemoryRegionSection *section, target_ulong vaddr, -- cgit 1.4.1 From a54c87b68a0410d0cf6f8b84e42074a5cf463732 Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 21 Jan 2016 14:15:05 +0000 Subject: exec.c: Pass MemTxAttrs to iotlb_to_region so it uses the right AS Pass the MemTxAttrs for the memory access to iotlb_to_region(); this allows it to determine the correct AddressSpace to use for the lookup. Signed-off-by: Peter Maydell Acked-by: Edgar E. Iglesias --- cputlb.c | 6 ++++-- exec.c | 5 +++-- include/exec/exec-all.h | 2 +- softmmu_template.h | 4 ++-- 4 files changed, 10 insertions(+), 7 deletions(-) (limited to 'include/exec/exec-all.h') diff --git a/cputlb.c b/cputlb.c index f1c1082069..f6fb161d15 100644 --- a/cputlb.c +++ b/cputlb.c @@ -449,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); @@ -456,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); diff --git a/exec.c b/exec.c index 884586ad2f..5bd304584c 100644 --- a/exec.c +++ b/exec.c @@ -2238,9 +2238,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; diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index ee9757f60d..587736e9fb 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -403,7 +403,7 @@ extern uintptr_t tci_tb_ptr; #if !defined(CONFIG_USER_ONLY) 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, uintptr_t retaddr); diff --git a/softmmu_template.h b/softmmu_template.h index 6803890e4f..208f808f3e 100644 --- a/softmmu_template.h +++ b/softmmu_template.h @@ -150,7 +150,7 @@ static inline DATA_TYPE glue(io_read, SUFFIX)(CPUArchState *env, uint64_t val; CPUState *cpu = ENV_GET_CPU(env); 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; cpu->mem_io_pc = retaddr; @@ -357,7 +357,7 @@ static inline void glue(io_write, SUFFIX)(CPUArchState *env, { CPUState *cpu = ENV_GET_CPU(env); 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; if (mr != &io_mem_rom && mr != &io_mem_notdirty && !cpu->can_do_io) { -- cgit 1.4.1 From 651a5bc03705102de519ebf079a40ecc1da991db Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 21 Jan 2016 14:15:05 +0000 Subject: exec.c: Add cpu_get_address_space() Add a function to return the AddressSpace for a CPU based on its numerical index. (Callers outside exec.c don't have access to the CPUAddressSpace struct so can't just fish it out of the CPUState struct directly.) Signed-off-by: Peter Maydell Acked-by: Edgar E. Iglesias --- exec.c | 6 ++++++ include/exec/exec-all.h | 9 +++++++++ 2 files changed, 15 insertions(+) (limited to 'include/exec/exec-all.h') diff --git a/exec.c b/exec.c index 5bd304584c..cbadca4b50 100644 --- a/exec.c +++ b/exec.c @@ -564,6 +564,12 @@ void cpu_address_space_init(CPUState *cpu, AddressSpace *as, int asidx) 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 #ifndef CONFIG_USER_ONLY diff --git a/include/exec/exec-all.h b/include/exec/exec-all.h index 587736e9fb..05a151da4a 100644 --- a/include/exec/exec-all.h +++ b/include/exec/exec-all.h @@ -103,6 +103,15 @@ void cpu_reloading_memory_map(void); * 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 */ /** * tlb_flush_page: -- cgit 1.4.1