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.

Backports commit 12ebc9a76dd7702aef0a3618717a826c19c34ef4 from qemu
This commit is contained in:
Peter Maydell 2018-02-17 22:33:49 -05:00 committed by Lioncash
parent f1b237236c
commit 51369b67cd
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
5 changed files with 28 additions and 11 deletions

View file

@ -114,6 +114,7 @@ static int qemu_tcg_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, &cpu->uc->as, 0);
}

View file

@ -385,25 +385,30 @@ CPUState *qemu_get_cpu(struct uc_struct *uc, 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. */
// Unicorn: commented out
//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(as->uc)) {
cpu->cpu_ases[0].tcg_as_listener.commit = tcg_commit;
memory_listener_register(as->uc, &cpu->cpu_ases[0].tcg_as_listener, as);
newas->tcg_as_listener.commit = tcg_commit;
memory_listener_register(as->uc, &newas->tcg_as_listener, as);
}
}
#endif
@ -413,8 +418,9 @@ void cpu_exec_init(CPUState *cpu, void *opaque)
struct uc_struct *uc = opaque;
CPUArchState *env = cpu->env_ptr;
cpu->cpu_index = 0;
cpu->as = NULL;
cpu->cpu_index = 0;
cpu->num_ases = 0;
cpu->uc = uc;
env->uc = uc;

View file

@ -95,6 +95,10 @@ void cpu_reload_memory_map(CPUState *cpu);
* 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);

View file

@ -209,6 +209,11 @@ struct CPUAddressSpace {
* This allows a single read-compare-cbranch-write sequence to test
* for both decrementer underflow and exceptions.
* @can_do_io: Nonzero if memory-mapped IO is safe.
* @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.
* @current_tb: Currently executing TB.
* @next_cpu: Next CPU sharing TB cache.

View file

@ -2607,6 +2607,7 @@ static int x86_cpu_realizefn(struct uc_struct *uc, DeviceState *dev, Error **err
memory_region_init_alias(uc, cpu->cpu_as_root, OBJECT(cpu), "memory",
get_system_memory(uc), 0, ~0ull);
memory_region_set_enabled(cpu->cpu_as_root, true);
cs->num_ases = 1;
address_space_init(uc, newas, cpu->cpu_as_root, "CPU");
cpu_address_space_init(cs, newas, 0);
}