[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v5 9/9] xen/x86: setup PVHv2 Dom0 ACPI tables
>>> On 19.01.17 at 18:29, <roger.pau@xxxxxxxxxx> wrote: > +static int __init pvh_setup_acpi_madt(struct domain *d, paddr_t *addr) > +{ > + struct acpi_table_madt *madt; > + struct acpi_table_header *table; > + struct acpi_madt_io_apic *io_apic; > + struct acpi_madt_local_apic *local_apic; > + struct acpi_madt_local_x2apic *x2apic; > + acpi_status status; > + unsigned long size; > + unsigned int i, max_vcpus; > + int rc; > + > + /* Count number of interrupt overrides in the MADT. */ > + acpi_table_parse_madt(ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, > + acpi_count_intr_ovr, UINT_MAX); > + > + /* Count number of NMI sources in the MADT. */ > + acpi_table_parse_madt(ACPI_MADT_TYPE_NMI_SOURCE, acpi_count_nmi_src, > + UINT_MAX); > + > + /* Check if there are x2APIC entries. */ > + acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_X2APIC, acpi_check_x2apic, 1); > + > + max_vcpus = dom0_max_vcpus(); > + /* Calculate the size of the crafted MADT. */ > + size = sizeof(*madt); > + size += sizeof(*io_apic); Still just a single IO-APIC and no fixme note. I see you have one below, but this line will need to remain in lock step. Or perhaps you could multiply by nr_ioapics here, accepting the transient waste of space. > + /* > + * The APIC ID field of the local APIC struct is only 1byte, so we need > + * to limit the number of local APIC entries to 128 because we only use > + * even numbers as APIC IDs. > + */ > + size += sizeof(*local_apic) * > + min(max_vcpus, 1U << (sizeof(local_apic->id) * 8)); This caps at 256 now. Perhaps it would anyway be better to use HVM_MAX_VCPUS here, or maybe the minimum of both? > + size += sizeof(*intsrcovr) * acpi_intr_overrides; > + size += sizeof(*nmisrc) * acpi_nmi_sources; > + size += acpi_x2apic ? sizeof(*x2apic) * dom0_max_vcpus() : 0; You have the function call result already latched in a local variable. Plus, when you cap LAPIC entries, you should also provide x2APIC ones (to be able to represent all vCPU-s). > + madt = xzalloc_bytes(size); > + if ( !madt ) > + { > + printk("Unable to allocate memory for MADT table\n"); > + return -ENOMEM; > + } > + > + /* Copy the native MADT table header. */ > + status = acpi_get_table(ACPI_SIG_MADT, 0, &table); > + if ( !ACPI_SUCCESS(status) ) > + { > + printk("Failed to get MADT ACPI table, aborting.\n"); > + return -EINVAL; > + } > + madt->header = *table; > + madt->address = APIC_DEFAULT_PHYS_BASE; > + /* > + * NB: this is currently set to 4, which is the revision in the ACPI > + * spec 6.1. Sadly ACPICA doesn't provide revision numbers for the > + * tables described in the headers. > + */ > + madt->header.revision = min_t(unsigned char, table->revision, 4); > + > + /* > + * Setup the IO APIC entry. > + * FIXME: the current vIO-APIC code just supports one IO-APIC instance > + * per domain. This must be fixed in order to provide the same amount of > + * IO APICs as available on bare metal, and with the same IDs as found in > + * the native IO APIC MADT entries. > + */ > + if ( nr_ioapics > 1 ) > + printk("WARNING: found %d IO APICs, Dom0 will only have access to 1 > emulated IO APIC\n", > + nr_ioapics); > + io_apic = (struct acpi_madt_io_apic *)(madt + 1); To aid readability you may want to use void in all such casts. > +static bool __init pvh_acpi_table_allowed(const char *sig) > +{ > + static const char __init banned_tables[][ACPI_NAME_SIZE] = { __initconst > + ACPI_SIG_HPET, ACPI_SIG_SLIT, ACPI_SIG_SRAT, ACPI_SIG_MPST, > + ACPI_SIG_PMTT, ACPI_SIG_MADT, ACPI_SIG_DMAR}; > + int i; unsigned int > +static int __init pvh_setup_acpi_xsdt(struct domain *d, paddr_t madt_addr, > + paddr_t *addr) > +{ > + struct acpi_table_xsdt *xsdt; > + struct acpi_table_header *table; > + struct acpi_table_rsdp *rsdp; > + unsigned long size = sizeof(*xsdt); > + unsigned int i, j, num_tables = 0; > + paddr_t xsdt_paddr; > + int rc; > + > + /* > + * Restore original DMAR table signature, we are going to filter it > + * from the new XSDT that is presented to the guest, so it no longer > + * makes sense to have it's signature zapped. "... so it is no longer necessary to ..."? > +static int __init pvh_setup_acpi(struct domain *d, paddr_t start_info) > +{ > + struct acpi_table_rsdp rsdp, *native_rsdp; > + unsigned long pfn, nr_pages; > + paddr_t madt_paddr, xsdt_paddr, rsdp_paddr; > + unsigned int i; > + int rc; > + > + /* 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 ( pvh_acpi_table_allowed(sig) || > + (strncmp(sig, ACPI_SIG_MADT, ACPI_NAME_SIZE) == 0 && > + !acpi_memory_banned(addr, size)) ) Indentation. But to me this would be clearer as if ( strncmp(sig, ACPI_SIG_MADT, ACPI_NAME_SIZE) ? pvh_acpi_table_allowed(sig) : !acpi_memory_banned(addr, size) ) anyway. > + 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. */ > + memset(&rsdp, 0, sizeof(rsdp)); Perhaps worth using an initializer again (with once again as many as possible of the items below folded there)? > + memcpy(rsdp.signature, ACPI_SIG_RSDP, sizeof(rsdp.signature)); > + native_rsdp = acpi_os_map_memory(acpi_os_get_root_pointer(), > sizeof(rsdp)); > + memcpy(rsdp.oem_id, native_rsdp->oem_id, sizeof(rsdp.oem_id)); > + acpi_os_unmap_memory(native_rsdp, sizeof(rsdp)); > + rsdp.revision = 2; > + rsdp.xsdt_physical_address = xsdt_paddr; > + rsdp.rsdt_physical_address = 0; This is redundant in any event. > + rsdp.length = sizeof(rsdp); > + /* > + * 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 after all for post boot access). Jan _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |