From patchwork Tue Oct 23 10:50:26 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Maydell X-Patchwork-Id: 1630011 Return-Path: X-Original-To: patchwork-kvm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork1.kernel.org (Postfix) with ESMTP id 080613FD85 for ; Tue, 23 Oct 2012 10:50:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752923Ab2JWKuf (ORCPT ); Tue, 23 Oct 2012 06:50:35 -0400 Received: from 38.0.169.217.in-addr.arpa ([217.169.0.38]:38502 "EHLO mnementh.archaic.org.uk" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1752208Ab2JWKuf (ORCPT ); Tue, 23 Oct 2012 06:50:35 -0400 Received: from pm215 by mnementh.archaic.org.uk with local (Exim 4.72) (envelope-from ) id 1TQc44-0000Fo-JS; Tue, 23 Oct 2012 11:50:28 +0100 From: Peter Maydell To: qemu-devel@nongnu.org Cc: kvm@vger.kernel.org, kvmarm@lists.cs.columbia.edu, patches@linaro.org, Blue Swirl , =?UTF-8?q?Andreas=20F=C3=A4rber?= , Avi Kivity , Marcelo Tosatti Subject: [RFC v3 6/8] target-arm: Use MemoryListener to identify GIC base address for KVM Date: Tue, 23 Oct 2012 11:50:26 +0100 Message-Id: <1350989428-941-7-git-send-email-peter.maydell@linaro.org> X-Mailer: git-send-email 1.7.2.5 In-Reply-To: <1350989428-941-1-git-send-email-peter.maydell@linaro.org> References: <1350989428-941-1-git-send-email-peter.maydell@linaro.org> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org When using an in-kernel GIC with KVM, we need to tell the kernel where the GIC's memory mapped registers live. Do this by registering a MemoryListener which tracks where the board model maps the A15's private peripherals, so we can finish the GIC initialisation when the GIC is actually mapped. Signed-off-by: Peter Maydell --- target-arm/kvm.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++ target-arm/kvm_arm.h | 32 +++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 target-arm/kvm_arm.h diff --git a/target-arm/kvm.c b/target-arm/kvm.c index f7d2235..955983d 100644 --- a/target-arm/kvm.c +++ b/target-arm/kvm.c @@ -19,6 +19,7 @@ #include "qemu-timer.h" #include "sysemu.h" #include "kvm.h" +#include "kvm_arm.h" #include "cpu.h" #include "hw/arm-misc.h" @@ -62,6 +63,88 @@ int kvm_arch_init_vcpu(CPUARMState *env) return ret; } +/* We track all the KVM devices which need their memory addresses + * passing to the kernel in a list of these structures. + * When board init is complete we run through the list and + * tell the kernel the base addresses of the memory regions. + * We use a MemoryListener to track mapping and unmapping of + * the regions during board creation, so the board models don't + * need to do anything special for the KVM case. + */ +typedef struct KVMDevice { + struct kvm_device_address kda; + MemoryRegion *mr; + QSLIST_ENTRY(KVMDevice) entries; +} KVMDevice; + +static QSLIST_HEAD(kvm_devices_head, KVMDevice) kvm_devices_head; + +static void kvm_arm_devlistener_add(MemoryListener *listener, + MemoryRegionSection *section) +{ + KVMDevice *kd; + QSLIST_FOREACH(kd, &kvm_devices_head, entries) { + if (section->mr == kd->mr) { + kd->kda.addr = section->offset_within_address_space; + } + } +} + +static void kvm_arm_devlistener_del(MemoryListener *listener, + MemoryRegionSection *section) +{ + KVMDevice *kd; + QSLIST_FOREACH(kd, &kvm_devices_head, entries) { + if (section->mr == kd->mr) { + kd->kda.addr = -1; + } + } +} + +static MemoryListener devlistener = { + .region_add = kvm_arm_devlistener_add, + .region_del = kvm_arm_devlistener_del, +}; + +static void kvm_arm_machine_init_done(Notifier *notifier, void *data) +{ + KVMDevice *kd, *tkd; + memory_listener_unregister(&devlistener); + QSLIST_FOREACH_SAFE(kd, &kvm_devices_head, entries, tkd) { + if (kd->kda.addr != -1) { + if (kvm_vm_ioctl(kvm_state, KVM_SET_DEVICE_ADDRESS, &kd->kda) < 0) { + fprintf(stderr, "KVM_SET_DEVICE_ADDRESS failed: %s\n", + strerror(errno)); + abort(); + } + } + g_free(kd); + } +} + +static Notifier notify = { + .notify = kvm_arm_machine_init_done, +}; + +void kvm_arm_register_device(MemoryRegion *mr, uint32_t devid) +{ + KVMDevice *kd; + + if (!kvm_irqchip_in_kernel()) { + return; + } + + if (QSLIST_EMPTY(&kvm_devices_head)) { + memory_listener_register(&devlistener, NULL); + qemu_add_machine_init_done_notifier(¬ify); + } + kd = g_new0(KVMDevice, 1); + kd->mr = mr; + kd->kda.id = devid; + kd->kda.addr = -1; + QSLIST_INSERT_HEAD(&kvm_devices_head, kd, entries); +} + typedef struct Reg { uint64_t id; int offset; diff --git a/target-arm/kvm_arm.h b/target-arm/kvm_arm.h new file mode 100644 index 0000000..93babb2 --- /dev/null +++ b/target-arm/kvm_arm.h @@ -0,0 +1,32 @@ +/* + * QEMU KVM support -- ARM specific functions. + * + * Copyright (c) 2012 Linaro Limited + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef QEMU_KVM_ARM_H +#define QEMU_KVM_ARM_H + +#include "kvm.h" +#include "memory.h" + +/** + * kvm_arm_register_device: + * @mr: memory region for this device + * @devid: the KVM device ID + * + * Remember the memory region @mr, and when it is mapped by the + * machine model, tell the kernel that base address using the + * KVM_SET_DEVICE_ADDRESS ioctl. @devid should be the ID of + * the device as defined by KVM_SET_DEVICE_ADDRESS. + * The machine model may map and unmap the device multiple times; + * the kernel will only be told the final address at the point + * where machine init is complete. + */ +void kvm_arm_register_device(MemoryRegion *mr, uint32_t devid); + +#endif