Message ID | 20180321163235.12529-38-andre.przywara@linaro.org |
---|---|
State | New |
Headers | show |
Series | New VGIC(-v2) implementation | expand |
On Wed, 21 Mar 2018, Andre Przywara wrote: > map_resources is the last initialization step needed before the first > VCPU is run. At that stage the code stores the MMIO base addresses used. > Also it registers the respective register frames with the MMIO framework. > > This is based on Linux commit cbae53e663ea, written by Eric Auger. > > Signed-off-by: Andre Przywara <andre.przywara@linaro.org> > Acked-by: Julien Grall <julien.grall@arm.com> > --- > xen/arch/arm/vgic/vgic-v2.c | 66 +++++++++++++++++++++++++++++++++++++++++++++ > xen/arch/arm/vgic/vgic.h | 1 + > 2 files changed, 67 insertions(+) > > diff --git a/xen/arch/arm/vgic/vgic-v2.c b/xen/arch/arm/vgic/vgic-v2.c > index ce77e58857..5516a8534f 100644 > --- a/xen/arch/arm/vgic/vgic-v2.c > +++ b/xen/arch/arm/vgic/vgic-v2.c > @@ -235,6 +235,72 @@ void vgic_v2_enable(struct vcpu *vcpu) > gic_hw_ops->update_hcr_status(GICH_HCR_EN, true); > } > > +int vgic_v2_map_resources(struct domain *d) > +{ > + struct vgic_dist *dist = &d->arch.vgic; > + paddr_t cbase, csize; > + paddr_t vbase; > + int ret; > + > + /* > + * The hardware domain gets the hardware address. > + * Guests get the virtual platform layout. > + */ > + if ( is_hardware_domain(d) ) > + { > + d->arch.vgic.vgic_dist_base = gic_v2_hw_data.dbase; > + /* > + * For the hardware domain, we always map the whole HW CPU > + * interface region in order to match the device tree (the "reg" > + * properties is copied as it is). > + * Note that we assume the size of the CPU interface is always > + * aligned to PAGE_SIZE. > + */ > + cbase = gic_v2_hw_data.cbase; /* was: dist->vgic_cpu_base */ > + csize = gic_v2_hw_data.csize; > + vbase = gic_v2_hw_data.vbase; /* was: kvm_vgic_global_state.vcpu_base */ NIT: do we really need "was: kvm_vgic_global_state.vcpu_base" here? > + } > + else > + { > + d->arch.vgic.vgic_dist_base = GUEST_GICD_BASE; > + /* > + * The CPU interface exposed to the guest is always 8kB. We may > + * need to add an offset to the virtual CPU interface base > + * address when in the GIC is aliased to get a 8kB contiguous > + * region. > + */ > + BUILD_BUG_ON(GUEST_GICC_SIZE != SZ_8K); > + cbase = GUEST_GICC_BASE; > + csize = GUEST_GICC_SIZE; > + vbase = gic_v2_hw_data.vbase + gic_v2_hw_data.aliased_offset; > + } > + > + > + ret = vgic_register_dist_iodev(d, gaddr_to_gfn(dist->vgic_dist_base), > + VGIC_V2); > + if ( ret ) > + { > + gdprintk(XENLOG_ERR, "Unable to register VGIC MMIO regions\n"); > + return ret; > + } > + > + /* > + * Map the gic virtual cpu interface in the gic cpu interface > + * region of the guest. > + */ > + ret = map_mmio_regions(d, gaddr_to_gfn(cbase), csize / PAGE_SIZE, > + maddr_to_mfn(vbase)); > + if ( ret ) > + { > + gdprintk(XENLOG_ERR, "Unable to remap VGIC CPU to VCPU\n"); > + return ret; > + } > + > + dist->ready = true; > + > + return 0; Code style With these fixed: Acked-by: Stefano Stabellini <sstabellini@kernel.org> > +} > + > /* > * Local variables: > * mode: C > diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h > index 112952fbf9..e8e407adbe 100644 > --- a/xen/arch/arm/vgic/vgic.h > +++ b/xen/arch/arm/vgic/vgic.h > @@ -67,6 +67,7 @@ void vgic_v2_fold_lr_state(struct vcpu *vcpu); > void vgic_v2_populate_lr(struct vcpu *vcpu, struct vgic_irq *irq, int lr); > void vgic_v2_set_underflow(struct vcpu *vcpu); > void vgic_v2_enable(struct vcpu *vcpu); > +int vgic_v2_map_resources(struct domain *d); > int vgic_register_dist_iodev(struct domain *d, gfn_t dist_base_fn, > enum vgic_type); > > -- > 2.14.1 >
diff --git a/xen/arch/arm/vgic/vgic-v2.c b/xen/arch/arm/vgic/vgic-v2.c index ce77e58857..5516a8534f 100644 --- a/xen/arch/arm/vgic/vgic-v2.c +++ b/xen/arch/arm/vgic/vgic-v2.c @@ -235,6 +235,72 @@ void vgic_v2_enable(struct vcpu *vcpu) gic_hw_ops->update_hcr_status(GICH_HCR_EN, true); } +int vgic_v2_map_resources(struct domain *d) +{ + struct vgic_dist *dist = &d->arch.vgic; + paddr_t cbase, csize; + paddr_t vbase; + int ret; + + /* + * The hardware domain gets the hardware address. + * Guests get the virtual platform layout. + */ + if ( is_hardware_domain(d) ) + { + d->arch.vgic.vgic_dist_base = gic_v2_hw_data.dbase; + /* + * For the hardware domain, we always map the whole HW CPU + * interface region in order to match the device tree (the "reg" + * properties is copied as it is). + * Note that we assume the size of the CPU interface is always + * aligned to PAGE_SIZE. + */ + cbase = gic_v2_hw_data.cbase; /* was: dist->vgic_cpu_base */ + csize = gic_v2_hw_data.csize; + vbase = gic_v2_hw_data.vbase; /* was: kvm_vgic_global_state.vcpu_base */ + } + else + { + d->arch.vgic.vgic_dist_base = GUEST_GICD_BASE; + /* + * The CPU interface exposed to the guest is always 8kB. We may + * need to add an offset to the virtual CPU interface base + * address when in the GIC is aliased to get a 8kB contiguous + * region. + */ + BUILD_BUG_ON(GUEST_GICC_SIZE != SZ_8K); + cbase = GUEST_GICC_BASE; + csize = GUEST_GICC_SIZE; + vbase = gic_v2_hw_data.vbase + gic_v2_hw_data.aliased_offset; + } + + + ret = vgic_register_dist_iodev(d, gaddr_to_gfn(dist->vgic_dist_base), + VGIC_V2); + if ( ret ) + { + gdprintk(XENLOG_ERR, "Unable to register VGIC MMIO regions\n"); + return ret; + } + + /* + * Map the gic virtual cpu interface in the gic cpu interface + * region of the guest. + */ + ret = map_mmio_regions(d, gaddr_to_gfn(cbase), csize / PAGE_SIZE, + maddr_to_mfn(vbase)); + if ( ret ) + { + gdprintk(XENLOG_ERR, "Unable to remap VGIC CPU to VCPU\n"); + return ret; + } + + dist->ready = true; + + return 0; +} + /* * Local variables: * mode: C diff --git a/xen/arch/arm/vgic/vgic.h b/xen/arch/arm/vgic/vgic.h index 112952fbf9..e8e407adbe 100644 --- a/xen/arch/arm/vgic/vgic.h +++ b/xen/arch/arm/vgic/vgic.h @@ -67,6 +67,7 @@ void vgic_v2_fold_lr_state(struct vcpu *vcpu); void vgic_v2_populate_lr(struct vcpu *vcpu, struct vgic_irq *irq, int lr); void vgic_v2_set_underflow(struct vcpu *vcpu); void vgic_v2_enable(struct vcpu *vcpu); +int vgic_v2_map_resources(struct domain *d); int vgic_register_dist_iodev(struct domain *d, gfn_t dist_base_fn, enum vgic_type);