int __init xsm_multiboot_policy_init(unsigned long *module_map, const multiboot_info_t *mbi, void *(*bootstrap_map)(const module_t *), void **policy_buffer, size_t *policy_size) { int i; module_t *mod = (module_t *)__va(mbi->mods_addr); int rc = 0; u32 *_policy_start; unsigned long _policy_len; /* * Try all modules and see whichever could be the binary policy. * Adjust module_map for the module that is the binary policy. */ for ( i = mbi->mods_count-1; i >= 1; i-- ) { if ( !test_bit(i, module_map) ) continue; _policy_start = bootstrap_map(mod + i); _policy_len = mod[i].mod_end; if ( (xsm_magic_t)(*_policy_start) == XSM_MAGIC ) { *policy_buffer = _policy_start; *policy_size = _policy_len; printk("Policy len %#lx, start at %p.\n", _policy_len,_policy_start); __clear_bit(i, module_map); break; } bootstrap_map(NULL); } return rc; }
int __init construct_dom0( struct domain *d, const module_t *image, unsigned long image_headroom, module_t *initrd, void *(*bootstrap_map)(const module_t *), char *cmdline) { int i, cpu, rc, compatible, compat32, order, machine; struct cpu_user_regs *regs; unsigned long pfn, mfn; unsigned long nr_pages; unsigned long nr_pt_pages; unsigned long alloc_spfn; unsigned long alloc_epfn; unsigned long initrd_pfn = -1, initrd_mfn = 0; unsigned long count; struct page_info *page = NULL; start_info_t *si; struct vcpu *v = d->vcpu[0]; unsigned long long value; char *image_base = bootstrap_map(image); unsigned long image_len = image->mod_end; char *image_start = image_base + image_headroom; unsigned long initrd_len = initrd ? initrd->mod_end : 0; #if CONFIG_PAGING_LEVELS < 4 module_t mpt; void *mpt_ptr; #else l4_pgentry_t *l4tab = NULL, *l4start = NULL; #endif l3_pgentry_t *l3tab = NULL, *l3start = NULL; l2_pgentry_t *l2tab = NULL, *l2start = NULL; l1_pgentry_t *l1tab = NULL, *l1start = NULL; /* * This fully describes the memory layout of the initial domain. All * *_start address are page-aligned, except v_start (and v_end) which are * superpage-aligned. */ struct elf_binary elf; struct elf_dom_parms parms; unsigned long vkern_start; unsigned long vkern_end; unsigned long vinitrd_start; unsigned long vinitrd_end; unsigned long vphysmap_start; unsigned long vphysmap_end; unsigned long vstartinfo_start; unsigned long vstartinfo_end; unsigned long vstack_start; unsigned long vstack_end; unsigned long vpt_start; unsigned long vpt_end; unsigned long v_start; unsigned long v_end; /* Machine address of next candidate page-table page. */ paddr_t mpt_alloc; /* Sanity! */ BUG_ON(d->domain_id != 0); BUG_ON(d->vcpu[0] == NULL); BUG_ON(v->is_initialised); printk("*** LOADING DOMAIN 0 ***\n"); d->max_pages = ~0U; if ( (rc = bzimage_parse(image_base, &image_start, &image_len)) != 0 ) return rc; if ( (rc = elf_init(&elf, image_start, image_len)) != 0 ) return rc; #ifdef VERBOSE elf_set_verbose(&elf); #endif elf_parse_binary(&elf); if ( (rc = elf_xen_parse(&elf, &parms)) != 0 ) return rc; /* compatibility check */ compatible = compat32 = 0; machine = elf_uval(&elf, elf.ehdr, e_machine); switch (CONFIG_PAGING_LEVELS) { case 3: /* x86_32p */ if (parms.pae == PAEKERN_bimodal) parms.pae = PAEKERN_extended_cr3; printk(" Xen kernel: 32-bit, PAE, lsb\n"); if (elf_32bit(&elf) && parms.pae && machine == EM_386) compatible = 1; break; case 4: /* x86_64 */ printk(" Xen kernel: 64-bit, lsb, compat32\n"); if (elf_32bit(&elf) && parms.pae == PAEKERN_bimodal) parms.pae = PAEKERN_extended_cr3; if (elf_32bit(&elf) && parms.pae && machine == EM_386) { compat32 = 1; compatible = 1; } if (elf_64bit(&elf) && machine == EM_X86_64) compatible = 1; break; } printk(" Dom0 kernel: %s%s, %s, paddr 0x%" PRIx64 " -> 0x%" PRIx64 "\n", elf_64bit(&elf) ? "64-bit" : "32-bit", parms.pae ? ", PAE" : "", elf_msb(&elf) ? "msb" : "lsb", elf.pstart, elf.pend); if ( elf.bsd_symtab_pstart ) printk(" Dom0 symbol map 0x%" PRIx64 " -> 0x%" PRIx64 "\n", elf.bsd_symtab_pstart, elf.bsd_symtab_pend); if ( !compatible ) { printk("Mismatch between Xen and DOM0 kernel\n"); return -EINVAL; } if ( parms.elf_notes[XEN_ELFNOTE_SUPPORTED_FEATURES].type != XEN_ENT_NONE && !test_bit(XENFEAT_dom0, parms.f_supported) ) { printk("Kernel does not support Dom0 operation\n"); return -EINVAL; } #if defined(__x86_64__) if ( compat32 ) { d->arch.is_32bit_pv = d->arch.has_32bit_shinfo = 1; v->vcpu_info = (void *)&d->shared_info->compat.vcpu_info[0]; if ( setup_compat_arg_xlat(v) != 0 ) BUG(); } #endif nr_pages = compute_dom0_nr_pages(d, &parms, initrd_len); if ( parms.pae == PAEKERN_extended_cr3 ) set_bit(VMASST_TYPE_pae_extended_cr3, &d->vm_assist); if ( (parms.virt_hv_start_low != UNSET_ADDR) && elf_32bit(&elf) ) { unsigned long mask = (1UL << L2_PAGETABLE_SHIFT) - 1; value = (parms.virt_hv_start_low + mask) & ~mask; BUG_ON(!is_pv_32bit_domain(d)); #if defined(__i386__) if ( value > HYPERVISOR_VIRT_START ) panic("Domain 0 expects too high a hypervisor start address.\n"); #else if ( value > __HYPERVISOR_COMPAT_VIRT_START ) panic("Domain 0 expects too high a hypervisor start address.\n"); HYPERVISOR_COMPAT_VIRT_START(d) = max_t(unsigned int, m2p_compat_vstart, value); #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; }