static int map_one_spi(struct domain *d, const char *what, unsigned int spi, unsigned int type) { unsigned int irq; int ret; irq = spi + 32; /* SPIs start at IRQ 32 */ ret = irq_set_spi_type(irq, type); if ( ret ) { printk("Failed to set the type for IRQ%u\n", irq); return ret; } printk("Additional IRQ %u (%s)\n", irq, what); if ( !vgic_reserve_virq(d, irq) ) printk("Failed to reserve vIRQ %u on dom%d\n", irq, d->domain_id); ret = route_irq_to_guest(d, irq, irq, what); if ( ret ) printk("Failed to route %s to dom%d\n", what, d->domain_id); return ret; }
int domain_vtimer_init(struct domain *d) { d->arch.phys_timer_base.offset = NOW(); d->arch.virt_timer_base.offset = READ_SYSREG64(CNTPCT_EL0); /* At this stage vgic_reserve_virq can't fail */ if ( is_hardware_domain(d) ) { if ( !vgic_reserve_virq(d, timer_get_irq(TIMER_PHYS_SECURE_PPI)) ) BUG(); if ( !vgic_reserve_virq(d, timer_get_irq(TIMER_PHYS_NONSECURE_PPI)) ) BUG(); if ( !vgic_reserve_virq(d, timer_get_irq(TIMER_VIRT_PPI)) ) BUG(); } else { if ( !vgic_reserve_virq(d, GUEST_TIMER_PHYS_S_PPI) ) BUG(); if ( !vgic_reserve_virq(d, GUEST_TIMER_PHYS_NS_PPI) ) BUG(); if ( !vgic_reserve_virq(d, GUEST_TIMER_VIRT_PPI) ) BUG(); } return 0; }
int domain_vtimer_init(struct domain *d, struct xen_arch_domainconfig *config) { d->arch.phys_timer_base.offset = NOW(); d->arch.virt_timer_base.offset = READ_SYSREG64(CNTPCT_EL0); d->time_offset_seconds = ticks_to_ns(d->arch.virt_timer_base.offset - boot_count); do_div(d->time_offset_seconds, 1000000000); config->clock_frequency = timer_dt_clock_frequency; /* At this stage vgic_reserve_virq can't fail */ if ( is_hardware_domain(d) ) { if ( !vgic_reserve_virq(d, timer_get_irq(TIMER_PHYS_SECURE_PPI)) ) BUG(); if ( !vgic_reserve_virq(d, timer_get_irq(TIMER_PHYS_NONSECURE_PPI)) ) BUG(); if ( !vgic_reserve_virq(d, timer_get_irq(TIMER_VIRT_PPI)) ) BUG(); } else { if ( !vgic_reserve_virq(d, GUEST_TIMER_PHYS_S_PPI) ) BUG(); if ( !vgic_reserve_virq(d, GUEST_TIMER_PHYS_NS_PPI) ) BUG(); if ( !vgic_reserve_virq(d, GUEST_TIMER_VIRT_PPI) ) BUG(); } return 0; }
int domain_vpl011_init(struct domain *d, struct vpl011_init_info *info) { int rc; struct vpl011 *vpl011 = &d->arch.vpl011; if ( vpl011->ring_buf ) return -EINVAL; /* Map the guest PFN to Xen address space. */ rc = prepare_ring_for_helper(d, gfn_x(info->gfn), &vpl011->ring_page, &vpl011->ring_buf); if ( rc < 0 ) goto out; rc = vgic_reserve_virq(d, GUEST_VPL011_SPI); if ( !rc ) { rc = -EINVAL; goto out1; } rc = alloc_unbound_xen_event_channel(d, 0, info->console_domid, vpl011_notification); if ( rc < 0 ) goto out2; vpl011->evtchn = info->evtchn = rc; spin_lock_init(&vpl011->lock); register_mmio_handler(d, &vpl011_mmio_handler, GUEST_PL011_BASE, GUEST_PL011_SIZE, NULL); return 0; out2: vgic_free_virq(d, GUEST_VPL011_SPI); out1: destroy_ring_for_helper(&vpl011->ring_buf, vpl011->ring_page); out: return rc; }
int arch_domain_create(struct domain *d, unsigned int domcr_flags, struct xen_arch_domainconfig *config) { int rc; uint8_t gic_version; d->arch.relmem = RELMEM_not_started; /* Idle domains do not need this setup */ if ( is_idle_domain(d) ) return 0; ASSERT(config != NULL); if ( (rc = p2m_init(d)) != 0 ) goto fail; rc = -ENOMEM; if ( (d->shared_info = alloc_xenheap_pages(0, 0)) == NULL ) goto fail; /* Default the virtual ID to match the physical */ d->arch.vpidr = boot_cpu_data.midr.bits; clear_page(d->shared_info); share_xen_page_with_guest( virt_to_page(d->shared_info), d, XENSHARE_writable); if ( (rc = domain_io_init(d)) != 0 ) goto fail; if ( (rc = p2m_alloc_table(d)) != 0 ) goto fail; /* * Currently the vGIC is emulating the same version of the * hardware GIC. Only the value XEN_DOMCTL_CONFIG_GIC_DEFAULT * is allowed. The DOMCTL will return the actual version of the * GIC. */ rc = -EOPNOTSUPP; if ( config->gic_version != XEN_DOMCTL_CONFIG_GIC_DEFAULT ) goto fail; switch ( gic_hw_version() ) { case GIC_V3: gic_version = XEN_DOMCTL_CONFIG_GIC_V3; break; case GIC_V2: gic_version = XEN_DOMCTL_CONFIG_GIC_V2; break; default: BUG(); } config->gic_version = gic_version; if ( (rc = gicv_setup(d)) != 0 ) goto fail; if ( (rc = domain_vgic_init(d)) != 0 ) goto fail; if ( (rc = domain_vtimer_init(d)) != 0 ) goto fail; /* * The hardware domain will get a PPI later in * arch/arm/domain_build.c depending on the * interrupt map of the hardware. */ if ( !is_hardware_domain(d) ) { d->arch.evtchn_irq = GUEST_EVTCHN_PPI; /* At this stage vgic_reserve_virq should never fail */ if ( !vgic_reserve_virq(d, GUEST_EVTCHN_PPI) ) BUG(); } /* * Virtual UART is only used by linux early printk and decompress code. * Only use it for the hardware domain because the linux kernel may not * support multi-platform. */ if ( is_hardware_domain(d) && (rc = domain_vuart_init(d)) ) goto fail; if ( (rc = iommu_domain_init(d)) != 0 ) goto fail; return 0; fail: d->is_dying = DOMDYING_dead; arch_domain_destroy(d); return rc; }
int arch_domain_create(struct domain *d, unsigned int domcr_flags, struct xen_arch_domainconfig *config) { int rc, count = 0; BUILD_BUG_ON(GUEST_MAX_VCPUS < MAX_VIRT_CPUS); d->arch.relmem = RELMEM_not_started; /* Idle domains do not need this setup */ if ( is_idle_domain(d) ) return 0; ASSERT(config != NULL); /* p2m_init relies on some value initialized by the IOMMU subsystem */ if ( (rc = iommu_domain_init(d)) != 0 ) goto fail; if ( (rc = p2m_init(d)) != 0 ) goto fail; rc = -ENOMEM; if ( (d->shared_info = alloc_xenheap_pages(0, 0)) == NULL ) goto fail; /* Default the virtual ID to match the physical */ d->arch.vpidr = boot_cpu_data.midr.bits; clear_page(d->shared_info); share_xen_page_with_guest( virt_to_page(d->shared_info), d, XENSHARE_writable); switch ( config->gic_version ) { case XEN_DOMCTL_CONFIG_GIC_NATIVE: switch ( gic_hw_version () ) { case GIC_V2: config->gic_version = XEN_DOMCTL_CONFIG_GIC_V2; d->arch.vgic.version = GIC_V2; break; case GIC_V3: config->gic_version = XEN_DOMCTL_CONFIG_GIC_V3; d->arch.vgic.version = GIC_V3; break; default: BUG(); } break; case XEN_DOMCTL_CONFIG_GIC_V2: d->arch.vgic.version = GIC_V2; break; case XEN_DOMCTL_CONFIG_GIC_V3: d->arch.vgic.version = GIC_V3; break; default: rc = -EOPNOTSUPP; goto fail; } if ( (rc = domain_vgic_register(d, &count)) != 0 ) goto fail; if ( (rc = domain_io_init(d, count + MAX_IO_HANDLER)) != 0 ) goto fail; if ( (rc = domain_vgic_init(d, config->nr_spis)) != 0 ) goto fail; if ( (rc = domain_vtimer_init(d, config)) != 0 ) goto fail; update_domain_wallclock_time(d); /* * The hardware domain will get a PPI later in * arch/arm/domain_build.c depending on the * interrupt map of the hardware. */ if ( !is_hardware_domain(d) ) { d->arch.evtchn_irq = GUEST_EVTCHN_PPI; /* At this stage vgic_reserve_virq should never fail */ if ( !vgic_reserve_virq(d, GUEST_EVTCHN_PPI) ) BUG(); } /* * Virtual UART is only used by linux early printk and decompress code. * Only use it for the hardware domain because the linux kernel may not * support multi-platform. */ if ( is_hardware_domain(d) && (rc = domain_vuart_init(d)) ) goto fail; return 0; fail: d->is_dying = DOMDYING_dead; arch_domain_destroy(d); return rc; }
int arch_domain_create(struct domain *d, unsigned int domcr_flags) { int rc; d->arch.relmem = RELMEM_not_started; /* Idle domains do not need this setup */ if ( is_idle_domain(d) ) return 0; if ( (rc = p2m_init(d)) != 0 ) goto fail; rc = -ENOMEM; if ( (d->shared_info = alloc_xenheap_pages(0, 0)) == NULL ) goto fail; /* Default the virtual ID to match the physical */ d->arch.vpidr = boot_cpu_data.midr.bits; clear_page(d->shared_info); share_xen_page_with_guest( virt_to_page(d->shared_info), d, XENSHARE_writable); if ( (rc = domain_io_init(d)) != 0 ) goto fail; if ( (rc = p2m_alloc_table(d)) != 0 ) goto fail; if ( (rc = gicv_setup(d)) != 0 ) goto fail; if ( (rc = domain_vgic_init(d)) != 0 ) goto fail; if ( (rc = domain_vtimer_init(d)) != 0 ) goto fail; /* * The hardware domain will get a PPI later in * arch/arm/domain_build.c depending on the * interrupt map of the hardware. */ if ( !is_hardware_domain(d) ) { d->arch.evtchn_irq = GUEST_EVTCHN_PPI; /* At this stage vgic_reserve_virq should never fail */ if ( !vgic_reserve_virq(d, GUEST_EVTCHN_PPI) ) BUG(); } /* * Virtual UART is only used by linux early printk and decompress code. * Only use it for the hardware domain because the linux kernel may not * support multi-platform. */ if ( is_hardware_domain(d) && (rc = domain_vuart_init(d)) ) goto fail; if ( (rc = iommu_domain_init(d)) != 0 ) goto fail; return 0; fail: d->is_dying = DOMDYING_dead; arch_domain_destroy(d); return rc; }