static int late_hwdom_init(struct domain *d) { #ifdef CONFIG_LATE_HWDOM struct domain *dom0; int rv; if ( d != hardware_domain || d->domain_id == 0 ) return 0; rv = xsm_init_hardware_domain(XSM_HOOK, d); if ( rv ) return rv; printk("Initialising hardware domain %d\n", hardware_domid); dom0 = rcu_lock_domain_by_id(0); ASSERT(dom0 != NULL); /* * Hardware resource ranges for domain 0 have been set up from * various sources intended to restrict the hardware domain's * access. Apply these ranges to the actual hardware domain. * * Because the lists are being swapped, a side effect of this * operation is that Domain 0's rangesets are cleared. Since * domain 0 should not be accessing the hardware when it constructs * a hardware domain, this should not be a problem. Both lists * may be modified after this hypercall returns if a more complex * device model is desired. */ rangeset_swap(d->irq_caps, dom0->irq_caps); rangeset_swap(d->iomem_caps, dom0->iomem_caps); #ifdef CONFIG_X86 rangeset_swap(d->arch.ioport_caps, dom0->arch.ioport_caps); #endif rcu_unlock_domain(dom0); iommu_hwdom_init(d); return rv; #else return 0; #endif }
static int __init pvh_setup_acpi(struct domain *d, paddr_t start_info) { unsigned long pfn, nr_pages; paddr_t madt_paddr, xsdt_paddr, rsdp_paddr; unsigned int i; int rc; struct acpi_table_rsdp *native_rsdp, rsdp = { .signature = ACPI_SIG_RSDP, .revision = 2, .length = sizeof(rsdp), }; /* Scan top-level tables and add their regions to the guest memory map. */ for( i = 0; i < acpi_gbl_root_table_list.count; i++ ) { const char *sig = acpi_gbl_root_table_list.tables[i].signature.ascii; unsigned long addr = acpi_gbl_root_table_list.tables[i].address; unsigned long size = acpi_gbl_root_table_list.tables[i].length; /* * Make sure the original MADT is also mapped, so that Dom0 can * properly access the data returned by _MAT methods in case it's * re-using MADT memory. */ if ( strncmp(sig, ACPI_SIG_MADT, ACPI_NAME_SIZE) ? pvh_acpi_table_allowed(sig) : !acpi_memory_banned(addr, size) ) pvh_add_mem_range(d, addr, addr + size, E820_ACPI); } /* Identity map ACPI e820 regions. */ for ( i = 0; i < d->arch.nr_e820; i++ ) { if ( d->arch.e820[i].type != E820_ACPI && d->arch.e820[i].type != E820_NVS ) continue; pfn = PFN_DOWN(d->arch.e820[i].addr); nr_pages = PFN_UP((d->arch.e820[i].addr & ~PAGE_MASK) + d->arch.e820[i].size); rc = modify_identity_mmio(d, pfn, nr_pages, true); if ( rc ) { printk("Failed to map ACPI region [%#lx, %#lx) into Dom0 memory map\n", pfn, pfn + nr_pages); return rc; } } rc = pvh_setup_acpi_madt(d, &madt_paddr); if ( rc ) return rc; rc = pvh_setup_acpi_xsdt(d, madt_paddr, &xsdt_paddr); if ( rc ) return rc; /* Craft a custom RSDP. */ native_rsdp = acpi_os_map_memory(acpi_os_get_root_pointer(), sizeof(rsdp)); if ( !native_rsdp ) { printk("Failed to map native RSDP\n"); return -ENOMEM; } memcpy(rsdp.oem_id, native_rsdp->oem_id, sizeof(rsdp.oem_id)); acpi_os_unmap_memory(native_rsdp, sizeof(rsdp)); rsdp.xsdt_physical_address = xsdt_paddr; /* * Calling acpi_tb_checksum here is a layering violation, but * introducing a wrapper for such simple usage seems overkill. */ rsdp.checksum -= acpi_tb_checksum(ACPI_CAST_PTR(u8, &rsdp), ACPI_RSDP_REV0_SIZE); rsdp.extended_checksum -= acpi_tb_checksum(ACPI_CAST_PTR(u8, &rsdp), sizeof(rsdp)); /* * Place the new RSDP in guest memory space. * * NB: this RSDP is not going to replace the original RSDP, which should * still be accessible to the guest. However that RSDP is going to point to * the native RSDT, and should not be used for the Dom0 kernel's boot * purposes (we keep it visible for post boot access). */ if ( pvh_steal_ram(d, sizeof(rsdp), 0, GB(4), &rsdp_paddr) ) { printk("Unable to allocate guest RAM for RSDP\n"); return -ENOMEM; } /* Mark this region as E820_ACPI. */ if ( pvh_add_mem_range(d, rsdp_paddr, rsdp_paddr + sizeof(rsdp), E820_ACPI) ) printk("Unable to add RSDP region to memory map\n"); /* Copy RSDP into guest memory. */ rc = hvm_copy_to_guest_phys(rsdp_paddr, &rsdp, sizeof(rsdp), d->vcpu[0]); if ( rc ) { printk("Unable to copy RSDP into guest memory\n"); return rc; } /* Copy RSDP address to start_info. */ rc = hvm_copy_to_guest_phys(start_info + offsetof(struct hvm_start_info, rsdp_paddr), &rsdp_paddr, sizeof(((struct hvm_start_info *) 0)->rsdp_paddr), d->vcpu[0]); if ( rc ) { printk("Unable to copy RSDP into guest memory\n"); return rc; } return 0; } int __init dom0_construct_pvh(struct domain *d, const module_t *image, unsigned long image_headroom, module_t *initrd, void *(*bootstrap_map)(const module_t *), char *cmdline) { paddr_t entry, start_info; int rc; printk("** Building a PVH Dom0 **\n"); iommu_hwdom_init(d); rc = pvh_setup_p2m(d); if ( rc ) { printk("Failed to setup Dom0 physical memory map\n"); return rc; } rc = pvh_load_kernel(d, image, image_headroom, initrd, bootstrap_map(image), cmdline, &entry, &start_info); if ( rc ) { printk("Failed to load Dom0 kernel\n"); return rc; } rc = pvh_setup_cpus(d, entry, start_info); if ( rc ) { printk("Failed to setup Dom0 CPUs: %d\n", rc); return rc; } rc = pvh_setup_acpi(d, start_info); if ( rc ) { printk("Failed to setup Dom0 ACPI tables: %d\n", rc); return rc; } panic("Building a PVHv2 Dom0 is not yet supported."); return 0; }