📄 domain_build.c
字号:
{ l1_pgentry_t gdt_l1e; d->arch.is_32bit_pv = d->arch.has_32bit_shinfo = 1; v->vcpu_info = (void *)&d->shared_info->compat.vcpu_info[0]; if ( nr_pages != (unsigned int)nr_pages ) nr_pages = UINT_MAX; /* * Map compatibility Xen segments into every VCPU's GDT. See * arch_domain_create() for further comments. */ gdt_l1e = l1e_from_page(virt_to_page(compat_gdt_table), PAGE_HYPERVISOR); for ( i = 0; i < MAX_VIRT_CPUS; i++ ) d->arch.mm_perdomain_pt[((i << GDT_LDT_VCPU_SHIFT) + FIRST_RESERVED_GDT_PAGE)] = gdt_l1e; flush_tlb_one_local(GDT_LDT_VIRT_START + FIRST_RESERVED_GDT_BYTE); }#endif 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 } domain_set_alloc_bitsize(d); /* * Why do we need this? The number of page-table frames depends on the * size of the bootstrap address space. But the size of the address space * depends on the number of page-table frames (since each one is mapped * read-only). We have a pair of simultaneous equations in two unknowns, * which we solve by exhaustive search. */ v_start = parms.virt_base; vkern_start = parms.virt_kstart; vkern_end = parms.virt_kend; vinitrd_start = round_pgup(vkern_end); vinitrd_end = vinitrd_start + initrd_len; vphysmap_start = round_pgup(vinitrd_end); vphysmap_end = vphysmap_start + (nr_pages * (!is_pv_32on64_domain(d) ? sizeof(unsigned long) : sizeof(unsigned int))); vstartinfo_start = round_pgup(vphysmap_end); vstartinfo_end = (vstartinfo_start + sizeof(struct start_info) + sizeof(struct dom0_vga_console_info)); vpt_start = round_pgup(vstartinfo_end); for ( nr_pt_pages = 2; ; nr_pt_pages++ ) { vpt_end = vpt_start + (nr_pt_pages * PAGE_SIZE); vstack_start = vpt_end; vstack_end = vstack_start + PAGE_SIZE; v_end = (vstack_end + (1UL<<22)-1) & ~((1UL<<22)-1); if ( (v_end - vstack_end) < (512UL << 10) ) v_end += 1UL << 22; /* Add extra 4MB to get >= 512kB padding. */#if defined(__i386__) /* 5 pages: 1x 3rd + 4x 2nd level */ if ( (((v_end - v_start + ((1UL<<L2_PAGETABLE_SHIFT)-1)) >> L2_PAGETABLE_SHIFT) + 5) <= nr_pt_pages ) break;#elif defined(__x86_64__)#define NR(_l,_h,_s) \ (((((_h) + ((1UL<<(_s))-1)) & ~((1UL<<(_s))-1)) - \ ((_l) & ~((1UL<<(_s))-1))) >> (_s)) if ( (1 + /* # L4 */ NR(v_start, v_end, L4_PAGETABLE_SHIFT) + /* # L3 */ (!is_pv_32on64_domain(d) ? NR(v_start, v_end, L3_PAGETABLE_SHIFT) : /* # L2 */ 4) + /* # compat L2 */ NR(v_start, v_end, L2_PAGETABLE_SHIFT)) /* # L1 */ <= nr_pt_pages ) break;#endif } order = get_order_from_bytes(v_end - v_start); if ( (1UL << order) > nr_pages ) panic("Domain 0 allocation is too small for kernel image.\n");#ifdef __i386__ /* Ensure that our low-memory 1:1 mapping covers the allocation. */ page = alloc_domheap_pages(d, order, MEMF_bits(30));#else page = alloc_domheap_pages(d, order, 0);#endif if ( page == NULL ) panic("Not enough RAM for domain 0 allocation.\n"); alloc_spfn = page_to_mfn(page); alloc_epfn = alloc_spfn + d->tot_pages; printk("PHYSICAL MEMORY ARRANGEMENT:\n" " Dom0 alloc.: %"PRIpaddr"->%"PRIpaddr, pfn_to_paddr(alloc_spfn), pfn_to_paddr(alloc_epfn)); if ( d->tot_pages < nr_pages ) printk(" (%lu pages to be allocated)", nr_pages - d->tot_pages); printk("\nVIRTUAL MEMORY ARRANGEMENT:\n" " Loaded kernel: %p->%p\n" " Init. ramdisk: %p->%p\n" " Phys-Mach map: %p->%p\n" " Start info: %p->%p\n" " Page tables: %p->%p\n" " Boot stack: %p->%p\n" " TOTAL: %p->%p\n", _p(vkern_start), _p(vkern_end), _p(vinitrd_start), _p(vinitrd_end), _p(vphysmap_start), _p(vphysmap_end), _p(vstartinfo_start), _p(vstartinfo_end), _p(vpt_start), _p(vpt_end), _p(vstack_start), _p(vstack_end), _p(v_start), _p(v_end)); printk(" ENTRY ADDRESS: %p\n", _p(parms.virt_entry)); if ( ((v_end - v_start)>>PAGE_SHIFT) > nr_pages ) { printk("Initial guest OS requires too much space\n" "(%luMB is greater than %luMB limit)\n", (v_end-v_start)>>20, nr_pages>>(20-PAGE_SHIFT)); return -ENOMEM; } mpt_alloc = (vpt_start - v_start) + (unsigned long)pfn_to_paddr(alloc_spfn);#if defined(__i386__) /* * Protect the lowest 1GB of memory. We use a temporary mapping there * from which we copy the kernel and ramdisk images. */ if ( v_start < (1UL<<30) ) { printk("Initial loading isn't allowed to lowest 1GB of memory.\n"); return -EINVAL; } /* WARNING: The new domain must have its 'processor' field filled in! */ l3start = l3tab = (l3_pgentry_t *)mpt_alloc; mpt_alloc += PAGE_SIZE; l2start = l2tab = (l2_pgentry_t *)mpt_alloc; mpt_alloc += 4*PAGE_SIZE; memcpy(l2tab, idle_pg_table_l2, 4*PAGE_SIZE); for (i = 0; i < 4; i++) { l3tab[i] = l3e_from_paddr((u32)l2tab + i*PAGE_SIZE, L3_PROT); l2tab[(LINEAR_PT_VIRT_START >> L2_PAGETABLE_SHIFT)+i] = l2e_from_paddr((u32)l2tab + i*PAGE_SIZE, __PAGE_HYPERVISOR); } v->arch.guest_table = pagetable_from_paddr((unsigned long)l3start); for ( i = 0; i < PDPT_L2_ENTRIES; i++ ) l2tab[l2_linear_offset(PERDOMAIN_VIRT_START) + i] = l2e_from_page(virt_to_page(d->arch.mm_perdomain_pt) + i, __PAGE_HYPERVISOR); l2tab += l2_linear_offset(v_start); mfn = alloc_spfn; for ( count = 0; count < ((v_end-v_start)>>PAGE_SHIFT); count++ ) { if ( !((unsigned long)l1tab & (PAGE_SIZE-1)) ) { l1start = l1tab = (l1_pgentry_t *)mpt_alloc; mpt_alloc += PAGE_SIZE; *l2tab = l2e_from_paddr((unsigned long)l1start, L2_PROT); l2tab++; clear_page(l1tab); if ( count == 0 ) l1tab += l1_table_offset(v_start); } *l1tab = l1e_from_pfn(mfn, L1_PROT); l1tab++; page = mfn_to_page(mfn); if ( !get_page_and_type(page, d, PGT_writable_page) ) BUG(); mfn++; } /* Pages that are part of page tables must be read only. */ l2tab = l2start + l2_linear_offset(vpt_start); l1start = l1tab = (l1_pgentry_t *)(u32)l2e_get_paddr(*l2tab); l1tab += l1_table_offset(vpt_start); for ( count = 0; count < nr_pt_pages; count++ ) { page = mfn_to_page(l1e_get_pfn(*l1tab)); if ( !opt_dom0_shadow ) l1e_remove_flags(*l1tab, _PAGE_RW); else if ( !get_page_type(page, PGT_writable_page) ) BUG(); switch ( count ) { case 0: page->u.inuse.type_info &= ~PGT_type_mask; page->u.inuse.type_info |= PGT_l3_page_table; get_page(page, d); /* an extra ref because of readable mapping */ /* Get another ref to L3 page so that it can be pinned. */ page->u.inuse.type_info++; page->count_info++; set_bit(_PGT_pinned, &page->u.inuse.type_info); break; case 1 ... 4: page->u.inuse.type_info &= ~PGT_type_mask; page->u.inuse.type_info |= PGT_l2_page_table; if ( count == 4 ) page->u.inuse.type_info |= PGT_pae_xen_l2; get_page(page, d); /* an extra ref because of readable mapping */ break; default: page->u.inuse.type_info &= ~PGT_type_mask; page->u.inuse.type_info |= PGT_l1_page_table; get_page(page, d); /* an extra ref because of readable mapping */ break; } if ( !((unsigned long)++l1tab & (PAGE_SIZE - 1)) ) l1start = l1tab = (l1_pgentry_t *)(u32)l2e_get_paddr(*++l2tab); }#elif defined(__x86_64__) /* Overlap with Xen protected area? */ if ( !is_pv_32on64_domain(d) ? ((v_start < HYPERVISOR_VIRT_END) && (v_end > HYPERVISOR_VIRT_START)) : (v_end > HYPERVISOR_COMPAT_VIRT_START(d)) ) { printk("DOM0 image overlaps with Xen private area.\n"); return -EINVAL; } if ( is_pv_32on64_domain(d) ) { v->arch.guest_context.failsafe_callback_cs = FLAT_COMPAT_KERNEL_CS; v->arch.guest_context.event_callback_cs = FLAT_COMPAT_KERNEL_CS; } /* WARNING: The new domain must have its 'processor' field filled in! */ if ( !is_pv_32on64_domain(d) ) { maddr_to_page(mpt_alloc)->u.inuse.type_info = PGT_l4_page_table; l4start = l4tab = __va(mpt_alloc); mpt_alloc += PAGE_SIZE; } else { page = alloc_domheap_page(NULL, 0); if ( !page ) panic("Not enough RAM for domain 0 PML4.\n"); page->u.inuse.type_info = PGT_l4_page_table|PGT_validated|1; l4start = l4tab = page_to_virt(page); } copy_page(l4tab, idle_pg_table); l4tab[0] = l4e_empty(); /* zap trampoline mapping */ l4tab[l4_table_offset(LINEAR_PT_VIRT_START)] = l4e_from_paddr(__pa(l4start), __PAGE_HYPERVISOR); l4tab[l4_table_offset(PERDOMAIN_VIRT_START)] = l4e_from_paddr(__pa(d->arch.mm_perdomain_l3), __PAGE_HYPERVISOR); v->arch.guest_table = pagetable_from_paddr(__pa(l4start)); if ( is_pv_32on64_domain(d) ) v->arch.guest_table_user = v->arch.guest_table; l4tab += l4_table_offset(v_start); mfn = alloc_spfn; for ( count = 0; count < ((v_end-v_start)>>PAGE_SHIFT); count++ ) { if ( !((unsigned long)l1tab & (PAGE_SIZE-1)) ) { maddr_to_page(mpt_alloc)->u.inuse.type_info = PGT_l1_page_table; l1start = l1tab = __va(mpt_alloc); mpt_alloc += PAGE_SIZE; clear_page(l1tab); if ( count == 0 ) l1tab += l1_table_offset(v_start); if ( !((unsigned long)l2tab & (PAGE_SIZE-1)) ) { maddr_to_page(mpt_alloc)->u.inuse.type_info = PGT_l2_page_table; l2start = l2tab = __va(mpt_alloc); mpt_alloc += PAGE_SIZE; clear_page(l2tab); if ( count == 0 ) l2tab += l2_table_offset(v_start); if ( !((unsigned long)l3tab & (PAGE_SIZE-1)) ) { maddr_to_page(mpt_alloc)->u.inuse.type_info = PGT_l3_page_table; l3start = l3tab = __va(mpt_alloc); mpt_alloc += PAGE_SIZE; clear_page(l3tab); if ( count == 0 ) l3tab += l3_table_offset(v_start); *l4tab = l4e_from_paddr(__pa(l3start), L4_PROT); l4tab++; } *l3tab = l3e_from_paddr(__pa(l2start), L3_PROT); l3tab++; } *l2tab = l2e_from_paddr(__pa(l1start), L2_PROT); l2tab++; } *l1tab = l1e_from_pfn(mfn, (!is_pv_32on64_domain(d) ? L1_PROT : COMPAT_L1_PROT)); l1tab++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -