diff -r f662f98d594b linux-2.6-xen-sparse/arch/ia64/xen/drivers/coreMakefile --- a/linux-2.6-xen-sparse/arch/ia64/xen/drivers/coreMakefile Mon Jun 05 14:28:39 2006 -0600 +++ b/linux-2.6-xen-sparse/arch/ia64/xen/drivers/coreMakefile Mon Jun 12 09:35:09 2006 +0200 @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -obj-y := gnttab.o features.o +obj-y := gnttab.o features.o reboot.o cpu_hotplug.o obj-$(CONFIG_PROC_FS) += xen_proc.o ifeq ($(ARCH),ia64) diff -r f662f98d594b linux-2.6-xen-sparse/arch/ia64/xen/drivers/xenia64_init.c --- a/linux-2.6-xen-sparse/arch/ia64/xen/drivers/xenia64_init.c Mon Jun 05 14:28:39 2006 -0600 +++ b/linux-2.6-xen-sparse/arch/ia64/xen/drivers/xenia64_init.c Mon Jun 12 09:35:09 2006 +0200 @@ -28,7 +28,6 @@ int xen_init(void) return -1; xen_start_info = __va(s->arch.start_info_pfn << PAGE_SHIFT); - xen_start_info->flags = s->arch.flags; printk("Running on Xen! start_info_pfn=0x%lx nr_pages=%ld flags=0x%x\n", s->arch.start_info_pfn, xen_start_info->nr_pages, xen_start_info->flags); diff -r f662f98d594b linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c --- a/linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c Mon Jun 05 14:28:39 2006 -0600 +++ b/linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c Mon Jun 12 09:35:09 2006 +0200 @@ -759,3 +759,24 @@ direct_remap_pfn_range(struct vm_area_st return error; } + +int +HYPERVISOR_suspend_1(void) +{ + struct sched_shutdown sched_shutdown = { + .reason = SHUTDOWN_suspend + }; + + int rc = _hypercall2(int, sched_op, SCHEDOP_shutdown, + &sched_shutdown); + + return rc; +} + +void +time_resume(void) +{ + extern void ia64_cpu_local_tick (void); + + ia64_cpu_local_tick (); +} diff -r f662f98d594b linux-2.6-xen-sparse/arch/ia64/xen/xensetup.S --- a/linux-2.6-xen-sparse/arch/ia64/xen/xensetup.S Mon Jun 05 14:28:39 2006 -0600 +++ b/linux-2.6-xen-sparse/arch/ia64/xen/xensetup.S Mon Jun 12 09:35:09 2006 +0200 @@ -22,3 +22,20 @@ GLOBAL_ENTRY(early_xen_setup) (p7) mov cr.iva=r10 br.ret.sptk.many rp;; END(early_xen_setup) + +#include + +GLOBAL_ENTRY(HYPERVISOR_suspend) + alloc r20=ar.pfs,0,0,0,0 + mov r14=2 + mov r15=r12 + ;; + flushrs + mov r2=__HYPERVISOR_sched_op + st4 [r12]=r14 + ;; + break 0x1000 + ;; + mov ar.pfs=r20 + br.ret.sptk.many b0 +END(HYPERVISOR_suspend) diff -r f662f98d594b linux-2.6-xen-sparse/drivers/xen/core/reboot.c --- a/linux-2.6-xen-sparse/drivers/xen/core/reboot.c Mon Jun 05 14:28:39 2006 -0600 +++ b/linux-2.6-xen-sparse/drivers/xen/core/reboot.c Mon Jun 12 09:35:09 2006 +0200 @@ -39,6 +39,7 @@ extern void ctrl_alt_del(void); */ #define SHUTDOWN_HALT 4 +#ifdef CONFIG_X86 void machine_emergency_restart(void) { /* We really want to get pending console data out before we die. */ @@ -71,7 +72,7 @@ EXPORT_SYMBOL(machine_restart); EXPORT_SYMBOL(machine_restart); EXPORT_SYMBOL(machine_halt); EXPORT_SYMBOL(machine_power_off); - +#endif /****************************************************************************** * Stop/pickle callback handling. @@ -101,22 +102,27 @@ static void switch_idle_mm(void) static int __do_suspend(void *ignore) { - int i, j, k, fpp, err; - + int err; + +#ifdef CONFIG_X86 + int i, j, k, fpp; extern unsigned long max_pfn; extern unsigned long *pfn_to_mfn_frame_list_list; extern unsigned long *pfn_to_mfn_frame_list[]; +#endif extern void time_resume(void); BUG_ON(smp_processor_id() != 0); BUG_ON(in_interrupt()); +#ifdef CONFIG_X86 if (xen_feature(XENFEAT_auto_translated_physmap)) { printk(KERN_WARNING "Cannot suspend in " "auto_translated_physmap mode.\n"); return -EOPNOTSUPP; } +#endif err = smp_suspend(); if (err) @@ -129,15 +135,22 @@ static int __do_suspend(void *ignore) #ifdef __i386__ kmem_cache_shrink(pgd_cache); #endif +#ifdef CONFIG_X86 mm_pin_all(); __cli(); +#endif +#ifdef __ia64__ + local_irq_disable(); +#endif preempt_enable(); gnttab_suspend(); +#ifdef CONFIG_X86 HYPERVISOR_shared_info = (shared_info_t *)empty_zero_page; clear_fixmap(FIX_SHARED_INFO); +#endif xen_start_info->store_mfn = mfn_to_pfn(xen_start_info->store_mfn); xen_start_info->console_mfn = mfn_to_pfn(xen_start_info->console_mfn); @@ -150,12 +163,14 @@ static int __do_suspend(void *ignore) shutting_down = SHUTDOWN_INVALID; +#ifdef CONFIG_X86 set_fixmap(FIX_SHARED_INFO, xen_start_info->shared_info); - HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt(FIX_SHARED_INFO); +#endif memset(empty_zero_page, 0, PAGE_SIZE); +#ifdef CONFIG_X86 HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list = virt_to_mfn(pfn_to_mfn_frame_list_list); @@ -171,6 +186,7 @@ static int __do_suspend(void *ignore) virt_to_mfn(&phys_to_machine_mapping[i]); } HYPERVISOR_shared_info->arch.max_pfn = max_pfn; +#endif gnttab_resume(); @@ -180,7 +196,12 @@ static int __do_suspend(void *ignore) switch_idle_mm(); +#ifdef CONFIG_X86 __sti(); +#endif +#ifdef __ia64__ + local_irq_enable(); +#endif xencons_resume(); diff -r f662f98d594b linux-2.6-xen-sparse/include/asm-ia64/hypercall.h --- a/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h Mon Jun 05 14:28:39 2006 -0600 +++ b/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h Mon Jun 12 09:35:09 2006 +0200 @@ -302,23 +302,7 @@ HYPERVISOR_vcpu_op( return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args); } -static inline int -HYPERVISOR_suspend( - unsigned long srec) -{ - struct sched_shutdown sched_shutdown = { - .reason = SHUTDOWN_suspend - }; - - int rc = _hypercall3(int, sched_op, SCHEDOP_shutdown, - &sched_shutdown, srec); - - if (rc == -ENOSYS) - rc = _hypercall3(int, sched_op_compat, SCHEDOP_shutdown, - SHUTDOWN_suspend, srec); - - return rc; -} +extern int HYPERVISOR_suspend(unsigned long srec); static inline int HYPERVISOR_callback_op( diff -r f662f98d594b tools/libxc/Makefile --- a/tools/libxc/Makefile Mon Jun 05 14:28:39 2006 -0600 +++ b/tools/libxc/Makefile Mon Jun 12 09:35:09 2006 +0200 @@ -31,6 +31,7 @@ GUEST_SRCS-y += xc_load_elf.c GUEST_SRCS-y += xc_load_elf.c GUEST_SRCS-y += xg_private.c GUEST_SRCS-$(CONFIG_IA64) += xc_ia64_stubs.c +GUEST_SRCS-$(CONFIG_IA64) += xc_ia64_linux_save.c xc_ia64_linux_restore.c GUEST_SRCS-$(CONFIG_PLAN9) += xc_load_aout9.c GUEST_SRCS-$(CONFIG_MIGRATE) += xc_linux_restore.c xc_linux_save.c GUEST_SRCS-$(CONFIG_HVM) += xc_hvm_build.c diff -r f662f98d594b tools/libxc/xc_ia64_stubs.c --- a/tools/libxc/xc_ia64_stubs.c Mon Jun 05 14:28:39 2006 -0600 +++ b/tools/libxc/xc_ia64_stubs.c Mon Jun 12 09:35:09 2006 +0200 @@ -22,20 +22,37 @@ unsigned long xc_ia64_fpsr_default(void) return FPSR_DEFAULT; } -int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, - uint32_t max_factor, uint32_t flags /* XCFLAGS_xxx */, - int (*suspend)(int domid)) -{ - PERROR("xc_linux_save not implemented\n"); - return -1; -} - -int xc_linux_restore(int xc_handle, int io_fd, uint32_t dom, unsigned long nr_pfns, - unsigned int store_evtchn, unsigned long *store_mfn, - unsigned int console_evtchn, unsigned long *console_mfn) -{ - PERROR("xc_linux_restore not implemented\n"); - return -1; +void +xc_disp_vcpu_context (struct vcpu_guest_context *ctxt) +{ + struct cpu_user_regs *r = &ctxt->regs; + int i; + + fprintf (stderr, "b6=%016lx b7=%016lx\n", r->b6, r->b7); + fprintf (stderr, "ipsr=%016lx iip=%016lx\n", r->cr_ipsr, r->cr_iip); + fprintf (stderr, "ifs=%016lx pfs=%016lx\n", r->cr_ifs, r->ar_pfs); + fprintf (stderr, "iva=%016lx dcr=%016lx\n", ctxt->extra_regs.iva, ctxt->extra_regs.dcr); + for (i = 0; i < 4; i++) { + fprintf (stderr, "tr[%d] itir=%016lx pte=%016lx\n", i, + ctxt->extra_regs.itrs[i].itir, ctxt->extra_regs.itrs[i].pte); + fprintf (stderr, " vadr=%016lx rid=%016lx\n", + ctxt->extra_regs.itrs[i].vadr, ctxt->extra_regs.itrs[i].rid); + } + fprintf (stderr, "r1 =%016lx r2 =%016lx\n", r->r1, r->r2); + fprintf (stderr, "r3 =%016lx r4 =%016lx\n", r->r3, r->r4); + fprintf (stderr, "r5 =%016lx r6 =%016lx\n", r->r5, r->r6); + fprintf (stderr, "r8 =%016lx r9 =%016lx\n", r->r8, r->r9); + fprintf (stderr, "r10=%016lx r11=%016lx\n", r->r10, r->r11); + fprintf (stderr, "r12=%016lx r13=%016lx\n", r->r12, r->r13); + fprintf (stderr, "r14=%016lx r15=%016lx\n", r->r14, r->r15); + fprintf (stderr, "r16=%016lx r17=%016lx\n", r->r16, r->r17); + fprintf (stderr, "r18=%016lx r19=%016lx\n", r->r18, r->r19); + fprintf (stderr, "r20=%016lx r21=%016lx\n", r->r20, r->r21); + fprintf (stderr, "r22=%016lx r23=%016lx\n", r->r22, r->r23); + fprintf (stderr, "r24=%016lx r25=%016lx\n", r->r24, r->r25); + fprintf (stderr, "r26=%016lx r27=%016lx\n", r->r26, r->r27); + fprintf (stderr, "r28=%016lx r29=%016lx\n", r->r28, r->r29); + fprintf (stderr, "r30=%016lx r31=%016lx\n", r->r30, r->r31); } int @@ -48,13 +65,13 @@ xc_plan9_build(int xc_handle, PERROR("xc_plan9_build not implemented\n"); return -1; } + /* VMM uses put_user to copy pfn_list to guest buffer, this maybe fail, VMM doesn't handle this now. This method will touch guest buffer to make sure the buffer's mapping is tracked by VMM, - */ - +*/ int xc_ia64_get_pfn_list(int xc_handle, uint32_t domid, unsigned long *pfn_buf, @@ -739,7 +756,6 @@ int xc_hvm_build(int xc_handle, ctxt->flags = VGCF_VMX_GUEST; ctxt->regs.cr_iip = 0x80000000ffffffb0UL; - ctxt->privregs = 0; memset( &launch_op, 0, sizeof(launch_op) ); diff -r f662f98d594b tools/libxc/xc_linux_build.c --- a/tools/libxc/xc_linux_build.c Mon Jun 05 14:28:39 2006 -0600 +++ b/tools/libxc/xc_linux_build.c Mon Jun 12 09:35:09 2006 +0200 @@ -2,6 +2,7 @@ * xc_linux_build.c */ +#include #include "xg_private.h" #include "xc_private.h" #include @@ -459,6 +460,11 @@ static int setup_guest(int xc_handle, unsigned long v_end; unsigned long start_page, pgnr; start_info_t *start_info; + unsigned long start_info_mpa; + struct xen_ia64_boot_param *bp; + shared_info_t *shared_info; + int i; + DECLARE_DOM0_OP; int rc; rc = probeimageformat(image, image_size, &load_funcs); @@ -475,6 +481,17 @@ static int setup_guest(int xc_handle, vinitrd_start = round_pgup(dsi.v_end); vinitrd_end = vinitrd_start + initrd->len; v_end = round_pgup(vinitrd_end); + start_info_mpa = (nr_pages - 3) << PAGE_SHIFT; + + /* Build firmware. */ + op.u.firmware_setup.domain = (domid_t)dom; + op.u.firmware_setup.bp = start_info_mpa + sizeof (start_info_t); + op.u.firmware_setup.hypercall_imm = 0x1000; + op.u.firmware_setup.maxmem = (nr_pages - 3) << PAGE_SHIFT; + + op.cmd = DOM0_FIRMWARE_SETUP; + if ( xc_dom0_op(xc_handle, &op) ) + goto error_out; start_page = dsi.v_start >> PAGE_SHIFT; pgnr = (v_end - dsi.v_start) >> PAGE_SHIFT; @@ -527,7 +544,7 @@ static int setup_guest(int xc_handle, printf("start_info: 0x%lx at 0x%lx, " "store_mfn: 0x%lx at 0x%lx, " "console_mfn: 0x%lx at 0x%lx\n", - page_array[0], nr_pages, + page_array[0], nr_pages - 3, *store_mfn, nr_pages - 2, *console_mfn, nr_pages - 1); @@ -542,22 +559,35 @@ static int setup_guest(int xc_handle, start_info->console_mfn = nr_pages - 1; start_info->console_evtchn = console_evtchn; start_info->nr_pages = nr_pages; // FIXME?: nr_pages - 2 ???? + + bp = (struct xen_ia64_boot_param *)(start_info + 1); + bp->command_line = start_info_mpa + offsetof(start_info_t, cmd_line); + if ( cmdline != NULL ) + { + strncpy((char *)start_info->cmd_line, cmdline, MAX_GUEST_CMDLINE); + start_info->cmd_line[MAX_GUEST_CMDLINE - 1] = 0; + } if ( initrd->len != 0 ) { - ctxt->initrd.start = vinitrd_start; - ctxt->initrd.size = initrd->len; - } - else - { - ctxt->initrd.start = 0; - ctxt->initrd.size = 0; - } - if ( cmdline != NULL ) - { - strncpy((char *)ctxt->cmdline, cmdline, IA64_COMMAND_LINE_SIZE); - ctxt->cmdline[IA64_COMMAND_LINE_SIZE-1] = '\0'; - } + bp->initrd_start = vinitrd_start; + bp->initrd_size = initrd->len; + } + ctxt->regs.r28 = start_info_mpa + sizeof (start_info_t); munmap(start_info, PAGE_SIZE); + + /* shared_info page starts its life empty. */ + shared_info = xc_map_foreign_range( + xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE, shared_info_frame); + printf ("shared_info = %p (%ld), %s frame=%lx\n", + shared_info, (unsigned long)shared_info, + strerror (errno), shared_info_frame); + //memset(shared_info, 0, sizeof(shared_info_t)); + /* Mask all upcalls... */ + for ( i = 0; i < MAX_VIRT_CPUS; i++ ) + shared_info->vcpu_info[i].evtchn_upcall_mask = 1; + shared_info->arch.start_info_pfn = nr_pages - 3; + + munmap(shared_info, PAGE_SIZE); free(page_array); return 0; @@ -1099,16 +1129,10 @@ static int xc_linux_build_internal(int x #ifdef __ia64__ /* based on new_thread in xen/arch/ia64/domain.c */ ctxt->flags = 0; - ctxt->shared.flags = flags; - ctxt->shared.start_info_pfn = nr_pages - 3; /* metaphysical */ ctxt->regs.cr_ipsr = 0; /* all necessary bits filled by hypervisor */ ctxt->regs.cr_iip = vkern_entry; ctxt->regs.cr_ifs = 1UL << 63; ctxt->regs.ar_fpsr = xc_ia64_fpsr_default(); - /* currently done by hypervisor, should move here */ - /* ctxt->regs.r28 = dom_fw_setup(); */ - ctxt->privregs = 0; - ctxt->sys_pgnr = 3; i = 0; /* silence unused variable warning */ #else /* x86 */ /* diff -r f662f98d594b tools/libxc/xg_save_restore.h --- a/tools/libxc/xg_save_restore.h Mon Jun 05 14:28:39 2006 -0600 +++ b/tools/libxc/xg_save_restore.h Mon Jun 12 09:35:09 2006 +0200 @@ -39,6 +39,7 @@ while (0) +#ifndef __ia64__ /* ** Determine various platform information required for save/restore, in ** particular: @@ -86,7 +87,7 @@ static int get_platform_info(int xc_hand return 1; } - +#endif /* ** Save/restore deal with the mfn_to_pfn (M2P) and pfn_to_mfn (P2M) tables. diff -r f662f98d594b tools/python/xen/xend/XendCheckpoint.py --- a/tools/python/xen/xend/XendCheckpoint.py Mon Jun 05 14:28:39 2006 -0600 +++ b/tools/python/xen/xend/XendCheckpoint.py Mon Jun 12 09:35:09 2006 +0200 @@ -87,12 +87,16 @@ def save(fd, dominfo, network, live, dst if line == "suspend": log.debug("Suspending %d ...", dominfo.getDomid()) dominfo.shutdown('suspend') + log.debug("Suspending %d (1)", dominfo.getDomid()) dominfo.waitForShutdown() + log.debug("Suspending %d (2)", dominfo.getDomid()) dominfo.migrateDevices(network, dst, DEV_MIGRATE_STEP2, domain_name) + log.debug("Suspending %d (3)", dominfo.getDomid()) log.info("Domain %d suspended.", dominfo.getDomid()) dominfo.migrateDevices(network, dst, DEV_MIGRATE_STEP3, domain_name) + log.debug("Suspending %d (4)", dominfo.getDomid()) tochild.write("done\n") tochild.flush() log.debug('Written done') diff -r f662f98d594b tools/python/xen/xend/XendDomainInfo.py --- a/tools/python/xen/xend/XendDomainInfo.py Mon Jun 05 14:28:39 2006 -0600 +++ b/tools/python/xen/xend/XendDomainInfo.py Mon Jun 12 09:35:09 2006 +0200 @@ -665,10 +665,14 @@ class XendDomainInfo: self.store_mfn = store_mfn self.console_mfn = console_mfn - + + log.debug("XendDomainInfo.completeRestore (1)") self.introduceDomain() + log.debug("XendDomainInfo.completeRestore (2)") self.storeDomDetails() + log.debug("XendDomainInfo.completeRestore (3)") self.registerWatches() + log.debug("XendDomainInfo.completeRestore (4)") self.refreshShutdown() log.debug("XendDomainInfo.completeRestore done") diff -r f662f98d594b xen/arch/ia64/linux-xen/entry.S --- a/xen/arch/ia64/linux-xen/entry.S Mon Jun 05 14:28:39 2006 -0600 +++ b/xen/arch/ia64/linux-xen/entry.S Mon Jun 12 09:35:09 2006 +0200 @@ -652,17 +652,8 @@ GLOBAL_ENTRY(ia64_ret_from_clone) ld8 r16 = [r16] ;; cmp.ne p6,p7 = r16, r0 - (p6) br.cond.spnt ia64_leave_hypervisor - (p7) br.cond.spnt ia64_leave_kernel - ;; -// adds r16 = IA64_VCPU_FLAGS_OFFSET, r13 -// ;; -// ld8 r16 = [r16] -// ;; -// cmp.ne p6,p7 = r16, r0 -// (p6) br.cond.spnt ia64_leave_hypervisor -// (p7) br.cond.spnt ia64_leave_kernel -// ;; + (p6) br.cond.spnt ia64_leave_hypervisor /* VTi */ + (p7) br.cond.spnt ia64_leave_kernel /* !VTi */ #else .ret8: adds r2=TI_FLAGS+IA64_TASK_SIZE,r13 diff -r f662f98d594b xen/arch/ia64/vmx/vmmu.c --- a/xen/arch/ia64/vmx/vmmu.c Mon Jun 05 14:28:39 2006 -0600 +++ b/xen/arch/ia64/vmx/vmmu.c Mon Jun 12 09:35:09 2006 +0200 @@ -290,6 +290,7 @@ int vhpt_enabled(VCPU *vcpu, uint64_t va int unimplemented_gva(VCPU *vcpu,u64 vadr) { +#if 0 int bit=vcpu->domain->arch.imp_va_msb; u64 ladr =(vadr<<3)>>(3+bit); if(!ladr||ladr==(1U<<(61-bit))-1){ @@ -297,6 +298,9 @@ int unimplemented_gva(VCPU *vcpu,u64 vad }else{ return 1; } +#else + return 0; +#endif } diff -r f662f98d594b xen/arch/ia64/vmx/vmx_hypercall.c --- a/xen/arch/ia64/vmx/vmx_hypercall.c Mon Jun 05 14:28:39 2006 -0600 +++ b/xen/arch/ia64/vmx/vmx_hypercall.c Mon Jun 12 09:35:09 2006 +0200 @@ -36,7 +36,6 @@ #include extern long do_sched_op_compat(int cmd, unsigned long arg); -extern unsigned long domain_mpa_to_imva(struct domain *,unsigned long mpaddr); void hyper_not_support(void) { diff -r f662f98d594b xen/arch/ia64/vmx/vmx_init.c --- a/xen/arch/ia64/vmx/vmx_init.c Mon Jun 05 14:28:39 2006 -0600 +++ b/xen/arch/ia64/vmx/vmx_init.c Mon Jun 12 09:35:09 2006 +0200 @@ -396,7 +396,6 @@ int vmx_build_physmap_table(struct domai list_ent = mfn_to_page(mfn)->list.next; ASSERT(list_ent == &d->page_list); - d->arch.max_pfn = end >> PAGE_SHIFT; d->arch.physmap_built = 1; set_bit(ARCH_VMX_CONTIG_MEM, &v->arch.arch_vmx.flags); return 0; diff -r f662f98d594b xen/arch/ia64/xen/dom0_ops.c --- a/xen/arch/ia64/xen/dom0_ops.c Mon Jun 05 14:28:39 2006 -0600 +++ b/xen/arch/ia64/xen/dom0_ops.c Mon Jun 12 09:35:09 2006 +0200 @@ -19,6 +19,10 @@ #include #include #include +#include + +void build_physmap_table(struct domain *d); + extern unsigned long total_pages; long arch_do_dom0_op(dom0_op_t *op, XEN_GUEST_HANDLE(dom0_op_t) u_dom0_op) { @@ -154,52 +158,37 @@ long arch_do_dom0_op(dom0_op_t *op, XEN_ case DOM0_GETMEMLIST: { - unsigned long i = 0; + unsigned long i; struct domain *d = find_domain_by_id(op->u.getmemlist.domain); unsigned long start_page = op->u.getmemlist.max_pfns >> 32; unsigned long nr_pages = op->u.getmemlist.max_pfns & 0xffffffff; unsigned long mfn; - struct list_head *list_ent; ret = -EINVAL; - if ( d != NULL ) - { - ret = 0; - - list_ent = d->page_list.next; - while ( (i != start_page) && (list_ent != &d->page_list)) { - mfn = page_to_mfn(list_entry( - list_ent, struct page_info, list)); - i++; - list_ent = mfn_to_page(mfn)->list.next; - } - - if (i == start_page) - { - while((i < (start_page + nr_pages)) && - (list_ent != &d->page_list)) - { - mfn = page_to_mfn(list_entry( - list_ent, struct page_info, list)); - - if ( copy_to_guest_offset(op->u.getmemlist.buffer, - i - start_page, &mfn, 1) ) - { - ret = -EFAULT; - break; - } - i++; - list_ent = mfn_to_page(mfn)->list.next; - } - } else - ret = -ENOMEM; - - op->u.getmemlist.num_pfns = i - start_page; - if (copy_to_guest(u_dom0_op, op, 1)) - ret = -EFAULT; - - put_domain(d); - } + if ( d == NULL ) + break; + for (i = 0; i < nr_pages; i++) { + pte_t *pte; + + pte = lookup_noalloc_domain_pte + (d, (start_page + i) << PAGE_SHIFT); + if (pte && pte_present (*pte)) + mfn = pte_pfn (*pte); + else + mfn = INVALID_MFN; + + if ( copy_to_guest_offset(op->u.getmemlist.buffer, i, &mfn, 1) ) + { + ret = -EFAULT; + break; + } + } + + op->u.getmemlist.num_pfns = i; + if (copy_to_guest(u_dom0_op, op, 1)) + ret = -EFAULT; + + put_domain(d); } break; @@ -225,6 +214,24 @@ long arch_do_dom0_op(dom0_op_t *op, XEN_ } break; + case DOM0_FIRMWARE_SETUP: + { + dom0_firmware_setup_t *fs = &op->u.firmware_setup; + struct domain *d = find_domain_by_id(op->u.getmemlist.domain); + + if ( d == NULL) { + ret = -EINVAL; + break; + } + if (!d->arch.physmap_built) + build_physmap_table(d); + d->arch.breakimm = fs->hypercall_imm; + dom_fw_setup (d, fs->bp, fs->maxmem); + printf ("dom_firmware_setup: bp=%lx\n", fs->bp); + put_domain(d); + } + break; + default: printf("arch_do_dom0_op: unrecognized dom0 op: %d!!!\n",op->cmd); ret = -ENOSYS; diff -r f662f98d594b xen/arch/ia64/xen/dom_fw.c --- a/xen/arch/ia64/xen/dom_fw.c Mon Jun 05 14:28:39 2006 -0600 +++ b/xen/arch/ia64/xen/dom_fw.c Mon Jun 12 09:35:09 2006 +0200 @@ -24,16 +24,16 @@ #include -static struct ia64_boot_param *dom_fw_init(struct domain *, const char *,int,char *,int); -extern unsigned long domain_mpa_to_imva(struct domain *,unsigned long mpaddr); +static void dom_fw_init (struct domain *d, struct ia64_boot_param *bp, char *fw_mem, int fw_mem_size, unsigned long maxmem); + extern struct domain *dom0; extern unsigned long dom0_start; extern unsigned long running_on_sim; - -unsigned long dom_fw_base_mpa = -1; -unsigned long imva_fw_base = -1; +/* Note: two domains cannot be created simulteanously! */ +static unsigned long dom_fw_base_mpa = -1; +static unsigned long imva_fw_base = -1; // return domain (meta)physical address for a given imva // this function is a call-back from dom_fw_init @@ -117,22 +117,20 @@ static void dom_fw_pal_hypercall_patch(s build_pal_hypercall_bundles(imva, d->arch.breakimm, FW_HYPERCALL_PAL_CALL); } - -// FIXME: This is really a hack: Forcing the boot parameter block -// at domain mpaddr 0 page, then grabbing only the low bits of the -// Xen imva, which is the offset into the page -unsigned long dom_fw_setup(struct domain *d, const char *args, int arglen) +void dom_fw_setup(struct domain *d, unsigned long bp_mpa, unsigned long maxmem) { struct ia64_boot_param *bp; dom_fw_base_mpa = 0; #ifndef CONFIG_XEN_IA64_DOM0_VP if (d == dom0) dom_fw_base_mpa += dom0_start; + if (d == dom0) bp_mpa += dom0_start; #endif ASSIGN_NEW_DOMAIN_PAGE_IF_DOM0(d, dom_fw_base_mpa); - imva_fw_base = domain_mpa_to_imva(d, dom_fw_base_mpa); - bp = dom_fw_init(d, args, arglen, (char *) imva_fw_base, PAGE_SIZE); - return dom_pa((unsigned long) bp); + imva_fw_base = (unsigned long) domain_mpa_to_imva(d, dom_fw_base_mpa); + ASSIGN_NEW_DOMAIN_PAGE_IF_DOM0(d, bp_mpa); + bp = domain_mpa_to_imva(d, bp_mpa); + dom_fw_init(d, bp, (char *) imva_fw_base, PAGE_SIZE, maxmem); } @@ -481,8 +479,8 @@ efi_mdt_cmp(const void *a, const void *b return 0; } -static struct ia64_boot_param * -dom_fw_init (struct domain *d, const char *args, int arglen, char *fw_mem, int fw_mem_size) +static void +dom_fw_init (struct domain *d, struct ia64_boot_param *bp, char *fw_mem, int fw_mem_size, unsigned long maxmem) { efi_system_table_t *efi_systab; efi_runtime_services_t *efi_runtime; @@ -492,12 +490,10 @@ dom_fw_init (struct domain *d, const cha struct ia64_sal_desc_ap_wakeup *sal_wakeup; fpswa_interface_t *fpswa_inf; efi_memory_desc_t *efi_memmap, *md; - struct ia64_boot_param *bp; unsigned long *pfn; unsigned char checksum = 0; - char *cp, *cmd_line, *fw_vendor; + char *cp, *fw_vendor; int i = 0; - unsigned long maxmem = (d->max_pages - d->arch.sys_pgnr) * PAGE_SIZE; #ifdef CONFIG_XEN_IA64_DOM0_VP const unsigned long start_mpaddr = 0; #else @@ -534,28 +530,17 @@ dom_fw_init (struct domain *d, const cha sal_wakeup = (void *) cp; cp += sizeof(*sal_wakeup); fpswa_inf = (void *) cp; cp += sizeof(*fpswa_inf); efi_memmap = (void *) cp; cp += NUM_MEM_DESCS*sizeof(*efi_memmap); - bp = (void *) cp; cp += sizeof(*bp); pfn = (void *) cp; cp += NFUNCPTRS * 2 * sizeof(pfn); - cmd_line = (void *) cp; /* Initialise for EFI_SET_VIRTUAL_ADDRESS_MAP emulation */ d->arch.efi_runtime = efi_runtime; d->arch.fpswa_inf = fpswa_inf; - - if (args) { - if (arglen >= 1024) - arglen = 1023; - memcpy(cmd_line, args, arglen); - } else { - arglen = 0; - } - cmd_line[arglen] = '\0'; memset(efi_systab, 0, sizeof(efi_systab)); efi_systab->hdr.signature = EFI_SYSTEM_TABLE_SIGNATURE; efi_systab->hdr.revision = EFI_SYSTEM_TABLE_REVISION; efi_systab->hdr.headersize = sizeof(efi_systab->hdr); - cp = fw_vendor = &cmd_line[arglen] + (2-(arglen&1)); // round to 16-bit boundary + fw_vendor = cp; #define FW_VENDOR "X\0e\0n\0/\0i\0a\0\066\0\064\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" cp += sizeof(FW_VENDOR) + (8-((unsigned long)cp & 7)); // round to 64-bit boundary @@ -825,7 +810,7 @@ dom_fw_init (struct domain *d, const cha bp->efi_memmap_size = i * sizeof(efi_memory_desc_t); bp->efi_memdesc_size = sizeof(efi_memory_desc_t); bp->efi_memdesc_version = EFI_MEMDESC_VERSION; - bp->command_line = dom_pa((unsigned long) cmd_line); + bp->command_line = 0; bp->console_info.num_cols = 80; bp->console_info.num_rows = 25; bp->console_info.orig_x = 0; @@ -835,12 +820,13 @@ dom_fw_init (struct domain *d, const cha int j; u64 addr; +#if 0 // XXX CONFIG_XEN_IA64_DOM0_VP // initrd_start address is hard coded in construct_dom0() bp->initrd_start = (dom0_start+dom0_size) - (PAGE_ALIGN(ia64_boot_param->initrd_size) + 4*1024*1024); bp->initrd_size = ia64_boot_param->initrd_size; - +#endif // dom0 doesn't need build_physmap_table() // see arch_set_info_guest() // instead we allocate pages manually. @@ -878,11 +864,12 @@ dom_fw_init (struct domain *d, const cha } d->arch.physmap_built = 1; } +#if 0 else { bp->initrd_start = d->arch.initrd_start; bp->initrd_size = d->arch.initrd_len; } printf(" initrd start 0x%lx", bp->initrd_start); printf(" initrd size 0x%lx\n", bp->initrd_size); - return bp; -} +#endif +} diff -r f662f98d594b xen/arch/ia64/xen/domain.c --- a/xen/arch/ia64/xen/domain.c Mon Jun 05 14:28:39 2006 -0600 +++ b/xen/arch/ia64/xen/domain.c Mon Jun 12 09:35:09 2006 +0200 @@ -70,7 +70,6 @@ integer_param("dom0_max_vcpus", dom0_max integer_param("dom0_max_vcpus", dom0_max_vcpus); // initialized by arch/ia64/setup.c:find_initrd() -unsigned long initrd_start = 0, initrd_end = 0; extern unsigned long running_on_sim; extern char dom0_command_line[]; @@ -81,7 +80,6 @@ extern void serial_input_init(void); extern void serial_input_init(void); static void init_switch_stack(struct vcpu *v); extern void vmx_do_launch(struct vcpu *); -void build_physmap_table(struct domain *d); /* this belongs in include/asm, but there doesn't seem to be a suitable place */ unsigned long context_switch_count = 0; @@ -120,6 +118,12 @@ void context_switch(struct vcpu *prev, s vmx_save_state(prev); if (VMX_DOMAIN(next)) vmx_load_state(next); + +#if 0 + if (next->domain != dom0) + printf ("switch to iip=%lx\n", vcpu_regs(next)->cr_iip); +#endif + /*ia64_psr(ia64_task_regs(next))->dfh = !ia64_is_local_fpu_owner(next);*/ prev = ia64_switch_to(next); @@ -235,10 +239,8 @@ struct vcpu *alloc_vcpu_struct(struct do alloc_xenheap_pages(get_order(sizeof(mapped_regs_t))); BUG_ON(v->arch.privregs == NULL); memset(v->arch.privregs, 0, PAGE_SIZE); - - if (!vcpu_id) - memset(&d->shared_info->evtchn_mask[0], 0xff, - sizeof(d->shared_info->evtchn_mask)); + share_xen_page_with_guest + (virt_to_page(v->arch.privregs), d, XENSHARE_writable); v->arch.metaphysical_rr0 = d->arch.metaphysical_rr0; v->arch.metaphysical_rr4 = d->arch.metaphysical_rr4; @@ -307,6 +309,8 @@ int arch_domain_create(struct domain *d) if ((d->shared_info = (void *)alloc_xenheap_page()) == NULL) goto fail_nomem; memset(d->shared_info, 0, PAGE_SIZE); + share_xen_page_with_guest + (virt_to_page(d->shared_info), d, XENSHARE_writable); d->max_pages = (128UL*1024*1024)/PAGE_SIZE; // 128MB default // FIXME /* We may also need emulation rid for region4, though it's unlikely @@ -315,7 +319,6 @@ int arch_domain_create(struct domain *d) */ if (!allocate_rid_range(d,0)) goto fail_nomem; - d->arch.sys_pgnr = 0; memset(&d->arch.mm, 0, sizeof(d->arch.mm)); @@ -347,15 +350,66 @@ void arch_domain_destroy(struct domain * void arch_getdomaininfo_ctxt(struct vcpu *v, struct vcpu_guest_context *c) { + int i; + struct vcpu_extra_regs *er = &c->extra_regs; + c->regs = *vcpu_regs (v); - c->shared = v->domain->shared_info->arch; + c->privregs_pfn = virt_to_maddr (v->arch.privregs) >> PAGE_SHIFT; + + /* Fill extra regs. */ + for (i = 0; i < 8; i++) { + er->itrs[i].pte = v->arch.itrs[i].pte.val; + er->itrs[i].itir = v->arch.itrs[i].itir; + er->itrs[i].vadr = v->arch.itrs[i].vadr; + er->itrs[i].rid = v->arch.itrs[i].rid; + } + for (i = 0; i < 8; i++) { + er->dtrs[i].pte = v->arch.dtrs[i].pte.val; + er->dtrs[i].itir = v->arch.dtrs[i].itir; + er->dtrs[i].vadr = v->arch.dtrs[i].vadr; + er->dtrs[i].rid = v->arch.dtrs[i].rid; + } + er->iva = v->arch.iva; + er->dcr = v->arch.dcr; + er->event_callback_ip = v->arch.event_callback_ip; } int arch_set_info_guest(struct vcpu *v, struct vcpu_guest_context *c) { struct pt_regs *regs = vcpu_regs (v); struct domain *d = v->domain; - unsigned long cmdline_addr; + + *regs = c->regs; + + if (!VMX_DOMAIN(v)) { + /* Also executed for a VMX vcpu before being initialized. + However, this will be overwritten. */ + /* domain runs at PL2 */ + regs->cr_ipsr |= 2UL << IA64_PSR_CPL0_BIT; + regs->ar_rsc |= (2 << 2); /* force PL2/3 */ + } + + if (c->flags & VGCF_EXTRA_REGS) { + int i; + struct vcpu_extra_regs *er = &c->extra_regs; + + for (i = 0; i < 8; i++) { + vcpu_set_itr (v, i, er->itrs[i].pte, + er->itrs[i].itir, + er->itrs[i].vadr, + er->itrs[i].rid); + } + for (i = 0; i < 8; i++) { + vcpu_set_dtr (v, i, + er->dtrs[i].pte, + er->dtrs[i].itir, + er->dtrs[i].vadr, + er->dtrs[i].rid); + } + v->arch.iva = er->iva; + v->arch.dcr = er->dcr; + v->arch.event_callback_ip = er->event_callback_ip; + } if ( test_bit(_VCPUF_initialised, &v->vcpu_flags) ) return 0; @@ -369,48 +423,10 @@ int arch_set_info_guest(struct vcpu *v, vmx_setup_platform(d, c); vmx_final_setup_guest(v); - } else if (!d->arch.physmap_built) - build_physmap_table(d); - - *regs = c->regs; - cmdline_addr = 0; - if (v == d->vcpu[0]) { - /* Only for first vcpu. */ - d->arch.sys_pgnr = c->sys_pgnr; - d->arch.initrd_start = c->initrd.start; - d->arch.initrd_len = c->initrd.size; - d->arch.cmdline = c->cmdline; - d->shared_info->arch = c->shared; - - if (!VMX_DOMAIN(v)) { - const char *cmdline = d->arch.cmdline; - int len; - - if (*cmdline == 0) { -#define DEFAULT_CMDLINE "nomca nosmp xencons=tty0 console=tty0 root=/dev/hda1" - cmdline = DEFAULT_CMDLINE; - len = sizeof (DEFAULT_CMDLINE); - printf("domU command line defaulted to" - DEFAULT_CMDLINE "\n"); - } - else - len = IA64_COMMAND_LINE_SIZE; - cmdline_addr = dom_fw_setup (d, cmdline, len); - } - - /* Cache synchronization seems to be done by the linux kernel - during mmap/unmap operation. However be conservative. */ - domain_cache_flush (d, 1); - } + } + + /* This overrides some registers. */ vcpu_init_regs (v); - regs->r28 = cmdline_addr; - - if ( c->privregs && copy_from_user(v->arch.privregs, - c->privregs, sizeof(mapped_regs_t))) { - printk("Bad ctxt address in arch_set_info_guest: %p\n", - c->privregs); - return -EFAULT; - } /* Don't redo final setup */ set_bit(_VCPUF_initialised, &v->vcpu_flags); @@ -689,8 +705,9 @@ int construct_dom0(struct domain *d, unsigned long pkern_end; unsigned long pinitrd_start = 0; unsigned long pstart_info; - unsigned long cmdline_addr; struct page_info *start_info_page; + unsigned long bp_mpa; + struct ia64_boot_param *bp; #ifdef VALIDATE_VT unsigned long mfn; @@ -839,8 +856,6 @@ int construct_dom0(struct domain *d, //if ( initrd_len != 0 ) // memcpy((void *)vinitrd_start, initrd_start, initrd_len); - d->shared_info->arch.flags = SIF_INITDOMAIN|SIF_PRIVILEGED; - /* 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); @@ -850,6 +865,8 @@ int construct_dom0(struct domain *d, memset(si, 0, PAGE_SIZE); sprintf(si->magic, "xen-%i.%i-ia64", XEN_VERSION, XEN_SUBVERSION); si->nr_pages = max_pages; + si->flags = SIF_INITDOMAIN|SIF_PRIVILEGED; + d->shared_info->arch.flags = si->flags; /* Give up the VGA console if DOM0 is configured to grab it. */ if (cmdline != NULL) @@ -864,15 +881,39 @@ int construct_dom0(struct domain *d, set_bit(_VCPUF_initialised, &v->vcpu_flags); - cmdline_addr = dom_fw_setup(d, dom0_command_line, COMMAND_LINE_SIZE); + /* 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); + dom_fw_setup (d, bp_mpa, max_pages * PAGE_SIZE); + + /* Fill boot param. */ + strncpy ((char *)si->cmd_line, + dom0_command_line, sizeof (si->cmd_line)); + si->cmd_line[sizeof(si->cmd_line)-1] = 0; + + bp = (struct ia64_boot_param *)(si + 1); + 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 = (dom0_start+dom0_size) - + (PAGE_ALIGN(ia64_boot_param->initrd_size) + 4*1024*1024); + bp->initrd_size = ia64_boot_param->initrd_size; vcpu_init_regs (v); + + vcpu_regs(v)->r28 = bp_mpa; #ifdef CONFIG_DOMAIN0_CONTIGUOUS pkern_entry += dom0_start; #endif vcpu_regs (v)->cr_iip = pkern_entry; - vcpu_regs (v)->r28 = cmdline_addr; physdev_init_dom0(d); diff -r f662f98d594b xen/arch/ia64/xen/efi_emul.c --- a/xen/arch/ia64/xen/efi_emul.c Mon Jun 05 14:28:39 2006 -0600 +++ b/xen/arch/ia64/xen/efi_emul.c Mon Jun 12 09:35:09 2006 +0200 @@ -25,7 +25,6 @@ #include extern unsigned long translate_domain_mpaddr(unsigned long); -extern unsigned long domain_mpa_to_imva(struct domain *,unsigned long mpaddr); // given a current domain (virtual or metaphysical) address, return the virtual address static unsigned long diff -r f662f98d594b xen/arch/ia64/xen/faults.c --- a/xen/arch/ia64/xen/faults.c Mon Jun 05 14:28:39 2006 -0600 +++ b/xen/arch/ia64/xen/faults.c Mon Jun 12 09:35:09 2006 +0200 @@ -232,6 +232,7 @@ void ia64_do_page_fault (unsigned long a again: fault = vcpu_translate(current,address,is_data,&pteval,&itir,&iha); if (fault == IA64_NO_FAULT || fault == IA64_USE_TLB) { + static int msg_cnt; u64 logps; pteval = translate_domain_pte(pteval, address, itir, &logps); vcpu_itc_no_srlz(current,is_data?2:1,address,pteval,-1UL,logps); @@ -240,6 +241,12 @@ void ia64_do_page_fault (unsigned long a matching. Undo the work. */ vcpu_flush_tlb_vhpt_range (address, 1); goto again; + } + if (current->domain != dom0 && msg_cnt < 10) { + printf ("page_fault: addr=%lx -> %lx, MP=%d\n", + address, pteval, + PSCB(current,metaphysical_mode)); + msg_cnt++; } return; } @@ -610,7 +617,7 @@ ia64_handle_reflection (unsigned long if vector = IA64_NAT_CONSUMPTION_VECTOR; break; } #endif - printf("*** NaT fault... attempting to handle as privop\n"); + printf("*** NaT fault... attempting to handle as privop (dom=%p)\n", current->domain); printf("isr=%016lx, ifa=%016lx, iip=%016lx, ipsr=%016lx\n", isr, ifa, regs->cr_iip, psr); //regs->eml_unat = 0; FIXME: DO WE NEED THIS??? diff -r f662f98d594b xen/arch/ia64/xen/mm.c --- a/xen/arch/ia64/xen/mm.c Mon Jun 05 14:28:39 2006 -0600 +++ b/xen/arch/ia64/xen/mm.c Mon Jun 12 09:35:09 2006 +0200 @@ -382,7 +382,7 @@ lookup_alloc_domain_pte(struct domain* d } //XXX xxx_none() should be used instread of !xxx_present()? -static pte_t* +pte_t* lookup_noalloc_domain_pte(struct domain* d, unsigned long mpaddr) { struct mm_struct *mm = &d->arch.mm; @@ -520,7 +520,7 @@ unsigned long lookup_domain_mpa(struct d // FIXME: ONLY USE FOR DOMAIN PAGE_SIZE == PAGE_SIZE #if 1 -unsigned long domain_mpa_to_imva(struct domain *d, unsigned long mpaddr) +void *domain_mpa_to_imva(struct domain *d, unsigned long mpaddr) { unsigned long pte = lookup_domain_mpa(d,mpaddr); unsigned long imva; @@ -528,7 +528,7 @@ unsigned long domain_mpa_to_imva(struct pte &= _PAGE_PPN_MASK; imva = (unsigned long) __va(pte); imva |= mpaddr & ~PAGE_MASK; - return(imva); + return (void*)imva; } #else unsigned long domain_mpa_to_imva(struct domain *d, unsigned long mpaddr) @@ -608,10 +608,9 @@ assign_new_domain_page(struct domain *d, pte = lookup_alloc_domain_pte(d, mpaddr); if (pte_none(*pte)) { p = __assign_new_domain_page(d, mpaddr, pte); - } else { + } else DPRINTK("%s: d 0x%p mpaddr %lx already mapped!\n", __func__, d, mpaddr); - } return p; #endif diff -r f662f98d594b xen/arch/ia64/xen/vcpu.c --- a/xen/arch/ia64/xen/vcpu.c Mon Jun 05 14:28:39 2006 -0600 +++ b/xen/arch/ia64/xen/vcpu.c Mon Jun 12 09:35:09 2006 +0200 @@ -1374,7 +1374,7 @@ static TR_ENTRY* static TR_ENTRY* vcpu_tr_lookup(VCPU* vcpu, unsigned long va, UINT64 rid, BOOLEAN is_data) { - unsigned int* regions; + unsigned char* regions; TR_ENTRY *trp; int tr_max; int i; @@ -1882,13 +1882,15 @@ IA64FAULT vcpu_set_pkr(VCPU *vcpu, UINT6 VCPU translation register access routines **************************************************************************/ -static void vcpu_set_tr_entry(TR_ENTRY *trp, UINT64 pte, UINT64 itir, UINT64 ifa) +static void vcpu_set_tr_entry_rid(TR_ENTRY *trp, + UINT64 pte, UINT64 itir, + UINT64 ifa, UINT64 rid) { UINT64 ps; union pte_flags new_pte; trp->itir = itir; - trp->rid = VCPU(current,rrs[ifa>>61]) & RR_RID_MASK; + trp->rid = rid; ps = trp->ps; new_pte.val = pte; if (new_pte.pl < 2) new_pte.pl = 2; @@ -1902,8 +1904,15 @@ static void vcpu_set_tr_entry(TR_ENTRY * trp->pte.val = new_pte.val; } +static inline void +vcpu_set_tr_entry(TR_ENTRY *trp, UINT64 pte, UINT64 itir, UINT64 ifa) +{ + vcpu_set_tr_entry_rid (trp, pte, itir, ifa, + VCPU(current,rrs[ifa>>61]) & RR_RID_MASK); +} + IA64FAULT vcpu_itr_d(VCPU *vcpu, UINT64 slot, UINT64 pte, - UINT64 itir, UINT64 ifa) + UINT64 itir, UINT64 ifa) { TR_ENTRY *trp; @@ -1916,7 +1925,7 @@ IA64FAULT vcpu_itr_d(VCPU *vcpu, UINT64 } IA64FAULT vcpu_itr_i(VCPU *vcpu, UINT64 slot, UINT64 pte, - UINT64 itir, UINT64 ifa) + UINT64 itir, UINT64 ifa) { TR_ENTRY *trp; @@ -1925,6 +1934,44 @@ IA64FAULT vcpu_itr_i(VCPU *vcpu, UINT64 //printf("***** itr.i: setting slot %d: ifa=%p\n",slot,ifa); vcpu_set_tr_entry(trp,pte,itir,ifa); vcpu_quick_region_set(PSCBX(vcpu,itr_regions),ifa); + return IA64_NO_FAULT; +} + +IA64FAULT vcpu_set_itr(VCPU *vcpu, u64 slot, u64 pte, + u64 itir, u64 ifa, u64 rid) +{ + TR_ENTRY *trp; + + if (slot >= NITRS) + return IA64_RSVDREG_FAULT; + trp = &PSCBX(vcpu,itrs[slot]); + vcpu_set_tr_entry_rid(trp,pte,itir,ifa, rid); + + /* Recompute the itr_region. */ + vcpu->arch.itr_regions = 0; + for (trp = vcpu->arch.itrs; trp < &vcpu->arch.itrs[NITRS]; trp++) + if (trp->pte.p) + vcpu_quick_region_set(vcpu->arch.itr_regions, + trp->vadr); + return IA64_NO_FAULT; +} + +IA64FAULT vcpu_set_dtr(VCPU *vcpu, u64 slot, u64 pte, + u64 itir, u64 ifa, u64 rid) +{ + TR_ENTRY *trp; + + if (slot >= NDTRS) + return IA64_RSVDREG_FAULT; + trp = &PSCBX(vcpu,dtrs[slot]); + vcpu_set_tr_entry_rid(trp,pte,itir,ifa, rid); + + /* Recompute the dtr_region. */ + vcpu->arch.dtr_regions = 0; + for (trp = vcpu->arch.dtrs; trp < &vcpu->arch.dtrs[NDTRS]; trp++) + if (trp->pte.p) + vcpu_quick_region_set(vcpu->arch.dtr_regions, + trp->vadr); return IA64_NO_FAULT; } @@ -2126,7 +2173,6 @@ IA64FAULT vcpu_ptr_i(VCPU *vcpu,UINT64 v vcpu_quick_region_set(vcpu->arch.itr_regions, trp->vadr); - vcpu_flush_tlb_vhpt_range (vadr, log_range); return IA64_NO_FAULT; diff -r f662f98d594b xen/include/asm-ia64/dom_fw.h --- a/xen/include/asm-ia64/dom_fw.h Mon Jun 05 14:28:39 2006 -0600 +++ b/xen/include/asm-ia64/dom_fw.h Mon Jun 12 09:35:09 2006 +0200 @@ -163,7 +163,7 @@ extern struct ia64_pal_retval xen_pal_em extern struct ia64_pal_retval xen_pal_emulator(UINT64, u64, u64, u64); extern struct sal_ret_values sal_emulator (long index, unsigned long in1, unsigned long in2, unsigned long in3, unsigned long in4, unsigned long in5, unsigned long in6, unsigned long in7); extern struct ia64_pal_retval pal_emulator_static (unsigned long); -extern unsigned long dom_fw_setup (struct domain *, const char *, int); +extern void dom_fw_setup (struct domain *, unsigned long bp_mpa, unsigned long maxmem); extern efi_status_t efi_emulator (struct pt_regs *regs, unsigned long *fault); extern void build_pal_hypercall_bundles(unsigned long *imva, unsigned long brkimm, unsigned long hypnum); diff -r f662f98d594b xen/include/asm-ia64/domain.h --- a/xen/include/asm-ia64/domain.h Mon Jun 05 14:28:39 2006 -0600 +++ b/xen/include/asm-ia64/domain.h Mon Jun 12 09:35:09 2006 +0200 @@ -50,10 +50,7 @@ struct arch_domain { int breakimm; /* The imm value for hypercalls. */ int physmap_built; /* Whether is physmap built or not */ - int imp_va_msb; - /* System pages out of guest memory, like for xenstore/console */ - unsigned long sys_pgnr; - unsigned long max_pfn; /* Max pfn including I/O holes */ + struct virtual_platform_def vmx_platform; #define hvm_domain vmx_platform /* platform defs are not vmx specific */ @@ -67,9 +64,7 @@ struct arch_domain { u64 xen_vastart; u64 xen_vaend; u64 shared_info_va; - unsigned long initrd_start; - unsigned long initrd_len; - char *cmdline; + /* There are these for EFI_SET_VIRTUAL_ADDRESS_MAP emulation. */ int efi_virt_mode; /* phys : 0 , virt : 1 */ /* Metaphysical address to efi_runtime_services_t in domain firmware memory is set. */ @@ -84,23 +79,28 @@ struct arch_domain { offsetof(vcpu_info_t, evtchn_upcall_mask)) struct arch_vcpu { + /* Save the state of vcpu. + This is the first entry to speed up accesses. */ + mapped_regs_t *privregs; + + /* TR and TC. */ TR_ENTRY itrs[NITRS]; TR_ENTRY dtrs[NDTRS]; TR_ENTRY itlb; TR_ENTRY dtlb; - unsigned int itr_regions; - unsigned int dtr_regions; - unsigned long irr[4]; - unsigned long insvc[4]; - unsigned long tc_regions; + + /* Bit is set if there is a tr/tc for the region. */ + unsigned char itr_regions; + unsigned char dtr_regions; + unsigned char tc_regions; + + unsigned long irr[4]; /* Interrupt request register. */ + unsigned long insvc[4]; /* Interrupt in service. */ unsigned long iva; unsigned long dcr; - unsigned long itc; unsigned long domain_itm; unsigned long domain_itm_last; - unsigned long xen_itm; - mapped_regs_t *privregs; /* save the state of vcpu */ unsigned long event_callback_ip; // event callback handler unsigned long failsafe_callback_ip; // Do we need it? diff -r f662f98d594b xen/include/asm-ia64/mm.h --- a/xen/include/asm-ia64/mm.h Mon Jun 05 14:28:39 2006 -0600 +++ b/xen/include/asm-ia64/mm.h Mon Jun 12 09:35:09 2006 +0200 @@ -429,6 +429,8 @@ extern void assign_domain_page(struct do extern void assign_domain_page(struct domain *d, unsigned long mpaddr, unsigned long physaddr); extern void assign_domain_io_page(struct domain *d, unsigned long mpaddr, unsigned long flags); extern unsigned long lookup_domain_mpa(struct domain *d, unsigned long mpaddr); +extern pte_t *lookup_noalloc_domain_pte(struct domain* d, unsigned long mpaddr); +extern void *domain_mpa_to_imva(struct domain *,unsigned long mpaddr); #ifdef CONFIG_XEN_IA64_DOM0_VP extern unsigned long assign_domain_mmio_page(struct domain *d, unsigned long mpaddr, unsigned long size); diff -r f662f98d594b xen/include/asm-ia64/vcpu.h --- a/xen/include/asm-ia64/vcpu.h Mon Jun 05 14:28:39 2006 -0600 +++ b/xen/include/asm-ia64/vcpu.h Mon Jun 12 09:35:09 2006 +0200 @@ -176,6 +176,11 @@ extern UINT64 vcpu_get_tmp(VCPU *, UINT6 extern UINT64 vcpu_get_tmp(VCPU *, UINT64); extern void vcpu_set_tmp(VCPU *, UINT64, UINT64); +extern IA64FAULT vcpu_set_dtr(VCPU *vcpu, u64 slot, + u64 pte, u64 itir, u64 ifa, u64 rid); +extern IA64FAULT vcpu_set_itr(VCPU *vcpu, u64 slot, + u64 pte, u64 itir, u64 ifa, u64 rid); + /* Initialize vcpu regs. */ extern void vcpu_init_regs (struct vcpu *v); diff -r f662f98d594b xen/include/public/arch-ia64.h --- a/xen/include/public/arch-ia64.h Mon Jun 05 14:28:39 2006 -0600 +++ b/xen/include/public/arch-ia64.h Mon Jun 12 09:35:09 2006 +0200 @@ -298,15 +298,16 @@ struct mapped_regs { unsigned long reserved7[4096]; }; typedef struct mapped_regs mapped_regs_t; +typedef mapped_regs_t vpd_t; struct arch_vcpu_info { }; typedef struct arch_vcpu_info arch_vcpu_info_t; - -typedef mapped_regs_t vpd_t; struct arch_shared_info { unsigned int flags; + + /* PFN of the start_info page. */ unsigned long start_info_pfn; /* Interrupt vector for event channel. */ @@ -314,33 +315,57 @@ struct arch_shared_info { }; typedef struct arch_shared_info arch_shared_info_t; -struct arch_initrd_info { - unsigned long start; - unsigned long size; -}; -typedef struct arch_initrd_info arch_initrd_info_t; - typedef unsigned long xen_callback_t; -#define IA64_COMMAND_LINE_SIZE 512 +struct ia64_tr_entry { + unsigned long pte; + unsigned long itir; + unsigned long vadr; + unsigned long rid; +}; + +struct vcpu_extra_regs { + struct ia64_tr_entry itrs[8]; + struct ia64_tr_entry dtrs[8]; + unsigned long iva; + unsigned long dcr; + unsigned long event_callback_ip; +}; + struct vcpu_guest_context { -#define VGCF_FPU_VALID (1<<0) -#define VGCF_VMX_GUEST (1<<1) -#define VGCF_IN_KERNEL (1<<2) +#define VGCF_VMX_GUEST (1<<0) +#define VGCF_EXTRA_REGS (1<<2) /* Get/Set extra regs. */ unsigned long flags; /* VGCF_* flags */ - unsigned long pt_base; /* PMT table base */ - unsigned long share_io_pg; /* Shared page for I/O emulation */ - unsigned long sys_pgnr; /* System pages out of domain memory */ unsigned long vm_assist; /* VMASST_TYPE_* bitmap, now none on IPF */ struct cpu_user_regs regs; - struct mapped_regs *privregs; - struct arch_shared_info shared; - struct arch_initrd_info initrd; - char cmdline[IA64_COMMAND_LINE_SIZE]; + struct vcpu_extra_regs extra_regs; + unsigned long privregs_pfn; }; typedef struct vcpu_guest_context vcpu_guest_context_t; DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t); + +/* Same layout as struct ia64_boot_param, but uses a xen identifier to avoid + redefinitions. */ +struct xen_ia64_boot_param { + unsigned long command_line; /* physical address of command line. */ + unsigned long efi_systab; /* physical address of EFI system table */ + unsigned long efi_memmap; /* physical address of EFI memory map */ + unsigned long efi_memmap_size; /* size of EFI memory map */ + unsigned long efi_memdesc_size; /* size of an EFI memory map descriptor */ + unsigned int efi_memdesc_version; /* memory descriptor version */ + struct { + unsigned short num_cols; /* number of columns on console */ + unsigned short num_rows; /* number of rows on console */ + unsigned short orig_x; /* cursor's x position */ + unsigned short orig_y; /* cursor's y position */ + } console_info; + unsigned long fpswa; /* physical address of the fpswa interface */ + unsigned long initrd_start; + unsigned long initrd_size; + unsigned long domain_start; /* virtual address where dom0 begins */ + unsigned long domain_size; /* how big is the boot domain */ +}; // dom0 vp op #define __HYPERVISOR_ia64_dom0vp_op __HYPERVISOR_arch_0 diff -r f662f98d594b xen/include/public/dom0_ops.h --- a/xen/include/public/dom0_ops.h Mon Jun 05 14:28:39 2006 -0600 +++ b/xen/include/public/dom0_ops.h Mon Jun 12 09:35:09 2006 +0200 @@ -513,6 +513,17 @@ struct dom0_hypercall_init { }; typedef struct dom0_hypercall_init dom0_hypercall_init_t; DEFINE_XEN_GUEST_HANDLE(dom0_hypercall_init_t); + +#define DOM0_FIRMWARE_SETUP 49 +#define DOM0_FIRMWARE_SETUP_VTI (1 << 0) +typedef struct dom0_firmware_setup { + domid_t domain; /* domain to be affected */ + unsigned long flags; + unsigned long bp; /* mpaddr of boot param area */ + unsigned long maxmem; /* Highest memory address for MDT. */ + unsigned int hypercall_imm; /* IIM for hypercall */ +} dom0_firmware_setup_t; +DEFINE_XEN_GUEST_HANDLE(dom0_firmware_setup_t); struct dom0_op { uint32_t cmd; @@ -555,6 +566,7 @@ struct dom0_op { struct dom0_irq_permission irq_permission; struct dom0_iomem_permission iomem_permission; struct dom0_hypercall_init hypercall_init; + struct dom0_firmware_setup firmware_setup; uint8_t pad[128]; } u; }; diff -r f662f98d594b tools/libxc/xc_ia64_linux_restore.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/libxc/xc_ia64_linux_restore.c Mon Jun 12 09:35:09 2006 +0200 @@ -0,0 +1,312 @@ +/****************************************************************************** + * xc_linux_restore.c + * + * Restore the state of a Linux session. + * + * Copyright (c) 2003, K A Fraser. + */ + +#include +#include + +#include "xg_private.h" +#include "xg_save_restore.h" + +void xc_disp_vcpu_context (struct vcpu_guest_context *ctxt); + +/* total number of pages used by the current guest */ +static unsigned long max_pfn; + +static ssize_t +read_exact(int fd, void *buf, size_t count) +{ + int r = 0, s; + unsigned char *b = buf; + + while (r < count) { + s = read(fd, &b[r], count - r); + if ((s == -1) && (errno == EINTR)) + continue; + if (s <= 0) { + break; + } + r += s; + } + + return (r == count) ? 1 : 0; +} + +static int +read_page (int xc_handle, int io_fd, uint32_t dom, unsigned long pfn) +{ + void *mem; + + mem = xc_map_foreign_range + (xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE, pfn); + if (mem == NULL) { + ERR("cannot map page"); + return -1; + } + if (!read_exact(io_fd, mem, PAGE_SIZE)) { + ERR("Error when reading from state file (5)"); + return -1; + } + munmap(mem, PAGE_SIZE); + return 0; +} + +int xc_linux_restore(int xc_handle, int io_fd, + uint32_t dom, unsigned long nr_pfns, + unsigned int store_evtchn, unsigned long *store_mfn, + unsigned int console_evtchn, unsigned long *console_mfn) +{ + DECLARE_DOM0_OP; + int rc = 1, i; + unsigned long mfn, pfn; + + /* The new domain's shared-info frame number. */ + unsigned long shared_info_frame; + unsigned char shared_info_page[PAGE_SIZE]; /* saved contents from file */ + shared_info_t *shared_info = (shared_info_t *)shared_info_page; + + /* A copy of the CPU context of the guest. */ + vcpu_guest_context_t ctxt; + + unsigned long *page_array = NULL; + + /* A temporary mapping of the guest's start_info page. */ + start_info_t *start_info; + + max_pfn = nr_pfns; + + DPRINTF("xc_linux_restore start: max_pfn = %ld\n", max_pfn); + + + if (mlock(&ctxt, sizeof(ctxt))) { + /* needed for build dom0 op, but might as well do early */ + ERR("Unable to mlock ctxt"); + return 1; + } + + /* Get the domain's shared-info frame. */ + op.cmd = DOM0_GETDOMAININFO; + op.u.getdomaininfo.domain = (domid_t)dom; + if (xc_dom0_op(xc_handle, &op) < 0) { + ERR("Could not get information on new domain"); + goto out; + } + shared_info_frame = op.u.getdomaininfo.shared_info_frame; + + if(xc_domain_setmaxmem(xc_handle, dom, PFN_TO_KB(max_pfn)) != 0) { + errno = ENOMEM; + goto out; + } + + if(xc_domain_memory_increase_reservation( + xc_handle, dom, max_pfn, 0, 0, NULL) != 0) { + ERR("Failed to increase reservation by %ld KB", PFN_TO_KB(max_pfn)); + errno = ENOMEM; + goto out; + } + + DPRINTF("Increased domain reservation by %ld KB\n", PFN_TO_KB(max_pfn)); + + /* Build firmware (will be overwritten). */ + op.u.firmware_setup.domain = (domid_t)dom; + op.u.firmware_setup.bp = ((nr_pfns - 3) << PAGE_SHIFT) + + sizeof (start_info_t); + op.u.firmware_setup.hypercall_imm = 0x1000; + op.u.firmware_setup.maxmem = (nr_pfns - 3) << PAGE_SHIFT; + + op.cmd = DOM0_FIRMWARE_SETUP; + if ( xc_dom0_op(xc_handle, &op) ) + goto out; + + + /* Get pages. */ + if ( (page_array = malloc(max_pfn * sizeof(unsigned long))) == NULL ) + { + ERR("Could not allocate memory"); + goto out; + } + + if ( xc_ia64_get_pfn_list(xc_handle, dom, page_array, + 0, max_pfn) != max_pfn ) + { + ERR("Could not get the page frame list"); + goto out; + } + + fprintf (stderr, "ia64_linux_restore: fd at %ld\n", + lseek (io_fd, 0, SEEK_CUR)); + + DPRINTF("Reloading memory pages: 0%%\n"); + + while (1) { + if (!read_exact(io_fd, &mfn, sizeof(unsigned long))) { + ERR("Error when reading batch size"); + goto out; + } + if (mfn == INVALID_MFN) + break; + + pfn = page_array[mfn]; + fprintf (stderr, "xc_linux_restore: page %lu/%lu at %lx\n", + mfn, max_pfn, pfn); + + if (read_page(xc_handle, io_fd, dom, page_array[mfn]) < 0) + goto out; + } + + DPRINTF("Received all pages\n"); + + /* Get the list of PFNs that are not in the psuedo-phys map */ + { + unsigned int count; + unsigned long *pfntab; + int rc; + + if (!read_exact(io_fd, &count, sizeof(count))) { + ERR("Error when reading pfn count"); + goto out; + } + + if(!(pfntab = malloc(sizeof(unsigned long) * count))) { + ERR("Out of memory"); + goto out; + } + + if (!read_exact(io_fd, pfntab, sizeof(unsigned long)*count)) { + ERR("Error when reading pfntab"); + goto out; + } + + fprintf (stderr, "Try to free %u pages\n", count); + + for (i = 0; i < count; i++) { + + volatile unsigned long pfn; + + struct xen_memory_reservation reservation = { + .nr_extents = 1, + .extent_order = 0, + .domid = dom + }; + set_xen_guest_handle(reservation.extent_start, + (unsigned long *)&pfn); + + pfn = pfntab[i]; + if ((rc = xc_memory_op(xc_handle, XENMEM_decrease_reservation, + &reservation)) != 1) { + ERR("Could not decrease reservation : %d", rc); + goto out; + } + } + + DPRINTF("Decreased reservation by %d pages\n", count); + } + + + if (!read_exact(io_fd, &ctxt, sizeof(ctxt))) { + ERR("Error when reading ctxt"); + goto out; + } + xc_disp_vcpu_context (&ctxt); + + + /* First to initialize. */ + op.cmd = DOM0_SETVCPUCONTEXT; + op.u.setvcpucontext.domain = (domid_t)dom; + op.u.setvcpucontext.vcpu = 0; + set_xen_guest_handle(op.u.setvcpucontext.ctxt, &ctxt); + if (xc_dom0_op(xc_handle, &op) != 0) { + ERR("Couldn't set vcpu context"); + goto out; + } + + /* Second to set registers... */ + ctxt.flags = VGCF_EXTRA_REGS; + op.cmd = DOM0_SETVCPUCONTEXT; + op.u.setvcpucontext.domain = (domid_t)dom; + op.u.setvcpucontext.vcpu = 0; + set_xen_guest_handle(op.u.setvcpucontext.ctxt, &ctxt); + if (xc_dom0_op(xc_handle, &op) != 0) { + ERR("Couldn't set vcpu context"); + goto out; + } + + /* Just a check. */ + if ( xc_vcpu_getcontext(xc_handle, dom, 0 /* XXX */, &ctxt)) { + ERR("Could not get vcpu context"); + goto out; + } + + xc_disp_vcpu_context (&ctxt); + + /* Then get privreg page. */ + if (read_page (xc_handle, io_fd, dom, ctxt.privregs_pfn) < 0) { + ERR("Could not read vcpu privregs"); + goto out; + } + + /* Read shared info. */ + shared_info = xc_map_foreign_range + (xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE, + shared_info_frame); + if (shared_info == NULL) { + ERR("cannot map page"); + goto out; + } + if (!read_exact(io_fd, shared_info, PAGE_SIZE)) { + ERR("Error when reading shared_info page"); + goto out; + } + + /* clear any pending events and the selector */ + memset(&(shared_info->evtchn_pending[0]), 0, + sizeof (shared_info->evtchn_pending)); + for ( i = 0; i < MAX_VIRT_CPUS; i++ ) + shared_info->vcpu_info[i].evtchn_pending_sel = 0; + + mfn = page_array[shared_info->arch.start_info_pfn]; + + munmap (shared_info, PAGE_SIZE); + + /* Uncanonicalise the suspend-record frame number and poke resume rec. */ + start_info = xc_map_foreign_range( + xc_handle, dom, PAGE_SIZE, PROT_READ | PROT_WRITE, mfn); + start_info->nr_pages = max_pfn; + start_info->shared_info = shared_info_frame << PAGE_SHIFT; + start_info->flags = 0; + *store_mfn = page_array[start_info->store_mfn]; + start_info->store_evtchn = store_evtchn; + *console_mfn = page_array[start_info->console_mfn]; + start_info->console_evtchn = console_evtchn; + munmap(start_info, PAGE_SIZE); + + /* + * Safety checking of saved context: + * 1. user_regs is fine, as Xen checks that on context switch. + * 2. fpu_ctxt is fine, as it can't hurt Xen. + * 3. trap_ctxt needs the code selectors checked. + * 4. ldt base must be page-aligned, no more than 8192 ents, ... + * 5. gdt already done, and further checking is done by Xen. + * 6. check that kernel_ss is safe. + * 7. pt_base is already done. + * 8. debugregs are checked by Xen. + * 9. callback code selectors need checking. + */ + DPRINTF("Domain ready to be built.\n"); + + rc = 0; + + out: + if ( (rc != 0) && (dom != 0) ) + xc_domain_destroy(xc_handle, dom); + + free (page_array); + + DPRINTF("Restore exit with rc=%d\n", rc); + + return rc; +} diff -r f662f98d594b tools/libxc/xc_ia64_linux_save.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/libxc/xc_ia64_linux_save.c Mon Jun 12 09:35:09 2006 +0200 @@ -0,0 +1,281 @@ +/****************************************************************************** + * xc_linux_save.c + * + * Save the state of a running Linux session. + * + * Copyright (c) 2003, K A Fraser. + */ + +#include +#include +#include +#include +#include + +#include "xc_private.h" +#include "xg_private.h" +#include "xg_save_restore.h" + +void +xc_disp_vcpu_context (struct vcpu_guest_context *ctxt); + +/* total number of pages used by the current guest */ +static unsigned long max_pfn; + +static inline ssize_t write_exact(int fd, void *buf, size_t count) +{ + if(write(fd, buf, count) != count) + return 0; + return 1; +} + +static int suspend_and_state(int (*suspend)(int), int xc_handle, int io_fd, + int dom, xc_dominfo_t *info) +{ + int i = 0; + + if (!(*suspend)(dom)) { + ERR("Suspend request failed"); + return -1; + } + + retry: + + if (xc_domain_getinfo(xc_handle, dom, 1, info) != 1) { + ERR("Could not get domain info"); + return -1; + } + + + if (info->shutdown && info->shutdown_reason == SHUTDOWN_suspend) + return 0; // success + + if (info->paused) { + // try unpausing domain, wait, and retest + xc_domain_unpause( xc_handle, dom ); + + ERR("Domain was paused. Wait and re-test."); + usleep(10000); // 10ms + + goto retry; + } + + + if( ++i < 100 ) { + ERR("Retry suspend domain."); + usleep(10000); // 10ms + goto retry; + } + + ERR("Unable to suspend domain."); + + return -1; +} + +int xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, + uint32_t max_factor, uint32_t flags, int (*suspend)(int)) +{ + xc_dominfo_t info; + + int rc = 1; + unsigned long N; + + //int live = (flags & XCFLAGS_LIVE); + //int debug = (flags & XCFLAGS_DEBUG); + + /* The new domain's shared-info frame number. */ + unsigned long shared_info_frame; + + /* A copy of the CPU context of the guest. */ + vcpu_guest_context_t ctxt; + + unsigned long *page_array = NULL; + + /* Live mapping of shared info structure */ + shared_info_t *live_shinfo = NULL; + + char *mem; + + fprintf (stderr, "xc_linux_save (ia64): started dom=%d\n", dom); + + if (xc_domain_getinfo(xc_handle, dom, 1, &info) != 1) { + ERR("Could not get domain info"); + return 1; + } + + fprintf (stderr, "xc_linux_save (ia64): 2\n"); + + shared_info_frame = info.shared_info_frame; + +#if 0 + /* cheesy sanity check */ + if ((info.max_memkb >> (PAGE_SHIFT - 10)) > max_mfn) { + ERR("Invalid state record -- pfn count out of range: %lu", + (info.max_memkb >> (PAGE_SHIFT - 10))); + goto out; + } +#endif + + fprintf (stderr, "xc_linux_save (ia64): 3\n"); + /* Map the shared info frame */ + if(!(live_shinfo = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, + PROT_READ, shared_info_frame))) { + ERR("Couldn't map live_shinfo"); + goto out; + } + + max_pfn = info.max_memkb >> (PAGE_SHIFT - 10); + + + fprintf (stderr, "xc_linux_save (ia64): 4 - max_pfn=%lx\n", max_pfn); + /* This is a non-live suspend. Issue the call back to get the + domain suspended */ + + if (suspend_and_state(suspend, xc_handle, io_fd, dom, &info)) { + ERR("Domain appears not to have suspended"); + goto out; + } + + fprintf (stderr, "xc_linux_save (ia64): 5\n"); + if ( (page_array = malloc(max_pfn * sizeof(unsigned long))) == NULL ) + { + ERR("Could not allocate memory"); + goto out; + } + + if ( xc_ia64_get_pfn_list(xc_handle, dom, page_array, + 0, max_pfn) != max_pfn ) + { + ERR("Could not get the page frame list"); + goto out; + } + + + if(!write_exact(io_fd, &max_pfn, sizeof(unsigned long))) { + ERR("write: max_pfn"); + goto out; + } + + fprintf (stderr, "xc_linux_save (ia64): 6, fd at %ld\n", + lseek (io_fd, 0, SEEK_CUR)); + + /* Start writing out the saved-domain record. */ + for (N = 0; N < max_pfn; N++) { + if (page_array[N] == INVALID_MFN) + continue; + fprintf (stderr, "xc_linux_save: page %lx (%lu/%lu)\n", + page_array[N], N, max_pfn); + + if(!write_exact(io_fd, &N, sizeof(N))) { + ERR("write: max_pfn"); + goto out; + } + + mem = xc_map_foreign_range + (xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE, page_array[N]); + if (mem == NULL) { + ERR("cannot map page"); + goto out; + } + if (write(io_fd, mem, PAGE_SIZE) != PAGE_SIZE) { + ERR("Error when writing to state file (5)"); + goto out; + } + munmap(mem, PAGE_SIZE); + } + + fprintf (stderr, "All memory is saved\n"); + + /* terminate */ + N = INVALID_MFN; + if (!write_exact(io_fd, &N, sizeof(N))) { + ERR("Error when writing to state file (6)"); + goto out; + } + + /* Send through a list of all the PFNs that were not in map at the close */ + { + unsigned int i,j; + unsigned long pfntab[1024]; + + for (i = 0, j = 0; i < max_pfn; i++) { + if (page_array[i] == INVALID_MFN) + j++; + } + + if(!write_exact(io_fd, &j, sizeof(unsigned int))) { + ERR("Error when writing to state file (6a)"); + goto out; + } + + for (i = 0, j = 0; i < max_pfn; ) { + + if (page_array[i] == INVALID_MFN) + pfntab[j++] = i; + + i++; + if (j == 1024 || i == max_pfn) { + if(!write_exact(io_fd, &pfntab, sizeof(unsigned long)*j)) { + ERR("Error when writing to state file (6b)"); + goto out; + } + j = 0; + } + } + + } + + + if (xc_vcpu_getcontext(xc_handle, dom, 0, &ctxt)) { + ERR("Could not get vcpu context"); + goto out; + } + + xc_disp_vcpu_context (&ctxt); + + if (!write_exact(io_fd, &ctxt, sizeof(ctxt))) { + ERR("Error when writing to state file (1)"); + goto out; + } + + mem = xc_map_foreign_range + (xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE, ctxt.privregs_pfn); + if (mem == NULL) { + ERR("cannot map privreg page"); + goto out; + } + if (write(io_fd, mem, PAGE_SIZE) != PAGE_SIZE) { + ERR("Error when writing privreg to state file (5)"); + goto out; + } + munmap(mem, PAGE_SIZE); + + if (!write_exact(io_fd, live_shinfo, PAGE_SIZE)) { + ERR("Error when writing to state file (1)"); + goto out; + } + + /* Success! */ + rc = 0; + + out: + + free (page_array); + + if (live_shinfo) + munmap(live_shinfo, PAGE_SIZE); + + fprintf(stderr,"Save exit rc=%d\n",rc); + + return !!rc; +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */