📄 domain.c
字号:
return rc;}// remove following line if not privifying in memory//#define HAVE_PRIVIFY_MEMORY#ifndef HAVE_PRIVIFY_MEMORY#define privify_memory(x,y) do {} while(0)#endifstatic void __init loaddomainelfimage(struct domain *d, struct elf_binary *elf, unsigned long phys_load_offset){ const elf_phdr *phdr; int phnum, h, filesz, memsz; unsigned long elfaddr, dom_mpaddr, dom_imva; struct page_info *p; phnum = elf_uval(elf, elf->ehdr, e_phnum); for (h = 0; h < phnum; h++) { phdr = elf_phdr_by_index(elf, h); if (!elf_phdr_is_loadable(elf, phdr)) continue; filesz = elf_uval(elf, phdr, p_filesz); memsz = elf_uval(elf, phdr, p_memsz); elfaddr = (unsigned long) elf->image + elf_uval(elf, phdr, p_offset); dom_mpaddr = elf_uval(elf, phdr, p_paddr); dom_mpaddr += phys_load_offset; while (memsz > 0) { p = assign_new_domain_page(d,dom_mpaddr); BUG_ON (unlikely(p == NULL)); dom_imva = __va_ul(page_to_maddr(p)); if (filesz > 0) { if (filesz >= PAGE_SIZE) copy_page((void *) dom_imva, (void *) elfaddr); else { // copy partial page memcpy((void *) dom_imva, (void *) elfaddr, filesz); // zero the rest of page memset((void *) dom_imva+filesz, 0, PAGE_SIZE-filesz); }//FIXME: This test for code seems to find a lot more than objdump -x does if (elf_uval(elf, phdr, p_flags) & PF_X) { privify_memory(dom_imva,PAGE_SIZE); flush_icache_range(dom_imva, dom_imva+PAGE_SIZE); } } else if (memsz > 0) { /* always zero out entire page */ clear_page((void *) dom_imva); } memsz -= PAGE_SIZE; filesz -= PAGE_SIZE; elfaddr += PAGE_SIZE; dom_mpaddr += PAGE_SIZE; } }}static void __init calc_dom0_size(void){ unsigned long domheap_pages; unsigned long p2m_pages; unsigned long spare_hv_pages; unsigned long max_dom0_size; /* Estimate maximum memory we can safely allocate for dom0 * by subtracting the p2m table allocation and a chunk of memory * for DMA and PCI mapping from the available domheap pages. The * chunk for DMA, PCI, etc., is a guestimate, as xen doesn't seem * to have a good idea of what those requirements might be ahead * of time, calculated at 128MB + 1MB per 4GB of system memory */ domheap_pages = avail_domheap_pages(); p2m_pages = domheap_pages / PTRS_PER_PTE; spare_hv_pages = 8192 + (domheap_pages / 4096); max_dom0_size = (domheap_pages - (p2m_pages + spare_hv_pages)) * PAGE_SIZE; printk("Maximum permitted dom0 size: %luMB\n", max_dom0_size / (1024*1024)); /* validate proposed dom0_size, fix up as needed */ if (dom0_size > max_dom0_size) { printk("Reducing dom0 memory allocation from %luK to %luK " "to fit available memory\n", dom0_size / 1024, max_dom0_size / 1024); dom0_size = max_dom0_size; } /* dom0_mem=0 can be passed in to give all available mem to dom0 */ if (dom0_size == 0) { printk("Allocating all available memory to dom0\n"); dom0_size = max_dom0_size; } /* Check dom0 size. */ if (dom0_size < 4 * 1024 * 1024) { panic("dom0_mem is too small, boot aborted" " (try e.g. dom0_mem=256M or dom0_mem=65536K)\n"); } if (running_on_sim) { dom0_size = 128*1024*1024; //FIXME: Should be configurable } /* no need to allocate pages for now * pages are allocated by map_new_domain_page() via loaddomainelfimage() */}/* * Domain 0 has direct access to all devices absolutely. However * the major point of this stub here, is to allow alloc_dom_mem * handled with order > 0 request. Dom0 requires that bit set to * allocate memory for other domains. */static void __init physdev_init_dom0(struct domain *d){ if (iomem_permit_access(d, 0UL, ~0UL)) BUG(); if (irqs_permit_access(d, 0, NR_IRQS-1)) BUG(); if (ioports_permit_access(d, 0, 0xffff)) BUG();}int __init construct_dom0(struct domain *d, unsigned long image_start, unsigned long image_len, unsigned long initrd_start, unsigned long initrd_len, char *cmdline){ int i, rc; start_info_t *si; dom0_vga_console_info_t *ci; struct vcpu *v = d->vcpu[0]; unsigned long max_pages; struct elf_binary elf; struct elf_dom_parms parms; unsigned long p_start; unsigned long pkern_start; unsigned long pkern_entry; unsigned long pkern_end; unsigned long pinitrd_start = 0; unsigned long pstart_info; unsigned long phys_load_offset; struct page_info *start_info_page; unsigned long bp_mpa; struct ia64_boot_param *bp;//printk("construct_dom0: starting\n"); /* Sanity! */ BUG_ON(d != dom0); BUG_ON(d->vcpu[0] == NULL); BUG_ON(v->is_initialised); printk("*** LOADING DOMAIN 0 ***\n"); calc_dom0_size(); max_pages = dom0_size / PAGE_SIZE; d->max_pages = max_pages; d->tot_pages = 0; rc = elf_init(&elf, (void*)image_start, image_len); if ( rc != 0 ) return rc;#ifdef VERBOSE elf_set_verbose(&elf);#endif elf_parse_binary(&elf); if (0 != (elf_xen_parse(&elf, &parms))) return rc; /* * We cannot rely on the load address in the ELF headers to * determine the meta physical address at which the image * is loaded. Patch the address to match the real one, based * on xen_pstart */ phys_load_offset = xen_pstart - elf.pstart; elf.pstart += phys_load_offset; elf.pend += phys_load_offset; parms.virt_kstart += phys_load_offset; parms.virt_kend += phys_load_offset; parms.virt_entry += phys_load_offset; printk(" Dom0 kernel: %s, %s, paddr 0x%" PRIx64 " -> 0x%" PRIx64 "\n", elf_64bit(&elf) ? "64-bit" : "32-bit", elf_msb(&elf) ? "msb" : "lsb", elf.pstart, elf.pend); if (!elf_64bit(&elf) || elf_uval(&elf, elf.ehdr, e_machine) != EM_IA_64) { printk("Incompatible kernel binary\n"); return -1; } p_start = parms.virt_base; pkern_start = parms.virt_kstart; pkern_end = parms.virt_kend; pkern_entry = parms.virt_entry;//printk("p_start=%lx, pkern_start=%lx, pkern_end=%lx, pkern_entry=%lx\n",p_start,pkern_start,pkern_end,pkern_entry); if ( (p_start & (PAGE_SIZE-1)) != 0 ) { printk("Initial guest OS must load to a page boundary.\n"); return -EINVAL; } pstart_info = PAGE_ALIGN(pkern_end); if(initrd_start && initrd_len){ unsigned long offset; /* The next page aligned boundary after the start info. Note: EFI_PAGE_SHIFT = 12 <= PAGE_SHIFT */ pinitrd_start = pstart_info + PAGE_SIZE; if ((pinitrd_start + initrd_len - phys_load_offset) >= dom0_size) panic("%s: not enough memory assigned to dom0", __func__); for (offset = 0; offset < initrd_len; offset += PAGE_SIZE) { struct page_info *p; p = assign_new_domain_page(d, pinitrd_start + offset); if (p == NULL) panic("%s: can't allocate page for initrd image", __func__); if (initrd_len < offset + PAGE_SIZE) memcpy(page_to_virt(p), (void*)(initrd_start + offset), initrd_len - offset); else copy_page(page_to_virt(p), (void*)(initrd_start + offset)); } } printk("METAPHYSICAL MEMORY ARRANGEMENT:\n" " Kernel image: %lx->%lx\n" " Entry address: %lx\n" " Init. ramdisk: %lx len %lx\n" " Start info.: %lx->%lx\n", pkern_start, pkern_end, pkern_entry, pinitrd_start, initrd_len, pstart_info, pstart_info + PAGE_SIZE); if ( (pkern_end - pkern_start) > (max_pages * PAGE_SIZE) ) { printk("Initial guest OS requires too much space\n" "(%luMB is greater than %luMB limit)\n", (pkern_end-pkern_start)>>20, (max_pages <<PAGE_SHIFT)>>20); return -ENOMEM; } // if high 3 bits of pkern start are non-zero, error // if pkern end is after end of metaphysical memory, error // (we should be able to deal with this... later) /* Mask all upcalls... */ for ( i = 1; i < MAX_VIRT_CPUS; i++ ) d->shared_info->vcpu_info[i].evtchn_upcall_mask = 1; if (dom0_max_vcpus == 0) dom0_max_vcpus = MAX_VIRT_CPUS; if (dom0_max_vcpus > num_online_cpus()) dom0_max_vcpus = num_online_cpus(); if (dom0_max_vcpus > MAX_VIRT_CPUS) dom0_max_vcpus = MAX_VIRT_CPUS; printk ("Dom0 max_vcpus=%d\n", dom0_max_vcpus); for ( i = 1; i < dom0_max_vcpus; i++ ) if (alloc_vcpu(d, i, i) == NULL) panic("Cannot allocate dom0 vcpu %d\n", i); /* Copy the OS image. */ loaddomainelfimage(d, &elf, phys_load_offset); BUILD_BUG_ON(sizeof(start_info_t) + sizeof(dom0_vga_console_info_t) + sizeof(struct ia64_boot_param) > PAGE_SIZE); /* Set up start info area. */ d->shared_info->arch.start_info_pfn = pstart_info >> PAGE_SHIFT; start_info_page = assign_new_domain_page(d, pstart_info); if (start_info_page == NULL) panic("can't allocate start info page"); si = page_to_virt(start_info_page); clear_page(si); snprintf(si->magic, sizeof(si->magic), "xen-3.0-ia64"); si->nr_pages = max_pages; si->flags = SIF_INITDOMAIN|SIF_PRIVILEGED; printk("Dom0: 0x%lx\n", (u64)dom0); v->is_initialised = 1; clear_bit(_VPF_down, &v->pause_flags); /* Build firmware. Note: Linux kernel reserve memory used by start_info, so there is no need to remove it from MDT. */ bp_mpa = pstart_info + sizeof(struct start_info); rc = dom_fw_setup(d, bp_mpa, max_pages * PAGE_SIZE); if (rc != 0) return rc; /* Fill boot param. */ strlcpy((char *)si->cmd_line, dom0_command_line, sizeof(si->cmd_line)); bp = (struct ia64_boot_param *)((unsigned char *)si + sizeof(start_info_t)); bp->command_line = pstart_info + offsetof (start_info_t, cmd_line); /* We assume console has reached the last line! */ bp->console_info.num_cols = ia64_boot_param->console_info.num_cols; bp->console_info.num_rows = ia64_boot_param->console_info.num_rows; bp->console_info.orig_x = 0; bp->console_info.orig_y = bp->console_info.num_rows == 0 ? 0 : bp->console_info.num_rows - 1; bp->initrd_start = pinitrd_start; bp->initrd_size = ia64_boot_param->initrd_size; ci = (dom0_vga_console_info_t *)((unsigned char *)si + sizeof(start_info_t) + sizeof(struct ia64_boot_param)); if (fill_console_start_info(ci)) { si->console.dom0.info_off = sizeof(start_info_t) + sizeof(struct ia64_boot_param); si->console.dom0.info_size = sizeof(dom0_vga_console_info_t); } vcpu_init_regs (v); vcpu_regs(v)->r28 = bp_mpa; vcpu_regs (v)->cr_iip = pkern_entry; physdev_init_dom0(d); return 0;}void machine_restart(unsigned int delay_millisecs){ mdelay(delay_millisecs); console_start_sync(); if (running_on_sim) printk ("machine_restart called. spinning...\n"); else (*efi.reset_system)(EFI_RESET_WARM,0,0,NULL); while(1);}extern void cpu_halt(void);void machine_halt(void){ console_start_sync();#ifdef CONFIG_SMP smp_send_stop();#endif printk ("machine_halt called. spinning...\n"); while(1);}void sync_vcpu_execstate(struct vcpu *v){// __ia64_save_fpu(v->arch._thread.fph); // FIXME SMP: Anything else needed here for SMP?}/* This function is taken from xen/arch/x86/domain.c */longarch_do_vcpu_op(int cmd, struct vcpu *v, XEN_GUEST_HANDLE(void) arg){ long rc = 0; switch (cmd) { case VCPUOP_register_runstate_memory_area: { struct vcpu_register_runstate_memory_area area; struct vcpu_runstate_info runstate; rc = -EFAULT; if (copy_from_guest(&area, arg, 1)) break; if (!guest_handle_okay(area.addr.h, 1)) break; rc = 0; runstate_guest(v) = area.addr.h; if (v == current) { __copy_to_guest(runstate_guest(v), &v->runstate, 1); } else { vcpu_runstate_get(v, &runstate); __copy_to_guest(runstate_guest(v), &runstate, 1); } break; } default: rc = -ENOSYS; break; } return rc;}static void __init parse_dom0_mem(char *s){ dom0_size = parse_size_and_unit(s, NULL);}custom_param("dom0_mem", parse_dom0_mem);/* * Helper function for the optimization stuff handling the identity mapping * feature. */static inline unsigned longoptf_identity_mapping_cmd_to_flg(unsigned long cmd){ switch(cmd) { case XEN_IA64_OPTF_IDENT_MAP_REG7: return XEN_IA64_OPTF_IDENT_MAP_REG7_FLG; case XEN_IA64_OPTF_IDENT_MAP_REG4: return XEN_IA64_OPTF_IDENT_MAP_REG4_FLG; case XEN_IA64_OPTF_IDENT_MAP_REG5: return XEN_IA64_OPTF_IDENT_MAP_REG5_FLG; default: BUG(); return 0; } /* NOTREACHED */}static inline voidoptf_set_identity_mapping(unsigned long* mask, struct identity_mapping* im, struct xen_ia64_opt_feature* f){ unsigned long flag = optf_identity_mapping_cmd_to_flg(f->cmd); if (f->on) { *mask |= flag; im->pgprot = f->pgprot; im->key = f->key; } else { *mask &= ~flag; im->pgprot = 0; im->key = 0; }}/* * Switch an optimization feature on/off. * The vcpu
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -