diff options
104 files changed, 7909 insertions, 3433 deletions
diff --git a/buildconfigs/linux-defconfig_xen0_ia64 b/buildconfigs/linux-defconfig_xen0_ia64 index 36b3dfc36e..400fbdc3c1 100644 --- a/buildconfigs/linux-defconfig_xen0_ia64 +++ b/buildconfigs/linux-defconfig_xen0_ia64 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.16.13-xen0 -# Fri Sep 1 11:03:26 2006 +# Linux kernel version: 2.6.16.29-xen0 +# Wed Oct 4 12:54:36 2006 # # @@ -92,6 +92,8 @@ CONFIG_EFI=y CONFIG_GENERIC_IOMAP=y CONFIG_XEN=y CONFIG_XEN_IA64_VDSO_PARAVIRT=y +CONFIG_XEN_IA64_EXPOSE_P2M=y +CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR=y CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y CONFIG_DMA_IS_DMA32=y # CONFIG_IA64_GENERIC is not set @@ -119,6 +121,7 @@ CONFIG_FORCE_MAX_ZONEORDER=11 CONFIG_SMP=y CONFIG_NR_CPUS=16 CONFIG_HOTPLUG_CPU=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y # CONFIG_SCHED_SMT is not set # CONFIG_PREEMPT is not set CONFIG_SELECT_MEMORY_MODEL=y @@ -1041,7 +1044,6 @@ CONFIG_SND_ATIIXP=y # CONFIG_SND_ES1968 is not set CONFIG_SND_FM801=y # CONFIG_SND_FM801_TEA575X_BOOL is not set -CONFIG_SND_FM801_TEA575X=y # CONFIG_SND_HDA_INTEL is not set # CONFIG_SND_HDSP is not set # CONFIG_SND_HDSPM is not set diff --git a/buildconfigs/linux-defconfig_xenU_ia64 b/buildconfigs/linux-defconfig_xenU_ia64 index da7f4e694d..a7e15190ee 100644 --- a/buildconfigs/linux-defconfig_xenU_ia64 +++ b/buildconfigs/linux-defconfig_xenU_ia64 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.16.13-xenU -# Fri Sep 1 10:50:54 2006 +# Linux kernel version: 2.6.16.29-xenU +# Wed Oct 4 12:54:26 2006 # # @@ -89,6 +89,8 @@ CONFIG_EFI=y CONFIG_GENERIC_IOMAP=y CONFIG_XEN=y CONFIG_XEN_IA64_VDSO_PARAVIRT=y +CONFIG_XEN_IA64_EXPOSE_P2M=y +CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR=y CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y CONFIG_DMA_IS_DMA32=y # CONFIG_IA64_GENERIC is not set @@ -116,6 +118,7 @@ CONFIG_FORCE_MAX_ZONEORDER=11 CONFIG_SMP=y CONFIG_NR_CPUS=16 # CONFIG_HOTPLUG_CPU is not set +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y # CONFIG_SCHED_SMT is not set # CONFIG_PREEMPT is not set CONFIG_SELECT_MEMORY_MODEL=y @@ -940,7 +943,6 @@ CONFIG_SND_AC97_BUS=y # CONFIG_SND_ES1968 is not set CONFIG_SND_FM801=y # CONFIG_SND_FM801_TEA575X_BOOL is not set -CONFIG_SND_FM801_TEA575X=y # CONFIG_SND_HDA_INTEL is not set # CONFIG_SND_HDSP is not set # CONFIG_SND_HDSPM is not set diff --git a/buildconfigs/linux-defconfig_xen_ia64 b/buildconfigs/linux-defconfig_xen_ia64 index a614cd9b8f..085d165ea7 100644 --- a/buildconfigs/linux-defconfig_xen_ia64 +++ b/buildconfigs/linux-defconfig_xen_ia64 @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Linux kernel version: 2.6.16.13-xen -# Fri Sep 1 10:58:55 2006 +# Linux kernel version: 2.6.16.29-xen +# Wed Oct 4 12:31:45 2006 # # @@ -92,6 +92,8 @@ CONFIG_EFI=y CONFIG_GENERIC_IOMAP=y CONFIG_XEN=y CONFIG_XEN_IA64_VDSO_PARAVIRT=y +CONFIG_XEN_IA64_EXPOSE_P2M=y +CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR=y CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y CONFIG_DMA_IS_DMA32=y # CONFIG_IA64_GENERIC is not set @@ -119,6 +121,7 @@ CONFIG_FORCE_MAX_ZONEORDER=11 CONFIG_SMP=y CONFIG_NR_CPUS=16 CONFIG_HOTPLUG_CPU=y +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y # CONFIG_SCHED_SMT is not set # CONFIG_PREEMPT is not set CONFIG_SELECT_MEMORY_MODEL=y @@ -1047,7 +1050,6 @@ CONFIG_SND_ATIIXP=y # CONFIG_SND_ES1968 is not set CONFIG_SND_FM801=y # CONFIG_SND_FM801_TEA575X_BOOL is not set -CONFIG_SND_FM801_TEA575X=y # CONFIG_SND_HDA_INTEL is not set # CONFIG_SND_HDSP is not set # CONFIG_SND_HDSPM is not set diff --git a/linux-2.6-xen-sparse/arch/ia64/Kconfig b/linux-2.6-xen-sparse/arch/ia64/Kconfig index 78f5e2b3e3..4073a04638 100644 --- a/linux-2.6-xen-sparse/arch/ia64/Kconfig +++ b/linux-2.6-xen-sparse/arch/ia64/Kconfig @@ -64,6 +64,20 @@ config XEN_IA64_VDSO_PARAVIRT help vDSO paravirtualization +config XEN_IA64_EXPOSE_P2M + bool "Xen/IA64 exposure p2m table" + depends on XEN + default y + help + expose p2m from xen + +config XEN_IA64_EXPOSE_P2M_USE_DTR + bool "Xen/IA64 map p2m table with dtr" + depends on XEN_IA64_EXPOSE_P2M + default y + help + use dtr to map the exposed p2m table + config SCHED_NO_NO_OMIT_FRAME_POINTER bool default y diff --git a/linux-2.6-xen-sparse/arch/ia64/kernel/Makefile b/linux-2.6-xen-sparse/arch/ia64/kernel/Makefile new file mode 100644 index 0000000000..003e9ee600 --- /dev/null +++ b/linux-2.6-xen-sparse/arch/ia64/kernel/Makefile @@ -0,0 +1,62 @@ +# +# Makefile for the linux kernel. +# + +extra-y := head.o init_task.o vmlinux.lds + +obj-y := acpi.o entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o \ + irq_lsapic.o ivt.o machvec.o pal.o patch.o process.o perfmon.o ptrace.o sal.o \ + salinfo.o semaphore.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o \ + unwind.o mca.o mca_asm.o topology.o + +obj-$(CONFIG_IA64_BRL_EMU) += brl_emu.o +obj-$(CONFIG_IA64_GENERIC) += acpi-ext.o +obj-$(CONFIG_IA64_HP_ZX1) += acpi-ext.o +obj-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += acpi-ext.o + +ifneq ($(CONFIG_ACPI_PROCESSOR),) +obj-y += acpi-processor.o +endif + +obj-$(CONFIG_IA64_PALINFO) += palinfo.o +obj-$(CONFIG_IOSAPIC) += iosapic.o +obj-$(CONFIG_MODULES) += module.o +obj-$(CONFIG_SMP) += smp.o smpboot.o +obj-$(CONFIG_NUMA) += numa.o +obj-$(CONFIG_PERFMON) += perfmon_default_smpl.o +obj-$(CONFIG_IA64_CYCLONE) += cyclone.o +obj-$(CONFIG_CPU_FREQ) += cpufreq/ +obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o +obj-$(CONFIG_KPROBES) += kprobes.o jprobes.o +obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o +mca_recovery-y += mca_drv.o mca_drv_asm.o + +# The gate DSO image is built using a special linker script. +targets += gate.so gate-syms.o + +extra-y += gate.so gate-syms.o gate.lds gate.o + +# fp_emulate() expects f2-f5,f16-f31 to contain the user-level state. +CFLAGS_traps.o += -mfixed-range=f2-f5,f16-f31 + +CPPFLAGS_gate.lds := -P -C -U$(ARCH) + +quiet_cmd_gate = GATE $@ + cmd_gate = $(CC) -nostdlib $(GATECFLAGS_$(@F)) -Wl,-T,$(filter-out FORCE,$^) -o $@ + +GATECFLAGS_gate.so = -shared -s -Wl,-soname=linux-gate.so.1 \ + $(call ld-option, -Wl$(comma)--hash-style=sysv) +$(obj)/gate.so: $(obj)/gate.lds $(obj)/gate.o FORCE + $(call if_changed,gate) + +$(obj)/built-in.o: $(obj)/gate-syms.o +$(obj)/built-in.o: ld_flags += -R $(obj)/gate-syms.o + +GATECFLAGS_gate-syms.o = -r +$(obj)/gate-syms.o: $(obj)/gate.lds $(obj)/gate.o FORCE + $(call if_changed,gate) + +# gate-data.o contains the gate DSO image as data in section .data.gate. +# We must build gate.so before we can assemble it. +# Note: kbuild does not track this dependency due to usage of .incbin +$(obj)/gate-data.o: $(obj)/gate.so diff --git a/linux-2.6-xen-sparse/arch/ia64/kernel/gate.lds.S b/linux-2.6-xen-sparse/arch/ia64/kernel/gate.lds.S index 5f0163f0be..45377beaa4 100644 --- a/linux-2.6-xen-sparse/arch/ia64/kernel/gate.lds.S +++ b/linux-2.6-xen-sparse/arch/ia64/kernel/gate.lds.S @@ -13,6 +13,7 @@ SECTIONS . = GATE_ADDR + SIZEOF_HEADERS; .hash : { *(.hash) } :readable + .gnu.hash : { *(.gnu.hash) } .dynsym : { *(.dynsym) } .dynstr : { *(.dynstr) } .gnu.version : { *(.gnu.version) } diff --git a/linux-2.6-xen-sparse/arch/ia64/kernel/setup.c b/linux-2.6-xen-sparse/arch/ia64/kernel/setup.c index f792900cf9..8f15b3001c 100644 --- a/linux-2.6-xen-sparse/arch/ia64/kernel/setup.c +++ b/linux-2.6-xen-sparse/arch/ia64/kernel/setup.c @@ -63,6 +63,7 @@ #include <asm/system.h> #ifdef CONFIG_XEN #include <asm/hypervisor.h> +#include <asm/xen/xencomm.h> #endif #include <linux/dma-mapping.h> @@ -433,6 +434,9 @@ setup_arch (char **cmdline_p) #ifdef CONFIG_XEN if (is_running_on_xen()) { + /* Must be done before any hypercall. */ + xencomm_init(); + setup_xen_features(); /* Register a call for panic conditions. */ notifier_chain_register(&panic_notifier_list, &xen_panic_block); diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/Makefile b/linux-2.6-xen-sparse/arch/ia64/xen/Makefile index c2b4f94edd..36434aac72 100644 --- a/linux-2.6-xen-sparse/arch/ia64/xen/Makefile +++ b/linux-2.6-xen-sparse/arch/ia64/xen/Makefile @@ -3,6 +3,7 @@ # obj-y := hypercall.o xenivt.o xenentry.o xensetup.o xenpal.o xenhpski.o \ - hypervisor.o pci-dma-xen.o util.o + hypervisor.o pci-dma-xen.o util.o xencomm.o xcom_hcall.o \ + xcom_mini.o xcom_privcmd.o pci-dma-xen-y := ../../i386/kernel/pci-dma-xen.o diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c b/linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c index 93de465364..2a85caa0d5 100644 --- a/linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c +++ b/linux-2.6-xen-sparse/arch/ia64/xen/hypervisor.c @@ -40,59 +40,11 @@ EXPORT_SYMBOL(xen_start_info); int running_on_xen; EXPORT_SYMBOL(running_on_xen); -//XXX xen/ia64 copy_from_guest() is broken. -// This is a temporal work around until it is fixed. -// used by balloon.c netfront.c - -// get_xen_guest_handle is defined only when __XEN_TOOLS__ is defined -// if the definition in arch-ia64.h is changed, this must be updated. -#define get_xen_guest_handle(val, hnd) do { val = (hnd).p; } while (0) - -int -ia64_xenmem_reservation_op(unsigned long op, - struct xen_memory_reservation* reservation__) -{ - struct xen_memory_reservation reservation = *reservation__; - unsigned long* frame_list; - unsigned long nr_extents = reservation__->nr_extents; - int ret = 0; - get_xen_guest_handle(frame_list, reservation__->extent_start); - - BUG_ON(op != XENMEM_increase_reservation && - op != XENMEM_decrease_reservation && - op != XENMEM_populate_physmap); - - while (nr_extents > 0) { - int tmp_ret; - volatile unsigned long dummy; - - set_xen_guest_handle(reservation.extent_start, frame_list); - reservation.nr_extents = nr_extents; - - dummy = frame_list[0];// re-install tlb entry before hypercall - tmp_ret = ____HYPERVISOR_memory_op(op, &reservation); - if (tmp_ret < 0) { - if (ret == 0) { - ret = tmp_ret; - } - break; - } - if (tmp_ret == 0) { - //XXX dirty work around for skbuff_ctor() - // of a non-privileged domain, - if ((op == XENMEM_increase_reservation || - op == XENMEM_populate_physmap) && - !is_initial_xendomain() && - reservation.extent_order > 0) - return ret; - } - frame_list += tmp_ret; - nr_extents -= tmp_ret; - ret += tmp_ret; - } - return ret; -} -EXPORT_SYMBOL(ia64_xenmem_reservation_op); +#ifdef CONFIG_XEN_IA64_EXPOSE_P2M +static int p2m_expose_init(void); +#else +#define p2m_expose_init() (-ENOSYS) +#endif //XXX same as i386, x86_64 contiguous_bitmap_set(), contiguous_bitmap_clear() // move those to lib/contiguous_bitmap? @@ -371,8 +323,6 @@ gnttab_map_grant_ref_pre(struct gnttab_map_grant_ref *uop) int HYPERVISOR_grant_table_op(unsigned int cmd, void *uop, unsigned int count) { - __u64 va1, va2, pa1, pa2; - if (cmd == GNTTABOP_map_grant_ref) { unsigned int i; for (i = 0; i < count; i++) { @@ -380,29 +330,7 @@ HYPERVISOR_grant_table_op(unsigned int cmd, void *uop, unsigned int count) (struct gnttab_map_grant_ref*)uop + i); } } - va1 = (__u64)uop & PAGE_MASK; - pa1 = pa2 = 0; - if ((REGION_NUMBER(va1) == 5) && - ((va1 - KERNEL_START) >= KERNEL_TR_PAGE_SIZE)) { - pa1 = ia64_tpa(va1); - if (cmd <= GNTTABOP_transfer) { - static uint32_t uop_size[GNTTABOP_transfer + 1] = { - sizeof(struct gnttab_map_grant_ref), - sizeof(struct gnttab_unmap_grant_ref), - sizeof(struct gnttab_setup_table), - sizeof(struct gnttab_dump_table), - sizeof(struct gnttab_transfer), - }; - va2 = (__u64)uop + (uop_size[cmd] * count) - 1; - va2 &= PAGE_MASK; - if (va1 != va2) { - /* maximum size of uop is 2pages */ - BUG_ON(va2 > va1 + PAGE_SIZE); - pa2 = ia64_tpa(va2); - } - } - } - return ____HYPERVISOR_grant_table_op(cmd, uop, count, pa1, pa2); + return xencomm_mini_hypercall_grant_table_op(cmd, uop, count); } EXPORT_SYMBOL(HYPERVISOR_grant_table_op); @@ -526,6 +454,10 @@ out: privcmd_resource_min, privcmd_resource_max, (privcmd_resource_max - privcmd_resource_min) >> 20); BUG_ON(privcmd_resource_min >= privcmd_resource_max); + + // XXX this should be somewhere appropriate + (void)p2m_expose_init(); + return 0; } late_initcall(xen_ia64_privcmd_init); @@ -845,3 +777,276 @@ time_resume(void) /* Just trigger a tick. */ ia64_cpu_local_tick(); } + +/////////////////////////////////////////////////////////////////////////// +// expose p2m table +#ifdef CONFIG_XEN_IA64_EXPOSE_P2M +#include <linux/cpu.h> +#include <asm/uaccess.h> + +int p2m_initialized __read_mostly = 0; + +unsigned long p2m_min_low_pfn __read_mostly; +unsigned long p2m_max_low_pfn __read_mostly; +unsigned long p2m_convert_min_pfn __read_mostly; +unsigned long p2m_convert_max_pfn __read_mostly; + +static struct resource p2m_resource = { + .name = "Xen p2m table", + .flags = IORESOURCE_MEM, +}; +static unsigned long p2m_assign_start_pfn __read_mostly; +static unsigned long p2m_assign_end_pfn __read_mostly; +volatile const pte_t* p2m_pte __read_mostly; + +#define GRNULE_PFN PTRS_PER_PTE +static unsigned long p2m_granule_pfn __read_mostly = GRNULE_PFN; + +#define ROUNDDOWN(x, y) ((x) & ~((y) - 1)) +#define ROUNDUP(x, y) (((x) + (y) - 1) & ~((y) - 1)) + +#define P2M_PREFIX "Xen p2m: " + +static int xen_ia64_p2m_expose __read_mostly = 1; +module_param(xen_ia64_p2m_expose, int, 0); +MODULE_PARM_DESC(xen_ia64_p2m_expose, + "enable/disable xen/ia64 p2m exposure optimization\n"); + +#ifdef CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR +static int xen_ia64_p2m_expose_use_dtr __read_mostly = 1; +module_param(xen_ia64_p2m_expose_use_dtr, int, 0); +MODULE_PARM_DESC(xen_ia64_p2m_expose_use_dtr, + "use/unuse dtr to map exposed p2m table\n"); + +static const int p2m_page_shifts[] = { + _PAGE_SIZE_4K, + _PAGE_SIZE_8K, + _PAGE_SIZE_16K, + _PAGE_SIZE_64K, + _PAGE_SIZE_256K, + _PAGE_SIZE_1M, + _PAGE_SIZE_4M, + _PAGE_SIZE_16M, + _PAGE_SIZE_64M, + _PAGE_SIZE_256M, +}; + +struct p2m_itr_arg { + unsigned long vaddr; + unsigned long pteval; + unsigned long log_page_size; +}; +static struct p2m_itr_arg p2m_itr_arg __read_mostly; + +// This should be in asm-ia64/kregs.h +#define IA64_TR_P2M_TABLE 3 + +static void +p2m_itr(void* info) +{ + struct p2m_itr_arg* arg = (struct p2m_itr_arg*)info; + ia64_itr(0x2, IA64_TR_P2M_TABLE, + arg->vaddr, arg->pteval, arg->log_page_size); + ia64_srlz_d(); +} + +static int +p2m_expose_dtr_call(struct notifier_block *self, + unsigned long event, void* ptr) +{ + unsigned int cpu = (unsigned int)(long)ptr; + if (event != CPU_ONLINE) + return 0; + if (!(p2m_initialized && xen_ia64_p2m_expose_use_dtr)) + smp_call_function_single(cpu, &p2m_itr, &p2m_itr_arg, 1, 1); + return 0; +} + +static struct notifier_block p2m_expose_dtr_hotplug_notifier = { + .notifier_call = p2m_expose_dtr_call, + .next = NULL, + .priority = 0 +}; +#endif + +static int +p2m_expose_init(void) +{ + unsigned long num_pfn; + unsigned long size = 0; + unsigned long p2m_size = 0; + unsigned long align = ~0UL; + int error = 0; +#ifdef CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR + int i; + unsigned long page_size; + unsigned long log_page_size = 0; +#endif + + if (!xen_ia64_p2m_expose) + return -ENOSYS; + if (p2m_initialized) + return 0; + +#ifdef CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR + error = register_cpu_notifier(&p2m_expose_dtr_hotplug_notifier); + if (error < 0) + return error; +#endif + + lock_cpu_hotplug(); + if (p2m_initialized) + goto out; + +#ifdef CONFIG_DISCONTIGMEM + p2m_min_low_pfn = min_low_pfn; + p2m_max_low_pfn = max_low_pfn; +#else + p2m_min_low_pfn = 0; + p2m_max_low_pfn = max_pfn; +#endif + +#ifdef CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR + if (xen_ia64_p2m_expose_use_dtr) { + unsigned long granule_pfn = 0; + p2m_size = p2m_max_low_pfn - p2m_min_low_pfn; + for (i = 0; + i < sizeof(p2m_page_shifts)/sizeof(p2m_page_shifts[0]); + i++) { + log_page_size = p2m_page_shifts[i]; + page_size = 1UL << log_page_size; + if (page_size < p2m_size) + continue; + + granule_pfn = max(page_size >> PAGE_SHIFT, + p2m_granule_pfn); + p2m_convert_min_pfn = ROUNDDOWN(p2m_min_low_pfn, + granule_pfn); + p2m_convert_max_pfn = ROUNDUP(p2m_max_low_pfn, + granule_pfn); + num_pfn = p2m_convert_max_pfn - p2m_convert_min_pfn; + size = num_pfn << PAGE_SHIFT; + p2m_size = num_pfn / PTRS_PER_PTE; + p2m_size = ROUNDUP(p2m_size, granule_pfn << PAGE_SHIFT); + if (p2m_size == page_size) + break; + } + if (p2m_size != page_size) { + printk(KERN_ERR "p2m_size != page_size\n"); + error = -EINVAL; + goto out; + } + align = max(privcmd_resource_align, granule_pfn << PAGE_SHIFT); + } else +#endif + { + BUG_ON(p2m_granule_pfn & (p2m_granule_pfn - 1)); + p2m_convert_min_pfn = ROUNDDOWN(p2m_min_low_pfn, + p2m_granule_pfn); + p2m_convert_max_pfn = ROUNDUP(p2m_max_low_pfn, p2m_granule_pfn); + num_pfn = p2m_convert_max_pfn - p2m_convert_min_pfn; + size = num_pfn << PAGE_SHIFT; + p2m_size = num_pfn / PTRS_PER_PTE; + p2m_size = ROUNDUP(p2m_size, p2m_granule_pfn << PAGE_SHIFT); + align = max(privcmd_resource_align, + p2m_granule_pfn << PAGE_SHIFT); + } + + // use privcmd region + error = allocate_resource(&iomem_resource, &p2m_resource, p2m_size, + privcmd_resource_min, privcmd_resource_max, + align, NULL, NULL); + if (error) { + printk(KERN_ERR P2M_PREFIX + "can't allocate region for p2m exposure " + "[0x%016lx, 0x%016lx) 0x%016lx\n", + p2m_convert_min_pfn, p2m_convert_max_pfn, p2m_size); + goto out; + } + + p2m_assign_start_pfn = p2m_resource.start >> PAGE_SHIFT; + p2m_assign_end_pfn = p2m_resource.end >> PAGE_SHIFT; + + error = HYPERVISOR_expose_p2m(p2m_convert_min_pfn, + p2m_assign_start_pfn, + size, p2m_granule_pfn); + if (error) { + printk(KERN_ERR P2M_PREFIX "failed expose p2m hypercall %d\n", + error); + printk(KERN_ERR P2M_PREFIX "conv 0x%016lx assign 0x%016lx " + "size 0x%016lx granule 0x%016lx\n", + p2m_convert_min_pfn, p2m_assign_start_pfn, + size, p2m_granule_pfn);; + release_resource(&p2m_resource); + goto out; + } + p2m_pte = (volatile const pte_t*)pfn_to_kaddr(p2m_assign_start_pfn); +#ifdef CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR + if (xen_ia64_p2m_expose_use_dtr) { + p2m_itr_arg.vaddr = (unsigned long)__va(p2m_assign_start_pfn + << PAGE_SHIFT); + p2m_itr_arg.pteval = pte_val(pfn_pte(p2m_assign_start_pfn, + PAGE_KERNEL)); + p2m_itr_arg.log_page_size = log_page_size; + smp_mb(); + smp_call_function(&p2m_itr, &p2m_itr_arg, 1, 1); + p2m_itr(&p2m_itr_arg); + } +#endif + smp_mb(); + p2m_initialized = 1; + printk(P2M_PREFIX "assign p2m table of [0x%016lx, 0x%016lx)\n", + p2m_convert_min_pfn << PAGE_SHIFT, + p2m_convert_max_pfn << PAGE_SHIFT); + printk(P2M_PREFIX "to [0x%016lx, 0x%016lx) (%ld KBytes)\n", + p2m_assign_start_pfn << PAGE_SHIFT, + p2m_assign_end_pfn << PAGE_SHIFT, + p2m_size / 1024); +out: + unlock_cpu_hotplug(); + return error; +} + +#ifdef notyet +void +p2m_expose_cleanup(void) +{ + BUG_ON(!p2m_initialized); +#ifdef CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR + unregister_cpu_notifier(&p2m_expose_dtr_hotplug_notifier); +#endif + release_resource(&p2m_resource); +} +#endif + +//XXX inlinize? +unsigned long +p2m_phystomach(unsigned long gpfn) +{ + volatile const pte_t* pte; + unsigned long mfn; + unsigned long pteval; + + if (!p2m_initialized || + gpfn < p2m_min_low_pfn || gpfn > p2m_max_low_pfn + /* || !pfn_valid(gpfn) */) + return INVALID_MFN; + pte = p2m_pte + (gpfn - p2m_convert_min_pfn); + + mfn = INVALID_MFN; + if (likely(__get_user(pteval, (unsigned long __user *)pte) == 0 && + pte_present(__pte(pteval)) && + pte_pfn(__pte(pteval)) != (INVALID_MFN >> PAGE_SHIFT))) + mfn = (pteval & _PFN_MASK) >> PAGE_SHIFT; + + return mfn; +} + +EXPORT_SYMBOL_GPL(p2m_initialized); +EXPORT_SYMBOL_GPL(p2m_min_low_pfn); +EXPORT_SYMBOL_GPL(p2m_max_low_pfn); +EXPORT_SYMBOL_GPL(p2m_convert_min_pfn); +EXPORT_SYMBOL_GPL(p2m_convert_max_pfn); +EXPORT_SYMBOL_GPL(p2m_pte); +EXPORT_SYMBOL_GPL(p2m_phystomach); +#endif diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/util.c b/linux-2.6-xen-sparse/arch/ia64/xen/util.c index 02dfaabc66..7df0c5f72c 100644 --- a/linux-2.6-xen-sparse/arch/ia64/xen/util.c +++ b/linux-2.6-xen-sparse/arch/ia64/xen/util.c @@ -28,6 +28,8 @@ #include <linux/vmalloc.h> #include <asm/uaccess.h> #include <xen/driver_util.h> +#include <xen/interface/memory.h> +#include <asm/hypercall.h> struct vm_struct *alloc_vm_area(unsigned long size) { diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/xcom_hcall.c b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_hcall.c new file mode 100644 index 0000000000..01842ba34a --- /dev/null +++ b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_hcall.c @@ -0,0 +1,273 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Tristan Gingold <tristan.gingold@bull.net> + */ +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/gfp.h> +#include <linux/module.h> +#include <xen/interface/xen.h> +#include <xen/interface/dom0_ops.h> +#include <xen/interface/memory.h> +#include <xen/interface/xencomm.h> +#include <xen/interface/version.h> +#include <xen/interface/sched.h> +#include <xen/interface/event_channel.h> +#include <xen/interface/physdev.h> +#include <xen/interface/grant_table.h> +#include <xen/interface/callback.h> +#include <xen/interface/acm_ops.h> +#include <xen/interface/hvm/params.h> +#include <asm/hypercall.h> +#include <asm/page.h> +#include <asm/uaccess.h> +#include <asm/xen/xencomm.h> + +/* Xencomm notes: + * This file defines hypercalls to be used by xencomm. The hypercalls simply + * create inlines descriptors for pointers and then call the raw arch hypercall + * xencomm_arch_hypercall_XXX + * + * If the arch wants to directly use these hypercalls, simply define macros + * in asm/hypercall.h, eg: + * #define HYPERVISOR_sched_op xencomm_hypercall_sched_op + * + * The arch may also define HYPERVISOR_xxx as a function and do more operations + * before/after doing the hypercall. + * + * Note: because only inline descriptors are created these functions must only + * be called with in kernel memory parameters. + */ + +int +xencomm_hypercall_console_io(int cmd, int count, char *str) +{ + return xencomm_arch_hypercall_console_io + (cmd, count, xencomm_create_inline(str)); +} + +int +xencomm_hypercall_event_channel_op(int cmd, void *op) +{ + return xencomm_arch_hypercall_event_channel_op + (cmd, xencomm_create_inline(op)); +} + +int +xencomm_hypercall_xen_version(int cmd, void *arg) +{ + switch (cmd) { + case XENVER_version: + case XENVER_extraversion: + case XENVER_compile_info: + case XENVER_capabilities: + case XENVER_changeset: + case XENVER_platform_parameters: + case XENVER_pagesize: + case XENVER_get_features: + break; + default: + printk("%s: unknown version cmd %d\n", __func__, cmd); + return -ENOSYS; + } + + return xencomm_arch_hypercall_xen_version + (cmd, xencomm_create_inline(arg)); +} + +int +xencomm_hypercall_physdev_op(int cmd, void *op) +{ + return xencomm_arch_hypercall_physdev_op + (cmd, xencomm_create_inline(op)); +} + +static void * +xencommize_grant_table_op(unsigned int cmd, void *op, unsigned int count) +{ + switch (cmd) { + case GNTTABOP_map_grant_ref: + case GNTTABOP_unmap_grant_ref: + break; + case GNTTABOP_setup_table: + { + struct gnttab_setup_table *setup = op; + struct xencomm_handle *frame_list; + + frame_list = xencomm_create_inline + (xen_guest_handle(setup->frame_list)); + + set_xen_guest_handle(setup->frame_list, (void *)frame_list); + break; + } + case GNTTABOP_dump_table: + case GNTTABOP_transfer: + case GNTTABOP_copy: + break; + default: + printk("%s: unknown grant table op %d\n", __func__, cmd); + BUG(); + } + + return xencomm_create_inline(op); +} + +int +xencomm_hypercall_grant_table_op(unsigned int cmd, void *op, unsigned int count) +{ + void *desc = xencommize_grant_table_op (cmd, op, count); + + return xencomm_arch_hypercall_grant_table_op(cmd, desc, count); +} + +int +xencomm_hypercall_sched_op(int cmd, void *arg) +{ + switch (cmd) { + case SCHEDOP_yield: + case SCHEDOP_block: + case SCHEDOP_shutdown: + case SCHEDOP_remote_shutdown: + break; + case SCHEDOP_poll: + { + sched_poll_t *poll = arg; + struct xencomm_handle *ports; + + ports = xencomm_create_inline(xen_guest_handle(poll->ports)); + + set_xen_guest_handle(poll->ports, (void *)ports); + break; + } + default: + printk("%s: unknown sched op %d\n", __func__, cmd); + return -ENOSYS; + } + + return xencomm_arch_hypercall_sched_op(cmd, xencomm_create_inline(arg)); +} + +int +xencomm_hypercall_multicall(void *call_list, int nr_calls) +{ + int i; + multicall_entry_t *mce; + + for (i = 0; i < nr_calls; i++) { + mce = (multicall_entry_t *)call_list + i; + + switch (mce->op) { + case __HYPERVISOR_update_va_mapping: + case __HYPERVISOR_mmu_update: + /* No-op on ia64. */ + break; + case __HYPERVISOR_grant_table_op: + mce->args[1] = (unsigned long)xencommize_grant_table_op + (mce->args[0], (void *)mce->args[1], + mce->args[2]); + break; + case __HYPERVISOR_memory_op: + default: + printk("%s: unhandled multicall op entry op %lu\n", + __func__, mce->op); + return -ENOSYS; + } + } + + return xencomm_arch_hypercall_multicall + (xencomm_create_inline(call_list), nr_calls); +} + +int +xencomm_hypercall_callback_op(int cmd, void *arg) +{ + switch (cmd) + { + case CALLBACKOP_register: + case CALLBACKOP_unregister: + break; + default: + printk("%s: unknown callback op %d\n", __func__, cmd); + return -ENOSYS; + } + + return xencomm_arch_hypercall_callback_op + (cmd, xencomm_create_inline(arg)); +} + +static void +xencommize_memory_reservation (xen_memory_reservation_t *mop) +{ + struct xencomm_handle *desc; + + desc = xencomm_create_inline(xen_guest_handle(mop->extent_start)); + set_xen_guest_handle(mop->extent_start, (void *)desc); +} + +int +xencomm_hypercall_memory_op(unsigned int cmd, void *arg) +{ + switch (cmd) { + case XENMEM_increase_reservation: + case XENMEM_decrease_reservation: + case XENMEM_populate_physmap: + xencommize_memory_reservation((xen_memory_reservation_t *)arg); + break; + + case XENMEM_maximum_ram_page: + break; + + case XENMEM_exchange: + xencommize_memory_reservation + (&((xen_memory_exchange_t *)arg)->in); + xencommize_memory_reservation + (&((xen_memory_exchange_t *)arg)->out); + break; + + default: + printk("%s: unknown memory op %d\n", __func__, cmd); + return -ENOSYS; + } + + return xencomm_arch_hypercall_memory_op + (cmd, xencomm_create_inline(arg)); +} + +unsigned long +xencomm_hypercall_hvm_op(int cmd, void *arg) +{ + switch (cmd) { + case HVMOP_set_param: + case HVMOP_get_param: + break; + default: + printk("%s: unknown hvm op %d\n", __func__, cmd); + return -ENOSYS; + } + + return xencomm_arch_hypercall_hvm_op(cmd, xencomm_create_inline(arg)); +} + +int +xencomm_hypercall_suspend(unsigned long srec) +{ + struct sched_shutdown arg; + + arg.reason = SHUTDOWN_suspend; + + return xencomm_arch_hypercall_suspend(xencomm_create_inline(&arg)); +} diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c new file mode 100644 index 0000000000..5adec0c325 --- /dev/null +++ b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_mini.c @@ -0,0 +1,319 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Tristan Gingold <tristan.gingold@bull.net> + */ +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <xen/interface/xen.h> +#include <xen/interface/dom0_ops.h> +#include <xen/interface/memory.h> +#include <xen/interface/xencomm.h> +#include <xen/interface/version.h> +#include <xen/interface/event_channel.h> +#include <xen/interface/physdev.h> +#include <xen/interface/grant_table.h> +#include <xen/interface/hvm/params.h> +#ifdef CONFIG_VMX_GUEST +#include <asm/hypervisor.h> +#else +#include <asm/hypercall.h> +#endif +#include <asm/xen/xencomm.h> + +int +xencomm_mini_hypercall_event_channel_op(int cmd, void *op) +{ + struct xencomm_mini xc_area[2]; + int nbr_area = 2; + struct xencomm_handle *desc; + int rc; + + rc = xencomm_create_mini(xc_area, &nbr_area, + op, sizeof(evtchn_op_t), &desc); + if (rc) + return rc; + + return xencomm_arch_hypercall_event_channel_op(cmd, desc); +} +EXPORT_SYMBOL(xencomm_mini_hypercall_event_channel_op); + +static int +xencommize_mini_grant_table_op(struct xencomm_mini *xc_area, int *nbr_area, + unsigned int cmd, void *op, unsigned int count, + struct xencomm_handle **desc) +{ + struct xencomm_handle *desc1; + unsigned int argsize; + int rc; + + switch (cmd) { + case GNTTABOP_map_grant_ref: + argsize = sizeof(struct gnttab_map_grant_ref); + break; + case GNTTABOP_unmap_grant_ref: + argsize = sizeof(struct gnttab_unmap_grant_ref); + break; + case GNTTABOP_setup_table: + { + struct gnttab_setup_table *setup = op; + + argsize = sizeof(*setup); + + if (count != 1) + return -EINVAL; + rc = xencomm_create_mini + (xc_area, nbr_area, + xen_guest_handle(setup->frame_list), + setup->nr_frames + * sizeof(*xen_guest_handle(setup->frame_list)), + &desc1); + if (rc) + return rc; + set_xen_guest_handle(setup->frame_list, (void *)desc1); + break; + } + case GNTTABOP_dump_table: + argsize = sizeof(struct gnttab_dump_table); + break; + case GNTTABOP_transfer: + argsize = sizeof(struct gnttab_transfer); + break; + default: + printk("%s: unknown mini grant table op %d\n", __func__, cmd); + BUG(); + } + + rc = xencomm_create_mini(xc_area, nbr_area, op, count * argsize, desc); + if (rc) + return rc; + + return 0; +} + +int +xencomm_mini_hypercall_grant_table_op(unsigned int cmd, void *op, + unsigned int count) +{ + int rc; + struct xencomm_handle *desc; + int nbr_area = 2; + struct xencomm_mini xc_area[2]; + + rc = xencommize_mini_grant_table_op(xc_area, &nbr_area, + cmd, op, count, &desc); + if (rc) + return rc; + + return xencomm_arch_hypercall_grant_table_op(cmd, desc, count); +} +EXPORT_SYMBOL(xencomm_mini_hypercall_grant_table_op); + +int +xencomm_mini_hypercall_multicall(void *call_list, int nr_calls) +{ + int i; + multicall_entry_t *mce; + int nbr_area = 2 + nr_calls * 3; + struct xencomm_mini xc_area[nbr_area]; + struct xencomm_handle *desc; + int rc; + + for (i = 0; i < nr_calls; i++) { + mce = (multicall_entry_t *)call_list + i; + + switch (mce->op) { + case __HYPERVISOR_update_va_mapping: + case __HYPERVISOR_mmu_update: + /* No-op on ia64. */ + break; + case __HYPERVISOR_grant_table_op: + rc = xencommize_mini_grant_table_op + (xc_area, &nbr_area, + mce->args[0], (void *)mce->args[1], + mce->args[2], &desc); + if (rc) + return rc; + mce->args[1] = (unsigned long)desc; + break; + case __HYPERVISOR_memory_op: + default: + printk("%s: unhandled multicall op entry op %lu\n", + __func__, mce->op); + return -ENOSYS; + } + } + + rc = xencomm_create_mini(xc_area, &nbr_area, call_list, + nr_calls * sizeof(multicall_entry_t), &desc); + if (rc) + return rc; + + return xencomm_arch_hypercall_multicall(desc, nr_calls); +} +EXPORT_SYMBOL(xencomm_mini_hypercall_multicall); + +static int +xencommize_mini_memory_reservation(struct xencomm_mini *area, int *nbr_area, + xen_memory_reservation_t *mop) +{ + struct xencomm_handle *desc; + int rc; + + rc = xencomm_create_mini + (area, nbr_area, + xen_guest_handle(mop->extent_start), + mop->nr_extents + * sizeof(*xen_guest_handle(mop->extent_start)), + &desc); + if (rc) + return rc; + + set_xen_guest_handle(mop->extent_start, (void *)desc); + + return 0; +} + +int +xencomm_mini_hypercall_memory_op(unsigned int cmd, void *arg) +{ + int nbr_area = 4; + struct xencomm_mini xc_area[4]; + struct xencomm_handle *desc; + int rc; + unsigned int argsize; + + switch (cmd) { + case XENMEM_increase_reservation: + case XENMEM_decrease_reservation: + case XENMEM_populate_physmap: + argsize = sizeof(xen_memory_reservation_t); + rc = xencommize_mini_memory_reservation + (xc_area, &nbr_area, (xen_memory_reservation_t *)arg); + if (rc) + return rc; + break; + + case XENMEM_maximum_ram_page: + argsize = 0; + break; + + case XENMEM_exchange: + argsize = sizeof(xen_memory_exchange_t); + rc = xencommize_mini_memory_reservation + (xc_area, &nbr_area, + &((xen_memory_exchange_t *)arg)->in); + if (rc) + return rc; + rc = xencommize_mini_memory_reservation + (xc_area, &nbr_area, + &((xen_memory_exchange_t *)arg)->out); + if (rc) + return rc; + break; + + case XENMEM_add_to_physmap: + argsize = sizeof (xen_add_to_physmap_t); + break; + + default: + printk("%s: unknown mini memory op %d\n", __func__, cmd); + return -ENOSYS; + } + + rc = xencomm_create_mini(xc_area, &nbr_area, arg, argsize, &desc); + if (rc) + return rc; + + return xencomm_arch_hypercall_memory_op(cmd, desc); +} +EXPORT_SYMBOL(xencomm_mini_hypercall_memory_op); + +unsigned long +xencomm_mini_hypercall_hvm_op(int cmd, void *arg) +{ + struct xencomm_handle *desc; + int nbr_area = 2; + struct xencomm_mini xc_area[2]; + unsigned int argsize; + int rc; + + switch (cmd) { + case HVMOP_get_param: + case HVMOP_set_param: + argsize = sizeof(xen_hvm_param_t); + break; + default: + printk("%s: unknown HVMOP %d\n", __func__, cmd); + return -EINVAL; + } + + rc = xencomm_create_mini(xc_area, &nbr_area, arg, argsize, &desc); + if (rc) + return rc; + + return xencomm_arch_hypercall_hvm_op(cmd, desc); +} +EXPORT_SYMBOL(xencomm_mini_hypercall_hvm_op); + +int +xencomm_mini_hypercall_xen_version(int cmd, void *arg) +{ + struct xencomm_handle *desc; + int nbr_area = 2; + struct xencomm_mini xc_area[2]; + unsigned int argsize; + int rc; + + switch (cmd) { + case XENVER_version: + /* do not actually pass an argument */ + return xencomm_arch_hypercall_xen_version(cmd, 0); + case XENVER_extraversion: + argsize = sizeof(xen_extraversion_t); + break; + case XENVER_compile_info: + argsize = sizeof(xen_compile_info_t); + break; + case XENVER_capabilities: + argsize = sizeof(xen_capabilities_info_t); + break; + case XENVER_changeset: + argsize = sizeof(xen_changeset_info_t); + break; + case XENVER_platform_parameters: + argsize = sizeof(xen_platform_parameters_t); + break; + case XENVER_pagesize: + argsize = (arg == NULL) ? 0 : sizeof(void *); + break; + case XENVER_get_features: + argsize = (arg == NULL) ? 0 : sizeof(xen_feature_info_t); + break; + + default: + printk("%s: unknown version op %d\n", __func__, cmd); + return -ENOSYS; + } + + rc = xencomm_create_mini(xc_area, &nbr_area, arg, argsize, &desc); + if (rc) + return rc; + + return xencomm_arch_hypercall_xen_version(cmd, desc); +} +EXPORT_SYMBOL(xencomm_mini_hypercall_xen_version); diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/xcom_privcmd.c b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_privcmd.c new file mode 100644 index 0000000000..c11fe1ec05 --- /dev/null +++ b/linux-2.6-xen-sparse/arch/ia64/xen/xcom_privcmd.c @@ -0,0 +1,600 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Authors: Hollis Blanchard <hollisb@us.ibm.com> + * Tristan Gingold <tristan.gingold@bull.net> + */ +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/kernel.h> +#include <linux/gfp.h> +#include <linux/module.h> +#include <xen/interface/xen.h> +#include <xen/interface/dom0_ops.h> +#define __XEN__ +#include <xen/interface/domctl.h> +#include <xen/interface/sysctl.h> +#include <xen/interface/memory.h> +#include <xen/interface/version.h> +#include <xen/interface/event_channel.h> +#include <xen/interface/acm_ops.h> +#include <xen/interface/hvm/params.h> +#include <xen/public/privcmd.h> +#include <asm/hypercall.h> +#include <asm/page.h> +#include <asm/uaccess.h> +#include <asm/xen/xencomm.h> + +#define ROUND_DIV(v,s) (((v) + (s) - 1) / (s)) + +static int +xencomm_privcmd_dom0_op(privcmd_hypercall_t *hypercall) +{ + dom0_op_t kern_op; + dom0_op_t __user *user_op = (dom0_op_t __user *)hypercall->arg[0]; + struct xencomm_handle *op_desc; + struct xencomm_handle *desc = NULL; + int ret = 0; + + if (copy_from_user(&kern_op, user_op, sizeof(dom0_op_t))) + return -EFAULT; + + if (kern_op.interface_version != DOM0_INTERFACE_VERSION) + return -EACCES; + + op_desc = xencomm_create_inline(&kern_op); + + switch (kern_op.cmd) { + default: + printk("%s: unknown dom0 cmd %d\n", __func__, kern_op.cmd); + return -ENOSYS; + } + + if (ret) { + /* error mapping the nested pointer */ + return ret; + } + + ret = xencomm_arch_hypercall_dom0_op(op_desc); + + /* FIXME: should we restore the handle? */ + if (copy_to_user(user_op, &kern_op, sizeof(dom0_op_t))) + ret = -EFAULT; + + if (desc) + xencomm_free(desc); + return ret; +} + +static int +xencomm_privcmd_sysctl(privcmd_hypercall_t *hypercall) +{ + xen_sysctl_t kern_op; + xen_sysctl_t __user *user_op; + struct xencomm_handle *op_desc; + struct xencomm_handle *desc = NULL; + struct xencomm_handle *desc1 = NULL; + int ret = 0; + + user_op = (xen_sysctl_t __user *)hypercall->arg[0]; + + if (copy_from_user(&kern_op, user_op, sizeof(xen_sysctl_t))) + return -EFAULT; + + if (kern_op.interface_version != XEN_SYSCTL_INTERFACE_VERSION) + return -EACCES; + + op_desc = xencomm_create_inline(&kern_op); + + switch (kern_op.cmd) { + case XEN_SYSCTL_readconsole: + ret = xencomm_create( + xen_guest_handle(kern_op.u.readconsole.buffer), + kern_op.u.readconsole.count, + &desc, GFP_KERNEL); + set_xen_guest_handle(kern_op.u.readconsole.buffer, + (void *)desc); + break; + case XEN_SYSCTL_tbuf_op: + case XEN_SYSCTL_physinfo: + case XEN_SYSCTL_sched_id: + break; + case XEN_SYSCTL_perfc_op: + ret = xencomm_create( + xen_guest_handle(kern_op.u.perfc_op.desc), + kern_op.u.perfc_op.nr_counters * + sizeof(xen_sysctl_perfc_desc_t), + &desc, GFP_KERNEL); + if (ret) + return ret; + set_xen_guest_handle(kern_op.u.perfc_op.val, + (void *)desc); + ret = xencomm_create( + xen_guest_handle(kern_op.u.perfc_op.val), + kern_op.u.perfc_op.nr_vals * + sizeof(xen_sysctl_perfc_desc_t), + &desc1, GFP_KERNEL); + if (ret) + xencomm_free(desc); + set_xen_guest_handle(kern_op.u.perfc_op.val, + (void *)desc1); + break; + case XEN_SYSCTL_getdomaininfolist: + ret = xencomm_create( + xen_guest_handle(kern_op.u.getdomaininfolist.buffer), + kern_op.u.getdomaininfolist.max_domains * + sizeof(xen_domctl_getdomaininfo_t), + &desc, GFP_KERNEL); + set_xen_guest_handle(kern_op.u.getdomaininfolist.buffer, + (void *)desc); + break; + default: + printk("%s: unknown sysctl cmd %d\n", __func__, kern_op.cmd); + return -ENOSYS; + } + + if (ret) { + /* error mapping the nested pointer */ + return ret; + } + + ret = xencomm_arch_hypercall_sysctl(op_desc); + + /* FIXME: should we restore the handle? */ + if (copy_to_user(user_op, &kern_op, sizeof(xen_sysctl_t))) + ret = -EFAULT; + + if (desc) + xencomm_free(desc); + if (desc1) + xencomm_free(desc1); + return ret; +} + +static int +xencomm_privcmd_domctl(privcmd_hypercall_t *hypercall) +{ + xen_domctl_t kern_op; + xen_domctl_t __user *user_op; + struct xencomm_handle *op_desc; + struct xencomm_handle *desc = NULL; + int ret = 0; + + user_op = (xen_domctl_t __user *)hypercall->arg[0]; + + if (copy_from_user(&kern_op, user_op, sizeof(xen_domctl_t))) + return -EFAULT; + + if (kern_op.interface_version != XEN_DOMCTL_INTERFACE_VERSION) + return -EACCES; + + op_desc = xencomm_create_inline(&kern_op); + + switch (kern_op.cmd) { + case XEN_DOMCTL_createdomain: + case XEN_DOMCTL_destroydomain: + case XEN_DOMCTL_pausedomain: + case XEN_DOMCTL_unpausedomain: + case XEN_DOMCTL_getdomaininfo: + break; + case XEN_DOMCTL_getmemlist: + { + unsigned long nr_pages = kern_op.u.getmemlist.max_pfns; + + ret = xencomm_create( + xen_guest_handle(kern_op.u.getmemlist.buffer), + nr_pages * sizeof(unsigned long), + &desc, GFP_KERNEL); + set_xen_guest_handle(kern_op.u.getmemlist.buffer, + (void *)desc); + break; + } + case XEN_DOMCTL_getpageframeinfo: + break; + case XEN_DOMCTL_getpageframeinfo2: + ret = xencomm_create( + xen_guest_handle(kern_op.u.getpageframeinfo2.array), + kern_op.u.getpageframeinfo2.num, + &desc, GFP_KERNEL); + set_xen_guest_handle(kern_op.u.getpageframeinfo2.array, + (void *)desc); + break; + case XEN_DOMCTL_shadow_op: + ret = xencomm_create( + xen_guest_handle(kern_op.u.shadow_op.dirty_bitmap), + ROUND_DIV(kern_op.u.shadow_op.pages, 8), + &desc, GFP_KERNEL); + set_xen_guest_handle(kern_op.u.shadow_op.dirty_bitmap, + (void *)desc); + break; + case XEN_DOMCTL_max_mem: + break; + case XEN_DOMCTL_setvcpucontext: + case XEN_DOMCTL_getvcpucontext: + ret = xencomm_create( + xen_guest_handle(kern_op.u.vcpucontext.ctxt), + sizeof(vcpu_guest_context_t), + &desc, GFP_KERNEL); + set_xen_guest_handle(kern_op.u.vcpucontext.ctxt, (void *)desc); + break; + case XEN_DOMCTL_getvcpuinfo: + break; + case XEN_DOMCTL_setvcpuaffinity: + case XEN_DOMCTL_getvcpuaffinity: + ret = xencomm_create( + xen_guest_handle(kern_op.u.vcpuaffinity.cpumap.bitmap), + ROUND_DIV(kern_op.u.vcpuaffinity.cpumap.nr_cpus, 8), + &desc, GFP_KERNEL); + set_xen_guest_handle(kern_op.u.vcpuaffinity.cpumap.bitmap, + (void *)desc); + break; + case XEN_DOMCTL_max_vcpus: + case XEN_DOMCTL_scheduler_op: + case XEN_DOMCTL_setdomainhandle: + case XEN_DOMCTL_setdebugging: + case XEN_DOMCTL_irq_permission: + case XEN_DOMCTL_iomem_permission: + case XEN_DOMCTL_ioport_permission: + case XEN_DOMCTL_hypercall_init: + case XEN_DOMCTL_arch_setup: + case XEN_DOMCTL_settimeoffset: + break; + default: + printk("%s: unknown domctl cmd %d\n", __func__, kern_op.cmd); + return -ENOSYS; + } + + if (ret) { + /* error mapping the nested pointer */ + return ret; + } + + ret = xencomm_arch_hypercall_domctl (op_desc); + + /* FIXME: should we restore the handle? */ + if (copy_to_user(user_op, &kern_op, sizeof(xen_domctl_t))) + ret = -EFAULT; + + if (desc) + xencomm_free(desc); + return ret; +} + +static int +xencomm_privcmd_acm_op(privcmd_hypercall_t *hypercall) +{ + int cmd = hypercall->arg[0]; + void __user *arg = (void __user *)hypercall->arg[1]; + struct xencomm_handle *op_desc; + struct xencomm_handle *desc = NULL; + int ret; + + switch (cmd) { + case ACMOP_getssid: + { + struct acm_getssid kern_arg; + + if (copy_from_user(&kern_arg, arg, sizeof (kern_arg))) + return -EFAULT; + + op_desc = xencomm_create_inline(&kern_arg); + + ret = xencomm_create(xen_guest_handle(kern_arg.ssidbuf), + kern_arg.ssidbuf_size, &desc, GFP_KERNEL); + if (ret) + return ret; + + set_xen_guest_handle(kern_arg.ssidbuf, (void *)desc); + + ret = xencomm_arch_hypercall_acm_op(cmd, op_desc); + + xencomm_free(desc); + + if (copy_to_user(arg, &kern_arg, sizeof (kern_arg))) + return -EFAULT; + + return ret; + } + default: + printk("%s: unknown acm_op cmd %d\n", __func__, cmd); + return -ENOSYS; + } + + return ret; +} + +static int +xencomm_privcmd_memory_op(privcmd_hypercall_t *hypercall) +{ + const unsigned long cmd = hypercall->arg[0]; + int ret = 0; + + switch (cmd) { + case XENMEM_increase_reservation: + case XENMEM_decrease_reservation: + case XENMEM_populate_physmap: + { + xen_memory_reservation_t kern_op; + xen_memory_reservation_t __user *user_op; + struct xencomm_handle *desc = NULL; + struct xencomm_handle *desc_op; + + user_op = (xen_memory_reservation_t __user *)hypercall->arg[1]; + if (copy_from_user(&kern_op, user_op, + sizeof(xen_memory_reservation_t))) + return -EFAULT; + desc_op = xencomm_create_inline(&kern_op); + + if (xen_guest_handle(kern_op.extent_start)) { + void * addr; + + addr = xen_guest_handle(kern_op.extent_start); + ret = xencomm_create + (addr, + kern_op.nr_extents * + sizeof(*xen_guest_handle + (kern_op.extent_start)), + &desc, GFP_KERNEL); + if (ret) + return ret; + set_xen_guest_handle(kern_op.extent_start, + (void *)desc); + } + + ret = xencomm_arch_hypercall_memory_op(cmd, desc_op); + + if (desc) + xencomm_free(desc); + + if (ret != 0) + return ret; + + if (copy_to_user(user_op, &kern_op, + sizeof(xen_memory_reservation_t))) + return -EFAULT; + + return ret; + } + case XENMEM_translate_gpfn_list: + { + xen_translate_gpfn_list_t kern_op; + xen_translate_gpfn_list_t __user *user_op; + struct xencomm_handle *desc_gpfn = NULL; + struct xencomm_handle *desc_mfn = NULL; + struct xencomm_handle *desc_op; + void *addr; + + user_op = (xen_translate_gpfn_list_t __user *) + hypercall->arg[1]; + if (copy_from_user(&kern_op, user_op, + sizeof(xen_translate_gpfn_list_t))) + return -EFAULT; + desc_op = xencomm_create_inline(&kern_op); + + if (kern_op.nr_gpfns) { + /* gpfn_list. */ + addr = xen_guest_handle(kern_op.gpfn_list); + + ret = xencomm_create(addr, kern_op.nr_gpfns * + sizeof(*xen_guest_handle + (kern_op.gpfn_list)), + &desc_gpfn, GFP_KERNEL); + if (ret) + return ret; + set_xen_guest_handle(kern_op.gpfn_list, + (void *)desc_gpfn); + + /* mfn_list. */ + addr = xen_guest_handle(kern_op.mfn_list); + + ret = xencomm_create(addr, kern_op.nr_gpfns * + sizeof(*xen_guest_handle + (kern_op.mfn_list)), + &desc_mfn, GFP_KERNEL); + if (ret) + return ret; + set_xen_guest_handle(kern_op.mfn_list, + (void *)desc_mfn); + } + + ret = xencomm_arch_hypercall_memory_op(cmd, desc_op); + + if (desc_gpfn) + xencomm_free(desc_gpfn); + + if (desc_mfn) + xencomm_free(desc_mfn); + + if (ret != 0) + return ret; + + return ret; + } + default: + printk("%s: unknown memory op %lu\n", __func__, cmd); + ret = -ENOSYS; + } + return ret; +} + +static int +xencomm_privcmd_xen_version(privcmd_hypercall_t *hypercall) +{ + int cmd = hypercall->arg[0]; + void __user *arg = (void __user *)hypercall->arg[1]; + struct xencomm_handle *desc; + size_t argsize; + int rc; + + switch (cmd) { + case XENVER_version: + /* do not actually pass an argument */ + return xencomm_arch_hypercall_xen_version(cmd, 0); + case XENVER_extraversion: + argsize = sizeof(xen_extraversion_t); + break; + case XENVER_compile_info: + argsize = sizeof(xen_compile_info_t); + break; + case XENVER_capabilities: + argsize = sizeof(xen_capabilities_info_t); + break; + case XENVER_changeset: + argsize = sizeof(xen_changeset_info_t); + break; + case XENVER_platform_parameters: + argsize = sizeof(xen_platform_parameters_t); + break; + case XENVER_pagesize: + argsize = (arg == NULL) ? 0 : sizeof(void *); + break; + case XENVER_get_features: + argsize = (arg == NULL) ? 0 : sizeof(xen_feature_info_t); + break; + + default: + printk("%s: unknown version op %d\n", __func__, cmd); + return -ENOSYS; + } + + rc = xencomm_create(arg, argsize, &desc, GFP_KERNEL); + if (rc) + return rc; + + rc = xencomm_arch_hypercall_xen_version(cmd, desc); + + xencomm_free(desc); + + return rc; +} + +static int +xencomm_privcmd_event_channel_op(privcmd_hypercall_t *hypercall) +{ + int cmd = hypercall->arg[0]; + struct xencomm_handle *desc; + unsigned int argsize; + int ret; + + switch (cmd) { + case EVTCHNOP_alloc_unbound: + argsize = sizeof(evtchn_alloc_unbound_t); + break; + + case EVTCHNOP_status: + argsize = sizeof(evtchn_status_t); + break; + + default: + printk("%s: unknown EVTCHNOP %d\n", __func__, cmd); + return -EINVAL; + } + + ret = xencomm_create((void *)hypercall->arg[1], argsize, + &desc, GFP_KERNEL); + if (ret) + return ret; + + ret = xencomm_arch_hypercall_event_channel_op(cmd, desc); + + xencomm_free(desc); + return ret; +} + +static int +xencomm_privcmd_hvm_op(privcmd_hypercall_t *hypercall) +{ + int cmd = hypercall->arg[0]; + struct xencomm_handle *desc; + unsigned int argsize; + int ret; + + switch (cmd) { + case HVMOP_get_param: + case HVMOP_set_param: + argsize = sizeof(xen_hvm_param_t); + break; + default: + printk("%s: unknown HVMOP %d\n", __func__, cmd); + return -EINVAL; + } + + ret = xencomm_create((void *)hypercall->arg[1], argsize, + &desc, GFP_KERNEL); + if (ret) + return ret; + + ret = xencomm_arch_hypercall_hvm_op(cmd, desc); + + xencomm_free(desc); + return ret; +} + +static int +xencomm_privcmd_sched_op(privcmd_hypercall_t *hypercall) +{ + int cmd = hypercall->arg[0]; + struct xencomm_handle *desc; + unsigned int argsize; + int ret; + + switch (cmd) { + case SCHEDOP_remote_shutdown: + argsize = sizeof(sched_remote_shutdown_t); + break; + default: + printk("%s: unknown SCHEDOP %d\n", __func__, cmd); + return -EINVAL; + } + + ret = xencomm_create((void *)hypercall->arg[1], argsize, + &desc, GFP_KERNEL); + if (ret) + return ret; + + ret = xencomm_arch_hypercall_sched_op(cmd, desc); + + xencomm_free(desc); + return ret; +} + +int +privcmd_hypercall(privcmd_hypercall_t *hypercall) +{ + switch (hypercall->op) { + case __HYPERVISOR_dom0_op: + return xencomm_privcmd_dom0_op(hypercall); + case __HYPERVISOR_domctl: + return xencomm_privcmd_domctl(hypercall); + case __HYPERVISOR_sysctl: + return xencomm_privcmd_sysctl(hypercall); + case __HYPERVISOR_acm_op: + return xencomm_privcmd_acm_op(hypercall); + case __HYPERVISOR_xen_version: + return xencomm_privcmd_xen_version(hypercall); + case __HYPERVISOR_memory_op: + return xencomm_privcmd_memory_op(hypercall); + case __HYPERVISOR_event_channel_op: + return xencomm_privcmd_event_channel_op(hypercall); + case __HYPERVISOR_hvm_op: + return xencomm_privcmd_hvm_op(hypercall); + case __HYPERVISOR_sched_op: + return xencomm_privcmd_sched_op(hypercall); + default: + printk("%s: unknown hcall (%ld)\n", __func__, hypercall->op); + return -ENOSYS; + } +} + diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/xencomm.c b/linux-2.6-xen-sparse/arch/ia64/xen/xencomm.c new file mode 100644 index 0000000000..3767e893fc --- /dev/null +++ b/linux-2.6-xen-sparse/arch/ia64/xen/xencomm.c @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2006 Hollis Blanchard <hollisb@us.ibm.com>, IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/gfp.h> +#include <linux/mm.h> +#include <xen/interface/xen.h> +#include <asm/page.h> +#include <asm/xen/xencomm.h> + +static int xencomm_debug = 0; + +static unsigned long kernel_start_pa; + +void +xencomm_init (void) +{ + kernel_start_pa = KERNEL_START - ia64_tpa(KERNEL_START); +} + +/* Translate virtual address to physical address. */ +unsigned long +xencomm_vaddr_to_paddr(unsigned long vaddr) +{ +#ifndef CONFIG_VMX_GUEST + struct page *page; + struct vm_area_struct *vma; +#endif + + if (vaddr == 0) + return 0; + +#ifdef __ia64__ + if (REGION_NUMBER(vaddr) == 5) { + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *ptep; + + /* On ia64, TASK_SIZE refers to current. It is not initialized + during boot. + Furthermore the kernel is relocatable and __pa() doesn't + work on addresses. */ + if (vaddr >= KERNEL_START + && vaddr < (KERNEL_START + KERNEL_TR_PAGE_SIZE)) { + return vaddr - kernel_start_pa; + } + + /* In kernel area -- virtually mapped. */ + pgd = pgd_offset_k(vaddr); + if (pgd_none(*pgd) || pgd_bad(*pgd)) + return ~0UL; + + pud = pud_offset(pgd, vaddr); + if (pud_none(*pud) || pud_bad(*pud)) + return ~0UL; + + pmd = pmd_offset(pud, vaddr); + if (pmd_none(*pmd) || pmd_bad(*pmd)) + return ~0UL; + + ptep = pte_offset_kernel(pmd, vaddr); + if (!ptep) + return ~0UL; + + return (pte_val(*ptep) & _PFN_MASK) | (vaddr & ~PAGE_MASK); + } +#endif + + if (vaddr > TASK_SIZE) { + /* kernel address */ + return __pa(vaddr); + } + + +#ifdef CONFIG_VMX_GUEST + /* No privcmd within vmx guest. */ + return ~0UL; +#else + /* XXX double-check (lack of) locking */ + vma = find_extend_vma(current->mm, vaddr); + if (!vma) + return ~0UL; + + /* We assume the page is modified. */ + page = follow_page(vma, vaddr, FOLL_WRITE | FOLL_TOUCH); + if (!page) + return ~0UL; + + return (page_to_pfn(page) << PAGE_SHIFT) | (vaddr & ~PAGE_MASK); +#endif +} + +static int +xencomm_init_desc(struct xencomm_desc *desc, void *buffer, unsigned long bytes) +{ + unsigned long recorded = 0; + int i = 0; + + BUG_ON((buffer == NULL) && (bytes > 0)); + + /* record the physical pages used */ + if (buffer == NULL) + desc->nr_addrs = 0; + + while ((recorded < bytes) && (i < desc->nr_addrs)) { + unsigned long vaddr = (unsigned long)buffer + recorded; + unsigned long paddr; + int offset; + int chunksz; + + offset = vaddr % PAGE_SIZE; /* handle partial pages */ + chunksz = min(PAGE_SIZE - offset, bytes - recorded); + + paddr = xencomm_vaddr_to_paddr(vaddr); + if (paddr == ~0UL) { + printk("%s: couldn't translate vaddr %lx\n", + __func__, vaddr); + return -EINVAL; + } + + desc->address[i++] = paddr; + recorded += chunksz; + } + + if (recorded < bytes) { + printk("%s: could only translate %ld of %ld bytes\n", + __func__, recorded, bytes); + return -ENOSPC; + } + + /* mark remaining addresses invalid (just for safety) */ + while (i < desc->nr_addrs) + desc->address[i++] = XENCOMM_INVALID; + + desc->magic = XENCOMM_MAGIC; + + return 0; +} + +static struct xencomm_desc * +xencomm_alloc(gfp_t gfp_mask) +{ + struct xencomm_desc *desc; + + desc = (struct xencomm_desc *)__get_free_page(gfp_mask); + if (desc == NULL) + panic("%s: page allocation failed\n", __func__); + + desc->nr_addrs = (PAGE_SIZE - sizeof(struct xencomm_desc)) / + sizeof(*desc->address); + + return desc; +} + +void +xencomm_free(struct xencomm_handle *desc) +{ + if (desc) + free_page((unsigned long)__va(desc)); +} + +int +xencomm_create(void *buffer, unsigned long bytes, + struct xencomm_handle **ret, gfp_t gfp_mask) +{ + struct xencomm_desc *desc; + struct xencomm_handle *handle; + int rc; + + if (xencomm_debug) + printk("%s: %p[%ld]\n", __func__, buffer, bytes); + + if (buffer == NULL || bytes == 0) { + *ret = (struct xencomm_handle *)NULL; + return 0; + } + + desc = xencomm_alloc(gfp_mask); + if (!desc) { + printk("%s failure\n", "xencomm_alloc"); + return -ENOMEM; + } + handle = (struct xencomm_handle *)__pa(desc); + + rc = xencomm_init_desc(desc, buffer, bytes); + if (rc) { + printk("%s failure: %d\n", "xencomm_init_desc", rc); + xencomm_free(handle); + return rc; + } + + *ret = handle; + return 0; +} + +/* "mini" routines, for stack-based communications: */ + +static void * +xencomm_alloc_mini(struct xencomm_mini *area, int *nbr_area) +{ + unsigned long base; + unsigned int pageoffset; + + while (*nbr_area >= 0) { + /* Allocate an area. */ + (*nbr_area)--; + + base = (unsigned long)(area + *nbr_area); + pageoffset = base % PAGE_SIZE; + + /* If the area does not cross a page, use it. */ + if ((PAGE_SIZE - pageoffset) >= sizeof(struct xencomm_mini)) + return &area[*nbr_area]; + } + /* No more area. */ + return NULL; +} + +int +xencomm_create_mini(struct xencomm_mini *area, int *nbr_area, + void *buffer, unsigned long bytes, + struct xencomm_handle **ret) +{ + struct xencomm_desc *desc; + int rc; + unsigned long res; + + desc = xencomm_alloc_mini(area, nbr_area); + if (!desc) + return -ENOMEM; + desc->nr_addrs = XENCOMM_MINI_ADDRS; + + rc = xencomm_init_desc(desc, buffer, bytes); + if (rc) + return rc; + + res = xencomm_vaddr_to_paddr((unsigned long)desc); + if (res == ~0UL) + return -EINVAL; + + *ret = (struct xencomm_handle*)res; + return 0; +} diff --git a/linux-2.6-xen-sparse/arch/ia64/xen/xensetup.S b/linux-2.6-xen-sparse/arch/ia64/xen/xensetup.S index 918622918e..e761278670 100644 --- a/linux-2.6-xen-sparse/arch/ia64/xen/xensetup.S +++ b/linux-2.6-xen-sparse/arch/ia64/xen/xensetup.S @@ -23,12 +23,11 @@ GLOBAL_ENTRY(early_xen_setup) mov cr.iva=r10 -#if XSI_BASE != 0xf100000000000000UL - /* Backward compatibility. */ -(isBP) mov r2=0x600 + /* Set xsi base. */ +#define FW_HYPERCALL_SET_SHARED_INFO_VA 0x600 +(isBP) mov r2=FW_HYPERCALL_SET_SHARED_INFO_VA (isBP) movl r28=XSI_BASE;; (isBP) break 0x1000;; -#endif br.ret.sptk.many rp ;; @@ -38,18 +37,18 @@ END(early_xen_setup) /* Stub for suspend. Just force the stacked registers to be written in memory. */ -GLOBAL_ENTRY(HYPERVISOR_suspend) +GLOBAL_ENTRY(xencomm_arch_hypercall_suspend) + mov r15=r32 + ;; alloc r20=ar.pfs,0,0,0,0 - mov r14=2 - mov r15=r12 - ;; + mov r2=__HYPERVISOR_sched_op + ;; /* We don't want to deal with RSE. */ flushrs - mov r2=__HYPERVISOR_sched_op - st4 [r12]=r14 + mov r14=2 // SCHEDOP_shutdown ;; break 0x1000 ;; mov ar.pfs=r20 br.ret.sptk.many b0 -END(HYPERVISOR_suspend) +END(xencomm_arch_hypercall_suspend) diff --git a/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c b/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c index ba67bec83e..a65b8744c2 100644 --- a/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c +++ b/linux-2.6-xen-sparse/drivers/xen/privcmd/privcmd.c @@ -87,18 +87,7 @@ static int privcmd_ioctl(struct inode *inode, struct file *file, : "r8", "r10", "memory" ); } #elif defined (__ia64__) - __asm__ __volatile__ ( - ";; mov r14=%2; mov r15=%3; " - "mov r16=%4; mov r17=%5; mov r18=%6;" - "mov r2=%1; break 0x1000;; mov %0=r8 ;;" - : "=r" (ret) - : "r" (hypercall.op), - "r" (hypercall.arg[0]), - "r" (hypercall.arg[1]), - "r" (hypercall.arg[2]), - "r" (hypercall.arg[3]), - "r" (hypercall.arg[4]) - : "r14","r15","r16","r17","r18","r2","r8","memory"); + ret = privcmd_hypercall(&hypercall); #endif } break; diff --git a/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h b/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h index 8375336941..43f88b1930 100644 --- a/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h +++ b/linux-2.6-xen-sparse/include/asm-ia64/hypercall.h @@ -33,12 +33,13 @@ #ifndef __HYPERCALL_H__ #define __HYPERCALL_H__ -#include <linux/string.h> /* memcpy() */ - #ifndef __HYPERVISOR_H__ # error "please don't include this file directly" #endif +#include <asm/xen/xcom_hcall.h> +struct xencomm_handle; + /* * Assembler stubs for hyper-calls. */ @@ -157,157 +158,117 @@ (type)__res; \ }) -static inline int -HYPERVISOR_sched_op_compat( - int cmd, unsigned long arg) -{ - return _hypercall2(int, sched_op_compat, cmd, arg); -} static inline int -HYPERVISOR_sched_op( - int cmd, void *arg) +xencomm_arch_hypercall_sched_op(int cmd, struct xencomm_handle *arg) { return _hypercall2(int, sched_op, cmd, arg); } static inline long -HYPERVISOR_set_timer_op( - u64 timeout) +HYPERVISOR_set_timer_op(u64 timeout) { - unsigned long timeout_hi = (unsigned long)(timeout>>32); - unsigned long timeout_lo = (unsigned long)timeout; - return _hypercall2(long, set_timer_op, timeout_lo, timeout_hi); + unsigned long timeout_hi = (unsigned long)(timeout >> 32); + unsigned long timeout_lo = (unsigned long)timeout; + return _hypercall2(long, set_timer_op, timeout_lo, timeout_hi); } static inline int -HYPERVISOR_dom0_op( - dom0_op_t *dom0_op) +xencomm_arch_hypercall_dom0_op(struct xencomm_handle *op) { - dom0_op->interface_version = DOM0_INTERFACE_VERSION; - return _hypercall1(int, dom0_op, dom0_op); + return _hypercall1(int, dom0_op, op); } static inline int -HYPERVISOR_multicall( - void *call_list, int nr_calls) +xencomm_arch_hypercall_sysctl(struct xencomm_handle *op) { - return _hypercall2(int, multicall, call_list, nr_calls); + return _hypercall1(int, sysctl, op); } -//XXX xen/ia64 copy_from_guest() is broken. -// This is a temporal work around until it is fixed. static inline int -____HYPERVISOR_memory_op( - unsigned int cmd, void *arg) +xencomm_arch_hypercall_domctl(struct xencomm_handle *op) { - return _hypercall2(int, memory_op, cmd, arg); + return _hypercall1(int, domctl, op); } -#include <xen/interface/memory.h> -#ifdef CONFIG_VMX_GUEST -# define ia64_xenmem_reservation_op(op, xmr) (0) -#else -int ia64_xenmem_reservation_op(unsigned long op, - struct xen_memory_reservation* reservation__); -#endif static inline int -HYPERVISOR_memory_op( - unsigned int cmd, void *arg) +xencomm_arch_hypercall_multicall(struct xencomm_handle *call_list, + int nr_calls) { - switch (cmd) { - case XENMEM_increase_reservation: - case XENMEM_decrease_reservation: - case XENMEM_populate_physmap: - return ia64_xenmem_reservation_op(cmd, - (struct xen_memory_reservation*)arg); - default: - return ____HYPERVISOR_memory_op(cmd, arg); - } - /* NOTREACHED */ + return _hypercall2(int, multicall, call_list, nr_calls); } static inline int -HYPERVISOR_event_channel_op( - int cmd, void *arg) +xencomm_arch_hypercall_memory_op(unsigned int cmd, struct xencomm_handle *arg) { - int rc = _hypercall2(int, event_channel_op, cmd, arg); - if (unlikely(rc == -ENOSYS)) { - struct evtchn_op op; - op.cmd = cmd; - memcpy(&op.u, arg, sizeof(op.u)); - rc = _hypercall1(int, event_channel_op_compat, &op); - } - return rc; + return _hypercall2(int, memory_op, cmd, arg); } static inline int -HYPERVISOR_acm_op( - unsigned int cmd, void *arg) +xencomm_arch_hypercall_event_channel_op(int cmd, struct xencomm_handle *arg) { - return _hypercall2(int, acm_op, cmd, arg); + return _hypercall2(int, event_channel_op, cmd, arg); } static inline int -HYPERVISOR_xen_version( - int cmd, void *arg) +xencomm_arch_hypercall_acm_op(unsigned int cmd, struct xencomm_handle *arg) { - return _hypercall2(int, xen_version, cmd, arg); + return _hypercall2(int, acm_op, cmd, arg); } static inline int -HYPERVISOR_console_io( - int cmd, int count, char *str) +xencomm_arch_hypercall_xen_version(int cmd, struct xencomm_handle *arg) { - return _hypercall3(int, console_io, cmd, count, str); + return _hypercall2(int, xen_version, cmd, arg); } static inline int -HYPERVISOR_physdev_op( - int cmd, void *arg) +xencomm_arch_hypercall_console_io(int cmd, int count, + struct xencomm_handle *str) { - int rc = _hypercall2(int, physdev_op, cmd, arg); - if (unlikely(rc == -ENOSYS)) { - struct physdev_op op; - op.cmd = cmd; - memcpy(&op.u, arg, sizeof(op.u)); - rc = _hypercall1(int, physdev_op_compat, &op); - } - return rc; + return _hypercall3(int, console_io, cmd, count, str); } -//XXX __HYPERVISOR_grant_table_op is used for this hypercall constant. static inline int -____HYPERVISOR_grant_table_op( - unsigned int cmd, void *uop, unsigned int count, - unsigned long pa1, unsigned long pa2) +xencomm_arch_hypercall_physdev_op(int cmd, struct xencomm_handle *arg) { - return _hypercall5(int, grant_table_op, cmd, uop, count, pa1, pa2); + return _hypercall2(int, physdev_op, cmd, arg); +} + +static inline int +xencomm_arch_hypercall_grant_table_op(unsigned int cmd, + struct xencomm_handle *uop, + unsigned int count) +{ + return _hypercall3(int, grant_table_op, cmd, uop, count); } int HYPERVISOR_grant_table_op(unsigned int cmd, void *uop, unsigned int count); +extern int xencomm_arch_hypercall_suspend(struct xencomm_handle *arg); + static inline int -HYPERVISOR_vcpu_op( - int cmd, int vcpuid, void *extra_args) +xencomm_arch_hypercall_callback_op(int cmd, struct xencomm_handle *arg) { - return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args); + return _hypercall2(int, callback_op, cmd, arg); } -extern int HYPERVISOR_suspend(unsigned long srec); - static inline unsigned long -HYPERVISOR_hvm_op( - int cmd, void *arg) +xencomm_arch_hypercall_hvm_op(int cmd, void *arg) { return _hypercall2(unsigned long, hvm_op, cmd, arg); } static inline int -HYPERVISOR_callback_op( - int cmd, void *arg) +HYPERVISOR_physdev_op(int cmd, void *arg) { - return _hypercall2(int, callback_op, cmd, arg); + switch (cmd) { + case PHYSDEVOP_eoi: + return _hypercall1(int, ia64_fast_eoi, + ((struct physdev_eoi *)arg)->irq); + default: + return xencomm_hypercall_physdev_op(cmd, arg); + } } extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs); @@ -417,7 +378,42 @@ HYPERVISOR_add_physmap(unsigned long gpfn, unsigned long mfn, return ret; } +#ifdef CONFIG_XEN_IA64_EXPOSE_P2M +static inline unsigned long +HYPERVISOR_expose_p2m(unsigned long conv_start_gpfn, + unsigned long assign_start_gpfn, + unsigned long expose_size, unsigned long granule_pfn) +{ + return _hypercall5(unsigned long, ia64_dom0vp_op, + IA64_DOM0VP_expose_p2m, conv_start_gpfn, + assign_start_gpfn, expose_size, granule_pfn); +} +#endif + // for balloon driver #define HYPERVISOR_update_va_mapping(va, new_val, flags) (0) +/* Use xencomm to do hypercalls. */ +#ifdef MODULE +#define HYPERVISOR_sched_op xencomm_mini_hypercall_sched_op +#define HYPERVISOR_event_channel_op xencomm_mini_hypercall_event_channel_op +#define HYPERVISOR_callback_op xencomm_mini_hypercall_callback_op +#define HYPERVISOR_multicall xencomm_mini_hypercall_multicall +#define HYPERVISOR_xen_version xencomm_mini_hypercall_xen_version +#define HYPERVISOR_console_io xencomm_mini_hypercall_console_io +#define HYPERVISOR_hvm_op xencomm_mini_hypercall_hvm_op +#define HYPERVISOR_memory_op xencomm_mini_hypercall_memory_op +#else +#define HYPERVISOR_sched_op xencomm_hypercall_sched_op +#define HYPERVISOR_event_channel_op xencomm_hypercall_event_channel_op +#define HYPERVISOR_callback_op xencomm_hypercall_callback_op +#define HYPERVISOR_multicall xencomm_hypercall_multicall +#define HYPERVISOR_xen_version xencomm_hypercall_xen_version +#define HYPERVISOR_console_io xencomm_hypercall_console_io +#define HYPERVISOR_hvm_op xencomm_hypercall_hvm_op +#define HYPERVISOR_memory_op xencomm_hypercall_memory_op +#endif + +#define HYPERVISOR_suspend xencomm_hypercall_suspend + #endif /* __HYPERCALL_H__ */ diff --git a/linux-2.6-xen-sparse/include/asm-ia64/hypervisor.h b/linux-2.6-xen-sparse/include/asm-ia64/hypervisor.h index acdf51203a..43db0a2367 100644 --- a/linux-2.6-xen-sparse/include/asm-ia64/hypervisor.h +++ b/linux-2.6-xen-sparse/include/asm-ia64/hypervisor.h @@ -75,9 +75,6 @@ HYPERVISOR_yield( { int rc = HYPERVISOR_sched_op(SCHEDOP_yield, NULL); - if (rc == -ENOSYS) - rc = HYPERVISOR_sched_op_compat(SCHEDOP_yield, 0); - return rc; } @@ -87,9 +84,6 @@ HYPERVISOR_block( { int rc = HYPERVISOR_sched_op(SCHEDOP_block, NULL); - if (rc == -ENOSYS) - rc = HYPERVISOR_sched_op_compat(SCHEDOP_block, 0); - return rc; } @@ -103,9 +97,6 @@ HYPERVISOR_shutdown( int rc = HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown); - if (rc == -ENOSYS) - rc = HYPERVISOR_sched_op_compat(SCHEDOP_shutdown, reason); - return rc; } @@ -122,8 +113,6 @@ HYPERVISOR_poll( set_xen_guest_handle(sched_poll.ports, ports); rc = HYPERVISOR_sched_op(SCHEDOP_poll, &sched_poll); - if (rc == -ENOSYS) - rc = HYPERVISOR_sched_op_compat(SCHEDOP_yield, 0); return rc; } diff --git a/linux-2.6-xen-sparse/include/asm-ia64/maddr.h b/linux-2.6-xen-sparse/include/asm-ia64/maddr.h index 55c6f94d10..7a26b2c6cc 100644 --- a/linux-2.6-xen-sparse/include/asm-ia64/maddr.h +++ b/linux-2.6-xen-sparse/include/asm-ia64/maddr.h @@ -10,11 +10,26 @@ #define INVALID_P2M_ENTRY (~0UL) +#ifdef CONFIG_XEN_IA64_EXPOSE_P2M +extern int p2m_initialized; +extern unsigned long p2m_min_low_pfn; +extern unsigned long p2m_max_low_pfn; +extern unsigned long p2m_convert_min_pfn; +extern unsigned long p2m_convert_max_pfn; +extern volatile const pte_t* p2m_pte; +unsigned long p2m_phystomach(unsigned long gpfn); +#else +#define p2m_initialized (0) +#define p2m_phystomach(gpfn) INVALID_MFN +#endif + /* XXX xen page size != page size */ static inline unsigned long pfn_to_mfn_for_dma(unsigned long pfn) { unsigned long mfn; + if (p2m_initialized) + return p2m_phystomach(pfn); mfn = HYPERVISOR_phystomach(pfn); BUG_ON(mfn == 0); // XXX BUG_ON(mfn == INVALID_P2M_ENTRY); // XXX diff --git a/linux-2.6-xen-sparse/include/asm-ia64/xen/privop.h b/linux-2.6-xen-sparse/include/asm-ia64/xen/privop.h index 073b3a2a77..6f3c20a8ed 100644 --- a/linux-2.6-xen-sparse/include/asm-ia64/xen/privop.h +++ b/linux-2.6-xen-sparse/include/asm-ia64/xen/privop.h @@ -14,12 +14,9 @@ #define IA64_PARAVIRTUALIZED -#if 0 -#undef XSI_BASE /* At 1 MB, before per-cpu space but still addressable using addl instead of movl. */ #define XSI_BASE 0xfffffffffff00000 -#endif /* Address of mapped regs. */ #define XMAPPEDREGS_BASE (XSI_BASE + XSI_SIZE) diff --git a/linux-2.6-xen-sparse/include/asm-ia64/xen/xcom_hcall.h b/linux-2.6-xen-sparse/include/asm-ia64/xen/xcom_hcall.h new file mode 100644 index 0000000000..3c073a71cd --- /dev/null +++ b/linux-2.6-xen-sparse/include/asm-ia64/xen/xcom_hcall.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2006 Tristan Gingold <tristan.gingold@bull.net>, Bull SAS + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _LINUX_XENCOMM_HCALL_H_ +#define _LINUX_XENCOMM_HCALL_H_ + +/* These function creates inline descriptor for the parameters and + calls the corresponding xencomm_arch_hypercall_X. + Architectures should defines HYPERVISOR_xxx as xencomm_hypercall_xxx unless + they want to use their own wrapper. */ +extern int xencomm_hypercall_console_io(int cmd, int count, char *str); + +extern int xencomm_hypercall_event_channel_op(int cmd, void *op); + +extern int xencomm_hypercall_xen_version(int cmd, void *arg); + +extern int xencomm_hypercall_physdev_op(int cmd, void *op); + +extern int xencomm_hypercall_grant_table_op(unsigned int cmd, void *op, + unsigned int count); + +extern int xencomm_hypercall_sched_op(int cmd, void *arg); + +extern int xencomm_hypercall_multicall(void *call_list, int nr_calls); + +extern int xencomm_hypercall_callback_op(int cmd, void *arg); + +extern int xencomm_hypercall_memory_op(unsigned int cmd, void *arg); + +extern unsigned long xencomm_hypercall_hvm_op(int cmd, void *arg); + +extern int xencomm_hypercall_suspend(unsigned long srec); + +/* Using mini xencomm. */ +extern int xencomm_mini_hypercall_console_io(int cmd, int count, char *str); + +extern int xencomm_mini_hypercall_event_channel_op(int cmd, void *op); + +extern int xencomm_mini_hypercall_xen_version(int cmd, void *arg); + +extern int xencomm_mini_hypercall_physdev_op(int cmd, void *op); + +extern int xencomm_mini_hypercall_grant_table_op(unsigned int cmd, void *op, + unsigned int count); + +extern int xencomm_mini_hypercall_sched_op(int cmd, void *arg); + +extern int xencomm_mini_hypercall_multicall(void *call_list, int nr_calls); + +extern int xencomm_mini_hypercall_callback_op(int cmd, void *arg); + +extern int xencomm_mini_hypercall_memory_op(unsigned int cmd, void *arg); + +extern unsigned long xencomm_mini_hypercall_hvm_op(int cmd, void *arg); + +/* For privcmd. Locally declare argument type to avoid include storm. + Type coherency will be checked within privcmd.c */ +struct privcmd_hypercall; +extern int privcmd_hypercall(struct privcmd_hypercall *hypercall); + +#endif /* _LINUX_XENCOMM_HCALL_H_ */ diff --git a/linux-2.6-xen-sparse/include/asm-ia64/xen/xencomm.h b/linux-2.6-xen-sparse/include/asm-ia64/xen/xencomm.h new file mode 100644 index 0000000000..eae11369f1 --- /dev/null +++ b/linux-2.6-xen-sparse/include/asm-ia64/xen/xencomm.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2006 Hollis Blanchard <hollisb@us.ibm.com>, IBM Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _LINUX_XENCOMM_H_ +#define _LINUX_XENCOMM_H_ + +#include <xen/interface/xencomm.h> + +#define XENCOMM_MINI_ADDRS 3 +struct xencomm_mini { + struct xencomm_desc _desc; + uint64_t address[XENCOMM_MINI_ADDRS]; +}; + +/* Must be called before any hypercall. */ +extern void xencomm_init (void); + +/* To avoid additionnal virt to phys conversion, an opaque structure is + presented. */ +struct xencomm_handle; + +extern int xencomm_create(void *buffer, unsigned long bytes, + struct xencomm_handle **desc, gfp_t type); +extern void xencomm_free(struct xencomm_handle *desc); + +extern int xencomm_create_mini(struct xencomm_mini *area, int *nbr_area, + void *buffer, unsigned long bytes, + struct xencomm_handle **ret); + +/* Translate virtual address to physical address. */ +extern unsigned long xencomm_vaddr_to_paddr(unsigned long vaddr); + +/* Inline version. To be used only on linear space (kernel space). */ +static inline struct xencomm_handle * +xencomm_create_inline(void *buffer) +{ + unsigned long paddr; + + paddr = xencomm_vaddr_to_paddr((unsigned long)buffer); + return (struct xencomm_handle *)(paddr | XENCOMM_INLINE_FLAG); +} + +#define xen_guest_handle(hnd) ((hnd).p) + +#endif /* _LINUX_XENCOMM_H_ */ diff --git a/linux-2.6-xen-sparse/lib/Makefile b/linux-2.6-xen-sparse/lib/Makefile index 2657bb5d10..1f96de0517 100644 --- a/linux-2.6-xen-sparse/lib/Makefile +++ b/linux-2.6-xen-sparse/lib/Makefile @@ -45,9 +45,7 @@ obj-$(CONFIG_TEXTSEARCH_BM) += ts_bm.o obj-$(CONFIG_TEXTSEARCH_FSM) += ts_fsm.o obj-$(CONFIG_SWIOTLB) += swiotlb.o -ifneq ($(CONFIG_XEN_IA64_DOM0_NON_VP),y) swiotlb-$(CONFIG_XEN) := ../arch/i386/kernel/swiotlb.o -endif hostprogs-y := gen_crc32table clean-files := crc32table.h diff --git a/tools/libxc/ia64/xc_ia64_linux_restore.c b/tools/libxc/ia64/xc_ia64_linux_restore.c index df6cf9dab6..e6aed35ead 100644 --- a/tools/libxc/ia64/xc_ia64_linux_restore.c +++ b/tools/libxc/ia64/xc_ia64_linux_restore.c @@ -225,6 +225,9 @@ xc_linux_restore(int xc_handle, int io_fd, uint32_t dom, goto out; } + fprintf(stderr, "ip=%016lx, b0=%016lx\n", ctxt.user_regs.cr_iip, + ctxt.user_regs.b0); + /* First to initialize. */ domctl.cmd = XEN_DOMCTL_setvcpucontext; domctl.domain = (domid_t)dom; diff --git a/tools/libxc/ia64/xc_ia64_linux_save.c b/tools/libxc/ia64/xc_ia64_linux_save.c index 68b7749954..42ec21c802 100644 --- a/tools/libxc/ia64/xc_ia64_linux_save.c +++ b/tools/libxc/ia64/xc_ia64_linux_save.c @@ -458,6 +458,9 @@ xc_linux_save(int xc_handle, int io_fd, uint32_t dom, uint32_t max_iters, goto out; } + fprintf(stderr, "ip=%016lx, b0=%016lx\n", ctxt.user_regs.cr_iip, + ctxt.user_regs.b0); + mem = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ|PROT_WRITE, ctxt.privregs_pfn); if (mem == NULL) { diff --git a/unmodified_drivers/linux-2.6/mkbuildtree b/unmodified_drivers/linux-2.6/mkbuildtree index be6b1a6d94..ce0a142447 100644 --- a/unmodified_drivers/linux-2.6/mkbuildtree +++ b/unmodified_drivers/linux-2.6/mkbuildtree @@ -27,6 +27,7 @@ mkdir -p include mkdir -p include/xen mkdir -p include/public mkdir -p include/asm +mkdir -p include/asm/xen lndir -silent ${XL}/include/xen include/xen ln -sf ${XEN}/include/public include/xen/interface @@ -54,6 +55,10 @@ i[34567]86) ln -sf ${XL}/include/asm-ia64/hypercall.h include/asm ln -sf ${XL}/include/asm-ia64/synch_bitops.h include/asm ln -sf ${XL}/include/asm-ia64/maddr.h include/asm + ln -sf ${XL}/include/asm-ia64/xen/xcom_hcall.h include/asm/xen + ln -sf ${XL}/include/asm-ia64/xen/xencomm.h include/asm/xen + ln -sf ${XL}/arch/ia64/xen/xcom_mini.c platform-pci + ln -sf ${XL}/arch/ia64/xen/xencomm.c platform-pci ;; *) echo unknown architecture $uname diff --git a/unmodified_drivers/linux-2.6/platform-pci/Kbuild b/unmodified_drivers/linux-2.6/platform-pci/Kbuild index a4c1961a8a..dda3d0e7cf 100644 --- a/unmodified_drivers/linux-2.6/platform-pci/Kbuild +++ b/unmodified_drivers/linux-2.6/platform-pci/Kbuild @@ -5,3 +5,8 @@ obj-m := xen-platform-pci.o EXTRA_CFLAGS += -I$(M)/platform-pci xen-platform-pci-objs := evtchn.o platform-pci.o gnttab.o xen_support.o features.o + +# Can we do better ? +ifeq ($(ARCH),ia64) + xen-platform-pci-objs += xcom_mini.o xencomm.o +endif diff --git a/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c b/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c index 36ad585fbf..cb9e8dd7e5 100644 --- a/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c +++ b/unmodified_drivers/linux-2.6/platform-pci/platform-pci.c @@ -35,6 +35,9 @@ #include <asm/hypervisor.h> #include <xen/interface/memory.h> #include <xen/features.h> +#ifdef __ia64__ +#include <asm/xen/xencomm.h> +#endif #include "platform-pci.h" @@ -59,6 +62,10 @@ static int __init init_xen_info(void) struct xen_add_to_physmap xatp; extern void *shared_info_area; +#ifdef __ia64__ + xencomm_init(); +#endif + setup_xen_features(); shared_info_frame = alloc_xen_mmio(PAGE_SIZE) >> PAGE_SHIFT; diff --git a/xen/arch/ia64/Rules.mk b/xen/arch/ia64/Rules.mk index 944d8d018e..8f69704d7d 100644 --- a/xen/arch/ia64/Rules.mk +++ b/xen/arch/ia64/Rules.mk @@ -5,6 +5,11 @@ HAS_ACPI := y HAS_VGA := y VALIDATE_VT ?= n no_warns ?= n +xen_ia64_expose_p2m ?= y +xen_ia64_pervcpu_vhpt ?= y +xen_ia64_tlb_track ?= y +xen_ia64_tlb_track_cnt ?= n +xen_ia64_tlbflush_clock ?= y ifneq ($(COMPILE_ARCH),$(TARGET_ARCH)) CROSS_COMPILE ?= /usr/local/sp_env/v2.2.5/i686/bin/ia64-unknown-linux- @@ -34,6 +39,21 @@ CFLAGS += -g ifeq ($(VALIDATE_VT),y) CFLAGS += -DVALIDATE_VT endif +ifeq ($(xen_ia64_expose_p2m),y) +CFLAGS += -DCONFIG_XEN_IA64_EXPOSE_P2M +endif +ifeq ($(xen_ia64_pervcpu_vhpt),y) +CFLAGS += -DCONFIG_XEN_IA64_PERVCPU_VHPT +endif +ifeq ($(xen_ia64_tlb_track),y) +CFLAGS += -DCONFIG_XEN_IA64_TLB_TRACK +endif +ifeq ($(xen_ia64_tlb_track_cnt),y) +CFLAGS += -DCONFIG_TLB_TRACK_CNT +endif +ifeq ($(xen_ia64_tlbflush_clock),y) +CFLAGS += -DCONFIG_XEN_IA64_TLBFLUSH_CLOCK +endif ifeq ($(no_warns),y) CFLAGS += -Wa,--fatal-warnings -Werror -Wno-uninitialized endif diff --git a/xen/arch/ia64/asm-offsets.c b/xen/arch/ia64/asm-offsets.c index 67b5725c56..32a7d076aa 100644 --- a/xen/arch/ia64/asm-offsets.c +++ b/xen/arch/ia64/asm-offsets.c @@ -37,6 +37,8 @@ void foo(void) DEFINE(IA64_MCA_CPU_INIT_STACK_OFFSET, offsetof (struct ia64_mca_cpu, init_stack)); BLANK(); + DEFINE(VCPU_VTM_OFFSET_OFS, offsetof(struct vcpu, arch.arch_vmx.vtm.vtm_offset)); + DEFINE(VCPU_VRR0_OFS, offsetof(struct vcpu, arch.arch_vmx.vrr[0])); #ifdef VTI_DEBUG DEFINE(IVT_CUR_OFS, offsetof(struct vcpu, arch.arch_vmx.ivt_current)); DEFINE(IVT_DBG_OFS, offsetof(struct vcpu, arch.arch_vmx.ivt_debug)); @@ -139,6 +141,7 @@ void foo(void) DEFINE(SWITCH_MPTA_OFFSET,offsetof(struct vcpu ,arch.arch_vmx.mpta)); DEFINE(IA64_PT_REGS_R16_SLOT, (((offsetof(struct pt_regs, r16)-sizeof(struct pt_regs))>>3)&0x3f)); DEFINE(IA64_VCPU_FLAGS_OFFSET,offsetof(struct vcpu ,arch.arch_vmx.flags)); + DEFINE(IA64_VCPU_MODE_FLAGS_OFFSET,offsetof(struct vcpu, arch.mode_flags)); BLANK(); diff --git a/xen/arch/ia64/linux-xen/entry.S b/xen/arch/ia64/linux-xen/entry.S index d80be440a3..2c73fc5d2b 100644 --- a/xen/arch/ia64/linux-xen/entry.S +++ b/xen/arch/ia64/linux-xen/entry.S @@ -262,13 +262,15 @@ GLOBAL_ENTRY(ia64_switch_to) #endif rsm psr.ic // interrupts (psr.i) are already disabled here movl r25=PAGE_KERNEL + movl r26 = IA64_GRANULE_SHIFT << 2 ;; srlz.d or r23=r25,r20 // construct PA | page properties - mov r25=IA64_GRANULE_SHIFT<<2 + ptr.d in0, r26 // to purge dtr[IA64_TR_VHPT] ;; - mov cr.itir=r25 + mov cr.itir=r26 mov cr.ifa=in0 // VA of next task... + srlz.d ;; mov r25=IA64_TR_CURRENT_STACK #ifdef XEN diff --git a/xen/arch/ia64/linux-xen/mca.c b/xen/arch/ia64/linux-xen/mca.c index 1e4a86061b..30803daced 100644 --- a/xen/arch/ia64/linux-xen/mca.c +++ b/xen/arch/ia64/linux-xen/mca.c @@ -80,6 +80,7 @@ #ifdef XEN #include <xen/symbols.h> #include <xen/mm.h> +#include <xen/console.h> #endif #if defined(IA64_MCA_DEBUG_INFO) @@ -1240,6 +1241,7 @@ ia64_init_handler (struct pt_regs *pt, struct switch_stack *sw) */ ms = (pal_min_state_area_t *)(ia64_sal_to_os_handoff_state.pal_min_state | (6ul<<61)); #else + console_start_sync(); /* Xen virtual address in region 7. */ ms = __va((pal_min_state_area_t *)(ia64_sal_to_os_handoff_state[cpu].pal_min_state)); #endif diff --git a/xen/arch/ia64/linux-xen/sal.c b/xen/arch/ia64/linux-xen/sal.c index ad81a29ad8..59cc613bbb 100644 --- a/xen/arch/ia64/linux-xen/sal.c +++ b/xen/arch/ia64/linux-xen/sal.c @@ -16,8 +16,10 @@ #ifdef XEN #include <linux/smp.h> +#include <asm/hw_irq.h> #include <xen/lib.h> #endif +#include <asm/delay.h> #include <asm/page.h> #include <asm/sal.h> #include <asm/pal.h> @@ -218,6 +220,77 @@ chk_nointroute_opt(void) static void __init sal_desc_ap_wakeup(void *p) { } #endif +/* + * HP rx5670 firmware polls for interrupts during SAL_CACHE_FLUSH by reading + * cr.ivr, but it never writes cr.eoi. This leaves any interrupt marked as + * "in-service" and masks other interrupts of equal or lower priority. + * + * HP internal defect reports: F1859, F2775, F3031. + */ +static int sal_cache_flush_drops_interrupts; + +static void __init +check_sal_cache_flush (void) +{ + unsigned long flags, itv; + int cpu; + u64 vector; + + cpu = get_cpu(); + local_irq_save(flags); + + /* + * Schedule a timer interrupt, wait until it's reported, and see if + * SAL_CACHE_FLUSH drops it. + */ + itv = ia64_get_itv(); + BUG_ON((itv & (1 << 16)) == 0); + + ia64_set_itv(IA64_TIMER_VECTOR); + ia64_set_itm(ia64_get_itc() + 1000); + + while (!ia64_get_irr(IA64_TIMER_VECTOR)) + cpu_relax(); + + ia64_sal_cache_flush(3); + + if (ia64_get_irr(IA64_TIMER_VECTOR)) { + vector = ia64_get_ivr(); + ia64_eoi(); + } else { + sal_cache_flush_drops_interrupts = 1; + printk(KERN_ERR "SAL: SAL_CACHE_FLUSH drops interrupts; " + "PAL_CACHE_FLUSH will be used instead\n"); + ia64_eoi(); + } + + ia64_set_itv(itv); + local_irq_restore(flags); + put_cpu(); +} + +s64 +ia64_sal_cache_flush (u64 cache_type) +{ + struct ia64_sal_retval isrv; + + if (sal_cache_flush_drops_interrupts) { + unsigned long flags; + u64 progress; + s64 rc; + + progress = 0; + local_irq_save(flags); + rc = ia64_pal_cache_flush(cache_type, + PAL_CACHE_FLUSH_INVALIDATE, &progress, NULL); + local_irq_restore(flags); + return rc; + } + + SAL_CALL(isrv, SAL_CACHE_FLUSH, cache_type, 0, 0, 0, 0, 0, 0); + return isrv.status; +} + void __init ia64_sal_init (struct ia64_sal_systab *systab) { @@ -271,6 +344,8 @@ ia64_sal_init (struct ia64_sal_systab *systab) } p += SAL_DESC_SIZE(*p); } + + check_sal_cache_flush(); } int diff --git a/xen/arch/ia64/linux-xen/tlb.c b/xen/arch/ia64/linux-xen/tlb.c index 9859923b77..2a6bffffb3 100644 --- a/xen/arch/ia64/linux-xen/tlb.c +++ b/xen/arch/ia64/linux-xen/tlb.c @@ -111,7 +111,10 @@ void local_flush_tlb_all (void) { unsigned long i, j, flags, count0, count1, stride0, stride1, addr; - +#ifdef XEN + /* increment flush clock before mTLB flush */ + u32 flush_time = tlbflush_clock_inc_and_return(); +#endif addr = local_cpu_data->ptce_base; count0 = local_cpu_data->ptce_count[0]; count1 = local_cpu_data->ptce_count[1]; @@ -128,6 +131,10 @@ local_flush_tlb_all (void) } local_irq_restore(flags); ia64_srlz_i(); /* srlz.i implies srlz.d */ +#ifdef XEN + /* update after mTLB flush. */ + tlbflush_update_time(&__get_cpu_var(tlbflush_time), flush_time); +#endif } EXPORT_SYMBOL(local_flush_tlb_all); diff --git a/xen/arch/ia64/linux-xen/unaligned.c b/xen/arch/ia64/linux-xen/unaligned.c index 9ef5d42470..86ecbd9374 100644 --- a/xen/arch/ia64/linux-xen/unaligned.c +++ b/xen/arch/ia64/linux-xen/unaligned.c @@ -304,7 +304,7 @@ set_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long val, unsigned unsigned long *bsp, *bspstore, *addr, *rnat_addr; unsigned long *kbs = (void *) current + IA64_RBS_OFFSET; unsigned long nat_mask; - unsigned long old_rsc,new_rsc; + unsigned long old_rsc, new_rsc, psr; unsigned long rnat; long sof = (regs->cr_ifs) & 0x7f; long sor = 8 * ((regs->cr_ifs >> 14) & 0xf); @@ -321,16 +321,17 @@ set_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long val, unsigned ridx = rotate_reg(sor, rrb_gr, ridx); old_rsc=ia64_get_rsc(); - new_rsc=old_rsc&(~0x3); + /* put RSC to lazy mode, and set loadrs 0 */ + new_rsc = old_rsc & (~0x3fff0003); ia64_set_rsc(new_rsc); + bsp = kbs + (regs->loadrs >> 19); /* 16 + 3 */ - bspstore = (unsigned long*)ia64_get_bspstore(); - bsp =kbs + (regs->loadrs >> 19);//16+3 - - addr = ia64_rse_skip_regs(bsp, -sof + ridx); + addr = ia64_rse_skip_regs(bsp, -sof + ridx); nat_mask = 1UL << ia64_rse_slot_num(addr); - rnat_addr = ia64_rse_rnat_addr(addr); - + rnat_addr = ia64_rse_rnat_addr(addr); + + local_irq_save(psr); + bspstore = (unsigned long*)ia64_get_bspstore(); if(addr >= bspstore){ ia64_flushrs (); @@ -358,6 +359,7 @@ set_rse_reg (struct pt_regs *regs, unsigned long r1, unsigned long val, unsigned ia64_set_bspstore (bspstore); ia64_set_rnat(rnat); } + local_irq_restore(psr); ia64_set_rsc(old_rsc); } diff --git a/xen/arch/ia64/tools/p2m_expose/Makefile b/xen/arch/ia64/tools/p2m_expose/Makefile new file mode 100644 index 0000000000..d346326d05 --- /dev/null +++ b/xen/arch/ia64/tools/p2m_expose/Makefile @@ -0,0 +1,28 @@ +ifneq ($(KERNELRELEASE),) +obj-m += expose_p2m.o +else +PWD := $(shell pwd) +TOPDIR ?= $(abspath $(PWD)/../../../../..) +KDIR ?= $(TOPDIR)/linux-$(shell awk '/^LINUX_VER\>/{print $$3}' $(TOPDIR)/buildconfigs/mk.linux-2.6-xen)-xen +#CROSS_COMPILE ?= ia64-unknown-linux- +#ARCH ?= ia64 + +ifneq ($(O),) +OPT_O := O=$(realpath $(O)) +endif + +ifneq ($(V),) +OPT_V := V=$(V) +endif + +ifneq ($(ARCH),) +OPT_ARCH := ARCH=$(ARCH) +endif + +ifneq ($(CROSS_COMPILE),) +OPT_CORSS_COMPILE := CROSS_COMPILE=$(CROSS_COMPILE) +endif + +default: + $(MAKE) -C $(KDIR) $(OPT_O) $(OPT_V) $(OPT_CORSS_COMPILE) $(OPT_ARCH) M=$(PWD) +endif diff --git a/xen/arch/ia64/tools/p2m_expose/README.p2m_expose b/xen/arch/ia64/tools/p2m_expose/README.p2m_expose new file mode 100644 index 0000000000..3b51e11305 --- /dev/null +++ b/xen/arch/ia64/tools/p2m_expose/README.p2m_expose @@ -0,0 +1,12 @@ +This directory contains Linux kernel module for p2m exposure test/benchmark. + +1. build kernel module + - At fist build, linux-xen as usual + - then type just 'make' in this directory, then you'll have expose_p2m.ko. + See Makefile for details. + +2. test, benchmark. + - type 'insmod expose_p2m.ko' on the system. + Then the result is printed out to your console. + insmod fails with EINVAL so that you don't have to execute rmmod. + diff --git a/xen/arch/ia64/tools/p2m_expose/expose_p2m.c b/xen/arch/ia64/tools/p2m_expose/expose_p2m.c new file mode 100644 index 0000000000..26e0b5188e --- /dev/null +++ b/xen/arch/ia64/tools/p2m_expose/expose_p2m.c @@ -0,0 +1,185 @@ +/****************************************************************************** + * arch/ia64/xen/expose_p2m.c + * + * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <asm/page.h> +#include <asm/pgtable.h> +#include <asm/hypercall.h> +#include <asm/hypervisor.h> + +#define printd(fmt, ...) printk("%s:%d " fmt, __func__, __LINE__, \ + ##__VA_ARGS__) + +// copied from arch/ia64/mm/tlb.c. it isn't exported. +void +local_flush_tlb_all (void) +{ + unsigned long i, j, flags, count0, count1, stride0, stride1, addr; + + addr = local_cpu_data->ptce_base; + count0 = local_cpu_data->ptce_count[0]; + count1 = local_cpu_data->ptce_count[1]; + stride0 = local_cpu_data->ptce_stride[0]; + stride1 = local_cpu_data->ptce_stride[1]; + + local_irq_save(flags); + for (i = 0; i < count0; ++i) { + for (j = 0; j < count1; ++j) { + ia64_ptce(addr); + addr += stride1; + } + addr += stride0; + } + local_irq_restore(flags); + ia64_srlz_i(); /* srlz.i implies srlz.d */ +} + +static void +do_p2m(unsigned long (*conv)(unsigned long), + const char* msg, const char* prefix, + unsigned long start_gpfn, unsigned end_gpfn, unsigned long stride) +{ + struct timeval before_tv; + struct timeval after_tv; + unsigned long gpfn; + unsigned long mfn; + unsigned long count; + nsec_t nsec; + + count = 0; + do_gettimeofday(&before_tv); + for (gpfn = start_gpfn; gpfn < end_gpfn; gpfn += stride) { + mfn = (*conv)(gpfn); + count++; + } + do_gettimeofday(&after_tv); + nsec = timeval_to_ns(&after_tv) - timeval_to_ns(&before_tv); + printk("%s stride %4ld %s: %9ld / %6ld = %5ld nsec\n", + msg, stride, prefix, + nsec, count, nsec/count); +} + + +static void +do_with_hypercall(const char* msg, + unsigned long start_gpfn, unsigned long end_gpfn, + unsigned long stride) +{ + do_p2m(&HYPERVISOR_phystomach, msg, "hypercall", + start_gpfn, end_gpfn, stride); +} + +static void +do_with_table(const char* msg, + unsigned long start_gpfn, unsigned long end_gpfn, + unsigned long stride) +{ + do_p2m(&p2m_phystomach, msg, "p2m table", + start_gpfn, end_gpfn, stride); +} + +static int __init +expose_p2m_init(void) +{ + unsigned long gpfn; + unsigned long mfn; + unsigned long p2m_mfn; + + int error_count = 0; + + const int strides[] = { + PTRS_PER_PTE, PTRS_PER_PTE/2, PTRS_PER_PTE/3, PTRS_PER_PTE/4, + L1_CACHE_BYTES/sizeof(pte_t), 1 + }; + int i; + + +#if 0 + printd("about to call p2m_expose_init()\n"); + if (p2m_expose_init() < 0) { + printd("p2m_expose_init() failed\n"); + return -EINVAL; + } + printd("p2m_expose_init() success\n"); +#else + if (!p2m_initialized) { + printd("p2m exposure isn't initialized\n"); + return -EINVAL; + } +#endif + + printd("p2m expose test begins\n"); + for (gpfn = p2m_min_low_pfn; gpfn < p2m_max_low_pfn; gpfn++) { + mfn = HYPERVISOR_phystomach(gpfn); + p2m_mfn = p2m_phystomach(gpfn); + if (mfn != p2m_mfn) { + printd("gpfn 0x%016lx " + "mfn 0x%016lx p2m_mfn 0x%016lx\n", + gpfn, mfn, p2m_mfn); + printd("mpaddr 0x%016lx " + "maddr 0x%016lx p2m_maddr 0x%016lx\n", + gpfn << PAGE_SHIFT, + mfn << PAGE_SHIFT, p2m_mfn << PAGE_SHIFT); + + error_count++; + if (error_count > 16) { + printk("too many errors\n"); + return -EINVAL; + } + } + } + printd("p2m expose test done!\n"); + + printk("type " + "stride " + "type : " + " nsec / count = " + "nsec per conv\n"); + for (i = 0; i < sizeof(strides)/sizeof(strides[0]); i++) { + int stride = strides[i]; + local_flush_tlb_all(); + do_with_hypercall("cold tlb", + p2m_min_low_pfn, p2m_max_low_pfn, stride); + do_with_hypercall("warm tlb", + p2m_min_low_pfn, p2m_max_low_pfn, stride); + + local_flush_tlb_all(); + do_with_table("cold tlb", + p2m_min_low_pfn, p2m_max_low_pfn, stride); + do_with_table("warm tlb", + p2m_min_low_pfn, p2m_max_low_pfn, stride); + } + + return -EINVAL; +} + +static void __exit +expose_p2m_cleanup(void) +{ +} + +module_init(expose_p2m_init); +module_exit(expose_p2m_cleanup); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Isaku Yamahata <yamahata@valinux.co.jp>"); diff --git a/xen/arch/ia64/vmx/Makefile b/xen/arch/ia64/vmx/Makefile index 9e90d955c9..5be2b4321c 100644 --- a/xen/arch/ia64/vmx/Makefile +++ b/xen/arch/ia64/vmx/Makefile @@ -17,3 +17,4 @@ obj-y += vmx_vcpu.o obj-y += vmx_virt.o obj-y += vmx_vsa.o obj-y += vtlb.o +obj-y += optvfault.o diff --git a/xen/arch/ia64/vmx/mm.c b/xen/arch/ia64/vmx/mm.c deleted file mode 100644 index 814df3dd8a..0000000000 --- a/xen/arch/ia64/vmx/mm.c +++ /dev/null @@ -1,153 +0,0 @@ -/****************************************************************************** - * arch/ia64/mm.c - * - * Copyright (c) 2002-2005 K A Fraser - * Copyright (c) 2004 Christian Limpach - * Copyright (c) 2005, Intel Corporation. - * Xuefei Xu (Anthony Xu) (Anthony.xu@intel.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -/* - * A description of the x86 page table API: - * - * Domains trap to do_mmu_update with a list of update requests. - * This is a list of (ptr, val) pairs, where the requested operation - * is *ptr = val. - * - * Reference counting of pages: - * ---------------------------- - * Each page has two refcounts: tot_count and type_count. - * - * TOT_COUNT is the obvious reference count. It counts all uses of a - * physical page frame by a domain, including uses as a page directory, - * a page table, or simple mappings via a PTE. This count prevents a - * domain from releasing a frame back to the free pool when it still holds - * a reference to it. - * - * TYPE_COUNT is more subtle. A frame can be put to one of three - * mutually-exclusive uses: it might be used as a page directory, or a - * page table, or it may be mapped writable by the domain [of course, a - * frame may not be used in any of these three ways!]. - * So, type_count is a count of the number of times a frame is being - * referred to in its current incarnation. Therefore, a page can only - * change its type when its type count is zero. - * - * Pinning the page type: - * ---------------------- - * The type of a page can be pinned/unpinned with the commands - * MMUEXT_[UN]PIN_L?_TABLE. Each page can be pinned exactly once (that is, - * pinning is not reference counted, so it can't be nested). - * This is useful to prevent a page's type count falling to zero, at which - * point safety checks would need to be carried out next time the count - * is increased again. - * - * A further note on writable page mappings: - * ----------------------------------------- - * For simplicity, the count of writable mappings for a page may not - * correspond to reality. The 'writable count' is incremented for every - * PTE which maps the page with the _PAGE_RW flag set. However, for - * write access to be possible the page directory entry must also have - * its _PAGE_RW bit set. We do not check this as it complicates the - * reference counting considerably [consider the case of multiple - * directory entries referencing a single page table, some with the RW - * bit set, others not -- it starts getting a bit messy]. - * In normal use, this simplification shouldn't be a problem. - * However, the logic can be added if required. - * - * One more note on read-only page mappings: - * ----------------------------------------- - * We want domains to be able to map pages for read-only access. The - * main reason is that page tables and directories should be readable - * by a domain, but it would not be safe for them to be writable. - * However, domains have free access to rings 1 & 2 of the Intel - * privilege model. In terms of page protection, these are considered - * to be part of 'supervisor mode'. The WP bit in CR0 controls whether - * read-only restrictions are respected in supervisor mode -- if the - * bit is clear then any mapped page is writable. - * - * We get round this by always setting the WP bit and disallowing - * updates to it. This is very unlikely to cause a problem for guest - * OS's, which will generally use the WP bit to simplify copy-on-write - * implementation (in that case, OS wants a fault when it writes to - * an application-supplied buffer). - */ - -#include <xen/config.h> -//#include <public/xen.h> -#include <xen/init.h> -#include <xen/lib.h> -#include <xen/mm.h> -#include <xen/errno.h> -#include <asm/vmx_vcpu.h> -#include <asm/vmmu.h> -#include <asm/regionreg.h> -#include <asm/vmx_mm_def.h> -/* - uregs->ptr is virtual address - uregs->val is pte value - */ -int vmx_do_mmu_update(mmu_update_t *ureqs,u64 count,u64 *pdone,u64 foreigndom) -{ - int i,cmd; - u64 mfn, gpfn; - VCPU *vcpu; - mmu_update_t req; - /* ia64_rr rr; */ - thash_cb_t *hcb; - /* thash_data_t entry={0},*ovl; */ - vcpu = current; - /* search_section_t sections; */ - hcb = vmx_vcpu_get_vtlb(vcpu); - for ( i = 0; i < count; i++ ) - { - copy_from_user(&req, ureqs, sizeof(req)); - cmd = req.ptr&3; - req.ptr &= ~3; -/* - if(cmd ==MMU_NORMAL_PT_UPDATE){ - entry.page_flags = req.val; - entry.locked = 1; - entry.tc = 1; - entry.cl = DSIDE_TLB; - rr = vmx_vcpu_rr(vcpu, req.ptr); - entry.ps = rr.ps; - entry.key = rr.rid; - entry.rid = rr.rid; - entry.vadr = PAGEALIGN(req.ptr,entry.ps); - sections.tr = 1; - sections.tc = 0; - ovl = thash_find_overlap(hcb, &entry, sections); - if (ovl) { - // generate MCA. - panic("Tlb conflict!!"); - return -1; - } - thash_purge_and_insert(hcb, &entry, req.ptr); - }else - */ - if(cmd == MMU_MACHPHYS_UPDATE){ - mfn = req.ptr >>PAGE_SHIFT; - gpfn = req.val; - set_machinetophys(mfn,gpfn); - }else{ - printf("Unkown command of mmu_update:ptr: %lx,val: %lx \n",req.ptr,req.val); - while(1); - } - ureqs ++; - } - return 0; -} diff --git a/xen/arch/ia64/vmx/mmio.c b/xen/arch/ia64/vmx/mmio.c index 95e7ec0351..cca3f7ccb4 100644 --- a/xen/arch/ia64/vmx/mmio.c +++ b/xen/arch/ia64/vmx/mmio.c @@ -428,7 +428,7 @@ void emulate_io_inst(VCPU *vcpu, u64 padr, u64 ma) IA64_BUNDLE bundle; int slot, dir=0, inst_type; size_t size; - u64 data, value,post_update, slot1a, slot1b, temp; + u64 data, post_update, slot1a, slot1b, temp; INST64 inst; regs=vcpu_regs(vcpu); if (IA64_RETRY == __vmx_get_domain_bundle(regs->cr_iip, &bundle)) { @@ -454,7 +454,6 @@ void emulate_io_inst(VCPU *vcpu, u64 padr, u64 ma) vcpu_get_gr_nat(vcpu,inst.M4.r2,&data); }else if((inst.M1.x6>>2)<0xb){ // read dir=IOREQ_READ; - vcpu_get_gr_nat(vcpu,inst.M1.r1,&value); } } // Integer Load + Reg update @@ -462,7 +461,6 @@ void emulate_io_inst(VCPU *vcpu, u64 padr, u64 ma) inst_type = SL_INTEGER; dir = IOREQ_READ; //write size = (inst.M2.x6&0x3); - vcpu_get_gr_nat(vcpu,inst.M2.r1,&value); vcpu_get_gr_nat(vcpu,inst.M2.r3,&temp); vcpu_get_gr_nat(vcpu,inst.M2.r2,&post_update); temp += post_update; @@ -485,7 +483,6 @@ void emulate_io_inst(VCPU *vcpu, u64 padr, u64 ma) }else if((inst.M3.x6>>2)<0xb){ // read dir=IOREQ_READ; - vcpu_get_gr_nat(vcpu,inst.M3.r1,&value); vcpu_get_gr_nat(vcpu,inst.M3.r3,&temp); post_update = (inst.M3.i<<7)+inst.M3.imm7; if(inst.M3.s) @@ -597,13 +594,6 @@ void emulate_io_inst(VCPU *vcpu, u64 padr, u64 ma) mmio_access(vcpu, padr, &data, size, ma, dir); }else{ mmio_access(vcpu, padr, &data, size, ma, dir); - if(size==1) - data = (value & 0xffffffffffffff00U) | (data & 0xffU); - else if(size==2) - data = (value & 0xffffffffffff0000U) | (data & 0xffffU); - else if(size==4) - data = (value & 0xffffffff00000000U) | (data & 0xffffffffU); - if(inst_type==SL_INTEGER){ //gp vcpu_set_gr(vcpu,inst.M1.r1,data,0); }else{ diff --git a/xen/arch/ia64/vmx/optvfault.S b/xen/arch/ia64/vmx/optvfault.S new file mode 100644 index 0000000000..55f9cd57fb --- /dev/null +++ b/xen/arch/ia64/vmx/optvfault.S @@ -0,0 +1,596 @@ +/* + * arch/ia64/vmx/optvfault.S + * optimize virtualization fault handler + * + * Copyright (C) 2006 Intel Co + * Xuefei Xu (Anthony Xu) <anthony.xu@intel.com> + */ + +#include <linux/config.h> +#include <asm/asmmacro.h> +#include <asm/kregs.h> +#include <asm/offsets.h> +#include <asm/percpu.h> +#include <asm/processor.h> +#include <asm/vmx_vpd.h> +#include <asm/vmx_pal_vsa.h> +#include <asm/asm-offsets.h> + +#define ACCE_MOV_FROM_AR +#define ACCE_MOV_FROM_RR +#define ACCE_MOV_TO_RR + +//mov r1=ar3 +GLOBAL_ENTRY(vmx_asm_mov_from_ar) +#ifndef ACCE_MOV_FROM_AR + br.many vmx_virtualization_fault_back +#endif + add r18=VCPU_VTM_OFFSET_OFS,r21 + mov r19=ar.itc + extr.u r17=r25,6,7 + ;; + ld8 r18=[r18] + movl r20=asm_mov_to_reg + ;; + adds r30=vmx_resume_to_guest-asm_mov_to_reg,r20 + shladd r17=r17,4,r20 + mov r24=b0 + ;; + add r19=r19,r18 + mov b0=r17 + br.sptk.few b0 + ;; +END(vmx_asm_mov_from_ar) + + +// mov r1=rr[r3] +GLOBAL_ENTRY(vmx_asm_mov_from_rr) +#ifndef ACCE_MOV_FROM_RR + br.many vmx_virtualization_fault_back +#endif + extr.u r16=r25,20,7 + extr.u r17=r25,6,7 + movl r20=asm_mov_from_reg + ;; + adds r30=vmx_asm_mov_from_rr_back_1-asm_mov_from_reg,r20 + shladd r16=r16,4,r20 + mov r24=b0 + ;; + add r27=VCPU_VRR0_OFS,r21 + mov b0=r16 + br.many b0 + ;; +vmx_asm_mov_from_rr_back_1: + adds r30=vmx_resume_to_guest-asm_mov_from_reg,r20 + adds r22=asm_mov_to_reg-asm_mov_from_reg,r20 + shr.u r26=r19,61 + ;; + shladd r17=r17,4,r22 + shladd r27=r26,3,r27 + ;; + ld8 r19=[r27] + mov b0=r17 + br.many b0 +END(vmx_asm_mov_from_rr) + + +// mov rr[r3]=r2 +GLOBAL_ENTRY(vmx_asm_mov_to_rr) +#ifndef ACCE_MOV_TO_RR + br.many vmx_virtualization_fault_back +#endif + extr.u r16=r25,20,7 + extr.u r17=r25,13,7 + movl r20=asm_mov_from_reg + ;; + adds r30=vmx_asm_mov_to_rr_back_1-asm_mov_from_reg,r20 + shladd r16=r16,4,r20 + mov r22=b0 + ;; + add r27=VCPU_VRR0_OFS,r21 + mov b0=r16 + br.many b0 + ;; +vmx_asm_mov_to_rr_back_1: + adds r30=vmx_asm_mov_to_rr_back_2-asm_mov_from_reg,r20 + shr.u r23=r19,61 + shladd r17=r17,4,r20 + ;; + //if rr7, go back + cmp.eq p6,p0=7,r23 + mov b0=r22 + (p6) br.cond.dpnt.many vmx_virtualization_fault_back + ;; + mov r28=r19 + mov b0=r17 + br.many b0 +vmx_asm_mov_to_rr_back_2: + adds r30=vmx_resume_to_guest-asm_mov_from_reg,r20 + shladd r27=r23,3,r27 + ;; // +starting_rid + st8 [r27]=r19 + mov b0=r30 + ;; + adds r16=IA64_VCPU_STARTING_RID_OFFSET,r21 + ;; + ld4 r16=[r16] + ;; + shl r16=r16,8 + ;; + add r19=r19,r16 + ;; //mangling rid 1 and 3 + extr.u r16=r19,8,8 + extr.u r17=r19,24,8 + extr.u r18=r19,2,6 + ;; + dep r19=r16,r19,24,8 + ;; + dep r19=r17,r19,8,8 + ;; //set ve 1 + dep r19=-1,r19,0,1 + cmp.lt p6,p0=14,r18 + ;; + (p6) mov r18=14 + ;; + (p6) dep r19=r18,r19,2,6 + ;; + cmp.eq p6,p0=0,r23 + ;; + cmp.eq.or p6,p0=4,r23 + ;; + adds r16=IA64_VCPU_MODE_FLAGS_OFFSET,r21 + (p6) adds r17=IA64_VCPU_META_SAVED_RR0_OFFSET,r21 + ;; + ld4 r16=[r16] + cmp.eq p7,p0=r0,r0 + (p6) shladd r17=r23,1,r17 + ;; + (p6) st8 [r17]=r19 + (p6) tbit.nz p6,p7=r16,0 + ;; + (p7) mov rr[r28]=r19 + mov r24=r22 + br.many b0 +END(vmx_asm_mov_to_rr) + + +#define MOV_TO_REG0 \ +{; \ + nop.b 0x0; \ + nop.b 0x0; \ + nop.b 0x0; \ + ;; \ +}; + + +#define MOV_TO_REG(n) \ +{; \ + mov r##n##=r19; \ + mov b0=r30; \ + br.sptk.many b0; \ + ;; \ +}; + + +#define MOV_FROM_REG(n) \ +{; \ + mov r19=r##n##; \ + mov b0=r30; \ + br.sptk.many b0; \ + ;; \ +}; + + +#define MOV_TO_BANK0_REG(n) \ +ENTRY_MIN_ALIGN(asm_mov_to_bank0_reg##n##); \ +{; \ + mov r26=r2; \ + mov r2=r19; \ + bsw.1; \ + ;; \ +}; \ +{; \ + mov r##n##=r2; \ + nop.b 0x0; \ + bsw.0; \ + ;; \ +}; \ +{; \ + mov r2=r26; \ + mov b0=r30; \ + br.sptk.many b0; \ + ;; \ +}; \ +END(asm_mov_to_bank0_reg##n##) + + +#define MOV_FROM_BANK0_REG(n) \ +ENTRY_MIN_ALIGN(asm_mov_from_bank0_reg##n##); \ +{; \ + mov r26=r2; \ + nop.b 0x0; \ + bsw.1; \ + ;; \ +}; \ +{; \ + mov r2=r##n##; \ + nop.b 0x0; \ + bsw.0; \ + ;; \ +}; \ +{; \ + mov r19=r2; \ + mov r2=r26; \ + mov b0=r30; \ +}; \ +{; \ + nop.b 0x0; \ + nop.b 0x0; \ + br.sptk.many b0; \ + ;; \ +}; \ +END(asm_mov_from_bank0_reg##n##) + + +#define JMP_TO_MOV_TO_BANK0_REG(n) \ +{; \ + nop.b 0x0; \ + nop.b 0x0; \ + br.sptk.many asm_mov_to_bank0_reg##n##; \ + ;; \ +} + + +#define JMP_TO_MOV_FROM_BANK0_REG(n) \ +{; \ + nop.b 0x0; \ + nop.b 0x0; \ + br.sptk.many asm_mov_from_bank0_reg##n##; \ + ;; \ +} + + +MOV_FROM_BANK0_REG(16) +MOV_FROM_BANK0_REG(17) +MOV_FROM_BANK0_REG(18) +MOV_FROM_BANK0_REG(19) +MOV_FROM_BANK0_REG(20) +MOV_FROM_BANK0_REG(21) +MOV_FROM_BANK0_REG(22) +MOV_FROM_BANK0_REG(23) +MOV_FROM_BANK0_REG(24) +MOV_FROM_BANK0_REG(25) +MOV_FROM_BANK0_REG(26) +MOV_FROM_BANK0_REG(27) +MOV_FROM_BANK0_REG(28) +MOV_FROM_BANK0_REG(29) +MOV_FROM_BANK0_REG(30) +MOV_FROM_BANK0_REG(31) + + +// mov from reg table +ENTRY(asm_mov_from_reg) + MOV_FROM_REG(0) + MOV_FROM_REG(1) + MOV_FROM_REG(2) + MOV_FROM_REG(3) + MOV_FROM_REG(4) + MOV_FROM_REG(5) + MOV_FROM_REG(6) + MOV_FROM_REG(7) + MOV_FROM_REG(8) + MOV_FROM_REG(9) + MOV_FROM_REG(10) + MOV_FROM_REG(11) + MOV_FROM_REG(12) + MOV_FROM_REG(13) + MOV_FROM_REG(14) + MOV_FROM_REG(15) + JMP_TO_MOV_FROM_BANK0_REG(16) + JMP_TO_MOV_FROM_BANK0_REG(17) + JMP_TO_MOV_FROM_BANK0_REG(18) + JMP_TO_MOV_FROM_BANK0_REG(19) + JMP_TO_MOV_FROM_BANK0_REG(20) + JMP_TO_MOV_FROM_BANK0_REG(21) + JMP_TO_MOV_FROM_BANK0_REG(22) + JMP_TO_MOV_FROM_BANK0_REG(23) + JMP_TO_MOV_FROM_BANK0_REG(24) + JMP_TO_MOV_FROM_BANK0_REG(25) + JMP_TO_MOV_FROM_BANK0_REG(26) + JMP_TO_MOV_FROM_BANK0_REG(27) + JMP_TO_MOV_FROM_BANK0_REG(28) + JMP_TO_MOV_FROM_BANK0_REG(29) + JMP_TO_MOV_FROM_BANK0_REG(30) + JMP_TO_MOV_FROM_BANK0_REG(31) + MOV_FROM_REG(32) + MOV_FROM_REG(33) + MOV_FROM_REG(34) + MOV_FROM_REG(35) + MOV_FROM_REG(36) + MOV_FROM_REG(37) + MOV_FROM_REG(38) + MOV_FROM_REG(39) + MOV_FROM_REG(40) + MOV_FROM_REG(41) + MOV_FROM_REG(42) + MOV_FROM_REG(43) + MOV_FROM_REG(44) + MOV_FROM_REG(45) + MOV_FROM_REG(46) + MOV_FROM_REG(47) + MOV_FROM_REG(48) + MOV_FROM_REG(49) + MOV_FROM_REG(50) + MOV_FROM_REG(51) + MOV_FROM_REG(52) + MOV_FROM_REG(53) + MOV_FROM_REG(54) + MOV_FROM_REG(55) + MOV_FROM_REG(56) + MOV_FROM_REG(57) + MOV_FROM_REG(58) + MOV_FROM_REG(59) + MOV_FROM_REG(60) + MOV_FROM_REG(61) + MOV_FROM_REG(62) + MOV_FROM_REG(63) + MOV_FROM_REG(64) + MOV_FROM_REG(65) + MOV_FROM_REG(66) + MOV_FROM_REG(67) + MOV_FROM_REG(68) + MOV_FROM_REG(69) + MOV_FROM_REG(70) + MOV_FROM_REG(71) + MOV_FROM_REG(72) + MOV_FROM_REG(73) + MOV_FROM_REG(74) + MOV_FROM_REG(75) + MOV_FROM_REG(76) + MOV_FROM_REG(77) + MOV_FROM_REG(78) + MOV_FROM_REG(79) + MOV_FROM_REG(80) + MOV_FROM_REG(81) + MOV_FROM_REG(82) + MOV_FROM_REG(83) + MOV_FROM_REG(84) + MOV_FROM_REG(85) + MOV_FROM_REG(86) + MOV_FROM_REG(87) + MOV_FROM_REG(88) + MOV_FROM_REG(89) + MOV_FROM_REG(90) + MOV_FROM_REG(91) + MOV_FROM_REG(92) + MOV_FROM_REG(93) + MOV_FROM_REG(94) + MOV_FROM_REG(95) + MOV_FROM_REG(96) + MOV_FROM_REG(97) + MOV_FROM_REG(98) + MOV_FROM_REG(99) + MOV_FROM_REG(100) + MOV_FROM_REG(101) + MOV_FROM_REG(102) + MOV_FROM_REG(103) + MOV_FROM_REG(104) + MOV_FROM_REG(105) + MOV_FROM_REG(106) + MOV_FROM_REG(107) + MOV_FROM_REG(108) + MOV_FROM_REG(109) + MOV_FROM_REG(110) + MOV_FROM_REG(111) + MOV_FROM_REG(112) + MOV_FROM_REG(113) + MOV_FROM_REG(114) + MOV_FROM_REG(115) + MOV_FROM_REG(116) + MOV_FROM_REG(117) + MOV_FROM_REG(118) + MOV_FROM_REG(119) + MOV_FROM_REG(120) + MOV_FROM_REG(121) + MOV_FROM_REG(122) + MOV_FROM_REG(123) + MOV_FROM_REG(124) + MOV_FROM_REG(125) + MOV_FROM_REG(126) + MOV_FROM_REG(127) +END(asm_mov_from_reg) + + +/* must be in bank 0 + * parameter: + * r31: pr + * r24: b0 + */ +ENTRY(vmx_resume_to_guest) + mov r16=cr.ipsr + movl r20=__vsa_base + ;; + ld8 r20=[r20] + adds r19=IA64_VPD_BASE_OFFSET,r21 + ;; + ld8 r25=[r19] + extr.u r17=r16,IA64_PSR_RI_BIT,2 + tbit.nz p6,p7=r16,IA64_PSR_RI_BIT+1 + ;; + (p6) mov r18=cr.iip + (p6) mov r17=r0 + ;; + (p6) add r18=0x10,r18 + (p7) add r17=1,r17 + ;; + (p6) mov cr.iip=r18 + dep r16=r17,r16,IA64_PSR_RI_BIT,2 + ;; + mov cr.ipsr=r16 + adds r19= VPD_VPSR_START_OFFSET,r25 + add r28=PAL_VPS_RESUME_NORMAL,r20 + add r29=PAL_VPS_RESUME_HANDLER,r20 + ;; + ld8 r19=[r19] + mov b0=r29 + cmp.ne p6,p7 = r0,r0 + ;; + tbit.z p6,p7 = r19,IA64_PSR_IC_BIT // p1=vpsr.ic + ;; + (p6) ld8 r26=[r25] + (p7) mov b0=r28 + mov pr=r31,-2 + br.sptk.many b0 // call pal service + ;; +END(vmx_resume_to_guest) + + +MOV_TO_BANK0_REG(16) +MOV_TO_BANK0_REG(17) +MOV_TO_BANK0_REG(18) +MOV_TO_BANK0_REG(19) +MOV_TO_BANK0_REG(20) +MOV_TO_BANK0_REG(21) +MOV_TO_BANK0_REG(22) +MOV_TO_BANK0_REG(23) +MOV_TO_BANK0_REG(24) +MOV_TO_BANK0_REG(25) +MOV_TO_BANK0_REG(26) +MOV_TO_BANK0_REG(27) +MOV_TO_BANK0_REG(28) +MOV_TO_BANK0_REG(29) +MOV_TO_BANK0_REG(30) +MOV_TO_BANK0_REG(31) + + +// mov to reg table +ENTRY(asm_mov_to_reg) + MOV_TO_REG0 + MOV_TO_REG(1) + MOV_TO_REG(2) + MOV_TO_REG(3) + MOV_TO_REG(4) + MOV_TO_REG(5) + MOV_TO_REG(6) + MOV_TO_REG(7) + MOV_TO_REG(8) + MOV_TO_REG(9) + MOV_TO_REG(10) + MOV_TO_REG(11) + MOV_TO_REG(12) + MOV_TO_REG(13) + MOV_TO_REG(14) + MOV_TO_REG(15) + JMP_TO_MOV_TO_BANK0_REG(16) + JMP_TO_MOV_TO_BANK0_REG(17) + JMP_TO_MOV_TO_BANK0_REG(18) + JMP_TO_MOV_TO_BANK0_REG(19) + JMP_TO_MOV_TO_BANK0_REG(20) + JMP_TO_MOV_TO_BANK0_REG(21) + JMP_TO_MOV_TO_BANK0_REG(22) + JMP_TO_MOV_TO_BANK0_REG(23) + JMP_TO_MOV_TO_BANK0_REG(24) + JMP_TO_MOV_TO_BANK0_REG(25) + JMP_TO_MOV_TO_BANK0_REG(26) + JMP_TO_MOV_TO_BANK0_REG(27) + JMP_TO_MOV_TO_BANK0_REG(28) + JMP_TO_MOV_TO_BANK0_REG(29) + JMP_TO_MOV_TO_BANK0_REG(30) + JMP_TO_MOV_TO_BANK0_REG(31) + MOV_TO_REG(32) + MOV_TO_REG(33) + MOV_TO_REG(34) + MOV_TO_REG(35) + MOV_TO_REG(36) + MOV_TO_REG(37) + MOV_TO_REG(38) + MOV_TO_REG(39) + MOV_TO_REG(40) + MOV_TO_REG(41) + MOV_TO_REG(42) + MOV_TO_REG(43) + MOV_TO_REG(44) + MOV_TO_REG(45) + MOV_TO_REG(46) + MOV_TO_REG(47) + MOV_TO_REG(48) + MOV_TO_REG(49) + MOV_TO_REG(50) + MOV_TO_REG(51) + MOV_TO_REG(52) + MOV_TO_REG(53) + MOV_TO_REG(54) + MOV_TO_REG(55) + MOV_TO_REG(56) + MOV_TO_REG(57) + MOV_TO_REG(58) + MOV_TO_REG(59) + MOV_TO_REG(60) + MOV_TO_REG(61) + MOV_TO_REG(62) + MOV_TO_REG(63) + MOV_TO_REG(64) + MOV_TO_REG(65) + MOV_TO_REG(66) + MOV_TO_REG(67) + MOV_TO_REG(68) + MOV_TO_REG(69) + MOV_TO_REG(70) + MOV_TO_REG(71) + MOV_TO_REG(72) + MOV_TO_REG(73) + MOV_TO_REG(74) + MOV_TO_REG(75) + MOV_TO_REG(76) + MOV_TO_REG(77) + MOV_TO_REG(78) + MOV_TO_REG(79) + MOV_TO_REG(80) + MOV_TO_REG(81) + MOV_TO_REG(82) + MOV_TO_REG(83) + MOV_TO_REG(84) + MOV_TO_REG(85) + MOV_TO_REG(86) + MOV_TO_REG(87) + MOV_TO_REG(88) + MOV_TO_REG(89) + MOV_TO_REG(90) + MOV_TO_REG(91) + MOV_TO_REG(92) + MOV_TO_REG(93) + MOV_TO_REG(94) + MOV_TO_REG(95) + MOV_TO_REG(96) + MOV_TO_REG(97) + MOV_TO_REG(98) + MOV_TO_REG(99) + MOV_TO_REG(100) + MOV_TO_REG(101) + MOV_TO_REG(102) + MOV_TO_REG(103) + MOV_TO_REG(104) + MOV_TO_REG(105) + MOV_TO_REG(106) + MOV_TO_REG(107) + MOV_TO_REG(108) + MOV_TO_REG(109) + MOV_TO_REG(110) + MOV_TO_REG(111) + MOV_TO_REG(112) + MOV_TO_REG(113) + MOV_TO_REG(114) + MOV_TO_REG(115) + MOV_TO_REG(116) + MOV_TO_REG(117) + MOV_TO_REG(118) + MOV_TO_REG(119) + MOV_TO_REG(120) + MOV_TO_REG(121) + MOV_TO_REG(122) + MOV_TO_REG(123) + MOV_TO_REG(124) + MOV_TO_REG(125) + MOV_TO_REG(126) + MOV_TO_REG(127) +END(asm_mov_to_reg) diff --git a/xen/arch/ia64/vmx/pal_emul.c b/xen/arch/ia64/vmx/pal_emul.c index 2c88fb34e2..8f3c9400d4 100644 --- a/xen/arch/ia64/vmx/pal_emul.c +++ b/xen/arch/ia64/vmx/pal_emul.c @@ -17,509 +17,46 @@ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place - Suite 330, Boston, MA 02111-1307 USA. */ - -#include <asm/vmx_vcpu.h> + +#include <xen/lib.h> +#include <asm/vcpu.h> +#include <asm/dom_fw.h> #include <asm/pal.h> #include <asm/sal.h> -#include <asm/dom_fw.h> -#include <asm/tlb.h> -#include <asm/vmx_mm_def.h> -#include <xen/hypercall.h> -#include <public/sched.h> - -/* - * Handy macros to make sure that the PAL return values start out - * as something meaningful. - */ -#define INIT_PAL_STATUS_UNIMPLEMENTED(x) \ - { \ - x.status = PAL_STATUS_UNIMPLEMENTED; \ - x.v0 = 0; \ - x.v1 = 0; \ - x.v2 = 0; \ - } - -#define INIT_PAL_STATUS_SUCCESS(x) \ - { \ - x.status = PAL_STATUS_SUCCESS; \ - x.v0 = 0; \ - x.v1 = 0; \ - x.v2 = 0; \ - } - -static void -get_pal_parameters(VCPU *vcpu, UINT64 *gr29, UINT64 *gr30, UINT64 *gr31) { - - vcpu_get_gr_nat(vcpu,29,gr29); - vcpu_get_gr_nat(vcpu,30,gr30); - vcpu_get_gr_nat(vcpu,31,gr31); -} - -static void -set_pal_result(VCPU *vcpu,struct ia64_pal_retval result) { - - vcpu_set_gr(vcpu,8, result.status,0); - vcpu_set_gr(vcpu,9, result.v0,0); - vcpu_set_gr(vcpu,10, result.v1,0); - vcpu_set_gr(vcpu,11, result.v2,0); -} - -static void -set_sal_result(VCPU *vcpu,struct sal_ret_values result) { - - vcpu_set_gr(vcpu,8, result.r8,0); - vcpu_set_gr(vcpu,9, result.r9,0); - vcpu_set_gr(vcpu,10, result.r10,0); - vcpu_set_gr(vcpu,11, result.r11,0); -} - -static struct ia64_pal_retval -pal_cache_flush(VCPU *vcpu) { - UINT64 gr28,gr29, gr30, gr31; - struct ia64_pal_retval result; - - get_pal_parameters(vcpu, &gr29, &gr30, &gr31); - vcpu_get_gr_nat(vcpu, 28, &gr28); - - /* Always call Host Pal in int=1 */ - gr30 = gr30 & ~0x2UL; - - /* - * Call Host PAL cache flush - * Clear psr.ic when call PAL_CACHE_FLUSH - */ - result = ia64_pal_call_static(gr28 ,gr29, gr30, gr31, 1); - - /* If host PAL call is interrupted, then loop to complete it */ -// while (result.status == 1) -// ia64_pal_call_static(gr28 ,gr29, gr30, result.v1, 1LL); -// - if (result.status != 0) - panic_domain(vcpu_regs(vcpu), "PAL_CACHE_FLUSH ERROR, " - "status %ld", result.status); - - return result; -} - -static struct ia64_pal_retval -pal_vm_tr_read(VCPU *vcpu) { - struct ia64_pal_retval result; - - INIT_PAL_STATUS_UNIMPLEMENTED(result); - - return result; -} - -static struct ia64_pal_retval -pal_prefetch_visibility(VCPU *vcpu) { - /* Due to current MM virtualization algorithm, - * We do not allow guest to change mapping attribute. - * Thus we will not support PAL_PREFETCH_VISIBILITY - */ - struct ia64_pal_retval result; - - INIT_PAL_STATUS_UNIMPLEMENTED(result); - - return result; -} - -static struct ia64_pal_retval -pal_platform_addr(VCPU *vcpu) { - struct ia64_pal_retval result; - - INIT_PAL_STATUS_SUCCESS(result); - - return result; -} - -static struct ia64_pal_retval -pal_halt(VCPU *vcpu) { - //bugbug: to be implement. - struct ia64_pal_retval result; - - INIT_PAL_STATUS_UNIMPLEMENTED(result); - - return result; -} - -static struct ia64_pal_retval -pal_halt_light(VCPU *vcpu) { - struct ia64_pal_retval result; - - if (!is_unmasked_irq(vcpu)) - do_sched_op_compat(SCHEDOP_block, 0); - - INIT_PAL_STATUS_SUCCESS(result); - - return result; -} - -static struct ia64_pal_retval -pal_cache_read(VCPU *vcpu) { - struct ia64_pal_retval result; - - INIT_PAL_STATUS_UNIMPLEMENTED(result); - - return result; -} - -static struct ia64_pal_retval -pal_cache_write(VCPU *vcpu) { - struct ia64_pal_retval result; - - INIT_PAL_STATUS_UNIMPLEMENTED(result); - - return result; -} - -static struct ia64_pal_retval -pal_bus_get_features(VCPU *vcpu) { - struct ia64_pal_retval result; - - INIT_PAL_STATUS_UNIMPLEMENTED(result); - - return result; -} - -static struct ia64_pal_retval -pal_cache_summary(VCPU *vcpu) { - struct ia64_pal_retval result; - - INIT_PAL_STATUS_UNIMPLEMENTED(result); - - return result; -} - -static struct ia64_pal_retval -pal_cache_init(VCPU *vcpu) { - struct ia64_pal_retval result; - - INIT_PAL_STATUS_SUCCESS(result); - - return result; -} - -static struct ia64_pal_retval -pal_cache_info(VCPU *vcpu) { - struct ia64_pal_retval result; - - INIT_PAL_STATUS_UNIMPLEMENTED(result); - - return result; -} - -static struct ia64_pal_retval -pal_cache_prot_info(VCPU *vcpu) { - struct ia64_pal_retval result; - - INIT_PAL_STATUS_UNIMPLEMENTED(result); - - return result; -} - -static struct ia64_pal_retval -pal_mem_attrib(VCPU *vcpu) { - struct ia64_pal_retval result; - - INIT_PAL_STATUS_UNIMPLEMENTED(result); - - return result; -} - -static struct ia64_pal_retval -pal_debug_info(VCPU *vcpu) { - struct ia64_pal_retval result; - - INIT_PAL_STATUS_UNIMPLEMENTED(result); - - return result; -} - -static struct ia64_pal_retval -pal_fixed_addr(VCPU *vcpu) { - struct ia64_pal_retval result; - - INIT_PAL_STATUS_UNIMPLEMENTED(result); - - return result; -} - -static struct ia64_pal_retval -pal_freq_base(VCPU *vcpu) { - struct ia64_pal_retval result; - struct ia64_sal_retval isrv; - - PAL_CALL(result,PAL_FREQ_BASE, 0, 0, 0); - /* - * PAL_FREQ_BASE may not be implemented in some platforms, - * call SAL instead. - */ - if (result.v0 == 0) { - SAL_CALL(isrv, SAL_FREQ_BASE, - SAL_FREQ_BASE_PLATFORM, 0, 0, 0, 0, 0, 0); - result.status = isrv.status; - result.v0 = isrv.v0; - result.v1 = result.v2 = 0; - } - return result; -} - -static struct ia64_pal_retval -pal_freq_ratios(VCPU *vcpu) { - struct ia64_pal_retval result; - - PAL_CALL(result, PAL_FREQ_RATIOS, 0, 0, 0); - return result; -} - -static struct ia64_pal_retval -pal_halt_info(VCPU *vcpu) { - struct ia64_pal_retval result; - - INIT_PAL_STATUS_UNIMPLEMENTED(result); - - return result; -} - -static struct ia64_pal_retval -pal_logical_to_physica(VCPU *vcpu) { - struct ia64_pal_retval result; - - INIT_PAL_STATUS_UNIMPLEMENTED(result); - - return result; -} - -static struct ia64_pal_retval -pal_perf_mon_info(VCPU *vcpu) { - struct ia64_pal_retval result; - - INIT_PAL_STATUS_UNIMPLEMENTED(result); - - return result; -} - -static struct ia64_pal_retval -pal_proc_get_features(VCPU *vcpu) { - struct ia64_pal_retval result; - - INIT_PAL_STATUS_UNIMPLEMENTED(result); - - return result; -} - -static struct ia64_pal_retval -pal_ptce_info(VCPU *vcpu) { - struct ia64_pal_retval result; - - INIT_PAL_STATUS_UNIMPLEMENTED(result); - - return result; -} - -static struct ia64_pal_retval -pal_register_info(VCPU *vcpu) { - struct ia64_pal_retval result; - - INIT_PAL_STATUS_UNIMPLEMENTED(result); - - return result; -} - -static struct ia64_pal_retval -pal_rse_info(VCPU *vcpu) { - struct ia64_pal_retval result; - - INIT_PAL_STATUS_UNIMPLEMENTED(result); - - return result; -} - -static struct ia64_pal_retval -pal_test_info(VCPU *vcpu) { - struct ia64_pal_retval result; - - INIT_PAL_STATUS_UNIMPLEMENTED(result); - - return result; -} - -static struct ia64_pal_retval -pal_vm_summary(VCPU *vcpu) { - pal_vm_info_1_u_t vminfo1; - pal_vm_info_2_u_t vminfo2; - struct ia64_pal_retval result; - - PAL_CALL(result, PAL_VM_SUMMARY, 0, 0, 0); - if (!result.status) { - vminfo1.pvi1_val = result.v0; - vminfo1.pal_vm_info_1_s.max_itr_entry = NITRS -1; - vminfo1.pal_vm_info_1_s.max_dtr_entry = NDTRS -1; - result.v0 = vminfo1.pvi1_val; - vminfo2.pal_vm_info_2_s.impl_va_msb = GUEST_IMPL_VA_MSB; - vminfo2.pal_vm_info_2_s.rid_size = - current->domain->arch.rid_bits; - result.v1 = vminfo2.pvi2_val; - } - return result; -} - -static struct ia64_pal_retval -pal_vm_info(VCPU *vcpu) { - struct ia64_pal_retval result; - - INIT_PAL_STATUS_UNIMPLEMENTED(result); - - return result; -} - -static struct ia64_pal_retval -pal_vm_page_size(VCPU *vcpu) { - struct ia64_pal_retval result; - - INIT_PAL_STATUS_UNIMPLEMENTED(result); - - return result; -} void -pal_emul(VCPU *vcpu) { - UINT64 gr28; +pal_emul(struct vcpu *vcpu) +{ + u64 gr28, gr29, gr30, gr31; struct ia64_pal_retval result; - vcpu_get_gr_nat(vcpu,28,&gr28); //bank1 - - perfc_incrc(vmx_pal_emul); - switch (gr28) { - case PAL_CACHE_FLUSH: - result = pal_cache_flush(vcpu); - break; - - case PAL_PREFETCH_VISIBILITY: - result = pal_prefetch_visibility(vcpu); - break; - - case PAL_VM_TR_READ: - result = pal_vm_tr_read(vcpu); - break; - - case PAL_HALT: - result = pal_halt(vcpu); - break; - - case PAL_HALT_LIGHT: - result = pal_halt_light(vcpu); - break; - - case PAL_CACHE_READ: - result = pal_cache_read(vcpu); - break; + vcpu_get_gr_nat(vcpu, 28, &gr28); //bank1 - case PAL_CACHE_WRITE: - result = pal_cache_write(vcpu); - break; + /* FIXME: works only for static calling convention ? */ + vcpu_get_gr_nat(vcpu, 29, &gr29); + vcpu_get_gr_nat(vcpu, 30, &gr30); + vcpu_get_gr_nat(vcpu, 31, &gr31); - case PAL_PLATFORM_ADDR: - result = pal_platform_addr(vcpu); - break; - - case PAL_FREQ_RATIOS: - result = pal_freq_ratios(vcpu); - break; - - case PAL_FREQ_BASE: - result = pal_freq_base(vcpu); - break; - - case PAL_BUS_GET_FEATURES : - result = pal_bus_get_features(vcpu); - break; - - case PAL_CACHE_SUMMARY : - result = pal_cache_summary(vcpu); - break; - - case PAL_CACHE_INIT : - result = pal_cache_init(vcpu); - break; - - case PAL_CACHE_INFO : - result = pal_cache_info(vcpu); - break; - - case PAL_CACHE_PROT_INFO : - result = pal_cache_prot_info(vcpu); - break; - - case PAL_MEM_ATTRIB : - result = pal_mem_attrib(vcpu); - break; - - case PAL_DEBUG_INFO : - result = pal_debug_info(vcpu); - break; - - case PAL_FIXED_ADDR : - result = pal_fixed_addr(vcpu); - break; - - case PAL_HALT_INFO : - result = pal_halt_info(vcpu); - break; - - case PAL_LOGICAL_TO_PHYSICAL : - result = pal_logical_to_physica(vcpu); - break; - - case PAL_PERF_MON_INFO : - result = pal_perf_mon_info(vcpu); - break; - - case PAL_PROC_GET_FEATURES: - result = pal_proc_get_features(vcpu); - break; - - case PAL_PTCE_INFO : - result = pal_ptce_info(vcpu); - break; - - case PAL_REGISTER_INFO : - result = pal_register_info(vcpu); - break; - - case PAL_RSE_INFO : - result = pal_rse_info(vcpu); - break; - - case PAL_TEST_PROC : - result = pal_test_info(vcpu); - break; - - case PAL_VM_SUMMARY : - result = pal_vm_summary(vcpu); - break; - - case PAL_VM_INFO : - result = pal_vm_info(vcpu); - break; - - case PAL_VM_PAGE_SIZE : - result = pal_vm_page_size(vcpu); - break; + perfc_incrc(vmx_pal_emul); + result = xen_pal_emulator(gr28, gr29, gr30, gr31); - default: - panic_domain(vcpu_regs(vcpu),"pal_emul(): guest " - "call unsupported pal" ); - } - set_pal_result(vcpu, result); + vcpu_set_gr(vcpu, 8, result.status, 0); + vcpu_set_gr(vcpu, 9, result.v0, 0); + vcpu_set_gr(vcpu, 10, result.v1, 0); + vcpu_set_gr(vcpu, 11, result.v2, 0); } void -sal_emul(VCPU *v) { +sal_emul(struct vcpu *v) +{ struct sal_ret_values result; result = sal_emulator(vcpu_get_gr(v, 32), vcpu_get_gr(v, 33), vcpu_get_gr(v, 34), vcpu_get_gr(v, 35), vcpu_get_gr(v, 36), vcpu_get_gr(v, 37), vcpu_get_gr(v, 38), vcpu_get_gr(v, 39)); - set_sal_result(v, result); + + vcpu_set_gr(v, 8, result.r8, 0); + vcpu_set_gr(v, 9, result.r9, 0); + vcpu_set_gr(v, 10, result.r10, 0); + vcpu_set_gr(v, 11, result.r11, 0); } diff --git a/xen/arch/ia64/vmx/vlsapic.c b/xen/arch/ia64/vmx/vlsapic.c index 0bc909f127..5ab03e4730 100644 --- a/xen/arch/ia64/vmx/vlsapic.c +++ b/xen/arch/ia64/vmx/vlsapic.c @@ -49,14 +49,67 @@ * Update the checked last_itc. */ -extern void vmx_reflect_interruption(UINT64 ifa,UINT64 isr,UINT64 iim, - UINT64 vector,REGS *regs); +extern void vmx_reflect_interruption(u64 ifa, u64 isr, u64 iim, + u64 vector, REGS *regs); static void update_last_itc(vtime_t *vtm, uint64_t cur_itc) { vtm->last_itc = cur_itc; } /* + * Next for vLSapic + */ + +#define NMI_VECTOR 2 +#define ExtINT_VECTOR 0 +#define NULL_VECTOR -1 + +static void update_vhpi(VCPU *vcpu, int vec) +{ + u64 vhpi; + + if (vec == NULL_VECTOR) + vhpi = 0; + else if (vec == NMI_VECTOR) + vhpi = 32; + else if (vec == ExtINT_VECTOR) + vhpi = 16; + else + vhpi = vec >> 4; + + VCPU(vcpu,vhpi) = vhpi; + // TODO: Add support for XENO + if (VCPU(vcpu,vac).a_int) + ia64_call_vsa(PAL_VPS_SET_PENDING_INTERRUPT, + (uint64_t)vcpu->arch.privregs, 0, 0, 0, 0, 0, 0); +} + + +/* + * May come from virtualization fault or + * nested host interrupt. + */ +static int vmx_vcpu_unpend_interrupt(VCPU *vcpu, uint8_t vector) +{ + uint64_t spsr; + int ret; + + if (vector & ~0xff) { + DPRINTK("vmx_vcpu_pend_interrupt: bad vector\n"); + return -1; + } + + local_irq_save(spsr); + ret = test_and_clear_bit(vector, &VCPU(vcpu, irr[0])); + local_irq_restore(spsr); + + if (ret) + vcpu->arch.irq_new_pending = 1; + + return ret; +} + +/* * ITC value saw in guest (host+offset+drift). */ static uint64_t now_itc(vtime_t *vtm) @@ -107,9 +160,6 @@ static void vtm_timer_fn(void *data) } vtm=&(vcpu->arch.arch_vmx.vtm); cur_itc = now_itc(vtm); - // vitm =VCPU(vcpu, itm); - //fire_itc2 = cur_itc; - //fire_itm2 = vitm; update_last_itc(vtm,cur_itc); // pseudo read to update vITC } @@ -137,6 +187,7 @@ uint64_t vtm_get_itc(VCPU *vcpu) vtm=&(vcpu->arch.arch_vmx.vtm); guest_itc = now_itc(vtm); + update_last_itc(vtm, guest_itc); // update vITC return guest_itc; } @@ -158,7 +209,7 @@ void vtm_set_itc(VCPU *vcpu, uint64_t new_itc) vtm->last_itc = new_itc; } if(vitm < new_itc){ - clear_bit(ITV_VECTOR(vitv), &VCPU(vcpu, irr[0])); + vmx_vcpu_unpend_interrupt(vcpu, ITV_VECTOR(vitv)); stop_timer(&vtm->vtm_timer); } } @@ -175,12 +226,12 @@ void vtm_set_itm(VCPU *vcpu, uint64_t val) vitv = VCPU(vcpu, itv); vtm=&(vcpu->arch.arch_vmx.vtm); // TODO; need to handle VHPI in future - clear_bit(ITV_VECTOR(vitv), &VCPU(vcpu, irr[0])); + vmx_vcpu_unpend_interrupt(vcpu, ITV_VECTOR(vitv)); VCPU(vcpu,itm)=val; - cur_itc =now_itc(vtm); - if(time_before(val, cur_itc)) - val = cur_itc; - if(val > vtm->last_itc){ + if (val >= vtm->last_itc) { + cur_itc = now_itc(vtm); + if (time_before(val, cur_itc)) + val = cur_itc; expires = NOW() + cycle_to_ns(val-cur_itc) + TIMER_SLOP; set_timer(&vtm->vtm_timer, expires); }else{ @@ -195,10 +246,10 @@ void vtm_set_itv(VCPU *vcpu, uint64_t val) olditv = VCPU(vcpu, itv); VCPU(vcpu, itv) = val; if(ITV_IRQ_MASK(val)){ - clear_bit(ITV_VECTOR(olditv), &VCPU(vcpu, irr[0])); + vmx_vcpu_unpend_interrupt(vcpu, ITV_VECTOR(olditv)); }else if(ITV_VECTOR(olditv)!=ITV_VECTOR(val)){ - if(test_and_clear_bit(ITV_VECTOR(olditv), &VCPU(vcpu, irr[0]))) - set_bit(ITV_VECTOR(val), &VCPU(vcpu, irr[0])); + if (vmx_vcpu_unpend_interrupt(vcpu, ITV_VECTOR(olditv))) + vmx_vcpu_pend_interrupt(vcpu, ITV_VECTOR(val)); } } @@ -272,36 +323,6 @@ void vtm_domain_in(VCPU *vcpu) } */ -/* - * Next for vLSapic - */ - -#define NMI_VECTOR 2 -#define ExtINT_VECTOR 0 -#define NULL_VECTOR -1 -static void update_vhpi(VCPU *vcpu, int vec) -{ - u64 vhpi; - if ( vec == NULL_VECTOR ) { - vhpi = 0; - } - else if ( vec == NMI_VECTOR ) { // NMI - vhpi = 32; - } else if (vec == ExtINT_VECTOR) { //ExtINT - vhpi = 16; - } - else { - vhpi = vec >> 4; - } - - VCPU(vcpu,vhpi) = vhpi; - // TODO: Add support for XENO - if ( VCPU(vcpu,vac).a_int ) { - ia64_call_vsa ( PAL_VPS_SET_PENDING_INTERRUPT, - (uint64_t) &(vcpu->arch.privregs), 0, 0,0,0,0,0); - } -} - #ifdef V_IOSAPIC_READY /* Assist to check virtual interrupt lines */ void vmx_virq_line_assist(struct vcpu *v) @@ -524,16 +545,20 @@ int vmx_vcpu_pend_interrupt(VCPU *vcpu, uint8_t vector) local_irq_save(spsr); ret = test_and_set_bit(vector, &VCPU(vcpu, irr[0])); local_irq_restore(spsr); - vcpu->arch.irq_new_pending = 1; + + if (!ret) + vcpu->arch.irq_new_pending = 1; + return ret; } + /* * Add batch of pending interrupt. * The interrupt source is contained in pend_irr[0-3] with * each bits stand for one interrupt. */ -void vmx_vcpu_pend_batch_interrupt(VCPU *vcpu, UINT64 *pend_irr) +void vmx_vcpu_pend_batch_interrupt(VCPU *vcpu, u64 *pend_irr) { uint64_t spsr; int i; @@ -559,14 +584,13 @@ void vmx_vcpu_pend_batch_interrupt(VCPU *vcpu, UINT64 *pend_irr) */ int vmx_check_pending_irq(VCPU *vcpu) { - uint64_t spsr, mask; - int h_pending, h_inservice; - uint64_t isr; - IA64_PSR vpsr; + int mask, h_pending, h_inservice; + uint64_t isr; + IA64_PSR vpsr; REGS *regs=vcpu_regs(vcpu); - local_irq_save(spsr); h_pending = highest_pending_irq(vcpu); if ( h_pending == NULL_VECTOR ) { + update_vhpi(vcpu, NULL_VECTOR); h_pending = SPURIOUS_VECTOR; goto chk_irq_exit; } @@ -578,13 +602,11 @@ int vmx_check_pending_irq(VCPU *vcpu) isr = vpsr.val & IA64_PSR_RI; if ( !vpsr.ic ) panic_domain(regs,"Interrupt when IC=0\n"); + update_vhpi(vcpu, h_pending); + vmx_reflect_interruption(0, isr, 0, 12, regs); // EXT IRQ + } else if (mask == IRQ_MASKED_BY_INSVC) { if (VCPU(vcpu, vhpi)) update_vhpi(vcpu, NULL_VECTOR); - vmx_reflect_interruption(0,isr,0, 12, regs ); // EXT IRQ - } - else if ( mask == IRQ_MASKED_BY_INSVC ) { - // cann't inject VHPI -// DPRINTK("IRQ masked by higher inservice\n"); } else { // masked by vpsr.i or vtpr. @@ -592,7 +614,6 @@ int vmx_check_pending_irq(VCPU *vcpu) } chk_irq_exit: - local_irq_restore(spsr); return h_pending; } @@ -602,17 +623,13 @@ chk_irq_exit: void guest_write_eoi(VCPU *vcpu) { int vec; - uint64_t spsr; vec = highest_inservice_irq(vcpu); if ( vec == NULL_VECTOR ) - panic_domain(vcpu_regs(vcpu),"Wrong vector to EOI\n"); - local_irq_save(spsr); + panic_domain(vcpu_regs(vcpu), "Wrong vector to EOI\n"); VLSAPIC_INSVC(vcpu,vec>>6) &= ~(1UL <<(vec&63)); - local_irq_restore(spsr); VCPU(vcpu, eoi)=0; // overwrite the data vcpu->arch.irq_new_pending=1; -// vmx_check_pending_irq(vcpu); } int is_unmasked_irq(VCPU *vcpu) @@ -631,23 +648,21 @@ int is_unmasked_irq(VCPU *vcpu) uint64_t guest_read_vivr(VCPU *vcpu) { - int vec, h_inservice; - uint64_t spsr; - - local_irq_save(spsr); + int vec, h_inservice, mask; vec = highest_pending_irq(vcpu); h_inservice = highest_inservice_irq(vcpu); - if ( vec == NULL_VECTOR || - irq_masked(vcpu, vec, h_inservice) != IRQ_NO_MASKED ) { - local_irq_restore(spsr); + mask = irq_masked(vcpu, vec, h_inservice); + if (vec == NULL_VECTOR || mask == IRQ_MASKED_BY_INSVC) { + if (VCPU(vcpu, vhpi)) + update_vhpi(vcpu, NULL_VECTOR); + return IA64_SPURIOUS_INT_VECTOR; + } + if (mask == IRQ_MASKED_BY_VTPR) { + update_vhpi(vcpu, vec); return IA64_SPURIOUS_INT_VECTOR; } - VLSAPIC_INSVC(vcpu,vec>>6) |= (1UL <<(vec&63)); - VCPU(vcpu, irr[vec>>6]) &= ~(1UL <<(vec&63)); - if (VCPU(vcpu, vhpi)) - update_vhpi(vcpu, NULL_VECTOR); // clear VHPI till EOI or IRR write - local_irq_restore(spsr); + vmx_vcpu_unpend_interrupt(vcpu, vec); return (uint64_t)vec; } @@ -657,7 +672,6 @@ static void generate_exirq(VCPU *vcpu) uint64_t isr; REGS *regs=vcpu_regs(vcpu); vpsr.val = VCPU(vcpu, vpsr); - update_vhpi(vcpu, NULL_VECTOR); isr = vpsr.val & IA64_PSR_RI; if ( !vpsr.ic ) panic_domain(regs,"Interrupt when IC=0\n"); @@ -669,7 +683,6 @@ void vhpi_detection(VCPU *vcpu) uint64_t threshold,vhpi; tpr_t vtpr; IA64_PSR vpsr; - vpsr.val = VCPU(vcpu, vpsr); vtpr.val = VCPU(vcpu, tpr); @@ -683,9 +696,5 @@ void vhpi_detection(VCPU *vcpu) void vmx_vexirq(VCPU *vcpu) { - static uint64_t vexirq_count=0; - - vexirq_count ++; - printk("Virtual ex-irq %ld\n", vexirq_count); generate_exirq (vcpu); } diff --git a/xen/arch/ia64/vmx/vmmu.c b/xen/arch/ia64/vmx/vmmu.c index 9412810f3d..17599de150 100644 --- a/xen/arch/ia64/vmx/vmmu.c +++ b/xen/arch/ia64/vmx/vmmu.c @@ -363,7 +363,7 @@ fetch_code(VCPU *vcpu, u64 gip, IA64_BUNDLE *pbundle) return IA64_NO_FAULT; } -IA64FAULT vmx_vcpu_itc_i(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa) +IA64FAULT vmx_vcpu_itc_i(VCPU *vcpu, u64 pte, u64 itir, u64 ifa) { #ifdef VTLB_DEBUG int slot; @@ -382,7 +382,7 @@ IA64FAULT vmx_vcpu_itc_i(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa) return IA64_NO_FAULT; } -IA64FAULT vmx_vcpu_itc_d(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa) +IA64FAULT vmx_vcpu_itc_d(VCPU *vcpu, u64 pte, u64 itir, u64 ifa) { u64 gpfn; #ifdef VTLB_DEBUG @@ -456,7 +456,15 @@ IA64FAULT vmx_vcpu_itr_d(VCPU *vcpu, u64 slot, u64 pte, u64 itir, u64 ifa) } #endif pte &= ~PAGE_FLAGS_RV_MASK; - thash_purge_entries(vcpu, va, ps); + + /* This is a bad workaround + In Linux, region 7 use 16M pagesize and is identity mapped. + VHPT page size is 16K in XEN. If purge VHPT while guest insert 16M, + it will iteratively purge VHPT 1024 times, which makes XEN/IPF very + slow. XEN doesn't purge VHPT + */ + if (ps != _PAGE_SIZE_16M) + thash_purge_entries(vcpu, va, ps); gpfn = (pte & _PAGE_PPN_MASK)>> PAGE_SHIFT; if (VMX_DOMAIN(vcpu) && __gpfn_is_io(vcpu->domain, gpfn)) pte |= VTLB_PTE_IO; @@ -470,7 +478,7 @@ IA64FAULT vmx_vcpu_itr_d(VCPU *vcpu, u64 slot, u64 pte, u64 itir, u64 ifa) -IA64FAULT vmx_vcpu_ptr_d(VCPU *vcpu,UINT64 ifa,UINT64 ps) +IA64FAULT vmx_vcpu_ptr_d(VCPU *vcpu,u64 ifa, u64 ps) { int index; u64 va; @@ -483,7 +491,7 @@ IA64FAULT vmx_vcpu_ptr_d(VCPU *vcpu,UINT64 ifa,UINT64 ps) return IA64_NO_FAULT; } -IA64FAULT vmx_vcpu_ptr_i(VCPU *vcpu,UINT64 ifa,UINT64 ps) +IA64FAULT vmx_vcpu_ptr_i(VCPU *vcpu, u64 ifa, u64 ps) { int index; u64 va; @@ -496,7 +504,7 @@ IA64FAULT vmx_vcpu_ptr_i(VCPU *vcpu,UINT64 ifa,UINT64 ps) return IA64_NO_FAULT; } -IA64FAULT vmx_vcpu_ptc_l(VCPU *vcpu, UINT64 va, UINT64 ps) +IA64FAULT vmx_vcpu_ptc_l(VCPU *vcpu, u64 va, u64 ps) { va = PAGEALIGN(va, ps); thash_purge_entries(vcpu, va, ps); @@ -504,19 +512,19 @@ IA64FAULT vmx_vcpu_ptc_l(VCPU *vcpu, UINT64 va, UINT64 ps) } -IA64FAULT vmx_vcpu_ptc_e(VCPU *vcpu, UINT64 va) +IA64FAULT vmx_vcpu_ptc_e(VCPU *vcpu, u64 va) { thash_purge_all(vcpu); return IA64_NO_FAULT; } -IA64FAULT vmx_vcpu_ptc_g(VCPU *vcpu, UINT64 va, UINT64 ps) +IA64FAULT vmx_vcpu_ptc_g(VCPU *vcpu, u64 va, u64 ps) { vmx_vcpu_ptc_ga(vcpu, va, ps); return IA64_ILLOP_FAULT; } /* -IA64FAULT vmx_vcpu_ptc_ga(VCPU *vcpu,UINT64 va,UINT64 ps) +IA64FAULT vmx_vcpu_ptc_ga(VCPU *vcpu, u64 va, u64 ps) { vmx_vcpu_ptc_l(vcpu, va, ps); return IA64_NO_FAULT; @@ -554,7 +562,7 @@ static void ptc_ga_remote_func (void *varg) } -IA64FAULT vmx_vcpu_ptc_ga(VCPU *vcpu,UINT64 va,UINT64 ps) +IA64FAULT vmx_vcpu_ptc_ga(VCPU *vcpu, u64 va, u64 ps) { struct domain *d = vcpu->domain; @@ -588,7 +596,7 @@ IA64FAULT vmx_vcpu_ptc_ga(VCPU *vcpu,UINT64 va,UINT64 ps) } -IA64FAULT vmx_vcpu_thash(VCPU *vcpu, UINT64 vadr, UINT64 *pval) +IA64FAULT vmx_vcpu_thash(VCPU *vcpu, u64 vadr, u64 *pval) { PTA vpta; ia64_rr vrr; @@ -608,7 +616,7 @@ IA64FAULT vmx_vcpu_thash(VCPU *vcpu, UINT64 vadr, UINT64 *pval) } -IA64FAULT vmx_vcpu_ttag(VCPU *vcpu, UINT64 vadr, UINT64 *pval) +IA64FAULT vmx_vcpu_ttag(VCPU *vcpu, u64 vadr, u64 *pval) { ia64_rr vrr; PTA vpta; @@ -624,7 +632,7 @@ IA64FAULT vmx_vcpu_ttag(VCPU *vcpu, UINT64 vadr, UINT64 *pval) -IA64FAULT vmx_vcpu_tpa(VCPU *vcpu, UINT64 vadr, UINT64 *padr) +IA64FAULT vmx_vcpu_tpa(VCPU *vcpu, u64 vadr, u64 *padr) { thash_data_t *data; ISR visr,pt_isr; @@ -637,37 +645,30 @@ IA64FAULT vmx_vcpu_tpa(VCPU *vcpu, UINT64 vadr, UINT64 *padr) visr.ei=pt_isr.ei; visr.ir=pt_isr.ir; vpsr.val = VCPU(vcpu, vpsr); - if(vpsr.ic==0){ - visr.ni=1; - } visr.na=1; data = vtlb_lookup(vcpu, vadr, DSIDE_TLB); if(data){ if(data->p==0){ - visr.na=1; vcpu_set_isr(vcpu,visr.val); - page_not_present(vcpu, vadr); + data_page_not_present(vcpu, vadr); return IA64_FAULT; }else if(data->ma == VA_MATTR_NATPAGE){ - visr.na = 1; vcpu_set_isr(vcpu, visr.val); dnat_page_consumption(vcpu, vadr); return IA64_FAULT; }else{ *padr = ((data->ppn >> (data->ps - 12)) << data->ps) | - (vadr & (PSIZE(data->ps) - 1)); + (vadr & (PSIZE(data->ps) - 1)); return IA64_NO_FAULT; } } data = vhpt_lookup(vadr); if(data){ if(data->p==0){ - visr.na=1; vcpu_set_isr(vcpu,visr.val); - page_not_present(vcpu, vadr); + data_page_not_present(vcpu, vadr); return IA64_FAULT; }else if(data->ma == VA_MATTR_NATPAGE){ - visr.na = 1; vcpu_set_isr(vcpu, visr.val); dnat_page_consumption(vcpu, vadr); return IA64_FAULT; @@ -717,7 +718,7 @@ IA64FAULT vmx_vcpu_tpa(VCPU *vcpu, UINT64 vadr, UINT64 *padr) } } -IA64FAULT vmx_vcpu_tak(VCPU *vcpu, UINT64 vadr, UINT64 *key) +IA64FAULT vmx_vcpu_tak(VCPU *vcpu, u64 vadr, u64 *key) { thash_data_t *data; PTA vpta; @@ -734,52 +735,3 @@ IA64FAULT vmx_vcpu_tak(VCPU *vcpu, UINT64 vadr, UINT64 *key) } return IA64_NO_FAULT; } - -/* - * [FIXME] Is there any effective way to move this routine - * into vmx_uaccess.h? struct exec_domain is incomplete type - * in that way... - * - * This is the interface to lookup virtual TLB, and then - * return corresponding machine address in 2nd parameter. - * The 3rd parameter contains how many bytes mapped by - * matched vTLB entry, thus to allow caller copy more once. - * - * If failed to lookup, -EFAULT is returned. Or else reutrn - * 0. All upper domain access utilities rely on this routine - * to determine the real machine address. - * - * Yes, put_user and get_user seems to somhow slow upon it. - * However it's the necessary steps for any vmx domain virtual - * address, since that's difference address space as HV's one. - * Later some short-circuit may be created for special case - */ -long -__domain_va_to_ma(unsigned long va, unsigned long* ma, unsigned long *len) -{ - unsigned long mpfn, gpfn, m, n = *len; - unsigned long end; /* end of the area mapped by current entry */ - thash_data_t *entry; - struct vcpu *v = current; - - entry = vtlb_lookup(v, va, DSIDE_TLB); - if (entry == NULL) - return -EFAULT; - - gpfn =(entry->ppn>>(PAGE_SHIFT-12)); - gpfn =PAGEALIGN(gpfn,(entry->ps-PAGE_SHIFT)); - gpfn = gpfn | POFFSET(va>>PAGE_SHIFT,(entry->ps-PAGE_SHIFT)); - - mpfn = gmfn_to_mfn(v->domain, gpfn); - m = (mpfn<<PAGE_SHIFT) | (va & (PAGE_SIZE - 1)); - /* machine address may be not continuous */ - end = PAGEALIGN(m, PAGE_SHIFT) + PAGE_SIZE; - /*end = PAGEALIGN(m, entry->ps) + PSIZE(entry->ps);*/ - /* Current entry can't map all requested area */ - if ((m + n) > end) - n = end - m; - - *ma = m; - *len = n; - return 0; -} diff --git a/xen/arch/ia64/vmx/vmx_entry.S b/xen/arch/ia64/vmx/vmx_entry.S index 53b00d9019..fa2a53670f 100644 --- a/xen/arch/ia64/vmx/vmx_entry.S +++ b/xen/arch/ia64/vmx/vmx_entry.S @@ -669,7 +669,7 @@ GLOBAL_ENTRY(vmx_switch_rr7) // re-pin mappings for guest_vhpt - mov r24=IA64_TR_PERVP_VHPT + mov r24=IA64_TR_VHPT movl r25=PAGE_KERNEL ;; or loc5 = r25,loc5 // construct PA | page properties diff --git a/xen/arch/ia64/vmx/vmx_init.c b/xen/arch/ia64/vmx/vmx_init.c index df1bc94de0..2694149d5b 100644 --- a/xen/arch/ia64/vmx/vmx_init.c +++ b/xen/arch/ia64/vmx/vmx_init.c @@ -378,7 +378,8 @@ static void vmx_build_physmap_table(struct domain *d) for (j = io_ranges[i].start; j < io_ranges[i].start + io_ranges[i].size; j += PAGE_SIZE) - __assign_domain_page(d, j, io_ranges[i].type, ASSIGN_writable); + (void)__assign_domain_page(d, j, io_ranges[i].type, + ASSIGN_writable); } /* Map normal memory below 3G */ diff --git a/xen/arch/ia64/vmx/vmx_interrupt.c b/xen/arch/ia64/vmx/vmx_interrupt.c index c1f6392c41..211aa93b36 100644 --- a/xen/arch/ia64/vmx/vmx_interrupt.c +++ b/xen/arch/ia64/vmx/vmx_interrupt.c @@ -383,14 +383,29 @@ dnat_page_consumption (VCPU *vcpu, uint64_t vadr) /* Deal with * Page not present vector */ -void -page_not_present(VCPU *vcpu, u64 vadr) +static void +__page_not_present(VCPU *vcpu, u64 vadr) { /* If vPSR.ic, IFA, ITIR */ set_ifa_itir_iha (vcpu, vadr, 1, 1, 0); inject_guest_interruption(vcpu, IA64_PAGE_NOT_PRESENT_VECTOR); } + +void +data_page_not_present(VCPU *vcpu, u64 vadr) +{ + __page_not_present(vcpu, vadr); +} + + +void +inst_page_not_present(VCPU *vcpu, u64 vadr) +{ + __page_not_present(vcpu, vadr); +} + + /* Deal with * Data access rights vector */ diff --git a/xen/arch/ia64/vmx/vmx_ivt.S b/xen/arch/ia64/vmx/vmx_ivt.S index 876c942165..625c1b01e5 100644 --- a/xen/arch/ia64/vmx/vmx_ivt.S +++ b/xen/arch/ia64/vmx/vmx_ivt.S @@ -772,12 +772,22 @@ ENTRY(vmx_single_step_trap) VMX_REFLECT(36) END(vmx_single_step_trap) + .global vmx_virtualization_fault_back .org vmx_ia64_ivt+0x6100 ///////////////////////////////////////////////////////////////////////////////////////// // 0x6100 Entry 37 (size 16 bundles) Virtualization Fault ENTRY(vmx_virtualization_fault) // VMX_DBG_FAULT(37) mov r31=pr + ;; + cmp.eq p6,p0=EVENT_MOV_FROM_AR,r24 + cmp.eq p7,p0=EVENT_MOV_FROM_RR,r24 + cmp.eq p8,p0=EVENT_MOV_TO_RR,r24 + (p6) br.dptk.many vmx_asm_mov_from_ar + (p7) br.dptk.many vmx_asm_mov_from_rr + (p8) br.dptk.many vmx_asm_mov_to_rr + ;; +vmx_virtualization_fault_back: mov r19=37 adds r16 = IA64_VCPU_CAUSE_OFFSET,r21 adds r17 = IA64_VCPU_OPCODE_OFFSET,r21 diff --git a/xen/arch/ia64/vmx/vmx_phy_mode.c b/xen/arch/ia64/vmx/vmx_phy_mode.c index 8745721d54..d59e74e0e0 100644 --- a/xen/arch/ia64/vmx/vmx_phy_mode.c +++ b/xen/arch/ia64/vmx/vmx_phy_mode.c @@ -126,10 +126,16 @@ void vmx_init_all_rr(VCPU *vcpu) { VMX(vcpu, vrr[VRN0]) = 0x38; + // enable vhpt in guest physical mode + vcpu->arch.metaphysical_rr0 |= 1; + vcpu->arch.metaphysical_saved_rr0 = vrrtomrr(vcpu, 0x38); VMX(vcpu, vrr[VRN1]) = 0x38; VMX(vcpu, vrr[VRN2]) = 0x38; VMX(vcpu, vrr[VRN3]) = 0x38; VMX(vcpu, vrr[VRN4]) = 0x38; + // enable vhpt in guest physical mode + vcpu->arch.metaphysical_rr4 |= 1; + vcpu->arch.metaphysical_saved_rr4 = vrrtomrr(vcpu, 0x38); VMX(vcpu, vrr[VRN5]) = 0x38; VMX(vcpu, vrr[VRN6]) = 0x38; VMX(vcpu, vrr[VRN7]) = 0x738; @@ -141,11 +147,9 @@ void vmx_load_all_rr(VCPU *vcpu) { unsigned long psr; - ia64_rr phy_rr; local_irq_save(psr); - /* WARNING: not allow co-exist of both virtual mode and physical * mode in same region */ @@ -154,24 +158,16 @@ vmx_load_all_rr(VCPU *vcpu) panic_domain(vcpu_regs(vcpu), "Unexpected domain switch in phy emul\n"); } - phy_rr.rrval = vcpu->arch.metaphysical_rr0; - //phy_rr.ps = PAGE_SHIFT; - phy_rr.ve = 1; - - ia64_set_rr((VRN0 << VRN_SHIFT), phy_rr.rrval); + ia64_set_rr((VRN0 << VRN_SHIFT), vcpu->arch.metaphysical_rr0); ia64_dv_serialize_data(); - phy_rr.rrval = vcpu->arch.metaphysical_rr4; - //phy_rr.ps = PAGE_SHIFT; - phy_rr.ve = 1; - - ia64_set_rr((VRN4 << VRN_SHIFT), phy_rr.rrval); + ia64_set_rr((VRN4 << VRN_SHIFT), vcpu->arch.metaphysical_rr4); ia64_dv_serialize_data(); } else { ia64_set_rr((VRN0 << VRN_SHIFT), - vrrtomrr(vcpu, VMX(vcpu, vrr[VRN0]))); + vcpu->arch.metaphysical_saved_rr0); ia64_dv_serialize_data(); ia64_set_rr((VRN4 << VRN_SHIFT), - vrrtomrr(vcpu, VMX(vcpu, vrr[VRN4]))); + vcpu->arch.metaphysical_saved_rr4); ia64_dv_serialize_data(); } @@ -208,22 +204,12 @@ vmx_load_all_rr(VCPU *vcpu) void switch_to_physical_rid(VCPU *vcpu) { - UINT64 psr; - ia64_rr phy_rr, mrr; - + u64 psr; /* Save original virtual mode rr[0] and rr[4] */ psr=ia64_clear_ic(); - phy_rr.rrval = vcpu->domain->arch.metaphysical_rr0; - mrr.rrval = ia64_get_rr(VRN0 << VRN_SHIFT); - phy_rr.ps = mrr.ps; - phy_rr.ve = 1; - ia64_set_rr(VRN0<<VRN_SHIFT, phy_rr.rrval); + ia64_set_rr(VRN0<<VRN_SHIFT, vcpu->arch.metaphysical_rr0); ia64_srlz_d(); - phy_rr.rrval = vcpu->domain->arch.metaphysical_rr4; - mrr.rrval = ia64_get_rr(VRN4 << VRN_SHIFT); - phy_rr.ps = mrr.ps; - phy_rr.ve = 1; - ia64_set_rr(VRN4<<VRN_SHIFT, phy_rr.rrval); + ia64_set_rr(VRN4<<VRN_SHIFT, vcpu->arch.metaphysical_rr4); ia64_srlz_d(); ia64_set_psr(psr); @@ -235,16 +221,11 @@ switch_to_physical_rid(VCPU *vcpu) void switch_to_virtual_rid(VCPU *vcpu) { - UINT64 psr; - ia64_rr mrr; - + u64 psr; psr=ia64_clear_ic(); - - vcpu_get_rr(vcpu,VRN0<<VRN_SHIFT,&mrr.rrval); - ia64_set_rr(VRN0<<VRN_SHIFT, vrrtomrr(vcpu, mrr.rrval)); + ia64_set_rr(VRN0<<VRN_SHIFT, vcpu->arch.metaphysical_saved_rr0); ia64_srlz_d(); - vcpu_get_rr(vcpu,VRN4<<VRN_SHIFT,&mrr.rrval); - ia64_set_rr(VRN4<<VRN_SHIFT, vrrtomrr(vcpu, mrr.rrval)); + ia64_set_rr(VRN4<<VRN_SHIFT, vcpu->arch.metaphysical_saved_rr4); ia64_srlz_d(); ia64_set_psr(psr); ia64_srlz_i(); diff --git a/xen/arch/ia64/vmx/vmx_process.c b/xen/arch/ia64/vmx/vmx_process.c index 7867fd3993..a0caebfa88 100644 --- a/xen/arch/ia64/vmx/vmx_process.c +++ b/xen/arch/ia64/vmx/vmx_process.c @@ -66,7 +66,7 @@ extern unsigned long handle_fpu_swa (int fp_fault, struct pt_regs *regs, unsigne #define DOMN_PAL_REQUEST 0x110000 #define DOMN_SAL_REQUEST 0x110001 -static UINT64 vec2off[68] = {0x0,0x400,0x800,0xc00,0x1000, 0x1400,0x1800, +static u64 vec2off[68] = {0x0,0x400,0x800,0xc00,0x1000,0x1400,0x1800, 0x1c00,0x2000,0x2400,0x2800,0x2c00,0x3000,0x3400,0x3800,0x3c00,0x4000, 0x4400,0x4800,0x4c00,0x5000,0x5100,0x5200,0x5300,0x5400,0x5500,0x5600, 0x5700,0x5800,0x5900,0x5a00,0x5b00,0x5c00,0x5d00,0x5e00,0x5f00,0x6000, @@ -78,24 +78,35 @@ static UINT64 vec2off[68] = {0x0,0x400,0x800,0xc00,0x1000, 0x1400,0x1800, -void vmx_reflect_interruption(UINT64 ifa,UINT64 isr,UINT64 iim, - UINT64 vector,REGS *regs) +void vmx_reflect_interruption(u64 ifa, u64 isr, u64 iim, + u64 vector, REGS *regs) { + u64 status; VCPU *vcpu = current; - UINT64 vpsr = VCPU(vcpu, vpsr); + u64 vpsr = VCPU(vcpu, vpsr); vector=vec2off[vector]; if(!(vpsr&IA64_PSR_IC)&&(vector!=IA64_DATA_NESTED_TLB_VECTOR)){ panic_domain(regs, "Guest nested fault vector=%lx!\n", vector); } else{ // handle fpswa emulation // fp fault - if(vector == IA64_FP_FAULT_VECTOR && !handle_fpu_swa(1, regs, isr)){ - vmx_vcpu_increment_iip(vcpu); - return; + if (vector == IA64_FP_FAULT_VECTOR) { + status = handle_fpu_swa(1, regs, isr); + if (!status) { + vmx_vcpu_increment_iip(vcpu); + return; + } else if (IA64_RETRY == status) + return; } //fp trap - else if(vector == IA64_FP_TRAP_VECTOR && !handle_fpu_swa(0, regs, isr)){ - return; + else if (vector == IA64_FP_TRAP_VECTOR) { + status = handle_fpu_swa(0, regs, isr); + if (!status) + return; + else if (IA64_RETRY == status) { + vmx_vcpu_decrement_iip(vcpu); + return; + } } } VCPU(vcpu,isr)=isr; @@ -187,7 +198,7 @@ void leave_hypervisor_tail(struct pt_regs *regs) { struct domain *d = current->domain; struct vcpu *v = current; - int callback_irq; + // FIXME: Will this work properly if doing an RFI??? if (!is_idle_domain(d) ) { // always comes from guest // struct pt_regs *user_regs = vcpu_regs(current); @@ -215,11 +226,14 @@ void leave_hypervisor_tail(struct pt_regs *regs) // v->arch.irq_new_pending = 1; // } - callback_irq = d->arch.hvm_domain.params[HVM_PARAM_CALLBACK_IRQ]; - if (callback_irq != 0 && local_events_need_delivery()) { - /*inject para-device call back irq*/ - v->vcpu_info->evtchn_upcall_mask = 1; - vmx_vcpu_pend_interrupt(v, callback_irq); + if (v->vcpu_id == 0) { + int callback_irq = + d->arch.hvm_domain.params[HVM_PARAM_CALLBACK_IRQ]; + if (callback_irq != 0 && local_events_need_delivery()) { + /*inject para-device call back irq*/ + v->vcpu_info->evtchn_upcall_mask = 1; + vmx_vcpu_pend_interrupt(v, callback_irq); + } } if ( v->arch.irq_new_pending ) { @@ -228,10 +242,7 @@ void leave_hypervisor_tail(struct pt_regs *regs) vmx_check_pending_irq(v); return; } - if (VCPU(v, vac).a_int) { - vhpi_detection(v); - return; - } + if (v->arch.irq_new_condition) { v->arch.irq_new_condition = 0; vhpi_detection(v); @@ -239,7 +250,7 @@ void leave_hypervisor_tail(struct pt_regs *regs) } } -extern ia64_rr vmx_vcpu_rr(VCPU *vcpu,UINT64 vadr); +extern ia64_rr vmx_vcpu_rr(VCPU *vcpu, u64 vadr); static int vmx_handle_lds(REGS* regs) { @@ -252,22 +263,27 @@ IA64FAULT vmx_hpw_miss(u64 vadr , u64 vec, REGS* regs) { IA64_PSR vpsr; - int type=ISIDE_TLB; + int type; u64 vhpt_adr, gppa, pteval, rr, itir; ISR misr; -// REGS *regs; + PTA vpta; thash_data_t *data; VCPU *v = current; -#ifdef VTLB_DEBUG - check_vtlb_sanity(vtlb); - dump_vtlb(vtlb); -#endif + vpsr.val = VCPU(v, vpsr); - misr.val=VMX(v,cr_isr); + misr.val = VMX(v,cr_isr); + + if (vec == 1) + type = ISIDE_TLB; + else if (vec == 2) + type = DSIDE_TLB; + else + panic_domain(regs, "wrong vec:%lx\n", vec); if(is_physical_mode(v)&&(!(vadr<<1>>62))){ if(vec==2){ - if(v->domain!=dom0&&__gpfn_is_io(v->domain,(vadr<<1)>>(PAGE_SHIFT+1))){ + if (v->domain != dom0 + && __gpfn_is_io(v->domain, (vadr << 1) >> (PAGE_SHIFT + 1))) { emulate_io_inst(v,((vadr<<1)>>1),4); // UC return IA64_FAULT; } @@ -275,11 +291,6 @@ vmx_hpw_miss(u64 vadr , u64 vec, REGS* regs) physical_tlb_miss(v, vadr); return IA64_FAULT; } - if(vec == 1) type = ISIDE_TLB; - else if(vec == 2) type = DSIDE_TLB; - else panic_domain(regs,"wrong vec:%lx\n",vec); - -// prepare_if_physical_mode(v); if((data=vtlb_lookup(v, vadr,type))!=0){ if (v->domain != dom0 && type == DSIDE_TLB) { @@ -298,95 +309,106 @@ vmx_hpw_miss(u64 vadr , u64 vec, REGS* regs) thash_vhpt_insert(v,data->page_flags, data->itir ,vadr); }else if(type == DSIDE_TLB){ + if (misr.sp) return vmx_handle_lds(regs); + if(!vhpt_enabled(v, vadr, misr.rs?RSE_REF:DATA_REF)){ if(vpsr.ic){ vcpu_set_isr(v, misr.val); alt_dtlb(v, vadr); return IA64_FAULT; } else{ - if(misr.sp){ - //TODO lds emulation - //panic("Don't support speculation load"); - return vmx_handle_lds(regs); - }else{ - nested_dtlb(v); - return IA64_FAULT; - } + nested_dtlb(v); + return IA64_FAULT; } - } else{ - vmx_vcpu_thash(v, vadr, &vhpt_adr); - if(!guest_vhpt_lookup(vhpt_adr, &pteval)){ - if ((pteval & _PAGE_P) && - ((pteval & _PAGE_MA_MASK) != _PAGE_MA_ST)) { - vcpu_get_rr(v, vadr, &rr); - itir = rr&(RR_RID_MASK | RR_PS_MASK); - thash_purge_and_insert(v, pteval, itir, vadr, DSIDE_TLB); - return IA64_NO_FAULT; - } - if(vpsr.ic){ + } + + vmx_vcpu_get_pta(v, &vpta.val); + if (vpta.vf) { + /* Long format is not yet supported. */ + if (vpsr.ic) { + vcpu_set_isr(v, misr.val); + dtlb_fault(v, vadr); + return IA64_FAULT; + } else { + nested_dtlb(v); + return IA64_FAULT; + } + } + + vmx_vcpu_thash(v, vadr, &vhpt_adr); + if (!guest_vhpt_lookup(vhpt_adr, &pteval)) { + /* VHPT successfully read. */ + if (!(pteval & _PAGE_P)) { + if (vpsr.ic) { vcpu_set_isr(v, misr.val); - dtlb_fault(v, vadr); + data_page_not_present(v, vadr); return IA64_FAULT; - }else{ - if(misr.sp){ - //TODO lds emulation - //panic("Don't support speculation load"); - return vmx_handle_lds(regs); - }else{ - nested_dtlb(v); - return IA64_FAULT; - } - } - }else{ - if(vpsr.ic){ - vcpu_set_isr(v, misr.val); - dvhpt_fault(v, vadr); + } else { + nested_dtlb(v); return IA64_FAULT; - }else{ - if(misr.sp){ - //TODO lds emulation - //panic("Don't support speculation load"); - return vmx_handle_lds(regs); - }else{ - nested_dtlb(v); - return IA64_FAULT; - } } + } else if ((pteval & _PAGE_MA_MASK) != _PAGE_MA_ST) { + vcpu_get_rr(v, vadr, &rr); + itir = rr & (RR_RID_MASK | RR_PS_MASK); + thash_purge_and_insert(v, pteval, itir, vadr, DSIDE_TLB); + return IA64_NO_FAULT; + } else if (vpsr.ic) { + vcpu_set_isr(v, misr.val); + dtlb_fault(v, vadr); + return IA64_FAULT; + }else{ + nested_dtlb(v); + return IA64_FAULT; + } + } else { + /* Can't read VHPT. */ + if (vpsr.ic) { + vcpu_set_isr(v, misr.val); + dvhpt_fault(v, vadr); + return IA64_FAULT; + } else { + nested_dtlb(v); + return IA64_FAULT; } } }else if(type == ISIDE_TLB){ + + if (!vpsr.ic) + misr.ni = 1; if(!vhpt_enabled(v, vadr, misr.rs?RSE_REF:DATA_REF)){ - if(!vpsr.ic){ - misr.ni=1; - } vcpu_set_isr(v, misr.val); alt_itlb(v, vadr); return IA64_FAULT; - } else{ - vmx_vcpu_thash(v, vadr, &vhpt_adr); - if(!guest_vhpt_lookup(vhpt_adr, &pteval)){ - if (pteval & _PAGE_P){ - vcpu_get_rr(v, vadr, &rr); - itir = rr&(RR_RID_MASK | RR_PS_MASK); - thash_purge_and_insert(v, pteval, itir, vadr, ISIDE_TLB); - return IA64_NO_FAULT; - } - if(!vpsr.ic){ - misr.ni=1; - } - vcpu_set_isr(v, misr.val); - itlb_fault(v, vadr); - return IA64_FAULT; - }else{ - if(!vpsr.ic){ - misr.ni=1; - } + } + + vmx_vcpu_get_pta(v, &vpta.val); + if (vpta.vf) { + /* Long format is not yet supported. */ + vcpu_set_isr(v, misr.val); + itlb_fault(v, vadr); + return IA64_FAULT; + } + + + vmx_vcpu_thash(v, vadr, &vhpt_adr); + if (!guest_vhpt_lookup(vhpt_adr, &pteval)) { + /* VHPT successfully read. */ + if (pteval & _PAGE_P) { + vcpu_get_rr(v, vadr, &rr); + itir = rr & (RR_RID_MASK | RR_PS_MASK); + thash_purge_and_insert(v, pteval, itir, vadr, ISIDE_TLB); + return IA64_NO_FAULT; + } else { vcpu_set_isr(v, misr.val); - ivhpt_fault(v, vadr); + inst_page_not_present(v, vadr); return IA64_FAULT; } + } else { + vcpu_set_isr(v, misr.val); + ivhpt_fault(v, vadr); + return IA64_FAULT; } } return IA64_NO_FAULT; diff --git a/xen/arch/ia64/vmx/vmx_vcpu.c b/xen/arch/ia64/vmx/vmx_vcpu.c index e6824d3ec9..3e2583b4fa 100644 --- a/xen/arch/ia64/vmx/vmx_vcpu.c +++ b/xen/arch/ia64/vmx/vmx_vcpu.c @@ -82,7 +82,7 @@ void vmx_vcpu_set_psr(VCPU *vcpu, unsigned long value) { - UINT64 mask; + u64 mask; REGS *regs; IA64_PSR old_psr, new_psr; old_psr.val=VCPU(vcpu, vpsr); @@ -172,6 +172,21 @@ IA64FAULT vmx_vcpu_increment_iip(VCPU *vcpu) } +IA64FAULT vmx_vcpu_decrement_iip(VCPU *vcpu) +{ + REGS *regs = vcpu_regs(vcpu); + IA64_PSR *ipsr = (IA64_PSR *)®s->cr_ipsr; + + if (ipsr->ri == 0) { + ipsr->ri = 2; + regs->cr_iip -= 16; + } else { + ipsr->ri--; + } + return (IA64_NO_FAULT); +} + + IA64FAULT vmx_vcpu_cover(VCPU *vcpu) { REGS *regs = vcpu_regs(vcpu); @@ -193,23 +208,36 @@ vmx_vcpu_get_plat(VCPU *vcpu) -IA64FAULT vmx_vcpu_set_rr(VCPU *vcpu, UINT64 reg, UINT64 val) +IA64FAULT vmx_vcpu_set_rr(VCPU *vcpu, u64 reg, u64 val) { ia64_rr oldrr,newrr; extern void * pal_vaddr; + u64 rrval; vcpu_get_rr(vcpu, reg, &oldrr.rrval); newrr.rrval=val; if (newrr.rid >= (1 << vcpu->domain->arch.rid_bits)) panic_domain (NULL, "use of invalid rid %x\n", newrr.rid); - VMX(vcpu,vrr[reg>>61]) = val; - switch((u64)(reg>>61)) { + VMX(vcpu,vrr[reg>>VRN_SHIFT]) = val; + switch((u64)(reg>>VRN_SHIFT)) { case VRN7: vmx_switch_rr7(vrrtomrr(vcpu,val),vcpu->domain->shared_info, (void *)vcpu->arch.privregs, (void *)vcpu->arch.vhpt.hash, pal_vaddr ); break; + case VRN4: + rrval = vrrtomrr(vcpu,val); + vcpu->arch.metaphysical_saved_rr4 = rrval; + if (!is_physical_mode(vcpu)) + ia64_set_rr(reg,rrval); + break; + case VRN0: + rrval = vrrtomrr(vcpu,val); + vcpu->arch.metaphysical_saved_rr0 = rrval; + if (!is_physical_mode(vcpu)) + ia64_set_rr(reg,rrval); + break; default: ia64_set_rr(reg,vrrtomrr(vcpu,val)); break; @@ -224,14 +252,14 @@ IA64FAULT vmx_vcpu_set_rr(VCPU *vcpu, UINT64 reg, UINT64 val) VCPU protection key register access routines **************************************************************************/ -IA64FAULT vmx_vcpu_get_pkr(VCPU *vcpu, UINT64 reg, UINT64 *pval) +IA64FAULT vmx_vcpu_get_pkr(VCPU *vcpu, u64 reg, u64 *pval) { - UINT64 val = (UINT64)ia64_get_pkr(reg); + u64 val = (u64)ia64_get_pkr(reg); *pval = val; return (IA64_NO_FAULT); } -IA64FAULT vmx_vcpu_set_pkr(VCPU *vcpu, UINT64 reg, UINT64 val) +IA64FAULT vmx_vcpu_set_pkr(VCPU *vcpu, u64 reg, u64 val) { ia64_set_pkr(reg,val); return (IA64_NO_FAULT); @@ -267,7 +295,7 @@ u64 vmx_vcpu_get_itir_on_fault(VCPU *vcpu, u64 ifa) IA64FAULT vmx_vcpu_rfi(VCPU *vcpu) { // TODO: Only allowed for current vcpu - UINT64 ifs, psr; + u64 ifs, psr; REGS *regs = vcpu_regs(vcpu); psr = VCPU(vcpu,ipsr); if (psr & IA64_PSR_BN) @@ -285,7 +313,7 @@ IA64FAULT vmx_vcpu_rfi(VCPU *vcpu) #if 0 IA64FAULT -vmx_vcpu_get_bgr(VCPU *vcpu, unsigned int reg, UINT64 *val) +vmx_vcpu_get_bgr(VCPU *vcpu, unsigned int reg, u64 *val) { IA64_PSR vpsr; @@ -338,7 +366,7 @@ vmx_vcpu_set_bgr(VCPU *vcpu, unsigned int reg, u64 val,int nat) #endif #if 0 IA64FAULT -vmx_vcpu_get_gr(VCPU *vcpu, unsigned reg, UINT64 * val) +vmx_vcpu_get_gr(VCPU *vcpu, unsigned reg, u64 * val) { REGS *regs=vcpu_regs(vcpu); int nat; @@ -385,18 +413,18 @@ vmx_vcpu_set_gr(VCPU *vcpu, unsigned reg, u64 value, int nat) This function gets guest PSR */ -UINT64 vmx_vcpu_get_psr(VCPU *vcpu) +u64 vmx_vcpu_get_psr(VCPU *vcpu) { - UINT64 mask; + u64 mask; REGS *regs = vcpu_regs(vcpu); mask = IA64_PSR_BE | IA64_PSR_UP | IA64_PSR_AC | IA64_PSR_MFL | IA64_PSR_MFH | IA64_PSR_CPL | IA64_PSR_RI; return (VCPU(vcpu, vpsr) & ~mask) | (regs->cr_ipsr & mask); } -IA64FAULT vmx_vcpu_reset_psr_sm(VCPU *vcpu, UINT64 imm24) +IA64FAULT vmx_vcpu_reset_psr_sm(VCPU *vcpu, u64 imm24) { - UINT64 vpsr; + u64 vpsr; vpsr = vmx_vcpu_get_psr(vcpu); vpsr &= (~imm24); vmx_vcpu_set_psr(vcpu, vpsr); @@ -404,9 +432,9 @@ IA64FAULT vmx_vcpu_reset_psr_sm(VCPU *vcpu, UINT64 imm24) } -IA64FAULT vmx_vcpu_set_psr_sm(VCPU *vcpu, UINT64 imm24) +IA64FAULT vmx_vcpu_set_psr_sm(VCPU *vcpu, u64 imm24) { - UINT64 vpsr; + u64 vpsr; vpsr = vmx_vcpu_get_psr(vcpu); vpsr |= imm24; vmx_vcpu_set_psr(vcpu, vpsr); @@ -414,7 +442,7 @@ IA64FAULT vmx_vcpu_set_psr_sm(VCPU *vcpu, UINT64 imm24) } -IA64FAULT vmx_vcpu_set_psr_l(VCPU *vcpu, UINT64 val) +IA64FAULT vmx_vcpu_set_psr_l(VCPU *vcpu, u64 val) { val = (val & MASK(0, 32)) | (vmx_vcpu_get_psr(vcpu) & MASK(32, 32)); vmx_vcpu_set_psr(vcpu, val); diff --git a/xen/arch/ia64/vmx/vmx_virt.c b/xen/arch/ia64/vmx/vmx_virt.c index 6fcb37090a..5c719309ea 100644 --- a/xen/arch/ia64/vmx/vmx_virt.c +++ b/xen/arch/ia64/vmx/vmx_virt.c @@ -32,7 +32,7 @@ #include <asm/vmx_phy_mode.h> void -ia64_priv_decoder(IA64_SLOT_TYPE slot_type, INST64 inst, UINT64 * cause) +ia64_priv_decoder(IA64_SLOT_TYPE slot_type, INST64 inst, u64 * cause) { *cause=0; switch (slot_type) { @@ -144,20 +144,20 @@ ia64_priv_decoder(IA64_SLOT_TYPE slot_type, INST64 inst, UINT64 * cause) IA64FAULT vmx_emul_rsm(VCPU *vcpu, INST64 inst) { - UINT64 imm24 = (inst.M44.i<<23)|(inst.M44.i2<<21)|inst.M44.imm; + u64 imm24 = (inst.M44.i << 23) | (inst.M44.i2 << 21) | inst.M44.imm; return vmx_vcpu_reset_psr_sm(vcpu,imm24); } IA64FAULT vmx_emul_ssm(VCPU *vcpu, INST64 inst) { - UINT64 imm24 = (inst.M44.i<<23)|(inst.M44.i2<<21)|inst.M44.imm; + u64 imm24 = (inst.M44.i << 23) | (inst.M44.i2 << 21) | inst.M44.imm; return vmx_vcpu_set_psr_sm(vcpu,imm24); } IA64FAULT vmx_emul_mov_from_psr(VCPU *vcpu, INST64 inst) { - UINT64 tgt = inst.M33.r1; - UINT64 val; + u64 tgt = inst.M33.r1; + u64 val; /* if ((fault = vmx_vcpu_get_psr(vcpu,&val)) == IA64_NO_FAULT) @@ -174,7 +174,7 @@ IA64FAULT vmx_emul_mov_from_psr(VCPU *vcpu, INST64 inst) */ IA64FAULT vmx_emul_mov_to_psr(VCPU *vcpu, INST64 inst) { - UINT64 val; + u64 val; if(vcpu_get_gr_nat(vcpu, inst.M35.r2, &val) != IA64_NO_FAULT) panic_domain(vcpu_regs(vcpu),"get_psr nat bit fault\n"); @@ -566,7 +566,7 @@ IA64FAULT vmx_emul_tak(VCPU *vcpu, INST64 inst) IA64FAULT vmx_emul_itr_d(VCPU *vcpu, INST64 inst) { - UINT64 itir, ifa, pte, slot; + u64 itir, ifa, pte, slot; #ifdef VMAL_NO_FAULT_CHECK IA64_PSR vpsr; vpsr.val=vmx_vcpu_get_psr(vcpu); @@ -623,7 +623,7 @@ IA64FAULT vmx_emul_itr_d(VCPU *vcpu, INST64 inst) IA64FAULT vmx_emul_itr_i(VCPU *vcpu, INST64 inst) { - UINT64 itir, ifa, pte, slot; + u64 itir, ifa, pte, slot; #ifdef VMAL_NO_FAULT_CHECK ISR isr; IA64_PSR vpsr; @@ -691,7 +691,7 @@ IA64FAULT itc_fault_check(VCPU *vcpu, INST64 inst, u64 *itir, u64 *ifa,u64 *pte) return IA64_FAULT; } - UINT64 fault; + u64 fault; ISR isr; if ( vpsr.cpl != 0) { /* Inject Privileged Operation fault into guest */ @@ -729,7 +729,7 @@ IA64FAULT itc_fault_check(VCPU *vcpu, INST64 inst, u64 *itir, u64 *ifa,u64 *pte) IA64FAULT vmx_emul_itc_d(VCPU *vcpu, INST64 inst) { - UINT64 itir, ifa, pte; + u64 itir, ifa, pte; if ( itc_fault_check(vcpu, inst, &itir, &ifa, &pte) == IA64_FAULT ) { return IA64_FAULT; @@ -740,7 +740,7 @@ IA64FAULT vmx_emul_itc_d(VCPU *vcpu, INST64 inst) IA64FAULT vmx_emul_itc_i(VCPU *vcpu, INST64 inst) { - UINT64 itir, ifa, pte; + u64 itir, ifa, pte; if ( itc_fault_check(vcpu, inst, &itir, &ifa, &pte) == IA64_FAULT ) { return IA64_FAULT; @@ -757,7 +757,7 @@ IA64FAULT vmx_emul_itc_i(VCPU *vcpu, INST64 inst) IA64FAULT vmx_emul_mov_to_ar_imm(VCPU *vcpu, INST64 inst) { // I27 and M30 are identical for these fields - UINT64 imm; + u64 imm; if(inst.M30.ar3!=44){ panic_domain(vcpu_regs(vcpu),"Can't support ar register other than itc"); @@ -1277,8 +1277,8 @@ IA64FAULT vmx_emul_mov_to_cr(VCPU *vcpu, INST64 inst) IA64FAULT vmx_emul_mov_from_cr(VCPU *vcpu, INST64 inst) { - UINT64 tgt = inst.M33.r1; - UINT64 val; + u64 tgt = inst.M33.r1; + u64 val; IA64FAULT fault; #ifdef CHECK_FAULT IA64_PSR vpsr; @@ -1353,7 +1353,7 @@ vmx_emulate(VCPU *vcpu, REGS *regs) { IA64FAULT status; INST64 inst; - UINT64 iip, cause, opcode; + u64 iip, cause, opcode; iip = regs->cr_iip; cause = VMX(vcpu,cause); opcode = VMX(vcpu,opcode); diff --git a/xen/arch/ia64/vmx/vtlb.c b/xen/arch/ia64/vmx/vtlb.c index 4fb31a0ec2..2e83358972 100644 --- a/xen/arch/ia64/vmx/vtlb.c +++ b/xen/arch/ia64/vmx/vtlb.c @@ -218,7 +218,6 @@ u64 guest_vhpt_lookup(u64 iha, u64 *pte) { u64 ret; thash_data_t * data; - PTA vpta; data = vhpt_lookup(iha); if (data == NULL) { @@ -227,13 +226,6 @@ u64 guest_vhpt_lookup(u64 iha, u64 *pte) thash_vhpt_insert(current, data->page_flags, data->itir ,iha); } - /* VHPT long format is not read. */ - vmx_vcpu_get_pta(current, &vpta.val); - if (vpta.vf == 1) { - *pte = 0; - return 0; - } - asm volatile ("rsm psr.ic|psr.i;;" "srlz.d;;" "ld8.s r9=[%1];;" diff --git a/xen/arch/ia64/xen/Makefile b/xen/arch/ia64/xen/Makefile index b51029f043..87f22f0966 100644 --- a/xen/arch/ia64/xen/Makefile +++ b/xen/arch/ia64/xen/Makefile @@ -25,5 +25,9 @@ obj-y += xensetup.o obj-y += xentime.o obj-y += flushd.o obj-y += privop_stat.o +obj-y += xenpatch.o +obj-y += xencomm.o obj-$(crash_debug) += gdbstub.o +obj-$(xen_ia64_tlb_track) += tlb_track.o +obj-$(xen_ia64_tlbflush_clock) += flushtlb.o diff --git a/xen/arch/ia64/xen/dom0_ops.c b/xen/arch/ia64/xen/dom0_ops.c index 8bb24010ce..341d66b7bf 100644 --- a/xen/arch/ia64/xen/dom0_ops.c +++ b/xen/arch/ia64/xen/dom0_ops.c @@ -256,6 +256,7 @@ do_dom0vp_op(unsigned long cmd, } else { ret = (ret & _PFN_MASK) >> PAGE_SHIFT;//XXX pte_pfn() } + perfc_incrc(dom0vp_phystomach); break; case IA64_DOM0VP_machtophys: if (!mfn_valid(arg0)) { @@ -263,6 +264,7 @@ do_dom0vp_op(unsigned long cmd, break; } ret = get_gpfn_from_mfn(arg0); + perfc_incrc(dom0vp_machtophys); break; case IA64_DOM0VP_zap_physmap: ret = dom0vp_zap_physmap(d, arg0, (unsigned int)arg1); @@ -271,6 +273,9 @@ do_dom0vp_op(unsigned long cmd, ret = dom0vp_add_physmap(d, arg0, arg1, (unsigned int)arg2, (domid_t)arg3); break; + case IA64_DOM0VP_expose_p2m: + ret = dom0vp_expose_p2m(d, arg0, arg1, arg2, arg3); + break; default: ret = -1; printf("unknown dom0_vp_op 0x%lx\n", cmd); diff --git a/xen/arch/ia64/xen/domain.c b/xen/arch/ia64/xen/domain.c index 2073fd52c7..13d0cab731 100644 --- a/xen/arch/ia64/xen/domain.c +++ b/xen/arch/ia64/xen/domain.c @@ -46,9 +46,10 @@ #include <asm/regionreg.h> #include <asm/dom_fw.h> #include <asm/shadow.h> +#include <xen/guest_access.h> +#include <asm/tlb_track.h> unsigned long dom0_size = 512*1024*1024; -unsigned long dom0_align = 64*1024*1024; /* dom0_max_vcpus: maximum number of VCPUs to create for dom0. */ static unsigned int dom0_max_vcpus = 1; @@ -58,13 +59,8 @@ extern unsigned long running_on_sim; extern char dom0_command_line[]; -/* FIXME: where these declarations should be there ? */ -extern void serial_input_init(void); +/* forward declaration */ static void init_switch_stack(struct vcpu *v); -extern void vmx_do_launch(struct vcpu *); - -/* this belongs in include/asm, but there doesn't seem to be a suitable place */ -extern struct vcpu *ia64_switch_to (struct vcpu *next_task); /* Address of vpsr.i (in fact evtchn_upcall_mask) of current vcpu. This is a Xen virtual address. */ @@ -73,33 +69,68 @@ DEFINE_PER_CPU(int *, current_psr_ic_addr); #include <xen/sched-if.h> -static void flush_vtlb_for_context_switch(struct vcpu* vcpu) +static void +ia64_disable_vhpt_walker(void) +{ + // disable VHPT. ia64_new_rr7() might cause VHPT + // fault without this because it flushes dtr[IA64_TR_VHPT] + // (VHPT_SIZE_LOG2 << 2) is just for avoid + // Reserved Register/Field fault. + ia64_set_pta(VHPT_SIZE_LOG2 << 2); +} + +static void flush_vtlb_for_context_switch(struct vcpu* prev, struct vcpu* next) { int cpu = smp_processor_id(); - int last_vcpu_id = vcpu->domain->arch.last_vcpu[cpu].vcpu_id; - int last_processor = vcpu->arch.last_processor; + int last_vcpu_id, last_processor; - if (is_idle_domain(vcpu->domain)) + if (!is_idle_domain(prev->domain)) + tlbflush_update_time + (&prev->domain->arch.last_vcpu[cpu].tlbflush_timestamp, + tlbflush_current_time()); + + if (is_idle_domain(next->domain)) return; - - vcpu->domain->arch.last_vcpu[cpu].vcpu_id = vcpu->vcpu_id; - vcpu->arch.last_processor = cpu; - if ((last_vcpu_id != vcpu->vcpu_id && + last_vcpu_id = next->domain->arch.last_vcpu[cpu].vcpu_id; + last_processor = next->arch.last_processor; + + next->domain->arch.last_vcpu[cpu].vcpu_id = next->vcpu_id; + next->arch.last_processor = cpu; + + if ((last_vcpu_id != next->vcpu_id && last_vcpu_id != INVALID_VCPU_ID) || - (last_vcpu_id == vcpu->vcpu_id && + (last_vcpu_id == next->vcpu_id && last_processor != cpu && last_processor != INVALID_PROCESSOR)) { +#ifdef CONFIG_XEN_IA64_TLBFLUSH_CLOCK + u32 last_tlbflush_timestamp = + next->domain->arch.last_vcpu[cpu].tlbflush_timestamp; +#endif + int vhpt_is_flushed = 0; // if the vTLB implementation was changed, // the followings must be updated either. - if (VMX_DOMAIN(vcpu)) { + if (VMX_DOMAIN(next)) { // currently vTLB for vt-i domian is per vcpu. // so any flushing isn't needed. + } else if (HAS_PERVCPU_VHPT(next->domain)) { + // nothing to do + } else { + if (NEED_FLUSH(__get_cpu_var(vhpt_tlbflush_timestamp), + last_tlbflush_timestamp)) { + local_vhpt_flush(); + vhpt_is_flushed = 1; + } + } + if (vhpt_is_flushed || NEED_FLUSH(__get_cpu_var(tlbflush_time), + last_tlbflush_timestamp)) { + local_flush_tlb_all(); + perfc_incrc(tlbflush_clock_cswitch_purge); } else { - vhpt_flush(); + perfc_incrc(tlbflush_clock_cswitch_skip); } - local_flush_tlb_all(); + perfc_incrc(flush_vtlb_for_context_switch); } } @@ -108,15 +139,15 @@ void schedule_tail(struct vcpu *prev) extern char ia64_ivt; context_saved(prev); + ia64_disable_vhpt_walker(); if (VMX_DOMAIN(current)) { vmx_do_launch(current); migrate_timer(¤t->arch.arch_vmx.vtm.vtm_timer, current->processor); } else { ia64_set_iva(&ia64_ivt); - ia64_set_pta(VHPT_ADDR | (1 << 8) | (VHPT_SIZE_LOG2 << 2) | - VHPT_ENABLED); load_region_regs(current); + ia64_set_pta(vcpu_pta(current)); vcpu_load_kernel_regs(current); __ia64_per_cpu_var(current_psr_i_addr) = ¤t->domain-> shared_info->vcpu_info[current->vcpu_id].evtchn_upcall_mask; @@ -124,13 +155,12 @@ void schedule_tail(struct vcpu *prev) (current->domain->arch.shared_info_va + XSI_PSR_IC_OFS); migrate_timer(¤t->arch.hlt_timer, current->processor); } - flush_vtlb_for_context_switch(current); + flush_vtlb_for_context_switch(prev, current); } void context_switch(struct vcpu *prev, struct vcpu *next) { uint64_t spsr; - uint64_t pta; local_irq_save(spsr); @@ -148,6 +178,8 @@ void context_switch(struct vcpu *prev, struct vcpu *next) } if (VMX_DOMAIN(next)) vmx_load_state(next); + + ia64_disable_vhpt_walker(); /*ia64_psr(ia64_task_regs(next))->dfh = !ia64_is_local_fpu_owner(next);*/ prev = ia64_switch_to(next); @@ -167,9 +199,8 @@ void context_switch(struct vcpu *prev, struct vcpu *next) nd = current->domain; if (!is_idle_domain(nd)) { - ia64_set_pta(VHPT_ADDR | (1 << 8) | (VHPT_SIZE_LOG2 << 2) | - VHPT_ENABLED); load_region_regs(current); + ia64_set_pta(vcpu_pta(current)); vcpu_load_kernel_regs(current); vcpu_set_next_timer(current); if (vcpu_timer_expired(current)) @@ -183,14 +214,12 @@ void context_switch(struct vcpu *prev, struct vcpu *next) * walker. Then all accesses happen within idle context will * be handled by TR mapping and identity mapping. */ - pta = ia64_get_pta(); - ia64_set_pta(pta & ~VHPT_ENABLED); __ia64_per_cpu_var(current_psr_i_addr) = NULL; __ia64_per_cpu_var(current_psr_ic_addr) = NULL; } } - flush_vtlb_for_context_switch(current); local_irq_restore(spsr); + flush_vtlb_for_context_switch(prev, current); context_saved(prev); } @@ -273,6 +302,13 @@ struct vcpu *alloc_vcpu_struct(struct domain *d, unsigned int vcpu_id) if (!d->arch.is_vti) { int order; int i; + // vti domain has its own vhpt policy. + if (HAS_PERVCPU_VHPT(d)) { + if (pervcpu_vhpt_alloc(v) < 0) { + free_xenheap_pages(v, KERNEL_STACK_SIZE_ORDER); + return NULL; + } + } /* Create privregs page only if not VTi. */ order = get_order_from_shift(XMAPPEDREGS_SHIFT); @@ -282,6 +318,9 @@ struct vcpu *alloc_vcpu_struct(struct domain *d, unsigned int vcpu_id) for (i = 0; i < (1 << order); i++) share_xen_page_with_guest(virt_to_page(v->arch.privregs) + i, d, XENSHARE_writable); + + tlbflush_update_time(&v->arch.tlbflush_timestamp, + tlbflush_current_time()); } v->arch.metaphysical_rr0 = d->arch.metaphysical_rr0; @@ -315,6 +354,8 @@ struct vcpu *alloc_vcpu_struct(struct domain *d, unsigned int vcpu_id) void relinquish_vcpu_resources(struct vcpu *v) { + if (HAS_PERVCPU_VHPT(v->domain)) + pervcpu_vhpt_free(v); if (v->arch.privregs != NULL) { free_xenheap_pages(v->arch.privregs, get_order_from_shift(XMAPPEDREGS_SHIFT)); @@ -325,7 +366,7 @@ void relinquish_vcpu_resources(struct vcpu *v) void free_vcpu_struct(struct vcpu *v) { - if (VMX_DOMAIN(v)) + if (v->domain->arch.is_vti) vmx_relinquish_vcpu_resources(v); else relinquish_vcpu_resources(v); @@ -350,6 +391,11 @@ static void init_switch_stack(struct vcpu *v) memset(v->arch._thread.fph,0,sizeof(struct ia64_fpreg)*96); } +#ifdef CONFIG_XEN_IA64_PERVCPU_VHPT +static int opt_pervcpu_vhpt = 1; +integer_param("pervcpu_vhpt", opt_pervcpu_vhpt); +#endif + int arch_domain_create(struct domain *d) { int i; @@ -364,6 +410,13 @@ int arch_domain_create(struct domain *d) if (is_idle_domain(d)) return 0; +#ifdef CONFIG_XEN_IA64_PERVCPU_VHPT + d->arch.has_pervcpu_vhpt = opt_pervcpu_vhpt; + DPRINTK("%s:%d domain %d pervcpu_vhpt %d\n", + __func__, __LINE__, d->domain_id, d->arch.has_pervcpu_vhpt); +#endif + if (tlb_track_create(d) < 0) + goto fail_nomem1; d->shared_info = alloc_xenheap_pages(get_order_from_shift(XSI_SHIFT)); if (d->shared_info == NULL) goto fail_nomem; @@ -392,6 +445,8 @@ int arch_domain_create(struct domain *d) return 0; fail_nomem: + tlb_track_destroy(d); +fail_nomem1: if (d->arch.mm.pgd != NULL) pgd_free(d->arch.mm.pgd); if (d->shared_info != NULL) @@ -407,6 +462,8 @@ void arch_domain_destroy(struct domain *d) if (d->arch.shadow_bitmap != NULL) xfree(d->arch.shadow_bitmap); + tlb_track_destroy(d); + /* Clear vTLB for the next domain. */ domain_flush_tlb_vhpt(d); @@ -844,23 +901,6 @@ void alloc_dom0(void) " (try e.g. dom0_mem=256M or dom0_mem=65536K)\n"); } - /* Check dom0 align. */ - if ((dom0_align - 1) & dom0_align) { /* not a power of two */ - panic("dom0_align (%lx) must be power of two, boot aborted" - " (try e.g. dom0_align=256M or dom0_align=65536K)\n", - dom0_align); - } - if (dom0_align < PAGE_SIZE) { - panic("dom0_align must be >= %ld, boot aborted" - " (try e.g. dom0_align=256M or dom0_align=65536K)\n", - PAGE_SIZE); - } - if (dom0_size % dom0_align) { - dom0_size = (dom0_size / dom0_align + 1) * dom0_align; - printf("dom0_size rounded up to %ld, due to dom0_align=%lx\n", - dom0_size,dom0_align); - } - if (running_on_sim) { dom0_size = 128*1024*1024; //FIXME: Should be configurable } @@ -1101,9 +1141,6 @@ int construct_dom0(struct domain *d, physdev_init_dom0(d); - // FIXME: Hack for keyboard input - //serial_input_init(); - return 0; } @@ -1142,10 +1179,3 @@ static void parse_dom0_mem(char *s) dom0_size = parse_size_and_unit(s); } custom_param("dom0_mem", parse_dom0_mem); - - -static void parse_dom0_align(char *s) -{ - dom0_align = parse_size_and_unit(s); -} -custom_param("dom0_align", parse_dom0_align); diff --git a/xen/arch/ia64/xen/faults.c b/xen/arch/ia64/xen/faults.c index f2e3a1bef7..75be0088e7 100644 --- a/xen/arch/ia64/xen/faults.c +++ b/xen/arch/ia64/xen/faults.c @@ -31,6 +31,7 @@ #include <asm/asm-xsi-offsets.h> #include <asm/shadow.h> #include <asm/uaccess.h> +#include <asm/p2m_entry.h> extern void die_if_kernel(char *str, struct pt_regs *regs, long err); /* FIXME: where these declarations shold be there ? */ @@ -202,8 +203,11 @@ void ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_reg fault = vcpu_translate(current,address,is_data,&pteval,&itir,&iha); if (fault == IA64_NO_FAULT || fault == IA64_USE_TLB) { struct p2m_entry entry; - pteval = translate_domain_pte(pteval, address, itir, &logps, &entry); - vcpu_itc_no_srlz(current,is_data?2:1,address,pteval,-1UL,logps); + unsigned long m_pteval; + m_pteval = translate_domain_pte(pteval, address, itir, + &logps, &entry); + vcpu_itc_no_srlz(current, (is_data? 2: 1) | 4, + address, m_pteval, pteval, logps, &entry); if ((fault == IA64_USE_TLB && !current->arch.dtlb.pte.p) || p2m_entry_retry(&entry)) { /* dtlb has been purged in-between. This dtlb was @@ -228,10 +232,10 @@ void ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_reg // indicate a bad xen pointer printk("*** xen_handle_domain_access: exception table" " lookup failed, iip=0x%lx, addr=0x%lx, spinning...\n", - iip, address); + iip, address); panic_domain(regs,"*** xen_handle_domain_access: exception table" - " lookup failed, iip=0x%lx, addr=0x%lx, spinning...\n", - iip, address); + " lookup failed, iip=0x%lx, addr=0x%lx, spinning...\n", + iip, address); } return; } diff --git a/xen/arch/ia64/xen/flushtlb.c b/xen/arch/ia64/xen/flushtlb.c new file mode 100644 index 0000000000..0c77c1b6df --- /dev/null +++ b/xen/arch/ia64/xen/flushtlb.c @@ -0,0 +1,117 @@ +/****************************************************************************** + * flushtlb.c + * based on x86 flushtlb.c + * + * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <xen/sched.h> +#include <xen/softirq.h> +#include <asm/vcpu.h> +#include <asm/vhpt.h> +#include <asm/flushtlb.h> + +/* Debug builds: Wrap frequently to stress-test the wrap logic. */ +#ifdef NDEBUG +#define WRAP_MASK (0xFFFFFFFFU) +#else +#define WRAP_MASK (0x000003FFU) +#endif + +volatile u32 tlbflush_clock = 1U; /* 1 greater than tlbflush_time. */ +DEFINE_PER_CPU(volatile u32, tlbflush_time); + +u32 +tlbflush_clock_inc_and_return(void) +{ + u32 t, t1, t2; + + t = tlbflush_clock; + do { + t1 = t2 = t; + /* Clock wrapped: someone else is leading a global TLB shootdown. */ + if (unlikely(t1 == 0)) + return t2; + t2 = (t + 1) & WRAP_MASK; + t = ia64_cmpxchg(acq, &tlbflush_clock, t1, t2, sizeof(tlbflush_clock)); + } while (unlikely(t != t1)); + + /* Clock wrapped: we will lead a global TLB shootdown. */ + if (unlikely(t2 == 0)) + raise_softirq(NEW_TLBFLUSH_CLOCK_PERIOD_SOFTIRQ); + + return t2; +} + +void +new_tlbflush_clock_period(void) +{ + /* + *XXX TODO + * If flushing all vcpu's vhpt takes too long, it can be done backgroundly. + * In such case tlbflush time comparison is done using only 31bit + * similar to linux jiffies comparison. + * vhpt should be flushed gradually before wraping 31bits. + * + * Sample calculation. + * Currently Xen/IA64 can create up to 64 domains at the same time. + * Vhpt size is currently 64KB. (This might be changed later though) + * Suppose each domains have 4 vcpus (or 16 vcpus). + * then the memory size which must be flushed is 16MB (64MB). + */ + struct domain* d; + struct vcpu* v; + /* flush all vhpt of vcpu of all existing domain. */ + read_lock(&domlist_lock); + for_each_domain(d) { + for_each_vcpu(d, v) { + vcpu_purge_tr_entry(&PSCBX(v,dtlb)); + vcpu_purge_tr_entry(&PSCBX(v,itlb)); + } + } + smp_mb(); + for_each_domain(d) { + for_each_vcpu(d, v) { + if (HAS_PERVCPU_VHPT(v->domain)) + vcpu_vhpt_flush(v); + } + } + read_unlock(&domlist_lock); + /* unlock has release semantics */ + + /* flush all vhpt of physical cpu and mTLB */ + on_each_cpu((void (*)(void *))local_flush_tlb_all, NULL, 1, 1); + + /* + * if global TLB shootdown is finished, increment tlbflush_time + * atomic operation isn't necessary because we know that tlbflush_clock + * stays 0. + */ + tlbflush_clock++; +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/ia64/xen/fw_emul.c b/xen/arch/ia64/xen/fw_emul.c index 77f1b288da..2c4af786e3 100644 --- a/xen/arch/ia64/xen/fw_emul.c +++ b/xen/arch/ia64/xen/fw_emul.c @@ -16,7 +16,6 @@ * */ #include <xen/config.h> -#include <xen/console.h> #include <asm/system.h> #include <asm/pgalloc.h> @@ -27,8 +26,11 @@ #include <public/sched.h> #include "hpsim_ssc.h" #include <asm/vcpu.h> +#include <asm/vmx_vcpu.h> #include <asm/dom_fw.h> #include <asm/uaccess.h> +#include <xen/console.h> +#include <xen/hypercall.h> extern unsigned long running_on_sim; @@ -173,6 +175,10 @@ xen_pal_emulator(unsigned long index, u64 in1, u64 in2, u64 in3) break; case PAL_FREQ_BASE: status = ia64_pal_freq_base(&r9); + if (status == PAL_STATUS_UNIMPLEMENTED) { + status = ia64_sal_freq_base(0, &r9, &r10); + r10 = 0; + } break; case PAL_PROC_GET_FEATURES: status = ia64_pal_proc_get_features(&r9,&r10,&r11); @@ -215,7 +221,7 @@ xen_pal_emulator(unsigned long index, u64 in1, u64 in2, u64 in3) { /* Use xen-specific values. hash_tag_id is somewhat random! */ - const pal_vm_info_1_u_t v1 = + static const pal_vm_info_1_u_t v1 = {.pal_vm_info_1_s = { .vw = 1, .phys_add_size = 44, @@ -232,11 +238,12 @@ xen_pal_emulator(unsigned long index, u64 in1, u64 in2, u64 in3) .num_tc_levels = 1 #endif }}; - const pal_vm_info_2_u_t v2 = - { .pal_vm_info_2_s = - { .impl_va_msb = 50, - .rid_size = current->domain->arch.rid_bits, - .reserved = 0 }}; + pal_vm_info_2_u_t v2; + v2.pvi2_val = 0; + v2.pal_vm_info_2_s.rid_size = + current->domain->arch.rid_bits; + v2.pal_vm_info_2_s.impl_va_msb = + VMX_DOMAIN(current) ? GUEST_IMPL_VA_MSB : 50; r9 = v1.pvi1_val; r10 = v2.pvi2_val; status = PAL_STATUS_SUCCESS; @@ -294,9 +301,20 @@ xen_pal_emulator(unsigned long index, u64 in1, u64 in2, u64 in3) status = ia64_pal_register_info(in1, &r9, &r10); break; case PAL_CACHE_FLUSH: - /* FIXME */ - printk("PAL_CACHE_FLUSH NOT IMPLEMENTED!\n"); - BUG(); + /* Always call Host Pal in int=0 */ + in2 &= ~PAL_CACHE_FLUSH_CHK_INTRS; + + /* + * Call Host PAL cache flush + * Clear psr.ic when call PAL_CACHE_FLUSH + */ + r10 = in3; + status = ia64_pal_cache_flush(in1, in2, &r10, &r9); + + if (status != 0) + panic_domain(NULL, "PAL_CACHE_FLUSH ERROR, " + "status %lx", status); + break; case PAL_PERF_MON_INFO: { @@ -343,15 +361,26 @@ xen_pal_emulator(unsigned long index, u64 in1, u64 in2, u64 in3) } break; case PAL_HALT: - if (current->domain == dom0) { - printf ("Domain0 halts the machine\n"); - console_start_sync(); - (*efi.reset_system)(EFI_RESET_SHUTDOWN,0,0,NULL); - } - else - domain_shutdown (current->domain, - SHUTDOWN_poweroff); - break; + if (current->domain == dom0) { + printf ("Domain0 halts the machine\n"); + console_start_sync(); + (*efi.reset_system)(EFI_RESET_SHUTDOWN,0,0,NULL); + } + else + domain_shutdown(current->domain, SHUTDOWN_poweroff); + break; + case PAL_HALT_LIGHT: + if (VMX_DOMAIN(current)) { + /* Called by VTI. */ + if (!is_unmasked_irq(current)) + do_sched_op_compat(SCHEDOP_block, 0); + status = PAL_STATUS_SUCCESS; + } + break; + case PAL_PLATFORM_ADDR: + if (VMX_DOMAIN(current)) + status = PAL_STATUS_SUCCESS; + break; default: printk("xen_pal_emulator: UNIMPLEMENTED PAL CALL %lu!!!!\n", index); diff --git a/xen/arch/ia64/xen/hypercall.c b/xen/arch/ia64/xen/hypercall.c index 17ad53bd71..8fc4c4c3cb 100644 --- a/xen/arch/ia64/xen/hypercall.c +++ b/xen/arch/ia64/xen/hypercall.c @@ -32,7 +32,6 @@ #include <xen/event.h> #include <xen/perfc.h> -static long do_physdev_op_compat(XEN_GUEST_HANDLE(physdev_op_t) uop); static long do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg); static long do_callback_op(int cmd, XEN_GUEST_HANDLE(void) arg); @@ -54,10 +53,10 @@ const hypercall_t ia64_hypercall_table[NR_hypercalls] = (hypercall_t)do_multicall, (hypercall_t)do_ni_hypercall, /* do_update_va_mapping */ (hypercall_t)do_ni_hypercall, /* do_set_timer_op */ /* 15 */ - (hypercall_t)do_event_channel_op_compat, + (hypercall_t)do_ni_hypercall, (hypercall_t)do_xen_version, (hypercall_t)do_console_io, - (hypercall_t)do_physdev_op_compat, + (hypercall_t)do_ni_hypercall, (hypercall_t)do_grant_table_op, /* 20 */ (hypercall_t)do_ni_hypercall, /* do_vm_assist */ (hypercall_t)do_ni_hypercall, /* do_update_va_mapping_othe */ @@ -108,19 +107,6 @@ static IA64FAULT xen_hypercall (struct pt_regs *regs) { uint32_t cmd = (uint32_t)regs->r2; - struct vcpu *v = current; - - if (cmd == __HYPERVISOR_grant_table_op) { - XEN_GUEST_HANDLE(void) uop; - - v->arch.hypercall_param.va = regs->r15; - v->arch.hypercall_param.pa1 = regs->r17; - v->arch.hypercall_param.pa2 = regs->r18; - set_xen_guest_handle(uop, (void *)regs->r15); - regs->r8 = do_grant_table_op(regs->r14, uop, regs->r16); - v->arch.hypercall_param.va = 0; - return IA64_NO_FAULT; - } if (cmd < NR_hypercalls) { perfc_incra(hypercalls, cmd); @@ -133,7 +119,21 @@ xen_hypercall (struct pt_regs *regs) regs->r19); } else regs->r8 = -ENOSYS; + + return IA64_NO_FAULT; +} +static IA64FAULT +xen_fast_hypercall (struct pt_regs *regs) +{ + uint32_t cmd = (uint32_t)regs->r2; + switch (cmd) { + case __HYPERVISOR_ia64_fast_eoi: + regs->r8 = pirq_guest_eoi(current->domain, regs->r14); + break; + default: + regs->r8 = -ENOSYS; + } return IA64_NO_FAULT; } @@ -201,8 +201,8 @@ fw_hypercall_fpswa (struct vcpu *v) return PSCBX(v, fpswa_ret); } -static IA64FAULT -fw_hypercall (struct pt_regs *regs) +IA64FAULT +ia64_hypercall(struct pt_regs *regs) { struct vcpu *v = current; struct sal_ret_values x; @@ -213,7 +213,13 @@ fw_hypercall (struct pt_regs *regs) perfc_incra(fw_hypercall, index >> 8); switch (index) { - case FW_HYPERCALL_PAL_CALL: + case FW_HYPERCALL_XEN: + return xen_hypercall(regs); + + case FW_HYPERCALL_XEN_FAST: + return xen_fast_hypercall(regs); + + case FW_HYPERCALL_PAL_CALL: //printf("*** PAL hypercall: index=%d\n",regs->r28); //FIXME: This should call a C routine #if 0 @@ -264,7 +270,7 @@ fw_hypercall (struct pt_regs *regs) regs->r10 = y.v1; regs->r11 = y.v2; } break; - case FW_HYPERCALL_SAL_CALL: + case FW_HYPERCALL_SAL_CALL: x = sal_emulator(vcpu_get_gr(v,32),vcpu_get_gr(v,33), vcpu_get_gr(v,34),vcpu_get_gr(v,35), vcpu_get_gr(v,36),vcpu_get_gr(v,37), @@ -272,46 +278,35 @@ fw_hypercall (struct pt_regs *regs) regs->r8 = x.r8; regs->r9 = x.r9; regs->r10 = x.r10; regs->r11 = x.r11; break; - case FW_HYPERCALL_SAL_RETURN: + case FW_HYPERCALL_SAL_RETURN: if ( !test_and_set_bit(_VCPUF_down, &v->vcpu_flags) ) vcpu_sleep_nosync(v); break; - case FW_HYPERCALL_EFI_CALL: + case FW_HYPERCALL_EFI_CALL: efi_ret_value = efi_emulator (regs, &fault); if (fault != IA64_NO_FAULT) return fault; regs->r8 = efi_ret_value; break; - case FW_HYPERCALL_IPI: + case FW_HYPERCALL_IPI: fw_hypercall_ipi (regs); break; - case FW_HYPERCALL_SET_SHARED_INFO_VA: + case FW_HYPERCALL_SET_SHARED_INFO_VA: regs->r8 = domain_set_shared_info_va (regs->r28); break; - case FW_HYPERCALL_FPSWA: + case FW_HYPERCALL_FPSWA: fpswa_ret = fw_hypercall_fpswa (v); regs->r8 = fpswa_ret.status; regs->r9 = fpswa_ret.err0; regs->r10 = fpswa_ret.err1; regs->r11 = fpswa_ret.err2; break; - default: + default: printf("unknown ia64 fw hypercall %lx\n", regs->r2); regs->r8 = do_ni_hypercall(); } return IA64_NO_FAULT; } -IA64FAULT -ia64_hypercall (struct pt_regs *regs) -{ - unsigned long index = regs->r2; - - if (index >= FW_HYPERCALL_FIRST_ARCH) - return fw_hypercall (regs); - else - return xen_hypercall (regs); -} - unsigned long hypercall_create_continuation( unsigned int op, const char *format, ...) { @@ -465,28 +460,6 @@ static long do_physdev_op(int cmd, XEN_GUEST_HANDLE(void) arg) return ret; } -/* Legacy hypercall (as of 0x00030202). */ -static long do_physdev_op_compat(XEN_GUEST_HANDLE(physdev_op_t) uop) -{ - struct physdev_op op; - - if ( unlikely(copy_from_guest(&op, uop, 1) != 0) ) - return -EFAULT; - - return do_physdev_op(op.cmd, guest_handle_from_ptr(&uop.p->u, void)); -} - -/* Legacy hypercall (as of 0x00030202). */ -long do_event_channel_op_compat(XEN_GUEST_HANDLE(evtchn_op_t) uop) -{ - struct evtchn_op op; - - if ( unlikely(copy_from_guest(&op, uop, 1) != 0) ) - return -EFAULT; - - return do_event_channel_op(op.cmd, guest_handle_from_ptr(&uop.p->u, void)); -} - static long register_guest_callback(struct callback_register *reg) { long ret = 0; diff --git a/xen/arch/ia64/xen/mm.c b/xen/arch/ia64/xen/mm.c index 6c656d53eb..27f66bf7f3 100644 --- a/xen/arch/ia64/xen/mm.c +++ b/xen/arch/ia64/xen/mm.c @@ -172,13 +172,15 @@ #include <asm/vhpt.h> #include <asm/vcpu.h> #include <asm/shadow.h> +#include <asm/p2m_entry.h> +#include <asm/tlb_track.h> #include <linux/efi.h> #include <xen/guest_access.h> #include <asm/page.h> #include <public/memory.h> static void domain_page_flush(struct domain* d, unsigned long mpaddr, - unsigned long old_mfn, unsigned long new_mfn); + volatile pte_t* ptep, pte_t old_pte); extern unsigned long ia64_iobase; @@ -396,6 +398,13 @@ gmfn_to_mfn_foreign(struct domain *d, unsigned long gpfn) { unsigned long pte; + // This function may be called from __gnttab_copy() + // during domain destruction with VNIF copy receiver. + // ** FIXME: This is not SMP-safe yet about p2m table. ** + if (unlikely(d->arch.mm.pgd == NULL)) { + BUG(); + return INVALID_MFN; + } pte = lookup_domain_mpa(d,gpfn << PAGE_SHIFT, NULL); if (!pte) { panic("gmfn_to_mfn_foreign: bad gpfn. spinning...\n"); @@ -702,6 +711,22 @@ void *domain_mpa_to_imva(struct domain *d, unsigned long mpaddr) } #endif +unsigned long +xencomm_paddr_to_maddr(unsigned long paddr) +{ + struct vcpu *v = current; + struct domain *d = v->domain; + u64 pa; + + pa = ____lookup_domain_mpa(d, paddr); + if (pa == INVALID_MFN) { + printf("%s: called with bad memory address: 0x%lx - iip=%lx\n", + __func__, paddr, vcpu_regs(v)->cr_iip); + return 0; + } + return __va_ul((pa & _PFN_MASK) | (paddr & ~PAGE_MASK)); +} + /* Allocate a new page for domain and map it to the specified metaphysical address. */ static struct page_info * @@ -776,15 +801,18 @@ flags_to_prot (unsigned long flags) res |= flags & ASSIGN_readonly ? _PAGE_AR_R: _PAGE_AR_RWX; res |= flags & ASSIGN_nocache ? _PAGE_MA_UC: _PAGE_MA_WB; +#ifdef CONFIG_XEN_IA64_TLB_TRACK + res |= flags & ASSIGN_tlb_track ? _PAGE_TLB_TRACKING: 0; +#endif return res; } /* map a physical address to the specified metaphysical addr */ -// flags: currently only ASSIGN_readonly, ASSIGN_nocache +// flags: currently only ASSIGN_readonly, ASSIGN_nocache, ASSIGN_tlb_tack // This is called by assign_domain_mmio_page(). // So accessing to pte is racy. -void +int __assign_domain_page(struct domain *d, unsigned long mpaddr, unsigned long physaddr, unsigned long flags) @@ -800,8 +828,25 @@ __assign_domain_page(struct domain *d, old_pte = __pte(0); new_pte = pfn_pte(physaddr >> PAGE_SHIFT, __pgprot(prot)); ret_pte = ptep_cmpxchg_rel(&d->arch.mm, mpaddr, pte, old_pte, new_pte); - if (pte_val(ret_pte) == pte_val(old_pte)) + if (pte_val(ret_pte) == pte_val(old_pte)) { smp_mb(); + return 0; + } + + // dom0 tries to map real machine's I/O region, but failed. + // It is very likely that dom0 doesn't boot correctly because + // it can't access I/O. So complain here. + if ((flags & ASSIGN_nocache) && + (pte_pfn(ret_pte) != (physaddr >> PAGE_SHIFT) || + !(pte_val(ret_pte) & _PAGE_MA_UC))) + printk("%s:%d WARNING can't assign page domain 0x%p id %d\n" + "\talready assigned pte_val 0x%016lx\n" + "\tmpaddr 0x%016lx physaddr 0x%016lx flags 0x%lx\n", + __func__, __LINE__, + d, d->domain_id, pte_val(ret_pte), + mpaddr, physaddr, flags); + + return -EAGAIN; } /* get_page() and map a physical address to the specified metaphysical addr */ @@ -818,7 +863,7 @@ assign_domain_page(struct domain *d, set_gpfn_from_mfn(physaddr >> PAGE_SHIFT, mpaddr >> PAGE_SHIFT); // because __assign_domain_page() uses set_pte_rel() which has // release semantics, smp_mb() isn't needed. - __assign_domain_page(d, mpaddr, physaddr, ASSIGN_writable); + (void)__assign_domain_page(d, mpaddr, physaddr, ASSIGN_writable); } int @@ -841,8 +886,8 @@ ioports_permit_access(struct domain *d, unsigned long fp, unsigned long lp) lp_offset = PAGE_ALIGN(IO_SPACE_SPARSE_ENCODING(lp)); for (off = fp_offset; off <= lp_offset; off += PAGE_SIZE) - __assign_domain_page(d, IO_PORTS_PADDR + off, - __pa(ia64_iobase) + off, ASSIGN_nocache); + (void)__assign_domain_page(d, IO_PORTS_PADDR + off, + __pa(ia64_iobase) + off, ASSIGN_nocache); return 0; } @@ -911,7 +956,7 @@ assign_domain_same_page(struct domain *d, //XXX optimization unsigned long end = PAGE_ALIGN(mpaddr + size); for (mpaddr &= PAGE_MASK; mpaddr < end; mpaddr += PAGE_SIZE) { - __assign_domain_page(d, mpaddr, mpaddr, flags); + (void)__assign_domain_page(d, mpaddr, mpaddr, flags); } } @@ -995,7 +1040,7 @@ assign_domain_mach_page(struct domain *d, // caller must call set_gpfn_from_mfn() before call if necessary. // because set_gpfn_from_mfn() result must be visible before pte xchg // caller must use memory barrier. NOTE: xchg has acquire semantics. -// flags: currently only ASSIGN_readonly +// flags: ASSIGN_xxx static void assign_domain_page_replace(struct domain *d, unsigned long mpaddr, unsigned long mfn, unsigned long flags) @@ -1029,12 +1074,13 @@ assign_domain_page_replace(struct domain *d, unsigned long mpaddr, set_gpfn_from_mfn(old_mfn, INVALID_M2P_ENTRY); } - domain_page_flush(d, mpaddr, old_mfn, mfn); + domain_page_flush(d, mpaddr, pte, old_pte); try_to_clear_PGC_allocate(d, old_page); put_page(old_page); } } + perfc_incrc(assign_domain_page_replace); } // caller must get_page(new_page) before @@ -1048,7 +1094,7 @@ assign_domain_page_cmpxchg_rel(struct domain* d, unsigned long mpaddr, struct mm_struct *mm = &d->arch.mm; volatile pte_t* pte; unsigned long old_mfn; - unsigned long old_arflags; + unsigned long old_prot; pte_t old_pte; unsigned long new_mfn; unsigned long new_prot; @@ -1058,12 +1104,12 @@ assign_domain_page_cmpxchg_rel(struct domain* d, unsigned long mpaddr, pte = lookup_alloc_domain_pte(d, mpaddr); again: - old_arflags = pte_val(*pte) & ~_PAGE_PPN_MASK; + old_prot = pte_val(*pte) & ~_PAGE_PPN_MASK; old_mfn = page_to_mfn(old_page); - old_pte = pfn_pte(old_mfn, __pgprot(old_arflags)); + old_pte = pfn_pte(old_mfn, __pgprot(old_prot)); if (!pte_present(old_pte)) { - DPRINTK("%s: old_pte 0x%lx old_arflags 0x%lx old_mfn 0x%lx\n", - __func__, pte_val(old_pte), old_arflags, old_mfn); + DPRINTK("%s: old_pte 0x%lx old_prot 0x%lx old_mfn 0x%lx\n", + __func__, pte_val(old_pte), old_prot, old_mfn); return -EINVAL; } @@ -1078,10 +1124,10 @@ assign_domain_page_cmpxchg_rel(struct domain* d, unsigned long mpaddr, goto again; } - DPRINTK("%s: old_pte 0x%lx old_arflags 0x%lx old_mfn 0x%lx " + DPRINTK("%s: old_pte 0x%lx old_prot 0x%lx old_mfn 0x%lx " "ret_pte 0x%lx ret_mfn 0x%lx\n", __func__, - pte_val(old_pte), old_arflags, old_mfn, + pte_val(old_pte), old_prot, old_mfn, pte_val(ret_pte), pte_pfn(ret_pte)); return -EINVAL; } @@ -1093,8 +1139,9 @@ assign_domain_page_cmpxchg_rel(struct domain* d, unsigned long mpaddr, set_gpfn_from_mfn(old_mfn, INVALID_M2P_ENTRY); - domain_page_flush(d, mpaddr, old_mfn, new_mfn); + domain_page_flush(d, mpaddr, pte, old_pte); put_page(old_page); + perfc_incrc(assign_domain_pge_cmpxchg_rel); return 0; } @@ -1161,12 +1208,13 @@ zap_domain_page_one(struct domain *d, unsigned long mpaddr, unsigned long mfn) set_gpfn_from_mfn(mfn, INVALID_M2P_ENTRY); } - domain_page_flush(d, mpaddr, mfn, INVALID_MFN); + domain_page_flush(d, mpaddr, pte, old_pte); if (page_get_owner(page) != NULL) { try_to_clear_PGC_allocate(d, page); } put_page(page); + perfc_incrc(zap_dcomain_page_one); } unsigned long @@ -1179,6 +1227,7 @@ dom0vp_zap_physmap(struct domain *d, unsigned long gpfn, } zap_domain_page_one(d, gpfn << PAGE_SHIFT, INVALID_MFN); + perfc_incrc(dom0vp_zap_physmap); return 0; } @@ -1224,11 +1273,132 @@ dom0vp_add_physmap(struct domain* d, unsigned long gpfn, unsigned long mfn, get_gpfn_from_mfn(mfn) != INVALID_M2P_ENTRY); assign_domain_page_replace(d, gpfn << PAGE_SHIFT, mfn, flags); //don't update p2m table because this page belongs to rd, not d. + perfc_incrc(dom0vp_add_physmap); out1: put_domain(rd); return error; } +#ifdef CONFIG_XEN_IA64_EXPOSE_P2M +static struct page_info* p2m_pte_zero_page = NULL; + +void +expose_p2m_init(void) +{ + pte_t* pte; + + pte = pte_alloc_one_kernel(NULL, 0); + BUG_ON(pte == NULL); + smp_mb();// make contents of the page visible. + p2m_pte_zero_page = virt_to_page(pte); +} + +static int +expose_p2m_page(struct domain* d, unsigned long mpaddr, struct page_info* page) +{ + // we can't get_page(page) here. + // pte page is allocated form xen heap.(see pte_alloc_one_kernel().) + // so that the page has NULL page owner and it's reference count + // is useless. + // see also relinquish_pte()'s page_get_owner() == NULL check. + BUG_ON(page_get_owner(page) != NULL); + + return __assign_domain_page(d, mpaddr, page_to_maddr(page), + ASSIGN_readonly); +} + +// It is possible to optimize loop, But this isn't performance critical. +unsigned long +dom0vp_expose_p2m(struct domain* d, + unsigned long conv_start_gpfn, + unsigned long assign_start_gpfn, + unsigned long expose_size, unsigned long granule_pfn) +{ + unsigned long expose_num_pfn = expose_size >> PAGE_SHIFT; + unsigned long i; + volatile pte_t* conv_pte; + volatile pte_t* assign_pte; + + if ((expose_size % PAGE_SIZE) != 0 || + (granule_pfn % PTRS_PER_PTE) != 0 || + (expose_num_pfn % PTRS_PER_PTE) != 0 || + (conv_start_gpfn % granule_pfn) != 0 || + (assign_start_gpfn % granule_pfn) != 0 || + (expose_num_pfn % granule_pfn) != 0) { + DPRINTK("%s conv_start_gpfn 0x%016lx assign_start_gpfn 0x%016lx " + "expose_size 0x%016lx granulte_pfn 0x%016lx\n", __func__, + conv_start_gpfn, assign_start_gpfn, expose_size, granule_pfn); + return -EINVAL; + } + + if (granule_pfn != PTRS_PER_PTE) { + DPRINTK("%s granule_pfn 0x%016lx PTRS_PER_PTE 0x%016lx\n", + __func__, granule_pfn, PTRS_PER_PTE); + return -ENOSYS; + } + + // allocate pgd, pmd. + i = conv_start_gpfn; + while (i < expose_num_pfn) { + conv_pte = lookup_noalloc_domain_pte(d, (conv_start_gpfn + i) << + PAGE_SHIFT); + if (conv_pte == NULL) { + i++; + continue; + } + + assign_pte = lookup_alloc_domain_pte(d, (assign_start_gpfn << + PAGE_SHIFT) + i * sizeof(pte_t)); + if (assign_pte == NULL) { + DPRINTK("%s failed to allocate pte page\n", __func__); + return -ENOMEM; + } + + // skip to next pte page + i += PTRS_PER_PTE; + i &= ~(PTRS_PER_PTE - 1); + } + + // expose pte page + i = 0; + while (i < expose_num_pfn) { + conv_pte = lookup_noalloc_domain_pte(d, (conv_start_gpfn + i) << + PAGE_SHIFT); + if (conv_pte == NULL) { + i++; + continue; + } + + if (expose_p2m_page(d, (assign_start_gpfn << PAGE_SHIFT) + + i * sizeof(pte_t), virt_to_page(conv_pte)) < 0) { + DPRINTK("%s failed to assign page\n", __func__); + return -EAGAIN; + } + + // skip to next pte page + i += PTRS_PER_PTE; + i &= ~(PTRS_PER_PTE - 1); + } + + // expose p2m_pte_zero_page + for (i = 0; i < expose_num_pfn / PTRS_PER_PTE + 1; i++) { + assign_pte = lookup_noalloc_domain_pte(d, (assign_start_gpfn + i) << + PAGE_SHIFT); + BUG_ON(assign_pte == NULL); + if (pte_present(*assign_pte)) { + continue; + } + if (expose_p2m_page(d, (assign_start_gpfn + i) << PAGE_SHIFT, + p2m_pte_zero_page) < 0) { + DPRINTK("%s failed to assign zero-pte page\n", __func__); + return -EAGAIN; + } + } + + return 0; +} +#endif + // grant table host mapping // mpaddr: host_addr: pseudo physical address // mfn: frame: machine page frame @@ -1253,8 +1423,13 @@ create_grant_host_mapping(unsigned long gpaddr, BUG_ON(ret == 0); BUG_ON(page_get_owner(mfn_to_page(mfn)) == d && get_gpfn_from_mfn(mfn) != INVALID_M2P_ENTRY); - assign_domain_page_replace(d, gpaddr, mfn, (flags & GNTMAP_readonly)? - ASSIGN_readonly: ASSIGN_writable); + assign_domain_page_replace(d, gpaddr, mfn, +#ifdef CONFIG_XEN_IA64_TLB_TRACK + ASSIGN_tlb_track | +#endif + ((flags & GNTMAP_readonly) ? + ASSIGN_readonly : ASSIGN_writable)); + perfc_incrc(create_grant_host_mapping); return GNTST_okay; } @@ -1308,12 +1483,13 @@ destroy_grant_host_mapping(unsigned long gpaddr, } BUG_ON(pte_pfn(old_pte) != mfn); - domain_page_flush(d, gpaddr, mfn, INVALID_MFN); + domain_page_flush(d, gpaddr, pte, old_pte); page = mfn_to_page(mfn); BUG_ON(page_get_owner(page) == d);//try_to_clear_PGC_allocate(d, page) is not needed. put_page(page); + perfc_incrc(destroy_grant_host_mapping); return GNTST_okay; } @@ -1374,6 +1550,7 @@ steal_page(struct domain *d, struct page_info *page, unsigned int memflags) free_domheap_page(new); return -1; } + perfc_incrc(steal_page_refcount); } spin_lock(&d->page_alloc_lock); @@ -1443,6 +1620,7 @@ steal_page(struct domain *d, struct page_info *page, unsigned int memflags) list_del(&page->list); spin_unlock(&d->page_alloc_lock); + perfc_incrc(steal_page); return 0; } @@ -1460,6 +1638,8 @@ guest_physmap_add_page(struct domain *d, unsigned long gpfn, assign_domain_page_replace(d, gpfn << PAGE_SHIFT, mfn, ASSIGN_writable); //BUG_ON(mfn != ((lookup_domain_mpa(d, gpfn << PAGE_SHIFT) & _PFN_MASK) >> PAGE_SHIFT)); + + perfc_incrc(guest_physmap_add_page); } void @@ -1468,18 +1648,51 @@ guest_physmap_remove_page(struct domain *d, unsigned long gpfn, { BUG_ON(mfn == 0);//XXX zap_domain_page_one(d, gpfn << PAGE_SHIFT, mfn); + perfc_incrc(guest_physmap_remove_page); } //XXX sledgehammer. // flush finer range. static void domain_page_flush(struct domain* d, unsigned long mpaddr, - unsigned long old_mfn, unsigned long new_mfn) + volatile pte_t* ptep, pte_t old_pte) { +#ifdef CONFIG_XEN_IA64_TLB_TRACK + struct tlb_track_entry* entry; +#endif + if (shadow_mode_enabled(d)) shadow_mark_page_dirty(d, mpaddr >> PAGE_SHIFT); +#ifndef CONFIG_XEN_IA64_TLB_TRACK domain_flush_vtlb_all(); +#else + switch (tlb_track_search_and_remove(d->arch.tlb_track, + ptep, old_pte, &entry)) { + case TLB_TRACK_NOT_TRACKED: + // DPRINTK("%s TLB_TRACK_NOT_TRACKED\n", __func__); + domain_flush_vtlb_all(); + break; + case TLB_TRACK_NOT_FOUND: + /* do nothing */ + // DPRINTK("%s TLB_TRACK_NOT_FOUND\n", __func__); + break; + case TLB_TRACK_FOUND: + // DPRINTK("%s TLB_TRACK_FOUND\n", __func__); + domain_flush_vtlb_track_entry(d, entry); + tlb_track_free_entry(d->arch.tlb_track, entry); + break; + case TLB_TRACK_MANY: + DPRINTK("%s TLB_TRACK_MANY\n", __func__); + domain_flush_vtlb_all(); + break; + case TLB_TRACK_AGAIN: + DPRINTK("%s TLB_TRACK_AGAIN\n", __func__); + BUG(); + break; + } +#endif + perfc_incrc(domain_page_flush); } int diff --git a/xen/arch/ia64/xen/privop.c b/xen/arch/ia64/xen/privop.c index 31e1ebc198..be94c3d6f8 100644 --- a/xen/arch/ia64/xen/privop.c +++ b/xen/arch/ia64/xen/privop.c @@ -9,13 +9,13 @@ #include <asm/privop.h> #include <asm/vcpu.h> #include <asm/processor.h> -#include <asm/delay.h> // Debug only +#include <asm/delay.h> // Debug only #include <asm/dom_fw.h> #include <asm/vhpt.h> #include <asm/bundle.h> #include <xen/perfc.h> -long priv_verbose=0; +long priv_verbose = 0; unsigned long privop_trace = 0; /* Set to 1 to handle privified instructions from the privify tool. */ @@ -29,200 +29,213 @@ static const int privify_en = 1; Privileged operation emulation routines **************************************************************************/ -static IA64FAULT priv_rfi(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_rfi(VCPU * vcpu, INST64 inst) { return vcpu_rfi(vcpu); } -static IA64FAULT priv_bsw0(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_bsw0(VCPU * vcpu, INST64 inst) { return vcpu_bsw0(vcpu); } -static IA64FAULT priv_bsw1(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_bsw1(VCPU * vcpu, INST64 inst) { return vcpu_bsw1(vcpu); } -static IA64FAULT priv_cover(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_cover(VCPU * vcpu, INST64 inst) { return vcpu_cover(vcpu); } -static IA64FAULT priv_ptc_l(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_ptc_l(VCPU * vcpu, INST64 inst) { - UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3); - UINT64 log_range; + u64 vadr = vcpu_get_gr(vcpu, inst.M45.r3); + u64 log_range; - log_range = ((vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2); - return vcpu_ptc_l(vcpu,vadr,log_range); + log_range = ((vcpu_get_gr(vcpu, inst.M45.r2) & 0xfc) >> 2); + return vcpu_ptc_l(vcpu, vadr, log_range); } -static IA64FAULT priv_ptc_e(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_ptc_e(VCPU * vcpu, INST64 inst) { - UINT src = inst.M28.r3; + unsigned int src = inst.M28.r3; // NOTE: ptc_e with source gr > 63 is emulated as a fc r(y-64) if (privify_en && src > 63) - return(vcpu_fc(vcpu,vcpu_get_gr(vcpu,src - 64))); - return vcpu_ptc_e(vcpu,vcpu_get_gr(vcpu,src)); + return vcpu_fc(vcpu, vcpu_get_gr(vcpu, src - 64)); + return vcpu_ptc_e(vcpu, vcpu_get_gr(vcpu, src)); } -static IA64FAULT priv_ptc_g(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_ptc_g(VCPU * vcpu, INST64 inst) { - UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3); - UINT64 addr_range; + u64 vadr = vcpu_get_gr(vcpu, inst.M45.r3); + u64 addr_range; - addr_range = 1 << ((vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2); - return vcpu_ptc_g(vcpu,vadr,addr_range); + addr_range = 1 << ((vcpu_get_gr(vcpu, inst.M45.r2) & 0xfc) >> 2); + return vcpu_ptc_g(vcpu, vadr, addr_range); } -static IA64FAULT priv_ptc_ga(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_ptc_ga(VCPU * vcpu, INST64 inst) { - UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3); - UINT64 addr_range; + u64 vadr = vcpu_get_gr(vcpu, inst.M45.r3); + u64 addr_range; - addr_range = 1 << ((vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2); - return vcpu_ptc_ga(vcpu,vadr,addr_range); + addr_range = 1 << ((vcpu_get_gr(vcpu, inst.M45.r2) & 0xfc) >> 2); + return vcpu_ptc_ga(vcpu, vadr, addr_range); } -static IA64FAULT priv_ptr_d(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_ptr_d(VCPU * vcpu, INST64 inst) { - UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3); - UINT64 log_range; + u64 vadr = vcpu_get_gr(vcpu, inst.M45.r3); + u64 log_range; - log_range = (vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2; - return vcpu_ptr_d(vcpu,vadr,log_range); + log_range = (vcpu_get_gr(vcpu, inst.M45.r2) & 0xfc) >> 2; + return vcpu_ptr_d(vcpu, vadr, log_range); } -static IA64FAULT priv_ptr_i(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_ptr_i(VCPU * vcpu, INST64 inst) { - UINT64 vadr = vcpu_get_gr(vcpu,inst.M45.r3); - UINT64 log_range; + u64 vadr = vcpu_get_gr(vcpu, inst.M45.r3); + u64 log_range; - log_range = (vcpu_get_gr(vcpu,inst.M45.r2) & 0xfc) >> 2; - return vcpu_ptr_i(vcpu,vadr,log_range); + log_range = (vcpu_get_gr(vcpu, inst.M45.r2) & 0xfc) >> 2; + return vcpu_ptr_i(vcpu, vadr, log_range); } -static IA64FAULT priv_tpa(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_tpa(VCPU * vcpu, INST64 inst) { - UINT64 padr; - UINT fault; - UINT src = inst.M46.r3; + u64 padr; + unsigned int fault; + unsigned int src = inst.M46.r3; // NOTE: tpa with source gr > 63 is emulated as a ttag rx=r(y-64) if (privify_en && src > 63) - fault = vcpu_ttag(vcpu,vcpu_get_gr(vcpu,src-64),&padr); - else fault = vcpu_tpa(vcpu,vcpu_get_gr(vcpu,src),&padr); + fault = vcpu_ttag(vcpu, vcpu_get_gr(vcpu, src - 64), &padr); + else + fault = vcpu_tpa(vcpu, vcpu_get_gr(vcpu, src), &padr); if (fault == IA64_NO_FAULT) return vcpu_set_gr(vcpu, inst.M46.r1, padr, 0); - else return fault; + else + return fault; } -static IA64FAULT priv_tak(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_tak(VCPU * vcpu, INST64 inst) { - UINT64 key; - UINT fault; - UINT src = inst.M46.r3; + u64 key; + unsigned int fault; + unsigned int src = inst.M46.r3; // NOTE: tak with source gr > 63 is emulated as a thash rx=r(y-64) if (privify_en && src > 63) - fault = vcpu_thash(vcpu,vcpu_get_gr(vcpu,src-64),&key); - else fault = vcpu_tak(vcpu,vcpu_get_gr(vcpu,src),&key); + fault = vcpu_thash(vcpu, vcpu_get_gr(vcpu, src - 64), &key); + else + fault = vcpu_tak(vcpu, vcpu_get_gr(vcpu, src), &key); if (fault == IA64_NO_FAULT) - return vcpu_set_gr(vcpu, inst.M46.r1, key,0); - else return fault; + return vcpu_set_gr(vcpu, inst.M46.r1, key, 0); + else + return fault; } /************************************ * Insert translation register/cache ************************************/ -static IA64FAULT priv_itr_d(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_itr_d(VCPU * vcpu, INST64 inst) { - UINT64 fault, itir, ifa, pte, slot; + u64 fault, itir, ifa, pte, slot; - //if (!vcpu_get_psr_ic(vcpu)) return(IA64_ILLOP_FAULT); - if ((fault = vcpu_get_itir(vcpu,&itir)) != IA64_NO_FAULT) - return(IA64_ILLOP_FAULT); - if ((fault = vcpu_get_ifa(vcpu,&ifa)) != IA64_NO_FAULT) - return(IA64_ILLOP_FAULT); - pte = vcpu_get_gr(vcpu,inst.M42.r2); - slot = vcpu_get_gr(vcpu,inst.M42.r3); + //if (!vcpu_get_psr_ic(vcpu)) + // return IA64_ILLOP_FAULT; + fault = vcpu_get_itir(vcpu, &itir); + if (fault != IA64_NO_FAULT) + return IA64_ILLOP_FAULT; + fault = vcpu_get_ifa(vcpu, &ifa); + if (fault != IA64_NO_FAULT) + return IA64_ILLOP_FAULT; + pte = vcpu_get_gr(vcpu, inst.M42.r2); + slot = vcpu_get_gr(vcpu, inst.M42.r3); - return (vcpu_itr_d(vcpu,slot,pte,itir,ifa)); + return vcpu_itr_d(vcpu, slot, pte, itir, ifa); } -static IA64FAULT priv_itr_i(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_itr_i(VCPU * vcpu, INST64 inst) { - UINT64 fault, itir, ifa, pte, slot; + u64 fault, itir, ifa, pte, slot; - //if (!vcpu_get_psr_ic(vcpu)) return(IA64_ILLOP_FAULT); - if ((fault = vcpu_get_itir(vcpu,&itir)) != IA64_NO_FAULT) - return(IA64_ILLOP_FAULT); - if ((fault = vcpu_get_ifa(vcpu,&ifa)) != IA64_NO_FAULT) - return(IA64_ILLOP_FAULT); - pte = vcpu_get_gr(vcpu,inst.M42.r2); - slot = vcpu_get_gr(vcpu,inst.M42.r3); + //if (!vcpu_get_psr_ic(vcpu)) return IA64_ILLOP_FAULT; + fault = vcpu_get_itir(vcpu, &itir); + if (fault != IA64_NO_FAULT) + return IA64_ILLOP_FAULT; + fault = vcpu_get_ifa(vcpu, &ifa); + if (fault != IA64_NO_FAULT) + return IA64_ILLOP_FAULT; + pte = vcpu_get_gr(vcpu, inst.M42.r2); + slot = vcpu_get_gr(vcpu, inst.M42.r3); - return (vcpu_itr_i(vcpu,slot,pte,itir,ifa)); + return vcpu_itr_i(vcpu, slot, pte, itir, ifa); } -static IA64FAULT priv_itc_d(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_itc_d(VCPU * vcpu, INST64 inst) { - UINT64 fault, itir, ifa, pte; + u64 fault, itir, ifa, pte; - //if (!vcpu_get_psr_ic(vcpu)) return(IA64_ILLOP_FAULT); - if ((fault = vcpu_get_itir(vcpu,&itir)) != IA64_NO_FAULT) - return(IA64_ILLOP_FAULT); - if ((fault = vcpu_get_ifa(vcpu,&ifa)) != IA64_NO_FAULT) - return(IA64_ILLOP_FAULT); - pte = vcpu_get_gr(vcpu,inst.M41.r2); + //if (!vcpu_get_psr_ic(vcpu)) return IA64_ILLOP_FAULT; + fault = vcpu_get_itir(vcpu, &itir); + if (fault != IA64_NO_FAULT) + return IA64_ILLOP_FAULT; + fault = vcpu_get_ifa(vcpu, &ifa); + if (fault != IA64_NO_FAULT) + return IA64_ILLOP_FAULT; + pte = vcpu_get_gr(vcpu, inst.M41.r2); - return (vcpu_itc_d(vcpu,pte,itir,ifa)); + return vcpu_itc_d(vcpu, pte, itir, ifa); } -static IA64FAULT priv_itc_i(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_itc_i(VCPU * vcpu, INST64 inst) { - UINT64 fault, itir, ifa, pte; + u64 fault, itir, ifa, pte; - //if (!vcpu_get_psr_ic(vcpu)) return(IA64_ILLOP_FAULT); - if ((fault = vcpu_get_itir(vcpu,&itir)) != IA64_NO_FAULT) - return(IA64_ILLOP_FAULT); - if ((fault = vcpu_get_ifa(vcpu,&ifa)) != IA64_NO_FAULT) - return(IA64_ILLOP_FAULT); - pte = vcpu_get_gr(vcpu,inst.M41.r2); + //if (!vcpu_get_psr_ic(vcpu)) return IA64_ILLOP_FAULT; + fault = vcpu_get_itir(vcpu, &itir); + if (fault != IA64_NO_FAULT) + return IA64_ILLOP_FAULT; + fault = vcpu_get_ifa(vcpu, &ifa); + if (fault != IA64_NO_FAULT) + return IA64_ILLOP_FAULT; + pte = vcpu_get_gr(vcpu, inst.M41.r2); - return (vcpu_itc_i(vcpu,pte,itir,ifa)); + return vcpu_itc_i(vcpu, pte, itir, ifa); } /************************************* * Moves to semi-privileged registers *************************************/ -static IA64FAULT priv_mov_to_ar_imm(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_mov_to_ar_imm(VCPU * vcpu, INST64 inst) { // I27 and M30 are identical for these fields - UINT64 ar3 = inst.M30.ar3; - UINT64 imm = vcpu_get_gr(vcpu,inst.M30.imm); - return (vcpu_set_ar(vcpu,ar3,imm)); + u64 ar3 = inst.M30.ar3; + u64 imm = vcpu_get_gr(vcpu, inst.M30.imm); + return vcpu_set_ar(vcpu, ar3, imm); } -static IA64FAULT priv_mov_to_ar_reg(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_mov_to_ar_reg(VCPU * vcpu, INST64 inst) { // I26 and M29 are identical for these fields - UINT64 ar3 = inst.M29.ar3; + u64 ar3 = inst.M29.ar3; if (privify_en && inst.M29.r2 > 63 && inst.M29.ar3 < 8) { // privified mov from kr - UINT64 val; - if (vcpu_get_ar(vcpu,ar3,&val) != IA64_ILLOP_FAULT) - return vcpu_set_gr(vcpu, inst.M29.r2-64, val,0); - else return IA64_ILLOP_FAULT; - } - else { - UINT64 r2 = vcpu_get_gr(vcpu,inst.M29.r2); - return (vcpu_set_ar(vcpu,ar3,r2)); + u64 val; + if (vcpu_get_ar(vcpu, ar3, &val) != IA64_ILLOP_FAULT) + return vcpu_set_gr(vcpu, inst.M29.r2 - 64, val, 0); + else + return IA64_ILLOP_FAULT; + } else { + u64 r2 = vcpu_get_gr(vcpu, inst.M29.r2); + return vcpu_set_ar(vcpu, ar3, r2); } } @@ -230,177 +243,205 @@ static IA64FAULT priv_mov_to_ar_reg(VCPU *vcpu, INST64 inst) * Moves to privileged registers ********************************/ -static IA64FAULT priv_mov_to_pkr(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_mov_to_pkr(VCPU * vcpu, INST64 inst) { - UINT64 r3 = vcpu_get_gr(vcpu,inst.M42.r3); - UINT64 r2 = vcpu_get_gr(vcpu,inst.M42.r2); - return (vcpu_set_pkr(vcpu,r3,r2)); + u64 r3 = vcpu_get_gr(vcpu, inst.M42.r3); + u64 r2 = vcpu_get_gr(vcpu, inst.M42.r2); + return vcpu_set_pkr(vcpu, r3, r2); } -static IA64FAULT priv_mov_to_rr(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_mov_to_rr(VCPU * vcpu, INST64 inst) { - UINT64 r3 = vcpu_get_gr(vcpu,inst.M42.r3); - UINT64 r2 = vcpu_get_gr(vcpu,inst.M42.r2); - return (vcpu_set_rr(vcpu,r3,r2)); + u64 r3 = vcpu_get_gr(vcpu, inst.M42.r3); + u64 r2 = vcpu_get_gr(vcpu, inst.M42.r2); + return vcpu_set_rr(vcpu, r3, r2); } -static IA64FAULT priv_mov_to_dbr(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_mov_to_dbr(VCPU * vcpu, INST64 inst) { - UINT64 r3 = vcpu_get_gr(vcpu,inst.M42.r3); - UINT64 r2 = vcpu_get_gr(vcpu,inst.M42.r2); - return (vcpu_set_dbr(vcpu,r3,r2)); + u64 r3 = vcpu_get_gr(vcpu, inst.M42.r3); + u64 r2 = vcpu_get_gr(vcpu, inst.M42.r2); + return vcpu_set_dbr(vcpu, r3, r2); } -static IA64FAULT priv_mov_to_ibr(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_mov_to_ibr(VCPU * vcpu, INST64 inst) { - UINT64 r3 = vcpu_get_gr(vcpu,inst.M42.r3); - UINT64 r2 = vcpu_get_gr(vcpu,inst.M42.r2); - return (vcpu_set_ibr(vcpu,r3,r2)); + u64 r3 = vcpu_get_gr(vcpu, inst.M42.r3); + u64 r2 = vcpu_get_gr(vcpu, inst.M42.r2); + return vcpu_set_ibr(vcpu, r3, r2); } -static IA64FAULT priv_mov_to_pmc(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_mov_to_pmc(VCPU * vcpu, INST64 inst) { - UINT64 r3 = vcpu_get_gr(vcpu,inst.M42.r3); - UINT64 r2 = vcpu_get_gr(vcpu,inst.M42.r2); - return (vcpu_set_pmc(vcpu,r3,r2)); + u64 r3 = vcpu_get_gr(vcpu, inst.M42.r3); + u64 r2 = vcpu_get_gr(vcpu, inst.M42.r2); + return vcpu_set_pmc(vcpu, r3, r2); } -static IA64FAULT priv_mov_to_pmd(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_mov_to_pmd(VCPU * vcpu, INST64 inst) { - UINT64 r3 = vcpu_get_gr(vcpu,inst.M42.r3); - UINT64 r2 = vcpu_get_gr(vcpu,inst.M42.r2); - return (vcpu_set_pmd(vcpu,r3,r2)); + u64 r3 = vcpu_get_gr(vcpu, inst.M42.r3); + u64 r2 = vcpu_get_gr(vcpu, inst.M42.r2); + return vcpu_set_pmd(vcpu, r3, r2); } -static IA64FAULT priv_mov_to_cr(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_mov_to_cr(VCPU * vcpu, INST64 inst) { - UINT64 val = vcpu_get_gr(vcpu, inst.M32.r2); + u64 val = vcpu_get_gr(vcpu, inst.M32.r2); perfc_incra(mov_to_cr, inst.M32.cr3); switch (inst.M32.cr3) { - case 0: return vcpu_set_dcr(vcpu,val); - case 1: return vcpu_set_itm(vcpu,val); - case 2: return vcpu_set_iva(vcpu,val); - case 8: return vcpu_set_pta(vcpu,val); - case 16:return vcpu_set_ipsr(vcpu,val); - case 17:return vcpu_set_isr(vcpu,val); - case 19:return vcpu_set_iip(vcpu,val); - case 20:return vcpu_set_ifa(vcpu,val); - case 21:return vcpu_set_itir(vcpu,val); - case 22:return vcpu_set_iipa(vcpu,val); - case 23:return vcpu_set_ifs(vcpu,val); - case 24:return vcpu_set_iim(vcpu,val); - case 25:return vcpu_set_iha(vcpu,val); - case 64:return vcpu_set_lid(vcpu,val); - case 65:return IA64_ILLOP_FAULT; - case 66:return vcpu_set_tpr(vcpu,val); - case 67:return vcpu_set_eoi(vcpu,val); - case 68:return IA64_ILLOP_FAULT; - case 69:return IA64_ILLOP_FAULT; - case 70:return IA64_ILLOP_FAULT; - case 71:return IA64_ILLOP_FAULT; - case 72:return vcpu_set_itv(vcpu,val); - case 73:return vcpu_set_pmv(vcpu,val); - case 74:return vcpu_set_cmcv(vcpu,val); - case 80:return vcpu_set_lrr0(vcpu,val); - case 81:return vcpu_set_lrr1(vcpu,val); - default: return IA64_ILLOP_FAULT; + case 0: + return vcpu_set_dcr(vcpu, val); + case 1: + return vcpu_set_itm(vcpu, val); + case 2: + return vcpu_set_iva(vcpu, val); + case 8: + return vcpu_set_pta(vcpu, val); + case 16: + return vcpu_set_ipsr(vcpu, val); + case 17: + return vcpu_set_isr(vcpu, val); + case 19: + return vcpu_set_iip(vcpu, val); + case 20: + return vcpu_set_ifa(vcpu, val); + case 21: + return vcpu_set_itir(vcpu, val); + case 22: + return vcpu_set_iipa(vcpu, val); + case 23: + return vcpu_set_ifs(vcpu, val); + case 24: + return vcpu_set_iim(vcpu, val); + case 25: + return vcpu_set_iha(vcpu, val); + case 64: + return vcpu_set_lid(vcpu, val); + case 65: + return IA64_ILLOP_FAULT; + case 66: + return vcpu_set_tpr(vcpu, val); + case 67: + return vcpu_set_eoi(vcpu, val); + case 68: + return IA64_ILLOP_FAULT; + case 69: + return IA64_ILLOP_FAULT; + case 70: + return IA64_ILLOP_FAULT; + case 71: + return IA64_ILLOP_FAULT; + case 72: + return vcpu_set_itv(vcpu, val); + case 73: + return vcpu_set_pmv(vcpu, val); + case 74: + return vcpu_set_cmcv(vcpu, val); + case 80: + return vcpu_set_lrr0(vcpu, val); + case 81: + return vcpu_set_lrr1(vcpu, val); + default: + return IA64_ILLOP_FAULT; } } -static IA64FAULT priv_rsm(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_rsm(VCPU * vcpu, INST64 inst) { - UINT64 imm24 = (inst.M44.i<<23)|(inst.M44.i2<<21)|inst.M44.imm; - return vcpu_reset_psr_sm(vcpu,imm24); + u64 imm24 = (inst.M44.i << 23) | (inst.M44.i2 << 21) | inst.M44.imm; + return vcpu_reset_psr_sm(vcpu, imm24); } -static IA64FAULT priv_ssm(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_ssm(VCPU * vcpu, INST64 inst) { - UINT64 imm24 = (inst.M44.i<<23)|(inst.M44.i2<<21)|inst.M44.imm; - return vcpu_set_psr_sm(vcpu,imm24); + u64 imm24 = (inst.M44.i << 23) | (inst.M44.i2 << 21) | inst.M44.imm; + return vcpu_set_psr_sm(vcpu, imm24); } /** * @todo Check for reserved bits and return IA64_RSVDREG_FAULT. */ -static IA64FAULT priv_mov_to_psr(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_mov_to_psr(VCPU * vcpu, INST64 inst) { - UINT64 val = vcpu_get_gr(vcpu, inst.M35.r2); - return vcpu_set_psr_l(vcpu,val); + u64 val = vcpu_get_gr(vcpu, inst.M35.r2); + return vcpu_set_psr_l(vcpu, val); } /********************************** * Moves from privileged registers **********************************/ -static IA64FAULT priv_mov_from_rr(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_mov_from_rr(VCPU * vcpu, INST64 inst) { - UINT64 val; + u64 val; IA64FAULT fault; - UINT64 reg; - - reg = vcpu_get_gr(vcpu,inst.M43.r3); + u64 reg; + + reg = vcpu_get_gr(vcpu, inst.M43.r3); if (privify_en && inst.M43.r1 > 63) { // privified mov from cpuid - fault = vcpu_get_cpuid(vcpu,reg,&val); + fault = vcpu_get_cpuid(vcpu, reg, &val); if (fault == IA64_NO_FAULT) - return vcpu_set_gr(vcpu, inst.M43.r1-64, val, 0); - } - else { - fault = vcpu_get_rr(vcpu,reg,&val); + return vcpu_set_gr(vcpu, inst.M43.r1 - 64, val, 0); + } else { + fault = vcpu_get_rr(vcpu, reg, &val); if (fault == IA64_NO_FAULT) return vcpu_set_gr(vcpu, inst.M43.r1, val, 0); } return fault; } -static IA64FAULT priv_mov_from_pkr(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_mov_from_pkr(VCPU * vcpu, INST64 inst) { - UINT64 val; + u64 val; IA64FAULT fault; - - fault = vcpu_get_pkr(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val); + + fault = vcpu_get_pkr(vcpu, vcpu_get_gr(vcpu, inst.M43.r3), &val); if (fault == IA64_NO_FAULT) return vcpu_set_gr(vcpu, inst.M43.r1, val, 0); - else return fault; + else + return fault; } -static IA64FAULT priv_mov_from_dbr(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_mov_from_dbr(VCPU * vcpu, INST64 inst) { - UINT64 val; + u64 val; IA64FAULT fault; - - fault = vcpu_get_dbr(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val); + + fault = vcpu_get_dbr(vcpu, vcpu_get_gr(vcpu, inst.M43.r3), &val); if (fault == IA64_NO_FAULT) return vcpu_set_gr(vcpu, inst.M43.r1, val, 0); - else return fault; + else + return fault; } -static IA64FAULT priv_mov_from_ibr(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_mov_from_ibr(VCPU * vcpu, INST64 inst) { - UINT64 val; + u64 val; IA64FAULT fault; - - fault = vcpu_get_ibr(vcpu,vcpu_get_gr(vcpu,inst.M43.r3),&val); + + fault = vcpu_get_ibr(vcpu, vcpu_get_gr(vcpu, inst.M43.r3), &val); if (fault == IA64_NO_FAULT) return vcpu_set_gr(vcpu, inst.M43.r1, val, 0); - else return fault; + else + return fault; } -static IA64FAULT priv_mov_from_pmc(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_mov_from_pmc(VCPU * vcpu, INST64 inst) { - UINT64 val; + u64 val; IA64FAULT fault; - UINT64 reg; - - reg = vcpu_get_gr(vcpu,inst.M43.r3); + u64 reg; + + reg = vcpu_get_gr(vcpu, inst.M43.r3); if (privify_en && inst.M43.r1 > 63) { // privified mov from pmd - fault = vcpu_get_pmd(vcpu,reg,&val); + fault = vcpu_get_pmd(vcpu, reg, &val); if (fault == IA64_NO_FAULT) - return vcpu_set_gr(vcpu, inst.M43.r1-64, val, 0); - } - else { - fault = vcpu_get_pmc(vcpu,reg,&val); + return vcpu_set_gr(vcpu, inst.M43.r1 - 64, val, 0); + } else { + fault = vcpu_get_pmc(vcpu, reg, &val); if (fault == IA64_NO_FAULT) return vcpu_set_gr(vcpu, inst.M43.r1, val, 0); } @@ -410,55 +451,84 @@ static IA64FAULT priv_mov_from_pmc(VCPU *vcpu, INST64 inst) #define cr_get(cr) \ ((fault = vcpu_get_##cr(vcpu,&val)) == IA64_NO_FAULT) ? \ vcpu_set_gr(vcpu, tgt, val, 0) : fault; - -static IA64FAULT priv_mov_from_cr(VCPU *vcpu, INST64 inst) + +static IA64FAULT priv_mov_from_cr(VCPU * vcpu, INST64 inst) { - UINT64 tgt = inst.M33.r1; - UINT64 val; + u64 tgt = inst.M33.r1; + u64 val; IA64FAULT fault; perfc_incra(mov_from_cr, inst.M33.cr3); switch (inst.M33.cr3) { - case 0: return cr_get(dcr); - case 1: return cr_get(itm); - case 2: return cr_get(iva); - case 8: return cr_get(pta); - case 16:return cr_get(ipsr); - case 17:return cr_get(isr); - case 19:return cr_get(iip); - case 20:return cr_get(ifa); - case 21:return cr_get(itir); - case 22:return cr_get(iipa); - case 23:return cr_get(ifs); - case 24:return cr_get(iim); - case 25:return cr_get(iha); - case 64:return cr_get(lid); - case 65:return cr_get(ivr); - case 66:return cr_get(tpr); - case 67:return vcpu_set_gr(vcpu,tgt,0L,0); - case 68:return cr_get(irr0); - case 69:return cr_get(irr1); - case 70:return cr_get(irr2); - case 71:return cr_get(irr3); - case 72:return cr_get(itv); - case 73:return cr_get(pmv); - case 74:return cr_get(cmcv); - case 80:return cr_get(lrr0); - case 81:return cr_get(lrr1); - default: return IA64_ILLOP_FAULT; + case 0: + return cr_get(dcr); + case 1: + return cr_get(itm); + case 2: + return cr_get(iva); + case 8: + return cr_get(pta); + case 16: + return cr_get(ipsr); + case 17: + return cr_get(isr); + case 19: + return cr_get(iip); + case 20: + return cr_get(ifa); + case 21: + return cr_get(itir); + case 22: + return cr_get(iipa); + case 23: + return cr_get(ifs); + case 24: + return cr_get(iim); + case 25: + return cr_get(iha); + case 64: + return cr_get(lid); + case 65: + return cr_get(ivr); + case 66: + return cr_get(tpr); + case 67: + return vcpu_set_gr(vcpu, tgt, 0L, 0); + case 68: + return cr_get(irr0); + case 69: + return cr_get(irr1); + case 70: + return cr_get(irr2); + case 71: + return cr_get(irr3); + case 72: + return cr_get(itv); + case 73: + return cr_get(pmv); + case 74: + return cr_get(cmcv); + case 80: + return cr_get(lrr0); + case 81: + return cr_get(lrr1); + default: + return IA64_ILLOP_FAULT; } return IA64_ILLOP_FAULT; } -static IA64FAULT priv_mov_from_psr(VCPU *vcpu, INST64 inst) +static IA64FAULT priv_mov_from_psr(VCPU * vcpu, INST64 inst) { - UINT64 tgt = inst.M33.r1; - UINT64 val; + u64 tgt = inst.M33.r1; + u64 val; IA64FAULT fault; - if ((fault = vcpu_get_psr(vcpu,&val)) == IA64_NO_FAULT) + fault = vcpu_get_psr(vcpu, &val); + if (fault == IA64_NO_FAULT) return vcpu_set_gr(vcpu, tgt, val, 0); - else return fault; + else + return fault; } /************************************************************************** @@ -483,28 +553,28 @@ static const IA64_SLOT_TYPE slot_types[0x20][3] = { }; // pointer to privileged emulation function -typedef IA64FAULT (*PPEFCN)(VCPU *vcpu, INST64 inst); +typedef IA64FAULT(*PPEFCN) (VCPU * vcpu, INST64 inst); static const PPEFCN Mpriv_funcs[64] = { - priv_mov_to_rr, priv_mov_to_dbr, priv_mov_to_ibr, priv_mov_to_pkr, - priv_mov_to_pmc, priv_mov_to_pmd, 0, 0, - 0, priv_ptc_l, priv_ptc_g, priv_ptc_ga, - priv_ptr_d, priv_ptr_i, priv_itr_d, priv_itr_i, - priv_mov_from_rr, priv_mov_from_dbr, priv_mov_from_ibr, priv_mov_from_pkr, - priv_mov_from_pmc, 0, 0, 0, - 0, 0, 0, 0, - 0, 0, priv_tpa, priv_tak, - 0, 0, 0, 0, - priv_mov_from_cr, priv_mov_from_psr, 0, 0, - 0, 0, 0, 0, - priv_mov_to_cr, priv_mov_to_psr, priv_itc_d, priv_itc_i, - 0, 0, 0, 0, - priv_ptc_e, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 + priv_mov_to_rr, priv_mov_to_dbr, priv_mov_to_ibr, priv_mov_to_pkr, + priv_mov_to_pmc, priv_mov_to_pmd, 0, 0, + 0, priv_ptc_l, priv_ptc_g, priv_ptc_ga, + priv_ptr_d, priv_ptr_i, priv_itr_d, priv_itr_i, + priv_mov_from_rr, priv_mov_from_dbr, priv_mov_from_ibr, + priv_mov_from_pkr, + priv_mov_from_pmc, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, priv_tpa, priv_tak, + 0, 0, 0, 0, + priv_mov_from_cr, priv_mov_from_psr, 0, 0, + 0, 0, 0, 0, + priv_mov_to_cr, priv_mov_to_psr, priv_itc_d, priv_itc_i, + 0, 0, 0, 0, + priv_ptc_e, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }; -static IA64FAULT -priv_handle_op(VCPU *vcpu, REGS *regs, int privlvl) +static IA64FAULT priv_handle_op(VCPU * vcpu, REGS * regs, int privlvl) { IA64_BUNDLE bundle; int slot; @@ -512,85 +582,97 @@ priv_handle_op(VCPU *vcpu, REGS *regs, int privlvl) INST64 inst; PPEFCN pfunc; unsigned long ipsr = regs->cr_ipsr; - UINT64 iip = regs->cr_iip; + u64 iip = regs->cr_iip; int x6; - + // make a local copy of the bundle containing the privop if (!vcpu_get_domain_bundle(vcpu, regs, iip, &bundle)) { //return vcpu_force_data_miss(vcpu, regs->cr_iip); return vcpu_force_inst_miss(vcpu, regs->cr_iip); } - #if 0 - if (iip==0xa000000100001820) { + if (iip == 0xa000000100001820) { static int firstpagefault = 1; if (firstpagefault) { - printf("*** First time to domain page fault!\n"); firstpagefault=0; + printf("*** First time to domain page fault!\n"); + firstpagefault = 0; } } #endif if (privop_trace) { static long i = 400; //if (i > 0) printf("priv_handle_op: at 0x%lx\n",iip); - if (i > 0) printf("priv_handle_op: privop trace at 0x%lx, itc=%lx, itm=%lx\n", - iip,ia64_get_itc(),ia64_get_itm()); + if (i > 0) + printf("priv_handle_op: privop trace at 0x%lx, " + "itc=%lx, itm=%lx\n", + iip, ia64_get_itc(), ia64_get_itm()); i--; } slot = ((struct ia64_psr *)&ipsr)->ri; - if (!slot) inst.inst = (bundle.i64[0]>>5) & MASK_41; + if (!slot) + inst.inst = (bundle.i64[0] >> 5) & MASK_41; else if (slot == 1) - inst.inst = ((bundle.i64[0]>>46) | bundle.i64[1]<<18) & MASK_41; - else if (slot == 2) inst.inst = (bundle.i64[1]>>23) & MASK_41; - else printf("priv_handle_op: illegal slot: %d\n", slot); + inst.inst = + ((bundle.i64[0] >> 46) | bundle.i64[1] << 18) & MASK_41; + else if (slot == 2) + inst.inst = (bundle.i64[1] >> 23) & MASK_41; + else + printf("priv_handle_op: illegal slot: %d\n", slot); slot_type = slot_types[bundle.template][slot]; if (priv_verbose) { - printf("priv_handle_op: checking bundle at 0x%lx (op=0x%016lx) slot %d (type=%d)\n", - iip, (UINT64)inst.inst, slot, slot_type); + printf("priv_handle_op: checking bundle at 0x%lx " + "(op=0x%016lx) slot %d (type=%d)\n", + iip, (u64) inst.inst, slot, slot_type); } if (slot_type == B && inst.generic.major == 0 && inst.B8.x6 == 0x0) { // break instr for privified cover - } - else if (privlvl != 2) return (IA64_ILLOP_FAULT); + } else if (privlvl != 2) + return IA64_ILLOP_FAULT; switch (slot_type) { - case M: + case M: if (inst.generic.major == 0) { #if 0 if (inst.M29.x6 == 0 && inst.M29.x3 == 0) { privcnt.cover++; - return priv_cover(vcpu,inst); + return priv_cover(vcpu, inst); } #endif - if (inst.M29.x3 != 0) break; + if (inst.M29.x3 != 0) + break; if (inst.M30.x4 == 8 && inst.M30.x2 == 2) { perfc_incrc(mov_to_ar_imm); - return priv_mov_to_ar_imm(vcpu,inst); + return priv_mov_to_ar_imm(vcpu, inst); } if (inst.M44.x4 == 6) { perfc_incrc(ssm); - return priv_ssm(vcpu,inst); + return priv_ssm(vcpu, inst); } if (inst.M44.x4 == 7) { perfc_incrc(rsm); - return priv_rsm(vcpu,inst); + return priv_rsm(vcpu, inst); } break; - } - else if (inst.generic.major != 1) break; + } else if (inst.generic.major != 1) + break; x6 = inst.M29.x6; if (x6 == 0x2a) { if (privify_en && inst.M29.r2 > 63 && inst.M29.ar3 < 8) perfc_incrc(mov_from_ar); // privified mov from kr else perfc_incrc(mov_to_ar_reg); - return priv_mov_to_ar_reg(vcpu,inst); + return priv_mov_to_ar_reg(vcpu, inst); } - if (inst.M29.x3 != 0) break; - if (!(pfunc = Mpriv_funcs[x6])) break; - if (x6 == 0x1e || x6 == 0x1f) { // tpa or tak are "special" + if (inst.M29.x3 != 0) + break; + if (!(pfunc = Mpriv_funcs[x6])) + break; + if (x6 == 0x1e || x6 == 0x1f) { // tpa or tak are "special" if (privify_en && inst.M46.r3 > 63) { - if (x6 == 0x1e) x6 = 0x1b; - else x6 = 0x1a; + if (x6 == 0x1e) + x6 = 0x1b; + else + x6 = 0x1a; } } if (privify_en && x6 == 52 && inst.M28.r3 > 63) @@ -599,61 +681,66 @@ priv_handle_op(VCPU *vcpu, REGS *regs, int privlvl) perfc_incrc(cpuid); else perfc_incra(misc_privop, x6); - return (*pfunc)(vcpu,inst); + return (*pfunc) (vcpu, inst); break; - case B: - if (inst.generic.major != 0) break; + case B: + if (inst.generic.major != 0) + break; if (inst.B8.x6 == 0x08) { IA64FAULT fault; perfc_incrc(rfi); - fault = priv_rfi(vcpu,inst); - if (fault == IA64_NO_FAULT) fault = IA64_RFI_IN_PROGRESS; + fault = priv_rfi(vcpu, inst); + if (fault == IA64_NO_FAULT) + fault = IA64_RFI_IN_PROGRESS; return fault; } if (inst.B8.x6 == 0x0c) { perfc_incrc(bsw0); - return priv_bsw0(vcpu,inst); + return priv_bsw0(vcpu, inst); } if (inst.B8.x6 == 0x0d) { perfc_incrc(bsw1); - return priv_bsw1(vcpu,inst); + return priv_bsw1(vcpu, inst); } if (inst.B8.x6 == 0x0) { // break instr for privified cover perfc_incrc(cover); - return priv_cover(vcpu,inst); + return priv_cover(vcpu, inst); } break; - case I: - if (inst.generic.major != 0) break; + case I: + if (inst.generic.major != 0) + break; #if 0 if (inst.I26.x6 == 0 && inst.I26.x3 == 0) { perfc_incrc(cover); - return priv_cover(vcpu,inst); + return priv_cover(vcpu, inst); } #endif - if (inst.I26.x3 != 0) break; // I26.x3 == I27.x3 + if (inst.I26.x3 != 0) + break; // I26.x3 == I27.x3 if (inst.I26.x6 == 0x2a) { if (privify_en && inst.I26.r2 > 63 && inst.I26.ar3 < 8) - perfc_incrc(mov_from_ar); // privified mov from kr - else + perfc_incrc(mov_from_ar); // privified mov from kr + else perfc_incrc(mov_to_ar_reg); - return priv_mov_to_ar_reg(vcpu,inst); + return priv_mov_to_ar_reg(vcpu, inst); } if (inst.I27.x6 == 0x0a) { perfc_incrc(mov_to_ar_imm); - return priv_mov_to_ar_imm(vcpu,inst); + return priv_mov_to_ar_imm(vcpu, inst); } break; - default: + default: break; } - //printf("We who are about do die salute you\n"); - printf("priv_handle_op: can't handle privop at 0x%lx (op=0x%016lx) slot %d (type=%d), ipsr=0x%lx\n", - iip, (UINT64)inst.inst, slot, slot_type, ipsr); - //printf("vtop(0x%lx)==0x%lx\n", iip, tr_vtop(iip)); - //thread_mozambique("privop fault\n"); - return (IA64_ILLOP_FAULT); + //printf("We who are about do die salute you\n"); + printf("priv_handle_op: can't handle privop at 0x%lx (op=0x%016lx) " + "slot %d (type=%d), ipsr=0x%lx\n", + iip, (u64) inst.inst, slot, slot_type, ipsr); + //printf("vtop(0x%lx)==0x%lx\n", iip, tr_vtop(iip)); + //thread_mozambique("privop fault\n"); + return IA64_ILLOP_FAULT; } /** Emulate a privileged operation. @@ -666,142 +753,139 @@ priv_handle_op(VCPU *vcpu, REGS *regs, int privlvl) * @param isrcode interrupt service routine code * @return fault */ -IA64FAULT -priv_emulate(VCPU *vcpu, REGS *regs, UINT64 isr) +IA64FAULT priv_emulate(VCPU * vcpu, REGS * regs, u64 isr) { IA64FAULT fault; - UINT64 ipsr = regs->cr_ipsr; - UINT64 isrcode = (isr >> 4) & 0xf; + u64 ipsr = regs->cr_ipsr; + u64 isrcode = (isr >> 4) & 0xf; int privlvl; // handle privops masked as illops? and breaks (6) if (isrcode != 1 && isrcode != 2 && isrcode != 0 && isrcode != 6) { - printf("priv_emulate: isrcode != 0 or 1 or 2\n"); + printf("priv_emulate: isrcode != 0 or 1 or 2\n"); printf("priv_emulate: returning ILLOP, not implemented!\n"); - while (1); + while (1) ; return IA64_ILLOP_FAULT; } //if (isrcode != 1 && isrcode != 2) return 0; privlvl = ia64_get_cpl(ipsr); // its OK for a privified-cover to be executed in user-land - fault = priv_handle_op(vcpu,regs,privlvl); - if ((fault == IA64_NO_FAULT) || (fault == IA64_EXTINT_VECTOR)) { // success!! + fault = priv_handle_op(vcpu, regs, privlvl); + if ((fault == IA64_NO_FAULT) || (fault == IA64_EXTINT_VECTOR)) { + // success!! // update iip/ipsr to point to the next instruction (void)vcpu_increment_iip(vcpu); } if (fault == IA64_ILLOP_FAULT) printf("priv_emulate: priv_handle_op fails, " - "isr=0x%lx iip=%lx\n",isr, regs->cr_iip); + "isr=0x%lx iip=%lx\n", isr, regs->cr_iip); return fault; } /* hyperprivops are generally executed in assembly (with physical psr.ic off) * so this code is primarily used for debugging them */ -int -ia64_hyperprivop(unsigned long iim, REGS *regs) +int ia64_hyperprivop(unsigned long iim, REGS * regs) { struct vcpu *v = current; - UINT64 val; - UINT64 itir, ifa; + u64 val; + u64 itir, ifa; if (!iim || iim > HYPERPRIVOP_MAX) { panic_domain(regs, "bad hyperprivop: iim=%lx, iip=0x%lx\n", - iim, regs->cr_iip); + iim, regs->cr_iip); return 1; } perfc_incra(slow_hyperprivop, iim); - switch(iim) { - case HYPERPRIVOP_RFI: - (void)vcpu_rfi(v); + switch (iim) { + case HYPERPRIVOP_RFI: + vcpu_rfi(v); return 0; // don't update iip - case HYPERPRIVOP_RSM_DT: - (void)vcpu_reset_psr_dt(v); + case HYPERPRIVOP_RSM_DT: + vcpu_reset_psr_dt(v); return 1; - case HYPERPRIVOP_SSM_DT: - (void)vcpu_set_psr_dt(v); + case HYPERPRIVOP_SSM_DT: + vcpu_set_psr_dt(v); return 1; - case HYPERPRIVOP_COVER: - (void)vcpu_cover(v); + case HYPERPRIVOP_COVER: + vcpu_cover(v); return 1; - case HYPERPRIVOP_ITC_D: - (void)vcpu_get_itir(v,&itir); - (void)vcpu_get_ifa(v,&ifa); - (void)vcpu_itc_d(v,regs->r8,itir,ifa); + case HYPERPRIVOP_ITC_D: + vcpu_get_itir(v, &itir); + vcpu_get_ifa(v, &ifa); + vcpu_itc_d(v, regs->r8, itir, ifa); return 1; - case HYPERPRIVOP_ITC_I: - (void)vcpu_get_itir(v,&itir); - (void)vcpu_get_ifa(v,&ifa); - (void)vcpu_itc_i(v,regs->r8,itir,ifa); + case HYPERPRIVOP_ITC_I: + vcpu_get_itir(v, &itir); + vcpu_get_ifa(v, &ifa); + vcpu_itc_i(v, regs->r8, itir, ifa); return 1; - case HYPERPRIVOP_SSM_I: - (void)vcpu_set_psr_i(v); + case HYPERPRIVOP_SSM_I: + vcpu_set_psr_i(v); return 1; - case HYPERPRIVOP_GET_IVR: - (void)vcpu_get_ivr(v,&val); + case HYPERPRIVOP_GET_IVR: + vcpu_get_ivr(v, &val); regs->r8 = val; return 1; - case HYPERPRIVOP_GET_TPR: - (void)vcpu_get_tpr(v,&val); + case HYPERPRIVOP_GET_TPR: + vcpu_get_tpr(v, &val); regs->r8 = val; return 1; - case HYPERPRIVOP_SET_TPR: - (void)vcpu_set_tpr(v,regs->r8); + case HYPERPRIVOP_SET_TPR: + vcpu_set_tpr(v, regs->r8); return 1; - case HYPERPRIVOP_EOI: - (void)vcpu_set_eoi(v,0L); + case HYPERPRIVOP_EOI: + vcpu_set_eoi(v, 0L); return 1; - case HYPERPRIVOP_SET_ITM: - (void)vcpu_set_itm(v,regs->r8); + case HYPERPRIVOP_SET_ITM: + vcpu_set_itm(v, regs->r8); return 1; - case HYPERPRIVOP_THASH: - (void)vcpu_thash(v,regs->r8,&val); + case HYPERPRIVOP_THASH: + vcpu_thash(v, regs->r8, &val); regs->r8 = val; return 1; - case HYPERPRIVOP_PTC_GA: - (void)vcpu_ptc_ga(v,regs->r8,(1L << ((regs->r9 & 0xfc) >> 2))); + case HYPERPRIVOP_PTC_GA: + vcpu_ptc_ga(v, regs->r8, (1L << ((regs->r9 & 0xfc) >> 2))); return 1; - case HYPERPRIVOP_ITR_D: - (void)vcpu_get_itir(v,&itir); - (void)vcpu_get_ifa(v,&ifa); - (void)vcpu_itr_d(v,regs->r8,regs->r9,itir,ifa); + case HYPERPRIVOP_ITR_D: + vcpu_get_itir(v, &itir); + vcpu_get_ifa(v, &ifa); + vcpu_itr_d(v, regs->r8, regs->r9, itir, ifa); return 1; - case HYPERPRIVOP_GET_RR: - (void)vcpu_get_rr(v,regs->r8,&val); + case HYPERPRIVOP_GET_RR: + vcpu_get_rr(v, regs->r8, &val); regs->r8 = val; return 1; - case HYPERPRIVOP_SET_RR: - (void)vcpu_set_rr(v,regs->r8,regs->r9); + case HYPERPRIVOP_SET_RR: + vcpu_set_rr(v, regs->r8, regs->r9); return 1; - case HYPERPRIVOP_SET_KR: - (void)vcpu_set_ar(v,regs->r8,regs->r9); + case HYPERPRIVOP_SET_KR: + vcpu_set_ar(v, regs->r8, regs->r9); return 1; - case HYPERPRIVOP_FC: - (void)vcpu_fc(v,regs->r8); + case HYPERPRIVOP_FC: + vcpu_fc(v, regs->r8); return 1; - case HYPERPRIVOP_GET_CPUID: - (void)vcpu_get_cpuid(v,regs->r8,&val); + case HYPERPRIVOP_GET_CPUID: + vcpu_get_cpuid(v, regs->r8, &val); regs->r8 = val; return 1; - case HYPERPRIVOP_GET_PMD: - (void)vcpu_get_pmd(v,regs->r8,&val); + case HYPERPRIVOP_GET_PMD: + vcpu_get_pmd(v, regs->r8, &val); regs->r8 = val; return 1; - case HYPERPRIVOP_GET_EFLAG: - (void)vcpu_get_ar(v,24,&val); + case HYPERPRIVOP_GET_EFLAG: + vcpu_get_ar(v, 24, &val); regs->r8 = val; return 1; - case HYPERPRIVOP_SET_EFLAG: - (void)vcpu_set_ar(v,24,regs->r8); + case HYPERPRIVOP_SET_EFLAG: + vcpu_set_ar(v, 24, regs->r8); return 1; - case HYPERPRIVOP_RSM_BE: - (void)vcpu_reset_psr_sm(v, IA64_PSR_BE); + case HYPERPRIVOP_RSM_BE: + vcpu_reset_psr_sm(v, IA64_PSR_BE); return 1; - case HYPERPRIVOP_GET_PSR: - (void)vcpu_get_psr(v, &val); + case HYPERPRIVOP_GET_PSR: + vcpu_get_psr(v, &val); regs->r8 = val; return 1; } return 0; } - - diff --git a/xen/arch/ia64/xen/regionreg.c b/xen/arch/ia64/xen/regionreg.c index 58c89201fb..2491c3ae62 100644 --- a/xen/arch/ia64/xen/regionreg.c +++ b/xen/arch/ia64/xen/regionreg.c @@ -17,7 +17,7 @@ #include <asm/vcpu.h> /* Defined in xemasm.S */ -extern void ia64_new_rr7(unsigned long rid, void *shared_info, void *shared_arch_info, unsigned long shared_info_va, unsigned long p_vhpt); +extern void ia64_new_rr7(unsigned long rid, void *shared_info, void *shared_arch_info, unsigned long shared_info_va, unsigned long va_vhpt); /* RID virtualization mechanism is really simple: domains have less rid bits than the host and the host rid space is shared among the domains. (Values @@ -260,7 +260,7 @@ int set_one_rr(unsigned long rr, unsigned long val) } else if (rreg == 7) { ia64_new_rr7(vmMangleRID(newrrv.rrval),v->domain->shared_info, v->arch.privregs, v->domain->arch.shared_info_va, - __get_cpu_var(vhpt_paddr)); + __va_ul(vcpu_vhpt_maddr(v))); } else { set_rr(rr,newrrv.rrval); } diff --git a/xen/arch/ia64/xen/tlb_track.c b/xen/arch/ia64/xen/tlb_track.c new file mode 100644 index 0000000000..49a8a79768 --- /dev/null +++ b/xen/arch/ia64/xen/tlb_track.c @@ -0,0 +1,506 @@ +/****************************************************************************** + * tlb_track.c + * + * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <asm/tlb_track.h> +#include <asm/p2m_entry.h> +#include <asm/vmx_mm_def.h> /* for IA64_RR_SHIFT */ +#include <asm/vmx_vcpu.h> /* for VRN7 */ +#include <asm/vcpu.h> /* for PSCB() */ + +#define CONFIG_TLB_TRACK_DEBUG +#ifdef CONFIG_TLB_TRACK_DEBUG +# define tlb_track_printd(fmt, ...) \ + printf("%s:%d " fmt, __func__, __LINE__, ##__VA_ARGS__) +#else +# define tlb_track_printd(fmt, ...) do { } while (0) +#endif + +static int +tlb_track_allocate_entries(struct tlb_track* tlb_track) +{ + struct page_info* entry_page; + struct tlb_track_entry* track_entries; + unsigned int allocated; + unsigned long i; + + BUG_ON(tlb_track->num_free > 0); + if (tlb_track->num_entries >= tlb_track->limit) { + DPRINTK("%s: num_entries %d limit %d\n", + __func__, tlb_track->num_entries, tlb_track->limit); + return -ENOMEM; + } + entry_page = alloc_domheap_page(NULL); + if (entry_page == NULL) { + DPRINTK("%s: domheap page failed. num_entries %d limit %d\n", + __func__, tlb_track->num_entries, tlb_track->limit); + return -ENOMEM; + } + + list_add(&entry_page->list, &tlb_track->page_list); + track_entries = (struct tlb_track_entry*)page_to_virt(entry_page); + allocated = PAGE_SIZE / sizeof(track_entries[0]); + tlb_track->num_entries += allocated; + tlb_track->num_free += allocated; + for (i = 0; i < allocated; i++) { + list_add(&track_entries[i].list, &tlb_track->free_list); + // tlb_track_printd("track_entries[%ld] 0x%p\n", i, &track_entries[i]); + } + tlb_track_printd("allocated %d num_entries %d num_free %d\n", + allocated, tlb_track->num_entries, tlb_track->num_free); + return 0; +} + + +int +tlb_track_create(struct domain* d) +{ + struct tlb_track* tlb_track = NULL; + struct page_info* hash_page = NULL; + unsigned int hash_size; + unsigned int hash_shift; + unsigned int i; + + tlb_track = xmalloc(struct tlb_track); + if (tlb_track == NULL) + goto out; + + hash_page = alloc_domheap_page(NULL); + if (hash_page == NULL) + goto out; + + spin_lock_init(&tlb_track->free_list_lock); + INIT_LIST_HEAD(&tlb_track->free_list); + tlb_track->limit = TLB_TRACK_LIMIT_ENTRIES; + tlb_track->num_entries = 0; + tlb_track->num_free = 0; + INIT_LIST_HEAD(&tlb_track->page_list); + if (tlb_track_allocate_entries(tlb_track) < 0) + goto out; + + spin_lock_init(&tlb_track->hash_lock); + /* XXX hash size optimization */ + hash_size = PAGE_SIZE / sizeof(tlb_track->hash[0]); + for (hash_shift = 0; (1 << (hash_shift + 1)) < hash_size; hash_shift++) + /* nothing */; + tlb_track->hash_size = (1 << hash_shift); + tlb_track->hash_shift = hash_shift; + tlb_track->hash_mask = (1 << hash_shift) - 1; + tlb_track->hash = page_to_virt(hash_page); + for (i = 0; i < tlb_track->hash_size; i++) + INIT_LIST_HEAD(&tlb_track->hash[i]); + + smp_mb(); /* make initialization visible before use. */ + d->arch.tlb_track = tlb_track; + printk("%s:%d hash 0x%p hash_size %d \n", + __func__, __LINE__, tlb_track->hash, tlb_track->hash_size); + + return 0; + +out: + if (hash_page != NULL) + free_domheap_page(hash_page); + + if (tlb_track != NULL) + xfree(tlb_track); + + return -ENOMEM; +} + +void +tlb_track_destroy(struct domain* d) +{ + struct tlb_track* tlb_track = d->arch.tlb_track; + struct page_info* page; + struct page_info* next; + + spin_lock(&tlb_track->free_list_lock); + BUG_ON(tlb_track->num_free != tlb_track->num_entries); + + list_for_each_entry_safe(page, next, &tlb_track->page_list, list) { + list_del(&page->list); + free_domheap_page(page); + } + + free_domheap_page(virt_to_page(tlb_track->hash)); + xfree(tlb_track); + // d->tlb_track = NULL; +} + +static struct tlb_track_entry* +tlb_track_get_entry(struct tlb_track* tlb_track) +{ + struct tlb_track_entry* entry = NULL; + spin_lock(&tlb_track->free_list_lock); + if (tlb_track->num_free == 0) + (void)tlb_track_allocate_entries(tlb_track); + + if (tlb_track->num_free > 0) { + BUG_ON(list_empty(&tlb_track->free_list)); + entry = list_entry(tlb_track->free_list.next, + struct tlb_track_entry, list); + tlb_track->num_free--; + list_del(&entry->list); + } + spin_unlock(&tlb_track->free_list_lock); + return entry; +} + +void +tlb_track_free_entry(struct tlb_track* tlb_track, + struct tlb_track_entry* entry) +{ + spin_lock(&tlb_track->free_list_lock); + list_add(&entry->list, &tlb_track->free_list); + tlb_track->num_free++; + spin_unlock(&tlb_track->free_list_lock); +} + + +#include <linux/hash.h> +/* XXX hash function. */ +static struct list_head* +tlb_track_hash_head(struct tlb_track* tlb_track, volatile pte_t* ptep) +{ + unsigned long hash = hash_long((unsigned long)ptep, tlb_track->hash_shift); + BUG_ON(hash >= tlb_track->hash_size); + BUG_ON((hash & tlb_track->hash_mask) != hash); + return &tlb_track->hash[hash]; +} + +static int +tlb_track_pte_zapped(pte_t old_pte, pte_t ret_pte) +{ + if (pte_pfn(old_pte) != pte_pfn(ret_pte) || + (pte_val(old_pte) & ~(_PFN_MASK | _PAGE_TLB_TRACK_MASK)) != + (pte_val(ret_pte) & ~(_PFN_MASK | _PAGE_TLB_TRACK_MASK))) { + /* Other thread zapped the p2m entry. */ + return 1; + } + return 0; +} + +static TLB_TRACK_RET_T +tlb_track_insert_or_dirty(struct tlb_track* tlb_track, struct mm_struct* mm, + volatile pte_t* ptep, pte_t old_pte, + unsigned long vaddr, unsigned long rid) +{ + unsigned long mfn = pte_pfn(old_pte); + struct list_head* head = tlb_track_hash_head(tlb_track, ptep); + struct tlb_track_entry* entry; + struct tlb_track_entry* new_entry = NULL; + unsigned long bit_to_be_set = _PAGE_TLB_INSERTED; + pte_t new_pte; + pte_t ret_pte; + + struct vcpu* v = current; + TLB_TRACK_RET_T ret = TLB_TRACK_NOT_FOUND; + +#if 0 /* this is done at vcpu_tlb_track_insert_or_dirty() */ + perfc_incrc(tlb_track_iod); + if (!pte_tlb_tracking(old_pte)) { + perfc_incrc(tlb_track_iod_not_tracked); + return TLB_TRACK_NOT_TRACKED; + } +#endif + if (pte_tlb_inserted_many(old_pte)) { + perfc_incrc(tlb_track_iod_tracked_many); + return TLB_TRACK_MANY; + } + + /* vaddr must be normalized so that it is in vrn7 and page aligned. */ + BUG_ON((vaddr >> IA64_RR_SHIFT) != VRN7); + BUG_ON((vaddr & ~PAGE_MASK) != 0); +#if 0 + tlb_track_printd("\n" + "\tmfn 0x%016lx\n" + "\told_pte 0x%016lx ptep 0x%p\n" + "\tptep_val 0x%016lx vaddr 0x%016lx rid %ld\n" + "\ttlb_track 0x%p head 0x%p\n", + mfn, + pte_val(old_pte), ptep, pte_val(*ptep), + vaddr, rid, + tlb_track, head); +#endif + + again: + /* + * zapping side may zap the p2m entry and then remove tlb track entry + * non-atomically. We may see the stale tlb track entry here. + * p2m_entry_retry() handles such a case. + * Or other thread may zap the p2m entry and remove tlb track entry + * and inserted new tlb track entry. + */ + spin_lock(&tlb_track->hash_lock); + list_for_each_entry(entry, head, list) { + if (entry->ptep != ptep) + continue; + + if (pte_pfn(entry->pte_val) == mfn) { + // tlb_track_entry_printf(entry); + if (entry->vaddr == vaddr && entry->rid == rid) { + // tlb_track_printd("TLB_TRACK_FOUND\n"); + ret = TLB_TRACK_FOUND; + perfc_incrc(tlb_track_iod_found); +#ifdef CONFIG_TLB_TRACK_CNT + entry->cnt++; + if (entry->cnt > TLB_TRACK_CNT_FORCE_MANY) { + /* + * heuristics: + * If a page is used to transfer data by dev channel, + * it would be unmapped with small amount access + * (once or twice tlb insert) after real device + * I/O completion. It would be short period. + * However this page seems to be accessed many times. + * We guess that this page is used I/O ring + * so that tracking this entry might be useless. + */ + // tlb_track_entry_printf(entry); + // tlb_track_printd("cnt = %ld\n", entry->cnt); + perfc_incrc(tlb_track_iod_force_many); + goto force_many; + } +#endif + goto found; + } else { +#ifdef CONFIG_TLB_TRACK_CNT + force_many: +#endif + if (!pte_tlb_inserted(old_pte)) { + printk("%s:%d racy update\n", __func__, __LINE__); + old_pte = __pte(pte_val(old_pte) | _PAGE_TLB_INSERTED); + } + new_pte = __pte(pte_val(old_pte) | _PAGE_TLB_INSERTED_MANY); + ret_pte = ptep_cmpxchg_rel(mm, vaddr, ptep, old_pte, new_pte); + if (pte_val(ret_pte) != pte_val(old_pte)) { + // tlb_track_printd("TLB_TRACK_AGAIN\n"); + ret = TLB_TRACK_AGAIN; + perfc_incrc(tlb_track_iod_again); + } else { + // tlb_track_printd("TLB_TRACK_MANY del entry 0x%p\n", + // entry); + ret = TLB_TRACK_MANY; + list_del(&entry->list); + // tlb_track_entry_printf(entry); + perfc_incrc(tlb_track_iod_tracked_many_del); + } + goto out; + } + } + + /* + * Other thread changed the p2m entry and removed and inserted new + * tlb tracn entry after we get old_pte, but before we get + * spinlock. + */ + // tlb_track_printd("TLB_TRACK_AGAIN\n"); + ret = TLB_TRACK_AGAIN; + perfc_incrc(tlb_track_iod_again); + goto out; + } + + entry = NULL; // prevent freeing entry. + if (pte_tlb_inserted(old_pte)) { + /* Other thread else removed the tlb_track_entry after we got old_pte + before we got spin lock. */ + ret = TLB_TRACK_AGAIN; + perfc_incrc(tlb_track_iod_again); + goto out; + } + if (new_entry == NULL && bit_to_be_set == _PAGE_TLB_INSERTED) { + spin_unlock(&tlb_track->hash_lock); + new_entry = tlb_track_get_entry(tlb_track); + if (new_entry == NULL) { + tlb_track_printd("get_entry failed\n"); + /* entry can't be allocated. + fall down into full flush mode. */ + bit_to_be_set |= _PAGE_TLB_INSERTED_MANY; + perfc_incrc(tlb_track_iod_new_failed); + } + // tlb_track_printd("new_entry 0x%p\n", new_entry); + perfc_incrc(tlb_track_iod_new_entry); + goto again; + } + + BUG_ON(pte_tlb_inserted_many(old_pte)); + new_pte = __pte(pte_val(old_pte) | bit_to_be_set); + ret_pte = ptep_cmpxchg_rel(mm, vaddr, ptep, old_pte, new_pte); + if (pte_val(old_pte) != pte_val(ret_pte)) { + if (tlb_track_pte_zapped(old_pte, ret_pte)) { + // tlb_track_printd("zapped TLB_TRACK_AGAIN\n"); + ret = TLB_TRACK_AGAIN; + perfc_incrc(tlb_track_iod_again); + goto out; + } + + /* Other thread set _PAGE_TLB_INSERTED and/or _PAGE_TLB_INSERTED_MANY */ + if (pte_tlb_inserted_many(ret_pte)) { + /* Other thread already set _PAGE_TLB_INSERTED_MANY and + removed the entry. */ + // tlb_track_printd("iserted TLB_TRACK_MANY\n"); + BUG_ON(!pte_tlb_inserted(ret_pte)); + ret = TLB_TRACK_MANY; + perfc_incrc(tlb_track_iod_new_many); + goto out; + } + BUG_ON(pte_tlb_inserted(ret_pte)); + BUG(); + } + if (new_entry) { + // tlb_track_printd("iserting new_entry 0x%p\n", new_entry); + entry = new_entry; + new_entry = NULL; + + entry->ptep = ptep; + entry->pte_val = old_pte; + entry->vaddr = vaddr; + entry->rid = rid; + cpus_clear(entry->pcpu_dirty_mask); + vcpus_clear(entry->vcpu_dirty_mask); + list_add(&entry->list, head); + +#ifdef CONFIG_TLB_TRACK_CNT + entry->cnt = 0; +#endif + perfc_incrc(tlb_track_iod_insert); + // tlb_track_entry_printf(entry); + } else { + goto out; + } + + found: + BUG_ON(v->processor >= NR_CPUS); + cpu_set(v->processor, entry->pcpu_dirty_mask); + BUG_ON(v->vcpu_id >= NR_CPUS); + vcpu_set(v->vcpu_id, entry->vcpu_dirty_mask); + perfc_incrc(tlb_track_iod_dirtied); + + out: + spin_unlock(&tlb_track->hash_lock); + if (ret == TLB_TRACK_MANY && entry != NULL) + tlb_track_free_entry(tlb_track, entry); + if (new_entry != NULL) + tlb_track_free_entry(tlb_track, new_entry); + return ret; +} + +void +__vcpu_tlb_track_insert_or_dirty(struct vcpu *vcpu, unsigned long vaddr, + struct p2m_entry* entry) +{ + unsigned long vrn = vaddr >> IA64_RR_SHIFT; + unsigned long rid = PSCB(vcpu, rrs[vrn]); + TLB_TRACK_RET_T ret; + + /* normalize vrn7 + When linux dom0 case, vrn7 is the most common case. */ + vaddr |= VRN7 << VRN_SHIFT; + vaddr &= PAGE_MASK; + ret = tlb_track_insert_or_dirty(vcpu->domain->arch.tlb_track, + &vcpu->domain->arch.mm, + entry->ptep, entry->used, + vaddr, rid); + if (ret == TLB_TRACK_AGAIN) + p2m_entry_set_retry(entry); +} + +TLB_TRACK_RET_T +tlb_track_search_and_remove(struct tlb_track* tlb_track, + volatile pte_t* ptep, pte_t old_pte, + struct tlb_track_entry** entryp) +{ + unsigned long mfn = pte_pfn(old_pte); + struct list_head* head = tlb_track_hash_head(tlb_track, ptep); + struct tlb_track_entry* entry; + + perfc_incrc(tlb_track_sar); + if (!pte_tlb_tracking(old_pte)) { + perfc_incrc(tlb_track_sar_not_tracked); + return TLB_TRACK_NOT_TRACKED; + } + if (!pte_tlb_inserted(old_pte)) { + BUG_ON(pte_tlb_inserted_many(old_pte)); + perfc_incrc(tlb_track_sar_not_found); + return TLB_TRACK_NOT_FOUND; + } + if (pte_tlb_inserted_many(old_pte)) { + BUG_ON(!pte_tlb_inserted(old_pte)); + perfc_incrc(tlb_track_sar_many); + return TLB_TRACK_MANY; + } + + spin_lock(&tlb_track->hash_lock); + list_for_each_entry(entry, head, list) { + if (entry->ptep != ptep) + continue; + + if (pte_pfn(entry->pte_val) == mfn) { + list_del(&entry->list); + spin_unlock(&tlb_track->hash_lock); + *entryp = entry; + perfc_incrc(tlb_track_sar_found); + // tlb_track_entry_printf(entry); +#ifdef CONFIG_TLB_TRACK_CNT + // tlb_track_printd("cnt = %ld\n", entry->cnt); +#endif + return TLB_TRACK_FOUND; + } + BUG(); + } + BUG(); + spin_unlock(&tlb_track->hash_lock); + return TLB_TRACK_NOT_TRACKED; +} + +/* for debug */ +void +__tlb_track_entry_printf(const char* func, int line, + const struct tlb_track_entry* entry) +{ + char pcpumask_buf[NR_CPUS + 1]; + char vcpumask_buf[MAX_VIRT_CPUS + 1]; + cpumask_scnprintf(pcpumask_buf, sizeof(pcpumask_buf), + entry->pcpu_dirty_mask); + vcpumask_scnprintf(vcpumask_buf, sizeof(vcpumask_buf), + entry->vcpu_dirty_mask); + printk("%s:%d\n" + "\tmfn 0x%016lx\n" + "\told_pte 0x%016lx ptep 0x%p\n" + "\tpte_val 0x%016lx vaddr 0x%016lx rid %ld\n" + "\tpcpu_dirty_mask %s vcpu_dirty_mask %s\n" + "\tentry 0x%p\n", + func, line, + pte_pfn(entry->pte_val), + pte_val(entry->pte_val), entry->ptep, pte_val(*entry->ptep), + entry->vaddr, entry->rid, + pcpumask_buf, vcpumask_buf, + entry); +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/ia64/xen/vcpu.c b/xen/arch/ia64/xen/vcpu.c index cab06b2576..7ead59ca7f 100644 --- a/xen/arch/ia64/xen/vcpu.c +++ b/xen/arch/ia64/xen/vcpu.c @@ -24,29 +24,35 @@ #include <asm/bundle.h> #include <asm/privop_stat.h> #include <asm/uaccess.h> +#include <asm/p2m_entry.h> +#include <asm/tlb_track.h> /* FIXME: where these declarations should be there ? */ -extern void getreg(unsigned long regnum, unsigned long *val, int *nat, struct pt_regs *regs); -extern void setreg(unsigned long regnum, unsigned long val, int nat, struct pt_regs *regs); -extern void getfpreg (unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs); +extern void getreg(unsigned long regnum, unsigned long *val, int *nat, + struct pt_regs *regs); +extern void setreg(unsigned long regnum, unsigned long val, int nat, + struct pt_regs *regs); +extern void getfpreg(unsigned long regnum, struct ia64_fpreg *fpval, + struct pt_regs *regs); -extern void setfpreg (unsigned long regnum, struct ia64_fpreg *fpval, struct pt_regs *regs); +extern void setfpreg(unsigned long regnum, struct ia64_fpreg *fpval, + struct pt_regs *regs); -typedef union { +typedef union { struct ia64_psr ia64_psr; unsigned long i64; } PSR; // this def for vcpu_regs won't work if kernel stack is present -//#define vcpu_regs(vcpu) ((struct pt_regs *) vcpu->arch.regs +//#define vcpu_regs(vcpu) ((struct pt_regs *) vcpu->arch.regs -#define TRUE 1 -#define FALSE 0 +#define TRUE 1 +#define FALSE 0 #define IA64_PTA_SZ_BIT 2 #define IA64_PTA_VF_BIT 8 #define IA64_PTA_BASE_BIT 15 #define IA64_PTA_LFMT (1UL << IA64_PTA_VF_BIT) -#define IA64_PTA_SZ(x) (x##UL << IA64_PTA_SZ_BIT) +#define IA64_PTA_SZ(x) (x##UL << IA64_PTA_SZ_BIT) unsigned long vcpu_verbose = 0; @@ -54,23 +60,23 @@ unsigned long vcpu_verbose = 0; VCPU general register access routines **************************************************************************/ #ifdef XEN -UINT64 -vcpu_get_gr(VCPU *vcpu, unsigned long reg) +u64 vcpu_get_gr(VCPU * vcpu, unsigned long reg) { REGS *regs = vcpu_regs(vcpu); - UINT64 val; + u64 val; - if (!reg) return 0; - getreg(reg,&val,0,regs); // FIXME: handle NATs later + if (!reg) + return 0; + getreg(reg, &val, 0, regs); // FIXME: handle NATs later return val; } -IA64FAULT -vcpu_get_gr_nat(VCPU *vcpu, unsigned long reg, UINT64 *val) + +IA64FAULT vcpu_get_gr_nat(VCPU * vcpu, unsigned long reg, u64 * val) { REGS *regs = vcpu_regs(vcpu); int nat; - getreg(reg,val,&nat,regs); // FIXME: handle NATs later + getreg(reg, val, &nat, regs); // FIXME: handle NATs later if (nat) return IA64_NAT_CONSUMPTION_VECTOR; return 0; @@ -79,32 +85,33 @@ vcpu_get_gr_nat(VCPU *vcpu, unsigned long reg, UINT64 *val) // returns: // IA64_ILLOP_FAULT if the register would cause an Illegal Operation fault // IA64_NO_FAULT otherwise -IA64FAULT -vcpu_set_gr(VCPU *vcpu, unsigned long reg, UINT64 value, int nat) +IA64FAULT vcpu_set_gr(VCPU * vcpu, unsigned long reg, u64 value, int nat) { REGS *regs = vcpu_regs(vcpu); long sof = (regs->cr_ifs) & 0x7f; - if (!reg) return IA64_ILLOP_FAULT; - if (reg >= sof + 32) return IA64_ILLOP_FAULT; - setreg(reg,value,nat,regs); // FIXME: handle NATs later + if (!reg) + return IA64_ILLOP_FAULT; + if (reg >= sof + 32) + return IA64_ILLOP_FAULT; + setreg(reg, value, nat, regs); // FIXME: handle NATs later return IA64_NO_FAULT; } IA64FAULT -vcpu_get_fpreg(VCPU *vcpu, unsigned long reg, struct ia64_fpreg *val) +vcpu_get_fpreg(VCPU * vcpu, unsigned long reg, struct ia64_fpreg * val) { REGS *regs = vcpu_regs(vcpu); - getfpreg(reg,val,regs); // FIXME: handle NATs later + getfpreg(reg, val, regs); // FIXME: handle NATs later return IA64_NO_FAULT; } IA64FAULT -vcpu_set_fpreg(VCPU *vcpu, unsigned long reg, struct ia64_fpreg *val) +vcpu_set_fpreg(VCPU * vcpu, unsigned long reg, struct ia64_fpreg * val) { REGS *regs = vcpu_regs(vcpu); - if(reg > 1) - setfpreg(reg,val,regs); // FIXME: handle NATs later + if (reg > 1) + setfpreg(reg, val, regs); // FIXME: handle NATs later return IA64_NO_FAULT; } @@ -112,38 +119,39 @@ vcpu_set_fpreg(VCPU *vcpu, unsigned long reg, struct ia64_fpreg *val) // returns: // IA64_ILLOP_FAULT if the register would cause an Illegal Operation fault // IA64_NO_FAULT otherwise -IA64FAULT -vcpu_set_gr(VCPU *vcpu, unsigned long reg, UINT64 value) +IA64FAULT vcpu_set_gr(VCPU * vcpu, unsigned long reg, u64 value) { REGS *regs = vcpu_regs(vcpu); long sof = (regs->cr_ifs) & 0x7f; - if (!reg) return IA64_ILLOP_FAULT; - if (reg >= sof + 32) return IA64_ILLOP_FAULT; - setreg(reg,value,0,regs); // FIXME: handle NATs later + if (!reg) + return IA64_ILLOP_FAULT; + if (reg >= sof + 32) + return IA64_ILLOP_FAULT; + setreg(reg, value, 0, regs); // FIXME: handle NATs later return IA64_NO_FAULT; } #endif -void vcpu_init_regs (struct vcpu *v) +void vcpu_init_regs(struct vcpu *v) { struct pt_regs *regs; - regs = vcpu_regs (v); + regs = vcpu_regs(v); if (VMX_DOMAIN(v)) { /* dt/rt/it:1;i/ic:1, si:1, vm/bn:1, ac:1 */ /* Need to be expanded as macro */ regs->cr_ipsr = 0x501008826008; } else { regs->cr_ipsr = ia64_getreg(_IA64_REG_PSR) - | IA64_PSR_BITS_TO_SET | IA64_PSR_BN; + | IA64_PSR_BITS_TO_SET | IA64_PSR_BN; regs->cr_ipsr &= ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_RI | IA64_PSR_IS); // domain runs at PL2 regs->cr_ipsr |= 2UL << IA64_PSR_CPL0_BIT; } - regs->cr_ifs = 1UL << 63; /* or clear? */ + regs->cr_ifs = 1UL << 63; /* or clear? */ regs->ar_fpsr = FPSR_DEFAULT; if (VMX_DOMAIN(v)) { @@ -153,13 +161,13 @@ void vcpu_init_regs (struct vcpu *v) VCPU(v, dcr) = 0; } else { init_all_rr(v); - regs->ar_rsc |= (2 << 2); /* force PL2/3 */ + regs->ar_rsc |= (2 << 2); /* force PL2/3 */ VCPU(v, banknum) = 1; VCPU(v, metaphysical_mode) = 1; VCPU(v, interrupt_mask_addr) = - (unsigned char *)v->domain->arch.shared_info_va + - INT_ENABLE_OFFSET(v); - VCPU(v, itv) = (1 << 16); /* timer vector masked */ + (unsigned char *)v->domain->arch.shared_info_va + + INT_ENABLE_OFFSET(v); + VCPU(v, itv) = (1 << 16); /* timer vector masked */ } v->arch.domain_itm_last = -1L; @@ -169,7 +177,7 @@ void vcpu_init_regs (struct vcpu *v) VCPU privileged application register access routines **************************************************************************/ -void vcpu_load_kernel_regs(VCPU *vcpu) +void vcpu_load_kernel_regs(VCPU * vcpu) { ia64_set_kr(0, VCPU(vcpu, krs[0])); ia64_set_kr(1, VCPU(vcpu, krs[1])); @@ -184,26 +192,33 @@ void vcpu_load_kernel_regs(VCPU *vcpu) /* GCC 4.0.2 seems not to be able to suppress this call!. */ #define ia64_setreg_unknown_kr() return IA64_ILLOP_FAULT -IA64FAULT vcpu_set_ar(VCPU *vcpu, UINT64 reg, UINT64 val) +IA64FAULT vcpu_set_ar(VCPU * vcpu, u64 reg, u64 val) { - if (reg == 44) return (vcpu_set_itc(vcpu,val)); - else if (reg == 27) return (IA64_ILLOP_FAULT); + if (reg == 44) + return vcpu_set_itc(vcpu, val); + else if (reg == 27) + return IA64_ILLOP_FAULT; else if (reg == 24) - printf("warning: setting ar.eflg is a no-op; no IA-32 support\n"); - else if (reg > 7) return (IA64_ILLOP_FAULT); + printf("warning: setting ar.eflg is a no-op; no IA-32 " + "support\n"); + else if (reg > 7) + return IA64_ILLOP_FAULT; else { - PSCB(vcpu,krs[reg]) = val; - ia64_set_kr(reg,val); + PSCB(vcpu, krs[reg]) = val; + ia64_set_kr(reg, val); } return IA64_NO_FAULT; } -IA64FAULT vcpu_get_ar(VCPU *vcpu, UINT64 reg, UINT64 *val) +IA64FAULT vcpu_get_ar(VCPU * vcpu, u64 reg, u64 * val) { if (reg == 24) - printf("warning: getting ar.eflg is a no-op; no IA-32 support\n"); - else if (reg > 7) return (IA64_ILLOP_FAULT); - else *val = PSCB(vcpu,krs[reg]); + printf("warning: getting ar.eflg is a no-op; no IA-32 " + "support\n"); + else if (reg > 7) + return IA64_ILLOP_FAULT; + else + *val = PSCB(vcpu, krs[reg]); return IA64_NO_FAULT; } @@ -211,24 +226,25 @@ IA64FAULT vcpu_get_ar(VCPU *vcpu, UINT64 reg, UINT64 *val) VCPU processor status register access routines **************************************************************************/ -void vcpu_set_metaphysical_mode(VCPU *vcpu, BOOLEAN newmode) +void vcpu_set_metaphysical_mode(VCPU * vcpu, BOOLEAN newmode) { /* only do something if mode changes */ - if (!!newmode ^ !!PSCB(vcpu,metaphysical_mode)) { - PSCB(vcpu,metaphysical_mode) = newmode; - if (newmode) set_metaphysical_rr0(); - else if (PSCB(vcpu,rrs[0]) != -1) - set_one_rr(0, PSCB(vcpu,rrs[0])); + if (!!newmode ^ !!PSCB(vcpu, metaphysical_mode)) { + PSCB(vcpu, metaphysical_mode) = newmode; + if (newmode) + set_metaphysical_rr0(); + else if (PSCB(vcpu, rrs[0]) != -1) + set_one_rr(0, PSCB(vcpu, rrs[0])); } } -IA64FAULT vcpu_reset_psr_dt(VCPU *vcpu) +IA64FAULT vcpu_reset_psr_dt(VCPU * vcpu) { - vcpu_set_metaphysical_mode(vcpu,TRUE); + vcpu_set_metaphysical_mode(vcpu, TRUE); return IA64_NO_FAULT; } -IA64FAULT vcpu_reset_psr_sm(VCPU *vcpu, UINT64 imm24) +IA64FAULT vcpu_reset_psr_sm(VCPU * vcpu, u64 imm24) { struct ia64_psr psr, imm, *ipsr; REGS *regs = vcpu_regs(vcpu); @@ -236,72 +252,89 @@ IA64FAULT vcpu_reset_psr_sm(VCPU *vcpu, UINT64 imm24) //PRIVOP_COUNT_ADDR(regs,_RSM); // TODO: All of these bits need to be virtualized // TODO: Only allowed for current vcpu - __asm__ __volatile ("mov %0=psr;;" : "=r"(psr) :: "memory"); + __asm__ __volatile("mov %0=psr;;":"=r"(psr)::"memory"); ipsr = (struct ia64_psr *)®s->cr_ipsr; imm = *(struct ia64_psr *)&imm24; // interrupt flag if (imm.i) - vcpu->vcpu_info->evtchn_upcall_mask = 1; - if (imm.ic) PSCB(vcpu,interrupt_collection_enabled) = 0; + vcpu->vcpu_info->evtchn_upcall_mask = 1; + if (imm.ic) + PSCB(vcpu, interrupt_collection_enabled) = 0; // interrupt collection flag //if (imm.ic) PSCB(vcpu,interrupt_delivery_enabled) = 0; // just handle psr.up and psr.pp for now - if (imm24 & ~(IA64_PSR_BE | IA64_PSR_PP | IA64_PSR_UP | IA64_PSR_SP - | IA64_PSR_I | IA64_PSR_IC | IA64_PSR_DT - | IA64_PSR_DFL | IA64_PSR_DFH)) - return (IA64_ILLOP_FAULT); - if (imm.dfh) ipsr->dfh = 0; - if (imm.dfl) ipsr->dfl = 0; + if (imm24 & ~(IA64_PSR_BE | IA64_PSR_PP | IA64_PSR_UP | IA64_PSR_SP | + IA64_PSR_I | IA64_PSR_IC | IA64_PSR_DT | + IA64_PSR_DFL | IA64_PSR_DFH)) + return IA64_ILLOP_FAULT; + if (imm.dfh) + ipsr->dfh = 0; + if (imm.dfl) + ipsr->dfl = 0; if (imm.pp) { ipsr->pp = 1; psr.pp = 1; // priv perf ctrs always enabled - PSCB(vcpu,vpsr_pp) = 0; // but fool the domain if it gets psr + PSCB(vcpu, vpsr_pp) = 0; // but fool the domain if it gets psr } - if (imm.up) { ipsr->up = 0; psr.up = 0; } - if (imm.sp) { ipsr->sp = 0; psr.sp = 0; } - if (imm.be) ipsr->be = 0; - if (imm.dt) vcpu_set_metaphysical_mode(vcpu,TRUE); - __asm__ __volatile (";; mov psr.l=%0;; srlz.d"::"r"(psr):"memory"); + if (imm.up) { + ipsr->up = 0; + psr.up = 0; + } + if (imm.sp) { + ipsr->sp = 0; + psr.sp = 0; + } + if (imm.be) + ipsr->be = 0; + if (imm.dt) + vcpu_set_metaphysical_mode(vcpu, TRUE); + __asm__ __volatile(";; mov psr.l=%0;; srlz.d"::"r"(psr):"memory"); return IA64_NO_FAULT; } - -IA64FAULT vcpu_set_psr_dt(VCPU *vcpu) +IA64FAULT vcpu_set_psr_dt(VCPU * vcpu) { - vcpu_set_metaphysical_mode(vcpu,FALSE); + vcpu_set_metaphysical_mode(vcpu, FALSE); return IA64_NO_FAULT; } -IA64FAULT vcpu_set_psr_i(VCPU *vcpu) +IA64FAULT vcpu_set_psr_i(VCPU * vcpu) { vcpu->vcpu_info->evtchn_upcall_mask = 0; - PSCB(vcpu,interrupt_collection_enabled) = 1; + PSCB(vcpu, interrupt_collection_enabled) = 1; return IA64_NO_FAULT; } -IA64FAULT vcpu_set_psr_sm(VCPU *vcpu, UINT64 imm24) +IA64FAULT vcpu_set_psr_sm(VCPU * vcpu, u64 imm24) { struct ia64_psr psr, imm, *ipsr; REGS *regs = vcpu_regs(vcpu); - UINT64 mask, enabling_interrupts = 0; + u64 mask, enabling_interrupts = 0; //PRIVOP_COUNT_ADDR(regs,_SSM); // TODO: All of these bits need to be virtualized - __asm__ __volatile ("mov %0=psr;;" : "=r"(psr) :: "memory"); + __asm__ __volatile("mov %0=psr;;":"=r"(psr)::"memory"); imm = *(struct ia64_psr *)&imm24; ipsr = (struct ia64_psr *)®s->cr_ipsr; // just handle psr.sp,pp and psr.i,ic (and user mask) for now - mask = IA64_PSR_PP|IA64_PSR_SP|IA64_PSR_I|IA64_PSR_IC|IA64_PSR_UM | - IA64_PSR_DT|IA64_PSR_DFL|IA64_PSR_DFH; - if (imm24 & ~mask) return (IA64_ILLOP_FAULT); - if (imm.dfh) ipsr->dfh = 1; - if (imm.dfl) ipsr->dfl = 1; + mask = + IA64_PSR_PP | IA64_PSR_SP | IA64_PSR_I | IA64_PSR_IC | IA64_PSR_UM | + IA64_PSR_DT | IA64_PSR_DFL | IA64_PSR_DFH; + if (imm24 & ~mask) + return IA64_ILLOP_FAULT; + if (imm.dfh) + ipsr->dfh = 1; + if (imm.dfl) + ipsr->dfl = 1; if (imm.pp) { ipsr->pp = 1; psr.pp = 1; - PSCB(vcpu,vpsr_pp) = 1; + PSCB(vcpu, vpsr_pp) = 1; + } + if (imm.sp) { + ipsr->sp = 1; + psr.sp = 1; } - if (imm.sp) { ipsr->sp = 1; psr.sp = 1; } if (imm.i) { if (vcpu->vcpu_info->evtchn_upcall_mask) { //printf("vcpu_set_psr_sm: psr.ic 0->1\n"); @@ -309,114 +342,169 @@ IA64FAULT vcpu_set_psr_sm(VCPU *vcpu, UINT64 imm24) } vcpu->vcpu_info->evtchn_upcall_mask = 0; } - if (imm.ic) PSCB(vcpu,interrupt_collection_enabled) = 1; + if (imm.ic) + PSCB(vcpu, interrupt_collection_enabled) = 1; // TODO: do this faster - if (imm.mfl) { ipsr->mfl = 1; psr.mfl = 1; } - if (imm.mfh) { ipsr->mfh = 1; psr.mfh = 1; } - if (imm.ac) { ipsr->ac = 1; psr.ac = 1; } - if (imm.up) { ipsr->up = 1; psr.up = 1; } + if (imm.mfl) { + ipsr->mfl = 1; + psr.mfl = 1; + } + if (imm.mfh) { + ipsr->mfh = 1; + psr.mfh = 1; + } + if (imm.ac) { + ipsr->ac = 1; + psr.ac = 1; + } + if (imm.up) { + ipsr->up = 1; + psr.up = 1; + } if (imm.be) { printf("*** DOMAIN TRYING TO TURN ON BIG-ENDIAN!!!\n"); - return (IA64_ILLOP_FAULT); + return IA64_ILLOP_FAULT; } - if (imm.dt) vcpu_set_metaphysical_mode(vcpu,FALSE); - __asm__ __volatile (";; mov psr.l=%0;; srlz.d"::"r"(psr):"memory"); + if (imm.dt) + vcpu_set_metaphysical_mode(vcpu, FALSE); + __asm__ __volatile(";; mov psr.l=%0;; srlz.d"::"r"(psr):"memory"); if (enabling_interrupts && - vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR) - PSCB(vcpu,pending_interruption) = 1; + vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR) + PSCB(vcpu, pending_interruption) = 1; return IA64_NO_FAULT; } -IA64FAULT vcpu_set_psr_l(VCPU *vcpu, UINT64 val) +IA64FAULT vcpu_set_psr_l(VCPU * vcpu, u64 val) { struct ia64_psr psr, newpsr, *ipsr; REGS *regs = vcpu_regs(vcpu); - UINT64 enabling_interrupts = 0; + u64 enabling_interrupts = 0; // TODO: All of these bits need to be virtualized - __asm__ __volatile ("mov %0=psr;;" : "=r"(psr) :: "memory"); + __asm__ __volatile("mov %0=psr;;":"=r"(psr)::"memory"); newpsr = *(struct ia64_psr *)&val; ipsr = (struct ia64_psr *)®s->cr_ipsr; // just handle psr.up and psr.pp for now - //if (val & ~(IA64_PSR_PP | IA64_PSR_UP | IA64_PSR_SP)) return (IA64_ILLOP_FAULT); + //if (val & ~(IA64_PSR_PP | IA64_PSR_UP | IA64_PSR_SP)) + // return IA64_ILLOP_FAULT; // however trying to set other bits can't be an error as it is in ssm - if (newpsr.dfh) ipsr->dfh = 1; - if (newpsr.dfl) ipsr->dfl = 1; + if (newpsr.dfh) + ipsr->dfh = 1; + if (newpsr.dfl) + ipsr->dfl = 1; if (newpsr.pp) { - ipsr->pp = 1; psr.pp = 1; - PSCB(vcpu,vpsr_pp) = 1; + ipsr->pp = 1; + psr.pp = 1; + PSCB(vcpu, vpsr_pp) = 1; + } else { + ipsr->pp = 1; + psr.pp = 1; + PSCB(vcpu, vpsr_pp) = 0; } - else { - ipsr->pp = 1; psr.pp = 1; - PSCB(vcpu,vpsr_pp) = 0; + if (newpsr.up) { + ipsr->up = 1; + psr.up = 1; + } + if (newpsr.sp) { + ipsr->sp = 1; + psr.sp = 1; } - if (newpsr.up) { ipsr->up = 1; psr.up = 1; } - if (newpsr.sp) { ipsr->sp = 1; psr.sp = 1; } if (newpsr.i) { if (vcpu->vcpu_info->evtchn_upcall_mask) enabling_interrupts = 1; vcpu->vcpu_info->evtchn_upcall_mask = 0; } - if (newpsr.ic) PSCB(vcpu,interrupt_collection_enabled) = 1; - if (newpsr.mfl) { ipsr->mfl = 1; psr.mfl = 1; } - if (newpsr.mfh) { ipsr->mfh = 1; psr.mfh = 1; } - if (newpsr.ac) { ipsr->ac = 1; psr.ac = 1; } - if (newpsr.up) { ipsr->up = 1; psr.up = 1; } - if (newpsr.dt && newpsr.rt) vcpu_set_metaphysical_mode(vcpu,FALSE); - else vcpu_set_metaphysical_mode(vcpu,TRUE); + if (newpsr.ic) + PSCB(vcpu, interrupt_collection_enabled) = 1; + if (newpsr.mfl) { + ipsr->mfl = 1; + psr.mfl = 1; + } + if (newpsr.mfh) { + ipsr->mfh = 1; + psr.mfh = 1; + } + if (newpsr.ac) { + ipsr->ac = 1; + psr.ac = 1; + } + if (newpsr.up) { + ipsr->up = 1; + psr.up = 1; + } + if (newpsr.dt && newpsr.rt) + vcpu_set_metaphysical_mode(vcpu, FALSE); + else + vcpu_set_metaphysical_mode(vcpu, TRUE); if (newpsr.be) { printf("*** DOMAIN TRYING TO TURN ON BIG-ENDIAN!!!\n"); - return (IA64_ILLOP_FAULT); + return IA64_ILLOP_FAULT; } if (enabling_interrupts && - vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR) - PSCB(vcpu,pending_interruption) = 1; + vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR) + PSCB(vcpu, pending_interruption) = 1; return IA64_NO_FAULT; } -IA64FAULT vcpu_get_psr(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_psr(VCPU * vcpu, u64 * pval) { REGS *regs = vcpu_regs(vcpu); struct ia64_psr newpsr; newpsr = *(struct ia64_psr *)®s->cr_ipsr; - if (newpsr.cpl == 2) newpsr.cpl = 0; - if (!vcpu->vcpu_info->evtchn_upcall_mask) newpsr.i = 1; - else newpsr.i = 0; - if (PSCB(vcpu,interrupt_collection_enabled)) newpsr.ic = 1; - else newpsr.ic = 0; - if (PSCB(vcpu,metaphysical_mode)) newpsr.dt = 0; - else newpsr.dt = 1; - if (PSCB(vcpu,vpsr_pp)) newpsr.pp = 1; - else newpsr.pp = 0; + if (newpsr.cpl == 2) + newpsr.cpl = 0; + if (!vcpu->vcpu_info->evtchn_upcall_mask) + newpsr.i = 1; + else + newpsr.i = 0; + if (PSCB(vcpu, interrupt_collection_enabled)) + newpsr.ic = 1; + else + newpsr.ic = 0; + if (PSCB(vcpu, metaphysical_mode)) + newpsr.dt = 0; + else + newpsr.dt = 1; + if (PSCB(vcpu, vpsr_pp)) + newpsr.pp = 1; + else + newpsr.pp = 0; *pval = *(unsigned long *)&newpsr; return IA64_NO_FAULT; } -BOOLEAN vcpu_get_psr_ic(VCPU *vcpu) +BOOLEAN vcpu_get_psr_ic(VCPU * vcpu) { - return !!PSCB(vcpu,interrupt_collection_enabled); + return !!PSCB(vcpu, interrupt_collection_enabled); } -BOOLEAN vcpu_get_psr_i(VCPU *vcpu) +BOOLEAN vcpu_get_psr_i(VCPU * vcpu) { return !vcpu->vcpu_info->evtchn_upcall_mask; } -UINT64 vcpu_get_ipsr_int_state(VCPU *vcpu,UINT64 prevpsr) +u64 vcpu_get_ipsr_int_state(VCPU * vcpu, u64 prevpsr) { - UINT64 dcr = PSCBX(vcpu,dcr); + u64 dcr = PSCBX(vcpu, dcr); PSR psr; //printf("*** vcpu_get_ipsr_int_state (0x%016lx)...\n",prevpsr); psr.i64 = prevpsr; - psr.ia64_psr.be = 0; if (dcr & IA64_DCR_BE) psr.ia64_psr.be = 1; - psr.ia64_psr.pp = 0; if (dcr & IA64_DCR_PP) psr.ia64_psr.pp = 1; - psr.ia64_psr.ic = PSCB(vcpu,interrupt_collection_enabled); + psr.ia64_psr.be = 0; + if (dcr & IA64_DCR_BE) + psr.ia64_psr.be = 1; + psr.ia64_psr.pp = 0; + if (dcr & IA64_DCR_PP) + psr.ia64_psr.pp = 1; + psr.ia64_psr.ic = PSCB(vcpu, interrupt_collection_enabled); psr.ia64_psr.i = !vcpu->vcpu_info->evtchn_upcall_mask; - psr.ia64_psr.bn = PSCB(vcpu,banknum); - psr.ia64_psr.dt = 1; psr.ia64_psr.it = 1; psr.ia64_psr.rt = 1; - if (psr.ia64_psr.cpl == 2) psr.ia64_psr.cpl = 0; // !!!! fool domain + psr.ia64_psr.bn = PSCB(vcpu, banknum); + psr.ia64_psr.dt = 1; + psr.ia64_psr.it = 1; + psr.ia64_psr.rt = 1; + if (psr.ia64_psr.cpl == 2) + psr.ia64_psr.cpl = 0; // !!!! fool domain // psr.pk = 1; //printf("returns 0x%016lx...\n",psr.i64); return psr.i64; @@ -426,223 +514,227 @@ UINT64 vcpu_get_ipsr_int_state(VCPU *vcpu,UINT64 prevpsr) VCPU control register access routines **************************************************************************/ -IA64FAULT vcpu_get_dcr(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_dcr(VCPU * vcpu, u64 * pval) { //verbose("vcpu_get_dcr: called @%p\n",PSCB(vcpu,iip)); // Reads of cr.dcr on Xen always have the sign bit set, so // a domain can differentiate whether it is running on SP or not - *pval = PSCBX(vcpu,dcr) | 0x8000000000000000L; - return (IA64_NO_FAULT); + *pval = PSCBX(vcpu, dcr) | 0x8000000000000000L; + return IA64_NO_FAULT; } -IA64FAULT vcpu_get_iva(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_iva(VCPU * vcpu, u64 * pval) { - if(VMX_DOMAIN(vcpu)){ - *pval = PSCB(vcpu,iva) & ~0x7fffL; - }else{ - *pval = PSCBX(vcpu,iva) & ~0x7fffL; - } - return (IA64_NO_FAULT); + if (VMX_DOMAIN(vcpu)) + *pval = PSCB(vcpu, iva) & ~0x7fffL; + else + *pval = PSCBX(vcpu, iva) & ~0x7fffL; + + return IA64_NO_FAULT; } -IA64FAULT vcpu_get_pta(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_pta(VCPU * vcpu, u64 * pval) { - *pval = PSCB(vcpu,pta); - return (IA64_NO_FAULT); + *pval = PSCB(vcpu, pta); + return IA64_NO_FAULT; } -IA64FAULT vcpu_get_ipsr(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_ipsr(VCPU * vcpu, u64 * pval) { //REGS *regs = vcpu_regs(vcpu); //*pval = regs->cr_ipsr; - *pval = PSCB(vcpu,ipsr); - return (IA64_NO_FAULT); + *pval = PSCB(vcpu, ipsr); + return IA64_NO_FAULT; } -IA64FAULT vcpu_get_isr(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_isr(VCPU * vcpu, u64 * pval) { - *pval = PSCB(vcpu,isr); - return (IA64_NO_FAULT); + *pval = PSCB(vcpu, isr); + return IA64_NO_FAULT; } -IA64FAULT vcpu_get_iip(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_iip(VCPU * vcpu, u64 * pval) { //REGS *regs = vcpu_regs(vcpu); //*pval = regs->cr_iip; - *pval = PSCB(vcpu,iip); - return (IA64_NO_FAULT); + *pval = PSCB(vcpu, iip); + return IA64_NO_FAULT; } -IA64FAULT vcpu_get_ifa(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_ifa(VCPU * vcpu, u64 * pval) { PRIVOP_COUNT_ADDR(vcpu_regs(vcpu), privop_inst_get_ifa); - *pval = PSCB(vcpu,ifa); - return (IA64_NO_FAULT); + *pval = PSCB(vcpu, ifa); + return IA64_NO_FAULT; } -unsigned long vcpu_get_rr_ps(VCPU *vcpu,UINT64 vadr) +unsigned long vcpu_get_rr_ps(VCPU * vcpu, u64 vadr) { ia64_rr rr; - rr.rrval = PSCB(vcpu,rrs)[vadr>>61]; - return(rr.ps); + rr.rrval = PSCB(vcpu, rrs)[vadr >> 61]; + return rr.ps; } -unsigned long vcpu_get_rr_rid(VCPU *vcpu,UINT64 vadr) +unsigned long vcpu_get_rr_rid(VCPU * vcpu, u64 vadr) { ia64_rr rr; - rr.rrval = PSCB(vcpu,rrs)[vadr>>61]; - return(rr.rid); + rr.rrval = PSCB(vcpu, rrs)[vadr >> 61]; + return rr.rid; } -unsigned long vcpu_get_itir_on_fault(VCPU *vcpu, UINT64 ifa) +unsigned long vcpu_get_itir_on_fault(VCPU * vcpu, u64 ifa) { ia64_rr rr; rr.rrval = 0; - rr.ps = vcpu_get_rr_ps(vcpu,ifa); - rr.rid = vcpu_get_rr_rid(vcpu,ifa); - return (rr.rrval); + rr.ps = vcpu_get_rr_ps(vcpu, ifa); + rr.rid = vcpu_get_rr_rid(vcpu, ifa); + return rr.rrval; } - -IA64FAULT vcpu_get_itir(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_itir(VCPU * vcpu, u64 * pval) { - UINT64 val = PSCB(vcpu,itir); + u64 val = PSCB(vcpu, itir); *pval = val; - return (IA64_NO_FAULT); + return IA64_NO_FAULT; } -IA64FAULT vcpu_get_iipa(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_iipa(VCPU * vcpu, u64 * pval) { - UINT64 val = PSCB(vcpu,iipa); + u64 val = PSCB(vcpu, iipa); // SP entry code does not save iipa yet nor does it get // properly delivered in the pscb // printf("*** vcpu_get_iipa: cr.iipa not fully implemented yet!!\n"); *pval = val; - return (IA64_NO_FAULT); + return IA64_NO_FAULT; } -IA64FAULT vcpu_get_ifs(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_ifs(VCPU * vcpu, u64 * pval) { //PSCB(vcpu,ifs) = PSCB(vcpu)->regs.cr_ifs; //*pval = PSCB(vcpu,regs).cr_ifs; - *pval = PSCB(vcpu,ifs); - PSCB(vcpu,incomplete_regframe) = 0; - return (IA64_NO_FAULT); + *pval = PSCB(vcpu, ifs); + PSCB(vcpu, incomplete_regframe) = 0; + return IA64_NO_FAULT; } -IA64FAULT vcpu_get_iim(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_iim(VCPU * vcpu, u64 * pval) { - UINT64 val = PSCB(vcpu,iim); + u64 val = PSCB(vcpu, iim); *pval = val; - return (IA64_NO_FAULT); + return IA64_NO_FAULT; } -IA64FAULT vcpu_get_iha(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_iha(VCPU * vcpu, u64 * pval) { PRIVOP_COUNT_ADDR(vcpu_regs(vcpu), privop_inst_thash); - *pval = PSCB(vcpu,iha); - return (IA64_NO_FAULT); + *pval = PSCB(vcpu, iha); + return IA64_NO_FAULT; } -IA64FAULT vcpu_set_dcr(VCPU *vcpu, UINT64 val) +IA64FAULT vcpu_set_dcr(VCPU * vcpu, u64 val) { // Reads of cr.dcr on SP always have the sign bit set, so // a domain can differentiate whether it is running on SP or not // Thus, writes of DCR should ignore the sign bit //verbose("vcpu_set_dcr: called\n"); - PSCBX(vcpu,dcr) = val & ~0x8000000000000000L; - return (IA64_NO_FAULT); + PSCBX(vcpu, dcr) = val & ~0x8000000000000000L; + return IA64_NO_FAULT; } -IA64FAULT vcpu_set_iva(VCPU *vcpu, UINT64 val) +IA64FAULT vcpu_set_iva(VCPU * vcpu, u64 val) { - if(VMX_DOMAIN(vcpu)){ - PSCB(vcpu,iva) = val & ~0x7fffL; - }else{ - PSCBX(vcpu,iva) = val & ~0x7fffL; - } - return (IA64_NO_FAULT); + if (VMX_DOMAIN(vcpu)) + PSCB(vcpu, iva) = val & ~0x7fffL; + else + PSCBX(vcpu, iva) = val & ~0x7fffL; + + return IA64_NO_FAULT; } -IA64FAULT vcpu_set_pta(VCPU *vcpu, UINT64 val) +IA64FAULT vcpu_set_pta(VCPU * vcpu, u64 val) { if (val & IA64_PTA_LFMT) { printf("*** No support for VHPT long format yet!!\n"); - return (IA64_ILLOP_FAULT); + return IA64_ILLOP_FAULT; } - if (val & (0x3f<<9)) /* reserved fields */ return IA64_RSVDREG_FAULT; - if (val & 2) /* reserved fields */ return IA64_RSVDREG_FAULT; - PSCB(vcpu,pta) = val; + if (val & (0x3f << 9)) /* reserved fields */ + return IA64_RSVDREG_FAULT; + if (val & 2) /* reserved fields */ + return IA64_RSVDREG_FAULT; + PSCB(vcpu, pta) = val; return IA64_NO_FAULT; } -IA64FAULT vcpu_set_ipsr(VCPU *vcpu, UINT64 val) +IA64FAULT vcpu_set_ipsr(VCPU * vcpu, u64 val) { - PSCB(vcpu,ipsr) = val; + PSCB(vcpu, ipsr) = val; return IA64_NO_FAULT; } -IA64FAULT vcpu_set_isr(VCPU *vcpu, UINT64 val) +IA64FAULT vcpu_set_isr(VCPU * vcpu, u64 val) { - PSCB(vcpu,isr) = val; + PSCB(vcpu, isr) = val; return IA64_NO_FAULT; } -IA64FAULT vcpu_set_iip(VCPU *vcpu, UINT64 val) +IA64FAULT vcpu_set_iip(VCPU * vcpu, u64 val) { - PSCB(vcpu,iip) = val; + PSCB(vcpu, iip) = val; return IA64_NO_FAULT; } -IA64FAULT vcpu_increment_iip(VCPU *vcpu) +IA64FAULT vcpu_increment_iip(VCPU * vcpu) { REGS *regs = vcpu_regs(vcpu); struct ia64_psr *ipsr = (struct ia64_psr *)®s->cr_ipsr; - if (ipsr->ri == 2) { ipsr->ri=0; regs->cr_iip += 16; } - else ipsr->ri++; - return (IA64_NO_FAULT); + if (ipsr->ri == 2) { + ipsr->ri = 0; + regs->cr_iip += 16; + } else + ipsr->ri++; + return IA64_NO_FAULT; } -IA64FAULT vcpu_set_ifa(VCPU *vcpu, UINT64 val) +IA64FAULT vcpu_set_ifa(VCPU * vcpu, u64 val) { - PSCB(vcpu,ifa) = val; + PSCB(vcpu, ifa) = val; return IA64_NO_FAULT; } -IA64FAULT vcpu_set_itir(VCPU *vcpu, UINT64 val) +IA64FAULT vcpu_set_itir(VCPU * vcpu, u64 val) { - PSCB(vcpu,itir) = val; + PSCB(vcpu, itir) = val; return IA64_NO_FAULT; } -IA64FAULT vcpu_set_iipa(VCPU *vcpu, UINT64 val) +IA64FAULT vcpu_set_iipa(VCPU * vcpu, u64 val) { // SP entry code does not save iipa yet nor does it get // properly delivered in the pscb // printf("*** vcpu_set_iipa: cr.iipa not fully implemented yet!!\n"); - PSCB(vcpu,iipa) = val; + PSCB(vcpu, iipa) = val; return IA64_NO_FAULT; } -IA64FAULT vcpu_set_ifs(VCPU *vcpu, UINT64 val) +IA64FAULT vcpu_set_ifs(VCPU * vcpu, u64 val) { //REGS *regs = vcpu_regs(vcpu); - PSCB(vcpu,ifs) = val; + PSCB(vcpu, ifs) = val; return IA64_NO_FAULT; } -IA64FAULT vcpu_set_iim(VCPU *vcpu, UINT64 val) +IA64FAULT vcpu_set_iim(VCPU * vcpu, u64 val) { - PSCB(vcpu,iim) = val; + PSCB(vcpu, iim) = val; return IA64_NO_FAULT; } -IA64FAULT vcpu_set_iha(VCPU *vcpu, UINT64 val) +IA64FAULT vcpu_set_iha(VCPU * vcpu, u64 val) { - PSCB(vcpu,iha) = val; + PSCB(vcpu, iha) = val; return IA64_NO_FAULT; } @@ -650,12 +742,12 @@ IA64FAULT vcpu_set_iha(VCPU *vcpu, UINT64 val) VCPU interrupt control register access routines **************************************************************************/ -void vcpu_pend_unspecified_interrupt(VCPU *vcpu) +void vcpu_pend_unspecified_interrupt(VCPU * vcpu) { - PSCB(vcpu,pending_interruption) = 1; + PSCB(vcpu, pending_interruption) = 1; } -void vcpu_pend_interrupt(VCPU *vcpu, UINT64 vector) +void vcpu_pend_interrupt(VCPU * vcpu, u64 vector) { if (vector & ~0xff) { printf("vcpu_pend_interrupt: bad vector\n"); @@ -663,15 +755,16 @@ void vcpu_pend_interrupt(VCPU *vcpu, UINT64 vector) } if (vcpu->arch.event_callback_ip) { - printf("Deprecated interface. Move to new event based solution\n"); + printf("Deprecated interface. Move to new event based " + "solution\n"); return; } - - if ( VMX_DOMAIN(vcpu) ) { - set_bit(vector,VCPU(vcpu,irr)); + + if (VMX_DOMAIN(vcpu)) { + set_bit(vector, VCPU(vcpu, irr)); } else { - set_bit(vector,PSCBX(vcpu,irr)); - PSCB(vcpu,pending_interruption) = 1; + set_bit(vector, PSCBX(vcpu, irr)); + PSCB(vcpu, pending_interruption) = 1; } } @@ -684,9 +777,9 @@ void vcpu_pend_interrupt(VCPU *vcpu, UINT64 vector) * semantics of "mov rx=cr.ivr" ignore the setting of the psr.i bit, * this routine also ignores pscb.interrupt_delivery_enabled * and this must be checked independently; see vcpu_deliverable interrupts() */ -UINT64 vcpu_check_pending_interrupts(VCPU *vcpu) +u64 vcpu_check_pending_interrupts(VCPU * vcpu) { - UINT64 *p, *r, bits, bitnum, mask, i, vector; + u64 *p, *r, bits, bitnum, mask, i, vector; if (vcpu->arch.event_callback_ip) return SPURIOUS_VECTOR; @@ -695,38 +788,41 @@ UINT64 vcpu_check_pending_interrupts(VCPU *vcpu) * event injection without handle. Later guest may throw out * the event itself. */ -check_start: - if (event_pending(vcpu) && - !test_bit(vcpu->domain->shared_info->arch.evtchn_vector, - &PSCBX(vcpu, insvc[0]))) - vcpu_pend_interrupt(vcpu, vcpu->domain->shared_info->arch.evtchn_vector); - - p = &PSCBX(vcpu,irr[3]); - r = &PSCBX(vcpu,insvc[3]); - for (i = 3; ; p--, r--, i--) { - bits = *p ; - if (bits) break; // got a potential interrupt + check_start: + if (event_pending(vcpu) && + !test_bit(vcpu->domain->shared_info->arch.evtchn_vector, + &PSCBX(vcpu, insvc[0]))) + vcpu_pend_interrupt(vcpu, + vcpu->domain->shared_info->arch. + evtchn_vector); + + p = &PSCBX(vcpu, irr[3]); + r = &PSCBX(vcpu, insvc[3]); + for (i = 3 ;; p--, r--, i--) { + bits = *p; + if (bits) + break; // got a potential interrupt if (*r) { // nothing in this word which is pending+inservice // but there is one inservice which masks lower return SPURIOUS_VECTOR; } if (i == 0) { - // checked all bits... nothing pending+inservice + // checked all bits... nothing pending+inservice return SPURIOUS_VECTOR; } } // have a pending,deliverable interrupt... see if it is masked bitnum = ia64_fls(bits); //printf("XXXXXXX vcpu_check_pending_interrupts: got bitnum=%p...\n",bitnum); - vector = bitnum+(i*64); + vector = bitnum + (i * 64); mask = 1L << bitnum; /* sanity check for guest timer interrupt */ - if (vector == (PSCB(vcpu,itv) & 0xff)) { + if (vector == (PSCB(vcpu, itv) & 0xff)) { uint64_t now = ia64_get_itc(); - if (now < PSCBX(vcpu,domain_itm)) { + if (now < PSCBX(vcpu, domain_itm)) { // printk("Ooops, pending guest timer before its due\n"); - PSCBX(vcpu,irr[i]) &= ~mask; + PSCBX(vcpu, irr[i]) &= ~mask; goto check_start; } } @@ -736,48 +832,47 @@ check_start: //printf("but masked by equal inservice\n"); return SPURIOUS_VECTOR; } - if (PSCB(vcpu,tpr) & IA64_TPR_MMI) { + if (PSCB(vcpu, tpr) & IA64_TPR_MMI) { // tpr.mmi is set //printf("but masked by tpr.mmi\n"); return SPURIOUS_VECTOR; } - if (((PSCB(vcpu,tpr) & IA64_TPR_MIC) + 15) >= vector) { + if (((PSCB(vcpu, tpr) & IA64_TPR_MIC) + 15) >= vector) { //tpr.mic masks class //printf("but masked by tpr.mic\n"); return SPURIOUS_VECTOR; } - //printf("returned to caller\n"); return vector; } -UINT64 vcpu_deliverable_interrupts(VCPU *vcpu) +u64 vcpu_deliverable_interrupts(VCPU * vcpu) { return (vcpu_get_psr_i(vcpu) && vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR); } -UINT64 vcpu_deliverable_timer(VCPU *vcpu) +u64 vcpu_deliverable_timer(VCPU * vcpu) { return (vcpu_get_psr_i(vcpu) && - vcpu_check_pending_interrupts(vcpu) == PSCB(vcpu,itv)); + vcpu_check_pending_interrupts(vcpu) == PSCB(vcpu, itv)); } -IA64FAULT vcpu_get_lid(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_lid(VCPU * vcpu, u64 * pval) { /* Use EID=0, ID=vcpu_id. */ *pval = vcpu->vcpu_id << 24; return IA64_NO_FAULT; } -IA64FAULT vcpu_get_ivr(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_ivr(VCPU * vcpu, u64 * pval) { int i; - UINT64 vector, mask; + u64 vector, mask; #define HEARTBEAT_FREQ 16 // period in seconds #ifdef HEARTBEAT_FREQ -#define N_DOMS 16 // period in seconds +#define N_DOMS 16 // period in seconds #if 0 static long count[N_DOMS] = { 0 }; #endif @@ -789,257 +884,269 @@ IA64FAULT vcpu_get_ivr(VCPU *vcpu, UINT64 *pval) static char firsttime[256]; if (firstivr) { int i; - for (i=0;i<256;i++) firsttime[i]=1; - firstivr=0; + for (i = 0; i < 256; i++) + firsttime[i] = 1; + firstivr = 0; } #endif vector = vcpu_check_pending_interrupts(vcpu); if (vector == SPURIOUS_VECTOR) { - PSCB(vcpu,pending_interruption) = 0; + PSCB(vcpu, pending_interruption) = 0; *pval = vector; return IA64_NO_FAULT; } #ifdef HEARTBEAT_FREQ - if (domid >= N_DOMS) domid = N_DOMS-1; + if (domid >= N_DOMS) + domid = N_DOMS - 1; #if 0 - if (vector == (PSCB(vcpu,itv) & 0xff)) { - if (!(++count[domid] & ((HEARTBEAT_FREQ*1024)-1))) { - printf("Dom%d heartbeat... ticks=%lx,nonticks=%lx\n", - domid, count[domid], nonclockcount[domid]); - //count[domid] = 0; - //dump_runq(); - } + if (vector == (PSCB(vcpu, itv) & 0xff)) { + if (!(++count[domid] & ((HEARTBEAT_FREQ * 1024) - 1))) { + printf("Dom%d heartbeat... ticks=%lx,nonticks=%lx\n", + domid, count[domid], nonclockcount[domid]); + //count[domid] = 0; + //dump_runq(); + } } #endif - else nonclockcount[domid]++; + else + nonclockcount[domid]++; #endif // now have an unmasked, pending, deliverable vector! // getting ivr has "side effects" #ifdef IRQ_DEBUG if (firsttime[vector]) { printf("*** First get_ivr on vector=%lu,itc=%lx\n", - vector,ia64_get_itc()); - firsttime[vector]=0; + vector, ia64_get_itc()); + firsttime[vector] = 0; } #endif /* if delivering a timer interrupt, remember domain_itm, which * needs to be done before clearing irr */ - if (vector == (PSCB(vcpu,itv) & 0xff)) { - PSCBX(vcpu,domain_itm_last) = PSCBX(vcpu,domain_itm); + if (vector == (PSCB(vcpu, itv) & 0xff)) { + PSCBX(vcpu, domain_itm_last) = PSCBX(vcpu, domain_itm); } i = vector >> 6; mask = 1L << (vector & 0x3f); //printf("ZZZZZZ vcpu_get_ivr: setting insvc mask for vector %lu\n",vector); - PSCBX(vcpu,insvc[i]) |= mask; - PSCBX(vcpu,irr[i]) &= ~mask; + PSCBX(vcpu, insvc[i]) |= mask; + PSCBX(vcpu, irr[i]) &= ~mask; //PSCB(vcpu,pending_interruption)--; *pval = vector; return IA64_NO_FAULT; } -IA64FAULT vcpu_get_tpr(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_tpr(VCPU * vcpu, u64 * pval) { - *pval = PSCB(vcpu,tpr); - return (IA64_NO_FAULT); + *pval = PSCB(vcpu, tpr); + return IA64_NO_FAULT; } -IA64FAULT vcpu_get_eoi(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_eoi(VCPU * vcpu, u64 * pval) { - *pval = 0L; // reads of eoi always return 0 - return (IA64_NO_FAULT); + *pval = 0L; // reads of eoi always return 0 + return IA64_NO_FAULT; } -IA64FAULT vcpu_get_irr0(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_irr0(VCPU * vcpu, u64 * pval) { *pval = PSCBX(vcpu, irr[0]); - return (IA64_NO_FAULT); + return IA64_NO_FAULT; } -IA64FAULT vcpu_get_irr1(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_irr1(VCPU * vcpu, u64 * pval) { *pval = PSCBX(vcpu, irr[1]); - return (IA64_NO_FAULT); + return IA64_NO_FAULT; } -IA64FAULT vcpu_get_irr2(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_irr2(VCPU * vcpu, u64 * pval) { *pval = PSCBX(vcpu, irr[2]); - return (IA64_NO_FAULT); + return IA64_NO_FAULT; } -IA64FAULT vcpu_get_irr3(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_irr3(VCPU * vcpu, u64 * pval) { *pval = PSCBX(vcpu, irr[3]); - return (IA64_NO_FAULT); + return IA64_NO_FAULT; } -IA64FAULT vcpu_get_itv(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_itv(VCPU * vcpu, u64 * pval) { - *pval = PSCB(vcpu,itv); - return (IA64_NO_FAULT); + *pval = PSCB(vcpu, itv); + return IA64_NO_FAULT; } -IA64FAULT vcpu_get_pmv(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_pmv(VCPU * vcpu, u64 * pval) { - *pval = PSCB(vcpu,pmv); - return (IA64_NO_FAULT); + *pval = PSCB(vcpu, pmv); + return IA64_NO_FAULT; } -IA64FAULT vcpu_get_cmcv(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_cmcv(VCPU * vcpu, u64 * pval) { - *pval = PSCB(vcpu,cmcv); - return (IA64_NO_FAULT); + *pval = PSCB(vcpu, cmcv); + return IA64_NO_FAULT; } -IA64FAULT vcpu_get_lrr0(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_lrr0(VCPU * vcpu, u64 * pval) { // fix this when setting values other than m-bit is supported printf("vcpu_get_lrr0: Unmasked interrupts unsupported\n"); *pval = (1L << 16); - return (IA64_NO_FAULT); + return IA64_NO_FAULT; } -IA64FAULT vcpu_get_lrr1(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_lrr1(VCPU * vcpu, u64 * pval) { // fix this when setting values other than m-bit is supported printf("vcpu_get_lrr1: Unmasked interrupts unsupported\n"); *pval = (1L << 16); - return (IA64_NO_FAULT); + return IA64_NO_FAULT; } -IA64FAULT vcpu_set_lid(VCPU *vcpu, UINT64 val) +IA64FAULT vcpu_set_lid(VCPU * vcpu, u64 val) { printf("vcpu_set_lid: Setting cr.lid is unsupported\n"); - return (IA64_ILLOP_FAULT); + return IA64_ILLOP_FAULT; } -IA64FAULT vcpu_set_tpr(VCPU *vcpu, UINT64 val) +IA64FAULT vcpu_set_tpr(VCPU * vcpu, u64 val) { - if (val & 0xff00) return IA64_RSVDREG_FAULT; - PSCB(vcpu,tpr) = val; + if (val & 0xff00) + return IA64_RSVDREG_FAULT; + PSCB(vcpu, tpr) = val; /* This can unmask interrupts. */ if (vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR) - PSCB(vcpu,pending_interruption) = 1; - return (IA64_NO_FAULT); + PSCB(vcpu, pending_interruption) = 1; + return IA64_NO_FAULT; } -IA64FAULT vcpu_set_eoi(VCPU *vcpu, UINT64 val) +IA64FAULT vcpu_set_eoi(VCPU * vcpu, u64 val) { - UINT64 *p, bits, vec, bitnum; + u64 *p, bits, vec, bitnum; int i; - p = &PSCBX(vcpu,insvc[3]); - for (i = 3; (i >= 0) && !(bits = *p); i--, p--); + p = &PSCBX(vcpu, insvc[3]); + for (i = 3; (i >= 0) && !(bits = *p); i--, p--) + ; if (i < 0) { printf("Trying to EOI interrupt when none are in-service.\n"); return IA64_NO_FAULT; } bitnum = ia64_fls(bits); - vec = bitnum + (i*64); + vec = bitnum + (i * 64); /* clear the correct bit */ bits &= ~(1L << bitnum); *p = bits; /* clearing an eoi bit may unmask another pending interrupt... */ - if (!vcpu->vcpu_info->evtchn_upcall_mask) { // but only if enabled... + if (!vcpu->vcpu_info->evtchn_upcall_mask) { // but only if enabled... // worry about this later... Linux only calls eoi // with interrupts disabled printf("Trying to EOI interrupt with interrupts enabled\n"); } if (vcpu_check_pending_interrupts(vcpu) != SPURIOUS_VECTOR) - PSCB(vcpu,pending_interruption) = 1; + PSCB(vcpu, pending_interruption) = 1; //printf("YYYYY vcpu_set_eoi: Successful\n"); - return (IA64_NO_FAULT); + return IA64_NO_FAULT; } -IA64FAULT vcpu_set_lrr0(VCPU *vcpu, UINT64 val) +IA64FAULT vcpu_set_lrr0(VCPU * vcpu, u64 val) { if (!(val & (1L << 16))) { printf("vcpu_set_lrr0: Unmasked interrupts unsupported\n"); - return (IA64_ILLOP_FAULT); + return IA64_ILLOP_FAULT; } // no place to save this state but nothing to do anyway - return (IA64_NO_FAULT); + return IA64_NO_FAULT; } -IA64FAULT vcpu_set_lrr1(VCPU *vcpu, UINT64 val) +IA64FAULT vcpu_set_lrr1(VCPU * vcpu, u64 val) { if (!(val & (1L << 16))) { printf("vcpu_set_lrr0: Unmasked interrupts unsupported\n"); - return (IA64_ILLOP_FAULT); + return IA64_ILLOP_FAULT; } // no place to save this state but nothing to do anyway - return (IA64_NO_FAULT); + return IA64_NO_FAULT; } -IA64FAULT vcpu_set_itv(VCPU *vcpu, UINT64 val) +IA64FAULT vcpu_set_itv(VCPU * vcpu, u64 val) { /* Check reserved fields. */ if (val & 0xef00) - return (IA64_ILLOP_FAULT); - PSCB(vcpu,itv) = val; + return IA64_ILLOP_FAULT; + PSCB(vcpu, itv) = val; if (val & 0x10000) { /* Disable itm. */ - PSCBX(vcpu,domain_itm) = 0; - } - else vcpu_set_next_timer(vcpu); - return (IA64_NO_FAULT); + PSCBX(vcpu, domain_itm) = 0; + } else + vcpu_set_next_timer(vcpu); + return IA64_NO_FAULT; } -IA64FAULT vcpu_set_pmv(VCPU *vcpu, UINT64 val) +IA64FAULT vcpu_set_pmv(VCPU * vcpu, u64 val) { - if (val & 0xef00) /* reserved fields */ return IA64_RSVDREG_FAULT; - PSCB(vcpu,pmv) = val; - return (IA64_NO_FAULT); + if (val & 0xef00) /* reserved fields */ + return IA64_RSVDREG_FAULT; + PSCB(vcpu, pmv) = val; + return IA64_NO_FAULT; } -IA64FAULT vcpu_set_cmcv(VCPU *vcpu, UINT64 val) +IA64FAULT vcpu_set_cmcv(VCPU * vcpu, u64 val) { - if (val & 0xef00) /* reserved fields */ return IA64_RSVDREG_FAULT; - PSCB(vcpu,cmcv) = val; - return (IA64_NO_FAULT); + if (val & 0xef00) /* reserved fields */ + return IA64_RSVDREG_FAULT; + PSCB(vcpu, cmcv) = val; + return IA64_NO_FAULT; } /************************************************************************** VCPU temporary register access routines **************************************************************************/ -UINT64 vcpu_get_tmp(VCPU *vcpu, UINT64 index) +u64 vcpu_get_tmp(VCPU * vcpu, u64 index) { - if (index > 7) return 0; - return PSCB(vcpu,tmp[index]); + if (index > 7) + return 0; + return PSCB(vcpu, tmp[index]); } -void vcpu_set_tmp(VCPU *vcpu, UINT64 index, UINT64 val) +void vcpu_set_tmp(VCPU * vcpu, u64 index, u64 val) { - if (index <= 7) PSCB(vcpu,tmp[index]) = val; + if (index <= 7) + PSCB(vcpu, tmp[index]) = val; } /************************************************************************** Interval timer routines **************************************************************************/ -BOOLEAN vcpu_timer_disabled(VCPU *vcpu) +BOOLEAN vcpu_timer_disabled(VCPU * vcpu) { - UINT64 itv = PSCB(vcpu,itv); - return(!itv || !!(itv & 0x10000)); + u64 itv = PSCB(vcpu, itv); + return (!itv || !!(itv & 0x10000)); } -BOOLEAN vcpu_timer_inservice(VCPU *vcpu) +BOOLEAN vcpu_timer_inservice(VCPU * vcpu) { - UINT64 itv = PSCB(vcpu,itv); - return (test_bit(itv, PSCBX(vcpu,insvc))); + u64 itv = PSCB(vcpu, itv); + return test_bit(itv, PSCBX(vcpu, insvc)); } -BOOLEAN vcpu_timer_expired(VCPU *vcpu) +BOOLEAN vcpu_timer_expired(VCPU * vcpu) { - unsigned long domain_itm = PSCBX(vcpu,domain_itm); + unsigned long domain_itm = PSCBX(vcpu, domain_itm); unsigned long now = ia64_get_itc(); - if (!domain_itm) return FALSE; - if (now < domain_itm) return FALSE; - if (vcpu_timer_disabled(vcpu)) return FALSE; + if (!domain_itm) + return FALSE; + if (now < domain_itm) + return FALSE; + if (vcpu_timer_disabled(vcpu)) + return FALSE; return TRUE; } @@ -1047,25 +1154,26 @@ void vcpu_safe_set_itm(unsigned long val) { unsigned long epsilon = 100; unsigned long flags; - UINT64 now = ia64_get_itc(); + u64 now = ia64_get_itc(); local_irq_save(flags); while (1) { //printf("*** vcpu_safe_set_itm: Setting itm to %lx, itc=%lx\n",val,now); ia64_set_itm(val); - if (val > (now = ia64_get_itc())) break; + if (val > (now = ia64_get_itc())) + break; val = now + epsilon; epsilon <<= 1; } local_irq_restore(flags); } -void vcpu_set_next_timer(VCPU *vcpu) +void vcpu_set_next_timer(VCPU * vcpu) { - UINT64 d = PSCBX(vcpu,domain_itm); - //UINT64 s = PSCBX(vcpu,xen_itm); - UINT64 s = local_cpu_data->itm_next; - UINT64 now = ia64_get_itc(); + u64 d = PSCBX(vcpu, domain_itm); + //u64 s = PSCBX(vcpu,xen_itm); + u64 s = local_cpu_data->itm_next; + u64 now = ia64_get_itc(); /* gloss over the wraparound problem for now... we know it exists * but it doesn't matter right now */ @@ -1079,25 +1187,24 @@ void vcpu_set_next_timer(VCPU *vcpu) if (d && (d > now) && (d < s)) { vcpu_safe_set_itm(d); //using_domain_as_itm++; - } - else { + } else { vcpu_safe_set_itm(s); //using_xen_as_itm++; } } -IA64FAULT vcpu_set_itm(VCPU *vcpu, UINT64 val) +IA64FAULT vcpu_set_itm(VCPU * vcpu, u64 val) { //UINT now = ia64_get_itc(); //if (val < now) val = now + 1000; //printf("*** vcpu_set_itm: called with %lx\n",val); - PSCBX(vcpu,domain_itm) = val; + PSCBX(vcpu, domain_itm) = val; vcpu_set_next_timer(vcpu); - return (IA64_NO_FAULT); + return IA64_NO_FAULT; } -IA64FAULT vcpu_set_itc(VCPU *vcpu, UINT64 val) +IA64FAULT vcpu_set_itc(VCPU * vcpu, u64 val) { #define DISALLOW_SETTING_ITC_FOR_NOW #ifdef DISALLOW_SETTING_ITC_FOR_NOW @@ -1108,58 +1215,59 @@ IA64FAULT vcpu_set_itc(VCPU *vcpu, UINT64 val) did_print = 1; } #else - UINT64 oldnow = ia64_get_itc(); - UINT64 olditm = PSCBX(vcpu,domain_itm); + u64 oldnow = ia64_get_itc(); + u64 olditm = PSCBX(vcpu, domain_itm); unsigned long d = olditm - oldnow; unsigned long x = local_cpu_data->itm_next - oldnow; - UINT64 newnow = val, min_delta; + u64 newnow = val, min_delta; local_irq_disable(); if (olditm) { -printf("**** vcpu_set_itc(%lx): vitm changed to %lx\n",val,newnow+d); - PSCBX(vcpu,domain_itm) = newnow + d; + printf("**** vcpu_set_itc(%lx): vitm changed to %lx\n", val, + newnow + d); + PSCBX(vcpu, domain_itm) = newnow + d; } local_cpu_data->itm_next = newnow + x; - d = PSCBX(vcpu,domain_itm); + d = PSCBX(vcpu, domain_itm); x = local_cpu_data->itm_next; ia64_set_itc(newnow); if (d && (d > newnow) && (d < x)) { vcpu_safe_set_itm(d); //using_domain_as_itm++; - } - else { + } else { vcpu_safe_set_itm(x); //using_xen_as_itm++; } local_irq_enable(); #endif - return (IA64_NO_FAULT); + return IA64_NO_FAULT; } -IA64FAULT vcpu_get_itm(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_itm(VCPU * vcpu, u64 * pval) { //FIXME: Implement this printf("vcpu_get_itm: Getting cr.itm is unsupported... continuing\n"); - return (IA64_NO_FAULT); - //return (IA64_ILLOP_FAULT); + return IA64_NO_FAULT; + //return IA64_ILLOP_FAULT; } -IA64FAULT vcpu_get_itc(VCPU *vcpu, UINT64 *pval) +IA64FAULT vcpu_get_itc(VCPU * vcpu, u64 * pval) { //TODO: Implement this printf("vcpu_get_itc: Getting ar.itc is unsupported\n"); - return (IA64_ILLOP_FAULT); + return IA64_ILLOP_FAULT; } -void vcpu_pend_timer(VCPU *vcpu) +void vcpu_pend_timer(VCPU * vcpu) { - UINT64 itv = PSCB(vcpu,itv) & 0xff; + u64 itv = PSCB(vcpu, itv) & 0xff; - if (vcpu_timer_disabled(vcpu)) return; + if (vcpu_timer_disabled(vcpu)) + return; //if (vcpu_timer_inservice(vcpu)) return; - if (PSCBX(vcpu,domain_itm_last) == PSCBX(vcpu,domain_itm)) { + if (PSCBX(vcpu, domain_itm_last) == PSCBX(vcpu, domain_itm)) { // already delivered an interrupt for this so // don't deliver another return; @@ -1177,13 +1285,15 @@ void vcpu_pend_timer(VCPU *vcpu) } // returns true if ready to deliver a timer interrupt too early -UINT64 vcpu_timer_pending_early(VCPU *vcpu) +u64 vcpu_timer_pending_early(VCPU * vcpu) { - UINT64 now = ia64_get_itc(); - UINT64 itm = PSCBX(vcpu,domain_itm); + u64 now = ia64_get_itc(); + u64 itm = PSCBX(vcpu, domain_itm); - if (vcpu_timer_disabled(vcpu)) return 0; - if (!itm) return 0; + if (vcpu_timer_disabled(vcpu)) + return 0; + if (!itm) + return 0; return (vcpu_deliverable_timer(vcpu) && (now < itm)); } @@ -1191,120 +1301,129 @@ UINT64 vcpu_timer_pending_early(VCPU *vcpu) Privileged operation emulation routines **************************************************************************/ -static void -vcpu_force_tlb_miss(VCPU* vcpu, UINT64 ifa) +static void vcpu_force_tlb_miss(VCPU * vcpu, u64 ifa) { PSCB(vcpu, ifa) = ifa; PSCB(vcpu, itir) = vcpu_get_itir_on_fault(vcpu, ifa); vcpu_thash(current, ifa, &PSCB(current, iha)); } -IA64FAULT vcpu_force_inst_miss(VCPU *vcpu, UINT64 ifa) +IA64FAULT vcpu_force_inst_miss(VCPU * vcpu, u64 ifa) { vcpu_force_tlb_miss(vcpu, ifa); - return (vcpu_get_rr_ve(vcpu, ifa)? IA64_INST_TLB_VECTOR: IA64_ALT_INST_TLB_VECTOR); + return vcpu_get_rr_ve(vcpu, ifa) ? IA64_INST_TLB_VECTOR : + IA64_ALT_INST_TLB_VECTOR; } -IA64FAULT vcpu_force_data_miss(VCPU *vcpu, UINT64 ifa) +IA64FAULT vcpu_force_data_miss(VCPU * vcpu, u64 ifa) { vcpu_force_tlb_miss(vcpu, ifa); - return (vcpu_get_rr_ve(vcpu, ifa)? IA64_DATA_TLB_VECTOR: IA64_ALT_DATA_TLB_VECTOR); + return vcpu_get_rr_ve(vcpu, ifa) ? IA64_DATA_TLB_VECTOR : + IA64_ALT_DATA_TLB_VECTOR; } -IA64FAULT vcpu_rfi(VCPU *vcpu) +IA64FAULT vcpu_rfi(VCPU * vcpu) { // TODO: Only allowed for current vcpu PSR psr; - UINT64 int_enable, regspsr = 0; - UINT64 ifs; + u64 int_enable, regspsr = 0; + u64 ifs; REGS *regs = vcpu_regs(vcpu); extern void dorfirfi(void); - psr.i64 = PSCB(vcpu,ipsr); - if (psr.ia64_psr.cpl < 3) psr.ia64_psr.cpl = 2; + psr.i64 = PSCB(vcpu, ipsr); + if (psr.ia64_psr.cpl < 3) + psr.ia64_psr.cpl = 2; int_enable = psr.ia64_psr.i; - if (psr.ia64_psr.ic) PSCB(vcpu,interrupt_collection_enabled) = 1; - if (psr.ia64_psr.dt && psr.ia64_psr.rt && psr.ia64_psr.it) vcpu_set_metaphysical_mode(vcpu,FALSE); - else vcpu_set_metaphysical_mode(vcpu,TRUE); - psr.ia64_psr.ic = 1; psr.ia64_psr.i = 1; - psr.ia64_psr.dt = 1; psr.ia64_psr.rt = 1; psr.ia64_psr.it = 1; + if (psr.ia64_psr.ic) + PSCB(vcpu, interrupt_collection_enabled) = 1; + if (psr.ia64_psr.dt && psr.ia64_psr.rt && psr.ia64_psr.it) + vcpu_set_metaphysical_mode(vcpu, FALSE); + else + vcpu_set_metaphysical_mode(vcpu, TRUE); + psr.ia64_psr.ic = 1; + psr.ia64_psr.i = 1; + psr.ia64_psr.dt = 1; + psr.ia64_psr.rt = 1; + psr.ia64_psr.it = 1; psr.ia64_psr.bn = 1; //psr.pk = 1; // checking pkeys shouldn't be a problem but seems broken if (psr.ia64_psr.be) { printf("*** DOMAIN TRYING TO TURN ON BIG-ENDIAN!!!\n"); - return (IA64_ILLOP_FAULT); + return IA64_ILLOP_FAULT; } - PSCB(vcpu,incomplete_regframe) = 0; // is this necessary? - ifs = PSCB(vcpu,ifs); + PSCB(vcpu, incomplete_regframe) = 0; // is this necessary? + ifs = PSCB(vcpu, ifs); //if ((ifs & regs->cr_ifs & 0x8000000000000000L) && ifs != regs->cr_ifs) { //if ((ifs & 0x8000000000000000L) && ifs != regs->cr_ifs) { if (ifs & regs->cr_ifs & 0x8000000000000000L) { // TODO: validate PSCB(vcpu,iip) // TODO: PSCB(vcpu,ipsr) = psr; - PSCB(vcpu,ipsr) = psr.i64; + PSCB(vcpu, ipsr) = psr.i64; // now set up the trampoline regs->cr_iip = *(unsigned long *)dorfirfi; // function pointer!! - __asm__ __volatile ("mov %0=psr;;":"=r"(regspsr)::"memory"); - regs->cr_ipsr = regspsr & ~(IA64_PSR_I | IA64_PSR_IC | IA64_PSR_BN); - } - else { + __asm__ __volatile("mov %0=psr;;":"=r"(regspsr)::"memory"); + regs->cr_ipsr = + regspsr & ~(IA64_PSR_I | IA64_PSR_IC | IA64_PSR_BN); + } else { regs->cr_ipsr = psr.i64; - regs->cr_iip = PSCB(vcpu,iip); + regs->cr_iip = PSCB(vcpu, iip); } - PSCB(vcpu,interrupt_collection_enabled) = 1; + PSCB(vcpu, interrupt_collection_enabled) = 1; vcpu_bsw1(vcpu); vcpu->vcpu_info->evtchn_upcall_mask = !int_enable; - return (IA64_NO_FAULT); + return IA64_NO_FAULT; } -IA64FAULT vcpu_cover(VCPU *vcpu) +IA64FAULT vcpu_cover(VCPU * vcpu) { // TODO: Only allowed for current vcpu REGS *regs = vcpu_regs(vcpu); - if (!PSCB(vcpu,interrupt_collection_enabled)) { - if (!PSCB(vcpu,incomplete_regframe)) - PSCB(vcpu,ifs) = regs->cr_ifs; - else PSCB(vcpu,incomplete_regframe) = 0; + if (!PSCB(vcpu, interrupt_collection_enabled)) { + if (!PSCB(vcpu, incomplete_regframe)) + PSCB(vcpu, ifs) = regs->cr_ifs; + else + PSCB(vcpu, incomplete_regframe) = 0; } regs->cr_ifs = 0; - return (IA64_NO_FAULT); -} - -IA64FAULT vcpu_thash(VCPU *vcpu, UINT64 vadr, UINT64 *pval) -{ - UINT64 pta = PSCB(vcpu,pta); - UINT64 pta_sz = (pta & IA64_PTA_SZ(0x3f)) >> IA64_PTA_SZ_BIT; - UINT64 pta_base = pta & ~((1UL << IA64_PTA_BASE_BIT)-1); - UINT64 Mask = (1L << pta_sz) - 1; - UINT64 Mask_60_15 = (Mask >> 15) & 0x3fffffffffff; - UINT64 compMask_60_15 = ~Mask_60_15; - UINT64 rr_ps = vcpu_get_rr_ps(vcpu,vadr); - UINT64 VHPT_offset = (vadr >> rr_ps) << 3; - UINT64 VHPT_addr1 = vadr & 0xe000000000000000L; - UINT64 VHPT_addr2a = - ((pta_base >> 15) & 0x3fffffffffff) & compMask_60_15; - UINT64 VHPT_addr2b = - ((VHPT_offset >> 15) & 0x3fffffffffff) & Mask_60_15; - UINT64 VHPT_addr3 = VHPT_offset & 0x7fff; - UINT64 VHPT_addr = VHPT_addr1 | ((VHPT_addr2a | VHPT_addr2b) << 15) | - VHPT_addr3; + return IA64_NO_FAULT; +} + +IA64FAULT vcpu_thash(VCPU * vcpu, u64 vadr, u64 * pval) +{ + u64 pta = PSCB(vcpu, pta); + u64 pta_sz = (pta & IA64_PTA_SZ(0x3f)) >> IA64_PTA_SZ_BIT; + u64 pta_base = pta & ~((1UL << IA64_PTA_BASE_BIT) - 1); + u64 Mask = (1L << pta_sz) - 1; + u64 Mask_60_15 = (Mask >> 15) & 0x3fffffffffff; + u64 compMask_60_15 = ~Mask_60_15; + u64 rr_ps = vcpu_get_rr_ps(vcpu, vadr); + u64 VHPT_offset = (vadr >> rr_ps) << 3; + u64 VHPT_addr1 = vadr & 0xe000000000000000L; + u64 VHPT_addr2a = + ((pta_base >> 15) & 0x3fffffffffff) & compMask_60_15; + u64 VHPT_addr2b = + ((VHPT_offset >> 15) & 0x3fffffffffff) & Mask_60_15; + u64 VHPT_addr3 = VHPT_offset & 0x7fff; + u64 VHPT_addr = VHPT_addr1 | ((VHPT_addr2a | VHPT_addr2b) << 15) | + VHPT_addr3; //verbose("vcpu_thash: vadr=%p, VHPT_addr=%p\n",vadr,VHPT_addr); *pval = VHPT_addr; - return (IA64_NO_FAULT); + return IA64_NO_FAULT; } -IA64FAULT vcpu_ttag(VCPU *vcpu, UINT64 vadr, UINT64 *padr) +IA64FAULT vcpu_ttag(VCPU * vcpu, u64 vadr, u64 * padr) { printf("vcpu_ttag: ttag instruction unsupported\n"); - return (IA64_ILLOP_FAULT); + return IA64_ILLOP_FAULT; } -int warn_region0_address = 0; // FIXME later: tie to a boot parameter? +int warn_region0_address = 0; // FIXME later: tie to a boot parameter? /* Return TRUE iff [b1,e1] and [b2,e2] partially or fully overlaps. */ -static inline int range_overlap (u64 b1, u64 e1, u64 b2, u64 e2) +static inline int range_overlap(u64 b1, u64 e1, u64 b2, u64 e2) { return (b1 <= e2) && (e1 >= b2); } @@ -1312,45 +1431,53 @@ static inline int range_overlap (u64 b1, u64 e1, u64 b2, u64 e2) /* Crash domain if [base, base + page_size] and Xen virtual space overlaps. Note: LSBs of base inside page_size are ignored. */ static inline void -check_xen_space_overlap (const char *func, u64 base, u64 page_size) +check_xen_space_overlap(const char *func, u64 base, u64 page_size) { + /* Overlaps can occur only in region 7. + (This is an optimization to bypass all the checks). */ + if (REGION_NUMBER(base) != 7) + return; + /* Mask LSBs of base. */ base &= ~(page_size - 1); /* FIXME: ideally an MCA should be generated... */ - if (range_overlap (HYPERVISOR_VIRT_START, HYPERVISOR_VIRT_END, - base, base + page_size)) - panic_domain (NULL, "%s on Xen virtual space (%lx)\n", - func, base); + if (range_overlap(HYPERVISOR_VIRT_START, HYPERVISOR_VIRT_END, + base, base + page_size) + || range_overlap(current->domain->arch.shared_info_va, + current->domain->arch.shared_info_va + + XSI_SIZE + XMAPPEDREGS_SIZE, + base, base + page_size)) + panic_domain(NULL, "%s on Xen virtual space (%lx)\n", + func, base); } // FIXME: also need to check && (!trp->key || vcpu_pkr_match(trp->key)) -static inline int vcpu_match_tr_entry_no_p(TR_ENTRY *trp, UINT64 ifa, UINT64 rid) +static inline int vcpu_match_tr_entry_no_p(TR_ENTRY * trp, u64 ifa, + u64 rid) { - return trp->rid == rid - && ifa >= trp->vadr - && ifa <= (trp->vadr + (1L << trp->ps) - 1); + return trp->rid == rid + && ifa >= trp->vadr && ifa <= (trp->vadr + (1L << trp->ps) - 1); } -static inline int vcpu_match_tr_entry(TR_ENTRY *trp, UINT64 ifa, UINT64 rid) +static inline int vcpu_match_tr_entry(TR_ENTRY * trp, u64 ifa, u64 rid) { return trp->pte.p && vcpu_match_tr_entry_no_p(trp, ifa, rid); } static inline int -vcpu_match_tr_entry_range(TR_ENTRY *trp, UINT64 rid, u64 b, u64 e) +vcpu_match_tr_entry_range(TR_ENTRY * trp, u64 rid, u64 b, u64 e) { return trp->rid == rid - && trp->pte.p - && range_overlap (b, e, - trp->vadr, trp->vadr + (1L << trp->ps) - 1); + && trp->pte.p + && range_overlap(b, e, trp->vadr, trp->vadr + (1L << trp->ps) - 1); } -static TR_ENTRY* -vcpu_tr_lookup(VCPU* vcpu, unsigned long va, UINT64 rid, BOOLEAN is_data) +static TR_ENTRY *vcpu_tr_lookup(VCPU * vcpu, unsigned long va, u64 rid, + BOOLEAN is_data) { - unsigned char* regions; + unsigned char *regions; TR_ENTRY *trp; int tr_max; int i; @@ -1359,12 +1486,12 @@ vcpu_tr_lookup(VCPU* vcpu, unsigned long va, UINT64 rid, BOOLEAN is_data) // data regions = &vcpu->arch.dtr_regions; trp = vcpu->arch.dtrs; - tr_max = sizeof(vcpu->arch.dtrs)/sizeof(vcpu->arch.dtrs[0]); + tr_max = sizeof(vcpu->arch.dtrs) / sizeof(vcpu->arch.dtrs[0]); } else { // instruction regions = &vcpu->arch.itr_regions; trp = vcpu->arch.itrs; - tr_max = sizeof(vcpu->arch.itrs)/sizeof(vcpu->arch.itrs[0]); + tr_max = sizeof(vcpu->arch.itrs) / sizeof(vcpu->arch.itrs[0]); } if (!vcpu_quick_region_check(*regions, va)) { @@ -1382,13 +1509,14 @@ vcpu_tr_lookup(VCPU* vcpu, unsigned long va, UINT64 rid, BOOLEAN is_data) // 0: failure // 1: success int -vcpu_get_domain_bundle(VCPU* vcpu, REGS* regs, UINT64 gip, IA64_BUNDLE* bundle) +vcpu_get_domain_bundle(VCPU * vcpu, REGS * regs, u64 gip, + IA64_BUNDLE * bundle) { - UINT64 gpip;// guest pseudo phyiscal ip + u64 gpip; // guest pseudo phyiscal ip unsigned long vaddr; - struct page_info* page; + struct page_info *page; -again: + again: #if 0 // Currently xen doesn't track psr.it bits. // it assumes always psr.it = 1. @@ -1401,7 +1529,7 @@ again: unsigned long rr = PSCB(vcpu, rrs)[region]; unsigned long rid = rr & RR_RID_MASK; BOOLEAN swap_rr0; - TR_ENTRY* trp; + TR_ENTRY *trp; // vcpu->arch.{i, d}tlb are volatile, // copy its value to the variable, tr, before use. @@ -1416,7 +1544,8 @@ again: // Last itc.i value is cached to PSCBX(vcpu, itlb). tr = PSCBX(vcpu, itlb); if (vcpu_match_tr_entry(&tr, gip, rid)) { - //DPRINTK("%s gip 0x%lx gpip 0x%lx\n", __func__, gip, gpip); + //DPRINTK("%s gip 0x%lx gpip 0x%lx\n", __func__, + // gip, gpip); goto found; } trp = vcpu_tr_lookup(vcpu, gip, rid, 1); @@ -1446,43 +1575,43 @@ again: return 0; } return 1; - + found: gpip = ((tr.pte.ppn >> (tr.ps - 12)) << tr.ps) | (gip & ((1 << tr.ps) - 1)); } - + vaddr = (unsigned long)domain_mpa_to_imva(vcpu->domain, gpip); page = virt_to_page(vaddr); if (get_page(page, vcpu->domain) == 0) { if (page_get_owner(page) != vcpu->domain) { // This page might be a page granted by another // domain. - panic_domain(regs, - "domain tries to execute foreign domain " - "page which might be mapped by grant " - "table.\n"); + panic_domain(regs, "domain tries to execute foreign " + "domain page which might be mapped by " + "grant table.\n"); } goto again; } - *bundle = *((IA64_BUNDLE*)vaddr); + *bundle = *((IA64_BUNDLE *) vaddr); put_page(page); return 1; } -IA64FAULT vcpu_translate(VCPU *vcpu, UINT64 address, BOOLEAN is_data, UINT64 *pteval, UINT64 *itir, UINT64 *iha) +IA64FAULT vcpu_translate(VCPU * vcpu, u64 address, BOOLEAN is_data, + u64 * pteval, u64 * itir, u64 * iha) { unsigned long region = address >> 61; unsigned long pta, rid, rr; union pte_flags pte; TR_ENTRY *trp; - if (PSCB(vcpu,metaphysical_mode) && !(!is_data && region)) { + if (PSCB(vcpu, metaphysical_mode) && !(!is_data && region)) { // dom0 may generate an uncacheable physical address (msb=1) if (region && ((region != 4) || (vcpu->domain != dom0))) { // FIXME: This seems to happen even though it shouldn't. Need to track // this down, but since it has been apparently harmless, just flag it for now -// panic_domain(vcpu_regs(vcpu), +// panic_domain(vcpu_regs(vcpu), /* * Guest may execute itc.d and rfi with psr.dt=0 @@ -1490,29 +1619,29 @@ IA64FAULT vcpu_translate(VCPU *vcpu, UINT64 address, BOOLEAN is_data, UINT64 *pt * At this time PSCB(vcpu,metaphysical_mode)=1, * region=5,VMM need to handle this tlb miss as if * PSCB(vcpu,metaphysical_mode)=0 - */ - printk("vcpu_translate: bad physical address: 0x%lx at %lx\n", - address, vcpu_regs (vcpu)->cr_iip); + */ + printk("vcpu_translate: bad physical address: 0x%lx " + "at %lx\n", address, vcpu_regs(vcpu)->cr_iip); } else { - *pteval = (address & _PAGE_PPN_MASK) | __DIRTY_BITS | - _PAGE_PL_2 | _PAGE_AR_RWX; + *pteval = (address & _PAGE_PPN_MASK) | + __DIRTY_BITS | _PAGE_PL_2 | _PAGE_AR_RWX; *itir = PAGE_SHIFT << 2; perfc_incrc(phys_translate); return IA64_NO_FAULT; } - } - else if (!region && warn_region0_address) { + } else if (!region && warn_region0_address) { REGS *regs = vcpu_regs(vcpu); - unsigned long viip = PSCB(vcpu,iip); - unsigned long vipsr = PSCB(vcpu,ipsr); + unsigned long viip = PSCB(vcpu, iip); + unsigned long vipsr = PSCB(vcpu, ipsr); unsigned long iip = regs->cr_iip; unsigned long ipsr = regs->cr_ipsr; - printk("vcpu_translate: bad address 0x%lx, viip=0x%lx, vipsr=0x%lx, iip=0x%lx, ipsr=0x%lx continuing\n", - address, viip, vipsr, iip, ipsr); + printk("vcpu_translate: bad address 0x%lx, viip=0x%lx, " + "vipsr=0x%lx, iip=0x%lx, ipsr=0x%lx continuing\n", + address, viip, vipsr, iip, ipsr); } - rr = PSCB(vcpu,rrs)[region]; + rr = PSCB(vcpu, rrs)[region]; rid = rr & RR_RID_MASK; if (is_data) { trp = vcpu_tr_lookup(vcpu, address, rid, 1); @@ -1524,7 +1653,7 @@ IA64FAULT vcpu_translate(VCPU *vcpu, UINT64 address, BOOLEAN is_data, UINT64 *pt } } // FIXME?: check itr's for data accesses too, else bad things happen? - /* else */ { + /* else */ { trp = vcpu_tr_lookup(vcpu, address, rid, 0); if (trp != NULL) { *pteval = trp->pte.val; @@ -1538,8 +1667,8 @@ IA64FAULT vcpu_translate(VCPU *vcpu, UINT64 address, BOOLEAN is_data, UINT64 *pt // FIXME?: check dtlb for inst accesses too, else bad things happen? trp = &vcpu->arch.dtlb; pte = trp->pte; - if (/* is_data && */ pte.p - && vcpu_match_tr_entry_no_p(trp,address,rid)) { + if ( /* is_data && */ pte.p + && vcpu_match_tr_entry_no_p(trp, address, rid)) { *pteval = pte.val; *itir = trp->itir; perfc_incrc(dtlb_translate); @@ -1547,10 +1676,10 @@ IA64FAULT vcpu_translate(VCPU *vcpu, UINT64 address, BOOLEAN is_data, UINT64 *pt } /* check guest VHPT */ - pta = PSCB(vcpu,pta); + pta = PSCB(vcpu, pta); if (pta & IA64_PTA_VF) { /* long format VHPT - not implemented */ - panic_domain(vcpu_regs(vcpu),"can't do long format VHPT\n"); - //return (is_data ? IA64_DATA_TLB_VECTOR:IA64_INST_TLB_VECTOR); + panic_domain(vcpu_regs(vcpu), "can't do long format VHPT\n"); + //return is_data ? IA64_DATA_TLB_VECTOR:IA64_INST_TLB_VECTOR; } *itir = rr & (RR_RID_MASK | RR_PS_MASK); @@ -1558,24 +1687,25 @@ IA64FAULT vcpu_translate(VCPU *vcpu, UINT64 address, BOOLEAN is_data, UINT64 *pt // xenlinux depends on it so should document it as part of PV interface vcpu_thash(vcpu, address, iha); if (!(rr & RR_VE_MASK) || !(pta & IA64_PTA_VE)) - return (is_data ? IA64_ALT_DATA_TLB_VECTOR : IA64_ALT_INST_TLB_VECTOR); + return is_data ? IA64_ALT_DATA_TLB_VECTOR : + IA64_ALT_INST_TLB_VECTOR; /* avoid recursively walking (short format) VHPT */ if (((address ^ pta) & ((itir_mask(pta) << 3) >> 3)) == 0) - return (is_data ? IA64_DATA_TLB_VECTOR : IA64_INST_TLB_VECTOR); + return is_data ? IA64_DATA_TLB_VECTOR : IA64_INST_TLB_VECTOR; - if (!__access_ok (*iha) + if (!__access_ok(*iha) || __copy_from_user(&pte, (void *)(*iha), sizeof(pte)) != 0) // virtual VHPT walker "missed" in TLB return IA64_VHPT_FAULT; /* - * Optimisation: this VHPT walker aborts on not-present pages - * instead of inserting a not-present translation, this allows - * vectoring directly to the miss handler. - */ + * Optimisation: this VHPT walker aborts on not-present pages + * instead of inserting a not-present translation, this allows + * vectoring directly to the miss handler. + */ if (!pte.p) - return (is_data ? IA64_DATA_TLB_VECTOR : IA64_INST_TLB_VECTOR); + return is_data ? IA64_DATA_TLB_VECTOR : IA64_INST_TLB_VECTOR; /* found mapping in guest VHPT! */ *itir = rr & RR_PS_MASK; @@ -1584,25 +1714,24 @@ IA64FAULT vcpu_translate(VCPU *vcpu, UINT64 address, BOOLEAN is_data, UINT64 *pt return IA64_NO_FAULT; } -IA64FAULT vcpu_tpa(VCPU *vcpu, UINT64 vadr, UINT64 *padr) +IA64FAULT vcpu_tpa(VCPU * vcpu, u64 vadr, u64 * padr) { - UINT64 pteval, itir, mask, iha; + u64 pteval, itir, mask, iha; IA64FAULT fault; fault = vcpu_translate(vcpu, vadr, TRUE, &pteval, &itir, &iha); - if (fault == IA64_NO_FAULT || fault == IA64_USE_TLB) - { + if (fault == IA64_NO_FAULT || fault == IA64_USE_TLB) { mask = itir_mask(itir); *padr = (pteval & _PAGE_PPN_MASK & mask) | (vadr & ~mask); - return (IA64_NO_FAULT); + return IA64_NO_FAULT; } - return vcpu_force_data_miss(vcpu,vadr); + return vcpu_force_data_miss(vcpu, vadr); } -IA64FAULT vcpu_tak(VCPU *vcpu, UINT64 vadr, UINT64 *key) +IA64FAULT vcpu_tak(VCPU * vcpu, u64 vadr, u64 * key) { printf("vcpu_tak: tak instruction unsupported\n"); - return (IA64_ILLOP_FAULT); + return IA64_ILLOP_FAULT; // HACK ALERT: tak does a thash for now //return vcpu_thash(vcpu,vadr,key); } @@ -1611,84 +1740,84 @@ IA64FAULT vcpu_tak(VCPU *vcpu, UINT64 vadr, UINT64 *key) VCPU debug breakpoint register access routines **************************************************************************/ -IA64FAULT vcpu_set_dbr(VCPU *vcpu, UINT64 reg, UINT64 val) +IA64FAULT vcpu_set_dbr(VCPU * vcpu, u64 reg, u64 val) { // TODO: unimplemented DBRs return a reserved register fault // TODO: Should set Logical CPU state, not just physical - ia64_set_dbr(reg,val); - return (IA64_NO_FAULT); + ia64_set_dbr(reg, val); + return IA64_NO_FAULT; } -IA64FAULT vcpu_set_ibr(VCPU *vcpu, UINT64 reg, UINT64 val) +IA64FAULT vcpu_set_ibr(VCPU * vcpu, u64 reg, u64 val) { // TODO: unimplemented IBRs return a reserved register fault // TODO: Should set Logical CPU state, not just physical - ia64_set_ibr(reg,val); - return (IA64_NO_FAULT); + ia64_set_ibr(reg, val); + return IA64_NO_FAULT; } -IA64FAULT vcpu_get_dbr(VCPU *vcpu, UINT64 reg, UINT64 *pval) +IA64FAULT vcpu_get_dbr(VCPU * vcpu, u64 reg, u64 * pval) { // TODO: unimplemented DBRs return a reserved register fault - UINT64 val = ia64_get_dbr(reg); + u64 val = ia64_get_dbr(reg); *pval = val; - return (IA64_NO_FAULT); + return IA64_NO_FAULT; } -IA64FAULT vcpu_get_ibr(VCPU *vcpu, UINT64 reg, UINT64 *pval) +IA64FAULT vcpu_get_ibr(VCPU * vcpu, u64 reg, u64 * pval) { // TODO: unimplemented IBRs return a reserved register fault - UINT64 val = ia64_get_ibr(reg); + u64 val = ia64_get_ibr(reg); *pval = val; - return (IA64_NO_FAULT); + return IA64_NO_FAULT; } /************************************************************************** VCPU performance monitor register access routines **************************************************************************/ -IA64FAULT vcpu_set_pmc(VCPU *vcpu, UINT64 reg, UINT64 val) +IA64FAULT vcpu_set_pmc(VCPU * vcpu, u64 reg, u64 val) { // TODO: Should set Logical CPU state, not just physical // NOTE: Writes to unimplemented PMC registers are discarded #ifdef DEBUG_PFMON -printf("vcpu_set_pmc(%x,%lx)\n",reg,val); + printf("vcpu_set_pmc(%x,%lx)\n", reg, val); #endif - ia64_set_pmc(reg,val); - return (IA64_NO_FAULT); + ia64_set_pmc(reg, val); + return IA64_NO_FAULT; } -IA64FAULT vcpu_set_pmd(VCPU *vcpu, UINT64 reg, UINT64 val) +IA64FAULT vcpu_set_pmd(VCPU * vcpu, u64 reg, u64 val) { // TODO: Should set Logical CPU state, not just physical // NOTE: Writes to unimplemented PMD registers are discarded #ifdef DEBUG_PFMON -printf("vcpu_set_pmd(%x,%lx)\n",reg,val); + printf("vcpu_set_pmd(%x,%lx)\n", reg, val); #endif - ia64_set_pmd(reg,val); - return (IA64_NO_FAULT); + ia64_set_pmd(reg, val); + return IA64_NO_FAULT; } -IA64FAULT vcpu_get_pmc(VCPU *vcpu, UINT64 reg, UINT64 *pval) +IA64FAULT vcpu_get_pmc(VCPU * vcpu, u64 reg, u64 * pval) { // NOTE: Reads from unimplemented PMC registers return zero - UINT64 val = (UINT64)ia64_get_pmc(reg); + u64 val = (u64) ia64_get_pmc(reg); #ifdef DEBUG_PFMON -printf("%lx=vcpu_get_pmc(%x)\n",val,reg); + printf("%lx=vcpu_get_pmc(%x)\n", val, reg); #endif *pval = val; - return (IA64_NO_FAULT); + return IA64_NO_FAULT; } -IA64FAULT vcpu_get_pmd(VCPU *vcpu, UINT64 reg, UINT64 *pval) +IA64FAULT vcpu_get_pmd(VCPU * vcpu, u64 reg, u64 * pval) { // NOTE: Reads from unimplemented PMD registers return zero - UINT64 val = (UINT64)ia64_get_pmd(reg); + u64 val = (u64) ia64_get_pmd(reg); #ifdef DEBUG_PFMON -printf("%lx=vcpu_get_pmd(%x)\n",val,reg); + printf("%lx=vcpu_get_pmd(%x)\n", val, reg); #endif *pval = val; - return (IA64_NO_FAULT); + return IA64_NO_FAULT; } /************************************************************************** @@ -1707,167 +1836,183 @@ do{ \ "r"(runat),"i"(IA64_PT_REGS_R16_SLOT):"memory"); \ }while(0) -IA64FAULT vcpu_bsw0(VCPU *vcpu) +IA64FAULT vcpu_bsw0(VCPU * vcpu) { // TODO: Only allowed for current vcpu REGS *regs = vcpu_regs(vcpu); unsigned long *r = ®s->r16; - unsigned long *b0 = &PSCB(vcpu,bank0_regs[0]); - unsigned long *b1 = &PSCB(vcpu,bank1_regs[0]); + unsigned long *b0 = &PSCB(vcpu, bank0_regs[0]); + unsigned long *b1 = &PSCB(vcpu, bank1_regs[0]); unsigned long *runat = ®s->eml_unat; - unsigned long *b0unat = &PSCB(vcpu,vbnat); - unsigned long *b1unat = &PSCB(vcpu,vnat); + unsigned long *b0unat = &PSCB(vcpu, vbnat); + unsigned long *b1unat = &PSCB(vcpu, vnat); unsigned long i; - if(VMX_DOMAIN(vcpu)){ - if(VCPU(vcpu,vpsr)&IA64_PSR_BN){ - for (i = 0; i < 16; i++) { *b1++ = *r; *r++ = *b0++; } - vcpu_bsw0_unat(i,b0unat,b1unat,runat,IA64_PT_REGS_R16_SLOT); - VCPU(vcpu,vpsr) &= ~IA64_PSR_BN; - } - }else{ - if (PSCB(vcpu,banknum)) { - for (i = 0; i < 16; i++) { *b1++ = *r; *r++ = *b0++; } - vcpu_bsw0_unat(i,b0unat,b1unat,runat,IA64_PT_REGS_R16_SLOT); - PSCB(vcpu,banknum) = 0; - } - } - return (IA64_NO_FAULT); -} - -#define vcpu_bsw1_unat(i,b0unat,b1unat,runat,IA64_PT_REGS_R16_SLOT) \ -do{ \ - __asm__ __volatile__ ( \ - ";;extr.u %0 = %3,%6,16;;\n" \ - "dep %1 = %0, %1, 16, 16;;\n" \ - "st8 [%4] = %1\n" \ - "extr.u %0 = %2, 0, 16;;\n" \ - "dep %3 = %0, %3, %6, 16;;\n" \ - "st8 [%5] = %3\n" \ - ::"r"(i),"r"(*b0unat),"r"(*b1unat),"r"(*runat),"r"(b0unat), \ - "r"(runat),"i"(IA64_PT_REGS_R16_SLOT):"memory"); \ -}while(0) + if (VMX_DOMAIN(vcpu)) { + if (VCPU(vcpu, vpsr) & IA64_PSR_BN) { + for (i = 0; i < 16; i++) { + *b1++ = *r; + *r++ = *b0++; + } + vcpu_bsw0_unat(i, b0unat, b1unat, runat, + IA64_PT_REGS_R16_SLOT); + VCPU(vcpu, vpsr) &= ~IA64_PSR_BN; + } + } else { + if (PSCB(vcpu, banknum)) { + for (i = 0; i < 16; i++) { + *b1++ = *r; + *r++ = *b0++; + } + vcpu_bsw0_unat(i, b0unat, b1unat, runat, + IA64_PT_REGS_R16_SLOT); + PSCB(vcpu, banknum) = 0; + } + } + return IA64_NO_FAULT; +} + +#define vcpu_bsw1_unat(i, b0unat, b1unat, runat, IA64_PT_REGS_R16_SLOT) \ +do { \ + __asm__ __volatile__ (";;extr.u %0 = %3,%6,16;;\n" \ + "dep %1 = %0, %1, 16, 16;;\n" \ + "st8 [%4] = %1\n" \ + "extr.u %0 = %2, 0, 16;;\n" \ + "dep %3 = %0, %3, %6, 16;;\n" \ + "st8 [%5] = %3\n" \ + ::"r"(i), "r"(*b0unat), "r"(*b1unat), \ + "r"(*runat), "r"(b0unat), "r"(runat), \ + "i"(IA64_PT_REGS_R16_SLOT): "memory"); \ +} while(0) -IA64FAULT vcpu_bsw1(VCPU *vcpu) +IA64FAULT vcpu_bsw1(VCPU * vcpu) { // TODO: Only allowed for current vcpu REGS *regs = vcpu_regs(vcpu); unsigned long *r = ®s->r16; - unsigned long *b0 = &PSCB(vcpu,bank0_regs[0]); - unsigned long *b1 = &PSCB(vcpu,bank1_regs[0]); + unsigned long *b0 = &PSCB(vcpu, bank0_regs[0]); + unsigned long *b1 = &PSCB(vcpu, bank1_regs[0]); unsigned long *runat = ®s->eml_unat; - unsigned long *b0unat = &PSCB(vcpu,vbnat); - unsigned long *b1unat = &PSCB(vcpu,vnat); + unsigned long *b0unat = &PSCB(vcpu, vbnat); + unsigned long *b1unat = &PSCB(vcpu, vnat); unsigned long i; - if(VMX_DOMAIN(vcpu)){ - if(!(VCPU(vcpu,vpsr)&IA64_PSR_BN)){ - for (i = 0; i < 16; i++) { *b0++ = *r; *r++ = *b1++; } - vcpu_bsw1_unat(i,b0unat,b1unat,runat,IA64_PT_REGS_R16_SLOT); - VCPU(vcpu,vpsr) |= IA64_PSR_BN; - } - }else{ - if (!PSCB(vcpu,banknum)) { - for (i = 0; i < 16; i++) { *b0++ = *r; *r++ = *b1++; } - vcpu_bsw1_unat(i,b0unat,b1unat,runat,IA64_PT_REGS_R16_SLOT); - PSCB(vcpu,banknum) = 1; - } - } - return (IA64_NO_FAULT); + if (VMX_DOMAIN(vcpu)) { + if (!(VCPU(vcpu, vpsr) & IA64_PSR_BN)) { + for (i = 0; i < 16; i++) { + *b0++ = *r; + *r++ = *b1++; + } + vcpu_bsw1_unat(i, b0unat, b1unat, runat, + IA64_PT_REGS_R16_SLOT); + VCPU(vcpu, vpsr) |= IA64_PSR_BN; + } + } else { + if (!PSCB(vcpu, banknum)) { + for (i = 0; i < 16; i++) { + *b0++ = *r; + *r++ = *b1++; + } + vcpu_bsw1_unat(i, b0unat, b1unat, runat, + IA64_PT_REGS_R16_SLOT); + PSCB(vcpu, banknum) = 1; + } + } + return IA64_NO_FAULT; } /************************************************************************** VCPU cpuid access routines **************************************************************************/ - -IA64FAULT vcpu_get_cpuid(VCPU *vcpu, UINT64 reg, UINT64 *pval) +IA64FAULT vcpu_get_cpuid(VCPU * vcpu, u64 reg, u64 * pval) { // FIXME: This could get called as a result of a rsvd-reg fault // if reg > 3 - switch(reg) { - case 0: - memcpy(pval,"Xen/ia64",8); + switch (reg) { + case 0: + memcpy(pval, "Xen/ia64", 8); break; - case 1: + case 1: *pval = 0; break; - case 2: + case 2: *pval = 0; break; - case 3: + case 3: *pval = ia64_get_cpuid(3); break; - case 4: + case 4: *pval = ia64_get_cpuid(4); break; - default: + default: if (reg > (ia64_get_cpuid(3) & 0xff)) return IA64_RSVDREG_FAULT; *pval = ia64_get_cpuid(reg); break; } - return (IA64_NO_FAULT); + return IA64_NO_FAULT; } /************************************************************************** VCPU region register access routines **************************************************************************/ -unsigned long vcpu_get_rr_ve(VCPU *vcpu,UINT64 vadr) +unsigned long vcpu_get_rr_ve(VCPU * vcpu, u64 vadr) { ia64_rr rr; - rr.rrval = PSCB(vcpu,rrs)[vadr>>61]; - return(rr.ve); + rr.rrval = PSCB(vcpu, rrs)[vadr >> 61]; + return rr.ve; } -IA64FAULT vcpu_set_rr(VCPU *vcpu, UINT64 reg, UINT64 val) +IA64FAULT vcpu_set_rr(VCPU * vcpu, u64 reg, u64 val) { - PSCB(vcpu,rrs)[reg>>61] = val; + PSCB(vcpu, rrs)[reg >> 61] = val; // warning: set_one_rr() does it "live" - set_one_rr(reg,val); - return (IA64_NO_FAULT); + set_one_rr(reg, val); + return IA64_NO_FAULT; } -IA64FAULT vcpu_get_rr(VCPU *vcpu, UINT64 reg, UINT64 *pval) +IA64FAULT vcpu_get_rr(VCPU * vcpu, u64 reg, u64 * pval) { - if(VMX_DOMAIN(vcpu)){ - *pval = VMX(vcpu,vrr[reg>>61]); - }else{ - *pval = PSCB(vcpu,rrs)[reg>>61]; - } - return (IA64_NO_FAULT); + if (VMX_DOMAIN(vcpu)) + *pval = VMX(vcpu, vrr[reg >> 61]); + else + *pval = PSCB(vcpu, rrs)[reg >> 61]; + + return IA64_NO_FAULT; } /************************************************************************** VCPU protection key register access routines **************************************************************************/ -IA64FAULT vcpu_get_pkr(VCPU *vcpu, UINT64 reg, UINT64 *pval) +IA64FAULT vcpu_get_pkr(VCPU * vcpu, u64 reg, u64 * pval) { #ifndef PKR_USE_FIXED printk("vcpu_get_pkr: called, not implemented yet\n"); return IA64_ILLOP_FAULT; #else - UINT64 val = (UINT64)ia64_get_pkr(reg); + u64 val = (u64) ia64_get_pkr(reg); *pval = val; - return (IA64_NO_FAULT); + return IA64_NO_FAULT; #endif } -IA64FAULT vcpu_set_pkr(VCPU *vcpu, UINT64 reg, UINT64 val) +IA64FAULT vcpu_set_pkr(VCPU * vcpu, u64 reg, u64 val) { #ifndef PKR_USE_FIXED printk("vcpu_set_pkr: called, not implemented yet\n"); return IA64_ILLOP_FAULT; #else -// if (reg >= NPKRS) return (IA64_ILLOP_FAULT); +// if (reg >= NPKRS) +// return IA64_ILLOP_FAULT; vcpu->pkrs[reg] = val; - ia64_set_pkr(reg,val); - return (IA64_NO_FAULT); + ia64_set_pkr(reg, val); + return IA64_NO_FAULT; #endif } @@ -1876,21 +2021,22 @@ IA64FAULT vcpu_set_pkr(VCPU *vcpu, UINT64 reg, UINT64 val) **************************************************************************/ static void -vcpu_set_tr_entry_rid(TR_ENTRY *trp, UINT64 pte, - UINT64 itir, UINT64 ifa, UINT64 rid) +vcpu_set_tr_entry_rid(TR_ENTRY * trp, u64 pte, + u64 itir, u64 ifa, u64 rid) { - UINT64 ps; + u64 ps; union pte_flags new_pte; trp->itir = itir; trp->rid = rid; ps = trp->ps; new_pte.val = pte; - if (new_pte.pl < 2) new_pte.pl = 2; + if (new_pte.pl < 2) + new_pte.pl = 2; trp->vadr = ifa & ~0xfff; - if (ps > 12) { // "ignore" relevant low-order bits - new_pte.ppn &= ~((1UL<<(ps-12))-1); - trp->vadr &= ~((1UL<<ps)-1); + if (ps > 12) { // "ignore" relevant low-order bits + new_pte.ppn &= ~((1UL << (ps - 12)) - 1); + trp->vadr &= ~((1UL << ps) - 1); } /* Atomic write. */ @@ -1898,25 +2044,26 @@ vcpu_set_tr_entry_rid(TR_ENTRY *trp, UINT64 pte, } static inline void -vcpu_set_tr_entry(TR_ENTRY *trp, UINT64 pte, UINT64 itir, UINT64 ifa) +vcpu_set_tr_entry(TR_ENTRY * trp, u64 pte, u64 itir, u64 ifa) { vcpu_set_tr_entry_rid(trp, pte, itir, ifa, - VCPU(current, rrs[ifa>>61]) & RR_RID_MASK); + VCPU(current, rrs[ifa >> 61]) & RR_RID_MASK); } -IA64FAULT vcpu_itr_d(VCPU *vcpu, UINT64 slot, UINT64 pte, - UINT64 itir, UINT64 ifa) +IA64FAULT vcpu_itr_d(VCPU * vcpu, u64 slot, u64 pte, + u64 itir, u64 ifa) { TR_ENTRY *trp; - if (slot >= NDTRS) return IA64_RSVDREG_FAULT; + if (slot >= NDTRS) + return IA64_RSVDREG_FAULT; vcpu_purge_tr_entry(&PSCBX(vcpu, dtlb)); - trp = &PSCBX(vcpu,dtrs[slot]); + trp = &PSCBX(vcpu, dtrs[slot]); //printf("***** itr.d: setting slot %d: ifa=%p\n",slot,ifa); - vcpu_set_tr_entry(trp,pte,itir,ifa); - vcpu_quick_region_set(PSCBX(vcpu,dtr_regions),ifa); + vcpu_set_tr_entry(trp, pte, itir, ifa); + vcpu_quick_region_set(PSCBX(vcpu, dtr_regions), ifa); /* * FIXME According to spec, vhpt should be purged, but this @@ -1930,19 +2077,20 @@ IA64FAULT vcpu_itr_d(VCPU *vcpu, UINT64 slot, UINT64 pte, return IA64_NO_FAULT; } -IA64FAULT vcpu_itr_i(VCPU *vcpu, UINT64 slot, UINT64 pte, - UINT64 itir, UINT64 ifa) +IA64FAULT vcpu_itr_i(VCPU * vcpu, u64 slot, u64 pte, + u64 itir, u64 ifa) { TR_ENTRY *trp; - if (slot >= NITRS) return IA64_RSVDREG_FAULT; + if (slot >= NITRS) + return IA64_RSVDREG_FAULT; vcpu_purge_tr_entry(&PSCBX(vcpu, itlb)); - trp = &PSCBX(vcpu,itrs[slot]); + trp = &PSCBX(vcpu, itrs[slot]); //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); + vcpu_set_tr_entry(trp, pte, itir, ifa); + vcpu_quick_region_set(PSCBX(vcpu, itr_regions), ifa); /* * FIXME According to spec, vhpt should be purged, but this @@ -1956,13 +2104,13 @@ IA64FAULT vcpu_itr_i(VCPU *vcpu, UINT64 slot, UINT64 pte, return IA64_NO_FAULT; } -IA64FAULT vcpu_set_itr(VCPU *vcpu, u64 slot, u64 pte, +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; + return IA64_RSVDREG_FAULT; trp = &PSCBX(vcpu, itrs[slot]); vcpu_set_tr_entry_rid(trp, pte, itir, ifa, rid); @@ -1975,7 +2123,7 @@ IA64FAULT vcpu_set_itr(VCPU *vcpu, u64 slot, u64 pte, return IA64_NO_FAULT; } -IA64FAULT vcpu_set_dtr(VCPU *vcpu, u64 slot, u64 pte, +IA64FAULT vcpu_set_dtr(VCPU * vcpu, u64 slot, u64 pte, u64 itir, u64 ifa, u64 rid) { TR_ENTRY *trp; @@ -1998,63 +2146,72 @@ IA64FAULT vcpu_set_dtr(VCPU *vcpu, u64 slot, u64 pte, VCPU translation cache access routines **************************************************************************/ -void vcpu_itc_no_srlz(VCPU *vcpu, UINT64 IorD, UINT64 vaddr, UINT64 pte, UINT64 mp_pte, UINT64 logps) +void +vcpu_itc_no_srlz(VCPU * vcpu, u64 IorD, u64 vaddr, u64 pte, + u64 mp_pte, u64 logps, struct p2m_entry *entry) { unsigned long psr; - unsigned long ps = (vcpu->domain==dom0) ? logps : PAGE_SHIFT; + unsigned long ps = (vcpu->domain == dom0) ? logps : PAGE_SHIFT; - check_xen_space_overlap ("itc", vaddr, 1UL << logps); + check_xen_space_overlap("itc", vaddr, 1UL << logps); // FIXME, must be inlined or potential for nested fault here! - if ((vcpu->domain==dom0) && (logps < PAGE_SHIFT)) - panic_domain (NULL, "vcpu_itc_no_srlz: domain trying to use " - "smaller page size!\n"); + if ((vcpu->domain == dom0) && (logps < PAGE_SHIFT)) + panic_domain(NULL, "vcpu_itc_no_srlz: domain trying to use " + "smaller page size!\n"); BUG_ON(logps > PAGE_SHIFT); + vcpu_tlb_track_insert_or_dirty(vcpu, vaddr, entry); psr = ia64_clear_ic(); - ia64_itc(IorD,vaddr,pte,ps); // FIXME: look for bigger mappings + ia64_itc(IorD, vaddr, pte, ps); // FIXME: look for bigger mappings ia64_set_psr(psr); // ia64_srlz_i(); // no srls req'd, will rfi later #ifdef VHPT_GLOBAL - if (vcpu->domain==dom0 && ((vaddr >> 61) == 7)) { + if (vcpu->domain == dom0 && ((vaddr >> 61) == 7)) { // FIXME: this is dangerous... vhpt_flush_address ensures these // addresses never get flushed. More work needed if this // ever happens. //printf("vhpt_insert(%p,%p,%p)\n",vaddr,pte,1L<<logps); - if (logps > PAGE_SHIFT) vhpt_multiple_insert(vaddr,pte,logps); - else vhpt_insert(vaddr,pte,logps<<2); + if (logps > PAGE_SHIFT) + vhpt_multiple_insert(vaddr, pte, logps); + else + vhpt_insert(vaddr, pte, logps << 2); } // even if domain pagesize is larger than PAGE_SIZE, just put // PAGE_SIZE mapping in the vhpt for now, else purging is complicated - else vhpt_insert(vaddr,pte,PAGE_SHIFT<<2); + else + vhpt_insert(vaddr, pte, PAGE_SHIFT << 2); #endif - if ((mp_pte == -1UL) || (IorD & 0x4)) // don't place in 1-entry TLB + if (IorD & 0x4) /* don't place in 1-entry TLB */ return; if (IorD & 0x1) { - vcpu_set_tr_entry(&PSCBX(vcpu,itlb),mp_pte,ps<<2,vaddr); + vcpu_set_tr_entry(&PSCBX(vcpu, itlb), mp_pte, ps << 2, vaddr); } if (IorD & 0x2) { - vcpu_set_tr_entry(&PSCBX(vcpu,dtlb),mp_pte,ps<<2,vaddr); + vcpu_set_tr_entry(&PSCBX(vcpu, dtlb), mp_pte, ps << 2, vaddr); } } -IA64FAULT vcpu_itc_d(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa) +IA64FAULT vcpu_itc_d(VCPU * vcpu, u64 pte, u64 itir, u64 ifa) { unsigned long pteval, logps = itir_ps(itir); - BOOLEAN swap_rr0 = (!(ifa>>61) && PSCB(vcpu,metaphysical_mode)); + BOOLEAN swap_rr0 = (!(ifa >> 61) && PSCB(vcpu, metaphysical_mode)); struct p2m_entry entry; if (logps < PAGE_SHIFT) - panic_domain (NULL, "vcpu_itc_d: domain trying to use " - "smaller page size!\n"); + panic_domain(NULL, "vcpu_itc_d: domain trying to use " + "smaller page size!\n"); -again: + again: //itir = (itir & ~0xfc) | (PAGE_SHIFT<<2); // ignore domain's pagesize pteval = translate_domain_pte(pte, ifa, itir, &logps, &entry); - if (!pteval) return IA64_ILLOP_FAULT; - if (swap_rr0) set_one_rr(0x0,PSCB(vcpu,rrs[0])); - vcpu_itc_no_srlz(vcpu,2,ifa,pteval,pte,logps); - if (swap_rr0) set_metaphysical_rr0(); + if (!pteval) + return IA64_ILLOP_FAULT; + if (swap_rr0) + set_one_rr(0x0, PSCB(vcpu, rrs[0])); + vcpu_itc_no_srlz(vcpu, 2, ifa, pteval, pte, logps, &entry); + if (swap_rr0) + set_metaphysical_rr0(); if (p2m_entry_retry(&entry)) { vcpu_flush_tlb_vhpt_range(ifa, logps); goto again; @@ -2062,22 +2219,25 @@ again: return IA64_NO_FAULT; } -IA64FAULT vcpu_itc_i(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa) +IA64FAULT vcpu_itc_i(VCPU * vcpu, u64 pte, u64 itir, u64 ifa) { unsigned long pteval, logps = itir_ps(itir); - BOOLEAN swap_rr0 = (!(ifa>>61) && PSCB(vcpu,metaphysical_mode)); + BOOLEAN swap_rr0 = (!(ifa >> 61) && PSCB(vcpu, metaphysical_mode)); struct p2m_entry entry; if (logps < PAGE_SHIFT) - panic_domain (NULL, "vcpu_itc_i: domain trying to use " - "smaller page size!\n"); -again: + panic_domain(NULL, "vcpu_itc_i: domain trying to use " + "smaller page size!\n"); + again: //itir = (itir & ~0xfc) | (PAGE_SHIFT<<2); // ignore domain's pagesize pteval = translate_domain_pte(pte, ifa, itir, &logps, &entry); - if (!pteval) return IA64_ILLOP_FAULT; - if (swap_rr0) set_one_rr(0x0,PSCB(vcpu,rrs[0])); - vcpu_itc_no_srlz(vcpu, 1,ifa,pteval,pte,logps); - if (swap_rr0) set_metaphysical_rr0(); + if (!pteval) + return IA64_ILLOP_FAULT; + if (swap_rr0) + set_one_rr(0x0, PSCB(vcpu, rrs[0])); + vcpu_itc_no_srlz(vcpu, 1, ifa, pteval, pte, logps, &entry); + if (swap_rr0) + set_metaphysical_rr0(); if (p2m_entry_retry(&entry)) { vcpu_flush_tlb_vhpt_range(ifa, logps); goto again; @@ -2085,18 +2245,18 @@ again: return IA64_NO_FAULT; } -IA64FAULT vcpu_ptc_l(VCPU *vcpu, UINT64 vadr, UINT64 log_range) +IA64FAULT vcpu_ptc_l(VCPU * vcpu, u64 vadr, u64 log_range) { BUG_ON(vcpu != current); - check_xen_space_overlap ("ptc_l", vadr, 1UL << log_range); + check_xen_space_overlap("ptc_l", vadr, 1UL << log_range); /* Purge TC */ - vcpu_purge_tr_entry(&PSCBX(vcpu,dtlb)); - vcpu_purge_tr_entry(&PSCBX(vcpu,itlb)); - + vcpu_purge_tr_entry(&PSCBX(vcpu, dtlb)); + vcpu_purge_tr_entry(&PSCBX(vcpu, itlb)); + /* Purge all tlb and vhpt */ - vcpu_flush_tlb_vhpt_range (vadr, log_range); + vcpu_flush_tlb_vhpt_range(vadr, log_range); return IA64_NO_FAULT; } @@ -2107,13 +2267,13 @@ IA64FAULT vcpu_ptc_l(VCPU *vcpu, UINT64 vadr, UINT64 log_range) // access rights fault, we have to translate the virtual address to a // physical address (possibly via a metaphysical address) and do the fc // on the physical address, which is guaranteed to flush the same cache line -IA64FAULT vcpu_fc(VCPU *vcpu, UINT64 vadr) +IA64FAULT vcpu_fc(VCPU * vcpu, u64 vadr) { // TODO: Only allowed for current vcpu - UINT64 mpaddr, paddr; + u64 mpaddr, paddr; IA64FAULT fault; -again: + again: fault = vcpu_tpa(vcpu, vadr, &mpaddr); if (fault == IA64_NO_FAULT) { struct p2m_entry entry; @@ -2125,7 +2285,7 @@ again: return fault; } -IA64FAULT vcpu_ptc_e(VCPU *vcpu, UINT64 vadr) +IA64FAULT vcpu_ptc_e(VCPU * vcpu, u64 vadr) { // Note that this only needs to be called once, i.e. the // architected loop to purge the entire TLB, should use @@ -2136,27 +2296,27 @@ IA64FAULT vcpu_ptc_e(VCPU *vcpu, UINT64 vadr) return IA64_NO_FAULT; } -IA64FAULT vcpu_ptc_g(VCPU *vcpu, UINT64 vadr, UINT64 addr_range) +IA64FAULT vcpu_ptc_g(VCPU * vcpu, u64 vadr, u64 addr_range) { printk("vcpu_ptc_g: called, not implemented yet\n"); return IA64_ILLOP_FAULT; } -IA64FAULT vcpu_ptc_ga(VCPU *vcpu,UINT64 vadr,UINT64 addr_range) +IA64FAULT vcpu_ptc_ga(VCPU * vcpu, u64 vadr, u64 addr_range) { // FIXME: validate not flushing Xen addresses // if (Xen address) return(IA64_ILLOP_FAULT); // FIXME: ??breaks if domain PAGE_SIZE < Xen PAGE_SIZE //printf("######## vcpu_ptc_ga(%p,%p) ##############\n",vadr,addr_range); - check_xen_space_overlap ("ptc_ga", vadr, addr_range); + check_xen_space_overlap("ptc_ga", vadr, addr_range); - domain_flush_vtlb_range (vcpu->domain, vadr, addr_range); + domain_flush_vtlb_range(vcpu->domain, vadr, addr_range); return IA64_NO_FAULT; } -IA64FAULT vcpu_ptr_d(VCPU *vcpu,UINT64 vadr,UINT64 log_range) +IA64FAULT vcpu_ptr_d(VCPU * vcpu, u64 vadr, u64 log_range) { unsigned long region = vadr >> 61; u64 addr_range = 1UL << log_range; @@ -2165,29 +2325,30 @@ IA64FAULT vcpu_ptr_d(VCPU *vcpu,UINT64 vadr,UINT64 log_range) TR_ENTRY *trp; BUG_ON(vcpu != current); - check_xen_space_overlap ("ptr_d", vadr, 1UL << log_range); + check_xen_space_overlap("ptr_d", vadr, 1UL << log_range); - rr = PSCB(vcpu,rrs)[region]; + rr = PSCB(vcpu, rrs)[region]; rid = rr & RR_RID_MASK; /* Purge TC */ - vcpu_purge_tr_entry(&PSCBX(vcpu,dtlb)); + vcpu_purge_tr_entry(&PSCBX(vcpu, dtlb)); /* Purge tr and recompute dtr_regions. */ vcpu->arch.dtr_regions = 0; for (trp = vcpu->arch.dtrs, i = NDTRS; i; i--, trp++) - if (vcpu_match_tr_entry_range (trp,rid, vadr, vadr+addr_range)) + if (vcpu_match_tr_entry_range + (trp, rid, vadr, vadr + addr_range)) vcpu_purge_tr_entry(trp); else if (trp->pte.p) vcpu_quick_region_set(vcpu->arch.dtr_regions, trp->vadr); - vcpu_flush_tlb_vhpt_range (vadr, log_range); + vcpu_flush_tlb_vhpt_range(vadr, log_range); return IA64_NO_FAULT; } -IA64FAULT vcpu_ptr_i(VCPU *vcpu,UINT64 vadr,UINT64 log_range) +IA64FAULT vcpu_ptr_i(VCPU * vcpu, u64 vadr, u64 log_range) { unsigned long region = vadr >> 61; u64 addr_range = 1UL << log_range; @@ -2196,49 +2357,25 @@ IA64FAULT vcpu_ptr_i(VCPU *vcpu,UINT64 vadr,UINT64 log_range) TR_ENTRY *trp; BUG_ON(vcpu != current); - check_xen_space_overlap ("ptr_i", vadr, 1UL << log_range); + check_xen_space_overlap("ptr_i", vadr, 1UL << log_range); - rr = PSCB(vcpu,rrs)[region]; + rr = PSCB(vcpu, rrs)[region]; rid = rr & RR_RID_MASK; /* Purge TC */ - vcpu_purge_tr_entry(&PSCBX(vcpu,itlb)); + vcpu_purge_tr_entry(&PSCBX(vcpu, itlb)); /* Purge tr and recompute itr_regions. */ vcpu->arch.itr_regions = 0; for (trp = vcpu->arch.itrs, i = NITRS; i; i--, trp++) - if (vcpu_match_tr_entry_range (trp,rid, vadr, vadr+addr_range)) + if (vcpu_match_tr_entry_range + (trp, rid, vadr, vadr + addr_range)) vcpu_purge_tr_entry(trp); else if (trp->pte.p) vcpu_quick_region_set(vcpu->arch.itr_regions, trp->vadr); - vcpu_flush_tlb_vhpt_range (vadr, log_range); + vcpu_flush_tlb_vhpt_range(vadr, log_range); return IA64_NO_FAULT; } - -int ia64_map_hypercall_param(void) -{ - struct vcpu *v = current; - struct domain *d = current->domain; - u64 vaddr = v->arch.hypercall_param.va & PAGE_MASK; - volatile pte_t* pte; - - if (v->arch.hypercall_param.va == 0) - return FALSE; - pte = lookup_noalloc_domain_pte(d, v->arch.hypercall_param.pa1); - if (!pte || !pte_present(*pte)) - return FALSE; - vcpu_itc_no_srlz(v, 2, vaddr, pte_val(*pte), -1UL, PAGE_SHIFT); - if (v->arch.hypercall_param.pa2) { - vaddr += PAGE_SIZE; - pte = lookup_noalloc_domain_pte(d, v->arch.hypercall_param.pa2); - if (pte && pte_present(*pte)) { - vcpu_itc_no_srlz(v, 2, vaddr, pte_val(*pte), - -1UL, PAGE_SHIFT); - } - } - ia64_srlz_d(); - return TRUE; -} diff --git a/xen/arch/ia64/xen/vhpt.c b/xen/arch/ia64/xen/vhpt.c index f8db5c6e17..5b9bd146bc 100644 --- a/xen/arch/ia64/xen/vhpt.c +++ b/xen/arch/ia64/xen/vhpt.c @@ -3,6 +3,10 @@ * * Copyright (C) 2004 Hewlett-Packard Co * Dan Magenheimer <dan.magenheimer@hp.com> + * + * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * per vcpu vhpt support */ #include <linux/config.h> #include <linux/kernel.h> @@ -14,28 +18,57 @@ #include <asm/page.h> #include <asm/vhpt.h> #include <asm/vcpu.h> +#include <asm/vcpumask.h> #include <asm/vmmu.h> /* Defined in tlb.c */ -extern void ia64_global_tlb_purge(UINT64 start, UINT64 end, UINT64 nbits); +extern void ia64_global_tlb_purge(u64 start, u64 end, u64 nbits); extern long running_on_sim; DEFINE_PER_CPU (unsigned long, vhpt_paddr); DEFINE_PER_CPU (unsigned long, vhpt_pend); +#ifdef CONFIG_XEN_IA64_TLBFLUSH_CLOCK +DEFINE_PER_CPU(volatile u32, vhpt_tlbflush_timestamp); +#endif -void vhpt_flush(void) +static void +__vhpt_flush(unsigned long vhpt_maddr) { - struct vhpt_lf_entry *v = __va(__ia64_per_cpu_var(vhpt_paddr)); + struct vhpt_lf_entry *v = (struct vhpt_lf_entry*)__va(vhpt_maddr); int i; for (i = 0; i < VHPT_NUM_ENTRIES; i++, v++) v->ti_tag = INVALID_TI_TAG; } -static void vhpt_erase(void) +void +local_vhpt_flush(void) +{ + /* increment flush clock before flush */ + u32 flush_time = tlbflush_clock_inc_and_return(); + __vhpt_flush(__ia64_per_cpu_var(vhpt_paddr)); + /* this must be after flush */ + tlbflush_update_time(&__get_cpu_var(vhpt_tlbflush_timestamp), + flush_time); + perfc_incrc(local_vhpt_flush); +} + +void +vcpu_vhpt_flush(struct vcpu* v) { - struct vhpt_lf_entry *v = (struct vhpt_lf_entry *)VHPT_ADDR; + /* increment flush clock before flush */ + u32 flush_time = tlbflush_clock_inc_and_return(); + __vhpt_flush(vcpu_vhpt_maddr(v)); + /* this must be after flush */ + tlbflush_update_time(&v->arch.tlbflush_timestamp, flush_time); + perfc_incrc(vcpu_vhpt_flush); +} + +static void +vhpt_erase(unsigned long vhpt_maddr) +{ + struct vhpt_lf_entry *v = (struct vhpt_lf_entry*)__va(vhpt_maddr); int i; for (i = 0; i < VHPT_NUM_ENTRIES; i++, v++) { @@ -47,17 +80,6 @@ static void vhpt_erase(void) // initialize cache too??? } - -static void vhpt_map(unsigned long pte) -{ - unsigned long psr; - - psr = ia64_clear_ic(); - ia64_itr(0x2, IA64_TR_VHPT, VHPT_ADDR, pte, VHPT_SIZE_LOG2); - ia64_set_psr(psr); - ia64_srlz_i(); -} - void vhpt_insert (unsigned long vadr, unsigned long pte, unsigned long logps) { struct vhpt_lf_entry *vlfe = (struct vhpt_lf_entry *)ia64_thash(vadr); @@ -102,7 +124,7 @@ void vhpt_multiple_insert(unsigned long vaddr, unsigned long pte, unsigned long void vhpt_init(void) { - unsigned long paddr, pte; + unsigned long paddr; struct page_info *page; #if !VHPT_ENABLED return; @@ -122,14 +144,83 @@ void vhpt_init(void) __get_cpu_var(vhpt_pend) = paddr + (1 << VHPT_SIZE_LOG2) - 1; printf("vhpt_init: vhpt paddr=0x%lx, end=0x%lx\n", paddr, __get_cpu_var(vhpt_pend)); - pte = pte_val(pfn_pte(paddr >> PAGE_SHIFT, PAGE_KERNEL)); - vhpt_map(pte); - ia64_set_pta(VHPT_ADDR | (1 << 8) | (VHPT_SIZE_LOG2 << 2) | - VHPT_ENABLED); - vhpt_erase(); + vhpt_erase(paddr); + // we don't enable VHPT here. + // context_switch() or schedule_tail() does it. +} + +#ifdef CONFIG_XEN_IA64_PERVCPU_VHPT +int +pervcpu_vhpt_alloc(struct vcpu *v) +{ + unsigned long vhpt_size_log2 = VHPT_SIZE_LOG2; + + v->arch.vhpt_entries = + (1UL << vhpt_size_log2) / sizeof(struct vhpt_lf_entry); + v->arch.vhpt_page = + alloc_domheap_pages(NULL, vhpt_size_log2 - PAGE_SHIFT, 0); + if (!v->arch.vhpt_page) + return -ENOMEM; + + v->arch.vhpt_maddr = page_to_maddr(v->arch.vhpt_page); + if (v->arch.vhpt_maddr & ((1 << VHPT_SIZE_LOG2) - 1)) + panic("pervcpu_vhpt_init: bad VHPT alignment!\n"); + + v->arch.pta.val = 0; // to zero reserved bits + v->arch.pta.ve = 1; // enable vhpt + v->arch.pta.size = VHPT_SIZE_LOG2; + v->arch.pta.vf = 1; // long format + v->arch.pta.base = __va_ul(v->arch.vhpt_maddr) >> 15; + + vhpt_erase(v->arch.vhpt_maddr); + smp_mb(); // per vcpu vhpt may be used by another physical cpu. + return 0; } +void +pervcpu_vhpt_free(struct vcpu *v) +{ + free_domheap_pages(v->arch.vhpt_page, VHPT_SIZE_LOG2 - PAGE_SHIFT); +} +#endif + +void +domain_purge_swtc_entries(struct domain *d) +{ + struct vcpu* v; + for_each_vcpu(d, v) { + if (!test_bit(_VCPUF_initialised, &v->vcpu_flags)) + continue; + + /* Purge TC entries. + FIXME: clear only if match. */ + vcpu_purge_tr_entry(&PSCBX(v,dtlb)); + vcpu_purge_tr_entry(&PSCBX(v,itlb)); + } +} + +void +domain_purge_swtc_entries_vcpu_dirty_mask(struct domain* d, + vcpumask_t vcpu_dirty_mask) +{ + int vcpu; + + for_each_vcpu_mask(vcpu, vcpu_dirty_mask) { + struct vcpu* v = d->vcpu[vcpu]; + if (!test_bit(_VCPUF_initialised, &v->vcpu_flags)) + continue; + + /* Purge TC entries. + FIXME: clear only if match. */ + vcpu_purge_tr_entry(&PSCBX(v, dtlb)); + vcpu_purge_tr_entry(&PSCBX(v, itlb)); + } +} +// SMP: we can't assume v == current, vcpu might move to another physical cpu. +// So memory barrier is necessary. +// if we can guranttee that vcpu can run on only this physical cpu +// (e.g. vcpu == current), smp_mb() is unnecessary. void vcpu_flush_vtlb_all(struct vcpu *v) { if (VMX_DOMAIN(v)) { @@ -137,6 +228,7 @@ void vcpu_flush_vtlb_all(struct vcpu *v) grant_table share page from guest_physmap_remove_page() in arch_memory_op() XENMEM_add_to_physmap to realize PV-on-HVM feature. */ + /* FIXME: This is not SMP-safe yet about p2m table */ /* Purge vTLB for VT-i domain */ thash_purge_all(v); } @@ -144,9 +236,14 @@ void vcpu_flush_vtlb_all(struct vcpu *v) /* First VCPU tlb. */ vcpu_purge_tr_entry(&PSCBX(v,dtlb)); vcpu_purge_tr_entry(&PSCBX(v,itlb)); + smp_mb(); /* Then VHPT. */ - vhpt_flush(); + if (HAS_PERVCPU_VHPT(v->domain)) + vcpu_vhpt_flush(v); + else + local_vhpt_flush(); + smp_mb(); /* Then mTLB. */ local_flush_tlb_all(); @@ -155,6 +252,8 @@ void vcpu_flush_vtlb_all(struct vcpu *v) /* We could clear bit in d->domain_dirty_cpumask only if domain d in not running on this processor. There is currently no easy way to check this. */ + + perfc_incrc(vcpu_flush_vtlb_all); } static void __vcpu_flush_vtlb_all(void *vcpu) @@ -174,32 +273,60 @@ void domain_flush_vtlb_all (void) if (v->processor == cpu) vcpu_flush_vtlb_all(v); else + // SMP: it is racy to reference v->processor. + // vcpu scheduler may move this vcpu to another + // physicall processor, and change the value + // using plain store. + // We may be seeing the old value of it. + // In such case, flush_vtlb_for_context_switch() + // takes care of mTLB flush. smp_call_function_single(v->processor, __vcpu_flush_vtlb_all, v, 1, 1); } + perfc_incrc(domain_flush_vtlb_all); } -static void cpu_flush_vhpt_range (int cpu, u64 vadr, u64 addr_range) +// Callers may need to call smp_mb() before/after calling this. +// Be carefull. +static void +__flush_vhpt_range(unsigned long vhpt_maddr, u64 vadr, u64 addr_range) { - void *vhpt_base = __va(per_cpu(vhpt_paddr, cpu)); + void *vhpt_base = __va(vhpt_maddr); while ((long)addr_range > 0) { /* Get the VHPT entry. */ - unsigned int off = ia64_thash(vadr) - VHPT_ADDR; - volatile struct vhpt_lf_entry *v; - v = vhpt_base + off; + unsigned int off = ia64_thash(vadr) - + __va_ul(vcpu_vhpt_maddr(current)); + struct vhpt_lf_entry *v = vhpt_base + off; v->ti_tag = INVALID_TI_TAG; addr_range -= PAGE_SIZE; vadr += PAGE_SIZE; } } +static void +cpu_flush_vhpt_range(int cpu, u64 vadr, u64 addr_range) +{ + __flush_vhpt_range(per_cpu(vhpt_paddr, cpu), vadr, addr_range); +} + +static void +vcpu_flush_vhpt_range(struct vcpu* v, u64 vadr, u64 addr_range) +{ + __flush_vhpt_range(vcpu_vhpt_maddr(v), vadr, addr_range); +} + void vcpu_flush_tlb_vhpt_range (u64 vadr, u64 log_range) { - cpu_flush_vhpt_range (current->processor, vadr, 1UL << log_range); + if (HAS_PERVCPU_VHPT(current->domain)) + vcpu_flush_vhpt_range(current, vadr, 1UL << log_range); + else + cpu_flush_vhpt_range(current->processor, + vadr, 1UL << log_range); ia64_ptcl(vadr, log_range << 2); ia64_srlz_i(); + perfc_incrc(vcpu_flush_tlb_vhpt_range); } void domain_flush_vtlb_range (struct domain *d, u64 vadr, u64 addr_range) @@ -214,34 +341,133 @@ void domain_flush_vtlb_range (struct domain *d, u64 vadr, u64 addr_range) } #endif - for_each_vcpu (d, v) { - if (!test_bit(_VCPUF_initialised, &v->vcpu_flags)) - continue; - - /* Purge TC entries. - FIXME: clear only if match. */ - vcpu_purge_tr_entry(&PSCBX(v,dtlb)); - vcpu_purge_tr_entry(&PSCBX(v,itlb)); - } + domain_purge_swtc_entries(d); smp_mb(); for_each_vcpu (d, v) { if (!test_bit(_VCPUF_initialised, &v->vcpu_flags)) continue; - /* Invalidate VHPT entries. */ - cpu_flush_vhpt_range (v->processor, vadr, addr_range); + if (HAS_PERVCPU_VHPT(d)) { + vcpu_flush_vhpt_range(v, vadr, addr_range); + } else { + // SMP: it is racy to reference v->processor. + // vcpu scheduler may move this vcpu to another + // physicall processor, and change the value + // using plain store. + // We may be seeing the old value of it. + // In such case, flush_vtlb_for_context_switch() + /* Invalidate VHPT entries. */ + cpu_flush_vhpt_range(v->processor, vadr, addr_range); + } } // ptc.ga has release semantics. /* ptc.ga */ ia64_global_tlb_purge(vadr,vadr+addr_range,PAGE_SHIFT); + perfc_incrc(domain_flush_vtlb_range); } +#ifdef CONFIG_XEN_IA64_TLB_TRACK +#include <asm/tlb_track.h> +#include <asm/vmx_vcpu.h> +void +__domain_flush_vtlb_track_entry(struct domain* d, + const struct tlb_track_entry* entry) +{ + unsigned long rr7_rid; + int swap_rr0 = 0; + unsigned long old_rid; + unsigned long vaddr = entry->vaddr; + struct vcpu* v; + int cpu; + int vcpu; + int local_purge = 1; + + BUG_ON((vaddr >> VRN_SHIFT) != VRN7); + /* + * heuristic: + * dom0linux accesses grant mapped pages via the kernel + * straight mapped area and it doesn't change rr7 rid. + * So it is likey that rr7 == entry->rid so that + * we can avoid rid change. + * When blktap is supported, this heuristic should be revised. + */ + vcpu_get_rr(current, VRN7 << VRN_SHIFT, &rr7_rid); + if (likely(rr7_rid == entry->rid)) { + perfc_incrc(tlb_track_use_rr7); + } else { + swap_rr0 = 1; + vaddr = (vaddr << 3) >> 3;// force vrn0 + perfc_incrc(tlb_track_swap_rr0); + } + + // tlb_track_entry_printf(entry); + if (swap_rr0) { + vcpu_get_rr(current, 0, &old_rid); + vcpu_set_rr(current, 0, entry->rid); + } + + if (HAS_PERVCPU_VHPT(d)) { + for_each_vcpu_mask(vcpu, entry->vcpu_dirty_mask) { + v = d->vcpu[vcpu]; + if (!test_bit(_VCPUF_initialised, &v->vcpu_flags)) + continue; + + /* Invalidate VHPT entries. */ + vcpu_flush_vhpt_range(v, vaddr, PAGE_SIZE); + + /* + * current->processor == v->processor + * is racy. we may see old v->processor and + * a new physical processor of v might see old + * vhpt entry and insert tlb. + */ + if (v != current) + local_purge = 0; + } + } else { + for_each_cpu_mask(cpu, entry->pcpu_dirty_mask) { + /* Invalidate VHPT entries. */ + cpu_flush_vhpt_range(cpu, vaddr, PAGE_SIZE); + + if (d->vcpu[cpu] != current) + local_purge = 0; + } + } + + /* ptc.ga */ + if (local_purge) { + ia64_ptcl(vaddr, PAGE_SHIFT << 2); + perfc_incrc(domain_flush_vtlb_local); + } else { + /* ptc.ga has release semantics. */ + ia64_global_tlb_purge(vaddr, vaddr + PAGE_SIZE, PAGE_SHIFT); + perfc_incrc(domain_flush_vtlb_global); + } + + if (swap_rr0) { + vcpu_set_rr(current, 0, old_rid); + } + perfc_incrc(domain_flush_vtlb_track_entry); +} + +void +domain_flush_vtlb_track_entry(struct domain* d, + const struct tlb_track_entry* entry) +{ + domain_purge_swtc_entries_vcpu_dirty_mask(d, entry->vcpu_dirty_mask); + smp_mb(); + + __domain_flush_vtlb_track_entry(d, entry); +} + +#endif + static void flush_tlb_vhpt_all (struct domain *d) { /* First VHPT. */ - vhpt_flush (); + local_vhpt_flush (); /* Then mTLB. */ local_flush_tlb_all (); @@ -250,7 +476,10 @@ static void flush_tlb_vhpt_all (struct domain *d) void domain_flush_tlb_vhpt(struct domain *d) { /* Very heavy... */ - on_each_cpu ((void (*)(void *))flush_tlb_vhpt_all, d, 1, 1); + if (HAS_PERVCPU_VHPT(d) || d->arch.is_vti) + on_each_cpu((void (*)(void *))local_flush_tlb_all, NULL, 1, 1); + else + on_each_cpu((void (*)(void *))flush_tlb_vhpt_all, d, 1, 1); cpus_clear (d->domain_dirty_cpumask); } diff --git a/xen/arch/ia64/xen/xen.lds.S b/xen/arch/ia64/xen/xen.lds.S index 3884f80679..96cd1ce14f 100644 --- a/xen/arch/ia64/xen/xen.lds.S +++ b/xen/arch/ia64/xen/xen.lds.S @@ -173,6 +173,9 @@ SECTIONS * kernel data */ + .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) + { *(.data.read_mostly) } + .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) { *(.data.cacheline_aligned) } diff --git a/xen/arch/ia64/xen/xenasm.S b/xen/arch/ia64/xen/xenasm.S index 0f0cff9620..af5f31c5b2 100644 --- a/xen/arch/ia64/xen/xenasm.S +++ b/xen/arch/ia64/xen/xenasm.S @@ -26,10 +26,11 @@ // void *shared_info, /* in1 */ // void *shared_arch_info, /* in2 */ // unsigned long shared_info_va, /* in3 */ -// unsigned long p_vhpt) /* in4 */ +// unsigned long va_vhpt) /* in4 */ //Local usage: // loc0=rp, loc1=ar.pfs, loc2=percpu_paddr, loc3=psr, loc4=ar.rse // loc5=pal_vaddr, loc6=xen_paddr, loc7=shared_archinfo_paddr, +// r16, r19, r20 are used by ia64_switch_mode_{phys, virt}() GLOBAL_ENTRY(ia64_new_rr7) // FIXME? not sure this unwind statement is correct... .prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(1) @@ -118,16 +119,31 @@ GLOBAL_ENTRY(ia64_new_rr7) // VHPT #if VHPT_ENABLED - mov r24=VHPT_SIZE_LOG2<<2 - movl r22=VHPT_ADDR +#if IA64_GRANULE_SHIFT < VHPT_SIZE_LOG2 +#error "it must be that VHPT_SIZE_LOG2 <= IA64_GRANULE_SHIFT" +#endif + // unless overlaps with KERNEL_TR and IA64_TR_CURRENT_STACK + dep r14=0,in4,0,KERNEL_TR_PAGE_SHIFT + dep r15=0,in4,0,IA64_GRANULE_SHIFT + dep r21=0,r13,0,IA64_GRANULE_SHIFT + ;; + cmp.eq p7,p0=r17,r14 + cmp.eq p8,p0=r15,r21 +(p7) br.cond.sptk .vhpt_overlaps +(p8) br.cond.sptk .vhpt_overlaps mov r21=IA64_TR_VHPT + dep r22=0,r15,60,4 // physical address of + // va_vhpt & ~(IA64_GRANULE_SIZE - 1) + mov r24=IA64_GRANULE_SHIFT<<2 ;; - ptr.d r22,r24 - or r23=in4,r26 // construct PA | page properties + ptr.d r15,r24 + or r23=r22,r26 // construct PA | page properties mov cr.itir=r24 - mov cr.ifa=r22 + mov cr.ifa=r15 + srlz.d ;; itr.d dtr[r21]=r23 // wire in new mapping... +.vhpt_overlaps: #endif // Shared info diff --git a/xen/arch/ia64/xen/xencomm.c b/xen/arch/ia64/xen/xencomm.c new file mode 100644 index 0000000000..a13eeff1fc --- /dev/null +++ b/xen/arch/ia64/xen/xencomm.c @@ -0,0 +1,380 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (C) IBM Corp. 2006 + * + * Authors: Hollis Blanchard <hollisb@us.ibm.com> + * Tristan Gingold <tristan.gingold@bull.net> + */ + +#include <xen/config.h> +#include <xen/mm.h> +#include <xen/sched.h> +#include <asm/current.h> +#include <asm/guest_access.h> +#include <public/xen.h> +#include <public/xencomm.h> +#include <xen/errno.h> + +#undef DEBUG +#ifdef DEBUG +static int xencomm_debug = 1; /* extremely verbose */ +#else +#define xencomm_debug 0 +#endif + +static int +xencomm_copy_chunk_from( + unsigned long to, + unsigned long paddr, + unsigned int len) +{ + unsigned long maddr; + struct page_info *page; + + while (1) { + maddr = xencomm_paddr_to_maddr(paddr); + if (xencomm_debug > 1) + printk("%lx[%d] -> %lx\n", maddr, len, to); + if (maddr == 0) + return -EFAULT; + + page = virt_to_page(maddr); + if (get_page(page, current->domain) == 0) { + if (page_get_owner(page) != current->domain) { + /* This page might be a page granted by another domain */ + panic_domain(NULL, "copy_from_guest from foreign domain\n"); + } + /* Try again. */ + continue; + } + memcpy((void *)to, (void *)maddr, len); + put_page(page); + return 0; + } +} + +/** + * xencomm_copy_from_guest: Copy a block of data from domain space. + * @to: Machine address. + * @from: Physical address to a xencomm buffer descriptor. + * @n: Number of bytes to copy. + * @skip: Number of bytes from the start to skip. + * + * Copy data from domain to hypervisor. + * + * Returns number of bytes that could not be copied. + * On success, this will be zero. + */ +unsigned long +xencomm_copy_from_guest( + void *to, + const void *from, + unsigned int n, + unsigned int skip) +{ + struct xencomm_desc *desc; + unsigned long desc_addr; + unsigned int from_pos = 0; + unsigned int to_pos = 0; + unsigned int i = 0; + + if (xencomm_debug) + printf("xencomm_copy_from_guest: from=%lx+%u n=%u\n", + (unsigned long)from, skip, n); + + if (XENCOMM_IS_INLINE(from)) { + unsigned long src_paddr = XENCOMM_INLINE_ADDR(from); + + src_paddr += skip; + + while (n > 0) { + unsigned int chunksz; + unsigned int bytes; + int res; + + chunksz = PAGE_SIZE - (src_paddr % PAGE_SIZE); + + bytes = min(chunksz, n); + + res = xencomm_copy_chunk_from((unsigned long)to, src_paddr, bytes); + if (res != 0) + return -EFAULT; + src_paddr += bytes; + to += bytes; + n -= bytes; + } + + /* Always successful. */ + return 0; + } + + /* first we need to access the descriptor */ + desc_addr = xencomm_paddr_to_maddr((unsigned long)from); + if (desc_addr == 0) + return -EFAULT; + + desc = (struct xencomm_desc *)desc_addr; + if (desc->magic != XENCOMM_MAGIC) { + printk("%s: error: %p magic was 0x%x\n", + __func__, desc, desc->magic); + return -EFAULT; + } + + /* iterate through the descriptor, copying up to a page at a time */ + while ((to_pos < n) && (i < desc->nr_addrs)) { + unsigned long src_paddr = desc->address[i]; + unsigned int pgoffset; + unsigned int chunksz; + unsigned int chunk_skip; + + if (src_paddr == XENCOMM_INVALID) { + i++; + continue; + } + + pgoffset = src_paddr % PAGE_SIZE; + chunksz = PAGE_SIZE - pgoffset; + + chunk_skip = min(chunksz, skip); + from_pos += chunk_skip; + chunksz -= chunk_skip; + skip -= chunk_skip; + + if (skip == 0) { + unsigned int bytes = min(chunksz, n - to_pos); + int res; + + if (xencomm_debug > 1) + printf ("src_paddr=%lx i=%d, skip=%d\n", + src_paddr, i, chunk_skip); + + res = xencomm_copy_chunk_from((unsigned long)to + to_pos, + src_paddr + chunk_skip, bytes); + if (res != 0) + return -EFAULT; + + from_pos += bytes; + to_pos += bytes; + } + + i++; + } + + return n - to_pos; +} + +static int +xencomm_copy_chunk_to( + unsigned long paddr, + unsigned long from, + unsigned int len) +{ + unsigned long maddr; + struct page_info *page; + + while (1) { + maddr = xencomm_paddr_to_maddr(paddr); + if (xencomm_debug > 1) + printk("%lx[%d] -> %lx\n", from, len, maddr); + if (maddr == 0) + return -EFAULT; + + page = virt_to_page(maddr); + if (get_page(page, current->domain) == 0) { + if (page_get_owner(page) != current->domain) { + /* This page might be a page granted by another domain */ + panic_domain(NULL, "copy_to_guest to foreign domain\n"); + } + /* Try again. */ + continue; + } + memcpy((void *)maddr, (void *)from, len); + put_page(page); + return 0; + } +} + +/** + * xencomm_copy_to_guest: Copy a block of data to domain space. + * @to: Physical address to xencomm buffer descriptor. + * @from: Machine address. + * @n: Number of bytes to copy. + * @skip: Number of bytes from the start to skip. + * + * Copy data from hypervisor to domain. + * + * Returns number of bytes that could not be copied. + * On success, this will be zero. + */ +unsigned long +xencomm_copy_to_guest( + void *to, + const void *from, + unsigned int n, + unsigned int skip) +{ + struct xencomm_desc *desc; + unsigned long desc_addr; + unsigned int from_pos = 0; + unsigned int to_pos = 0; + unsigned int i = 0; + + if (xencomm_debug) + printf ("xencomm_copy_to_guest: to=%lx+%u n=%u\n", + (unsigned long)to, skip, n); + + if (XENCOMM_IS_INLINE(to)) { + unsigned long dest_paddr = XENCOMM_INLINE_ADDR(to); + + dest_paddr += skip; + + while (n > 0) { + unsigned int chunksz; + unsigned int bytes; + int res; + + chunksz = PAGE_SIZE - (dest_paddr % PAGE_SIZE); + + bytes = min(chunksz, n); + + res = xencomm_copy_chunk_to(dest_paddr, (unsigned long)from, bytes); + if (res != 0) + return res; + + dest_paddr += bytes; + from += bytes; + n -= bytes; + } + + /* Always successful. */ + return 0; + } + + /* first we need to access the descriptor */ + desc_addr = xencomm_paddr_to_maddr((unsigned long)to); + if (desc_addr == 0) + return -EFAULT; + + desc = (struct xencomm_desc *)desc_addr; + if (desc->magic != XENCOMM_MAGIC) { + printk("%s error: %p magic was 0x%x\n", __func__, desc, desc->magic); + return -EFAULT; + } + + /* iterate through the descriptor, copying up to a page at a time */ + while ((from_pos < n) && (i < desc->nr_addrs)) { + unsigned long dest_paddr = desc->address[i]; + unsigned int pgoffset; + unsigned int chunksz; + unsigned int chunk_skip; + + if (dest_paddr == XENCOMM_INVALID) { + i++; + continue; + } + + pgoffset = dest_paddr % PAGE_SIZE; + chunksz = PAGE_SIZE - pgoffset; + + chunk_skip = min(chunksz, skip); + to_pos += chunk_skip; + chunksz -= chunk_skip; + skip -= chunk_skip; + dest_paddr += chunk_skip; + + if (skip == 0) { + unsigned int bytes = min(chunksz, n - from_pos); + int res; + + res = xencomm_copy_chunk_to(dest_paddr, + (unsigned long)from + from_pos, bytes); + if (res != 0) + return res; + + from_pos += bytes; + to_pos += bytes; + } + + i++; + } + return n - from_pos; +} + +/* Offset page addresses in 'handle' to skip 'bytes' bytes. Set completely + * exhausted pages to XENCOMM_INVALID. */ +void * +xencomm_add_offset( + void *handle, + unsigned int bytes) +{ + struct xencomm_desc *desc; + unsigned long desc_addr; + int i = 0; + + if (XENCOMM_IS_INLINE(handle)) + return (void *)((unsigned long)handle + bytes); + + /* first we need to access the descriptor */ + desc_addr = xencomm_paddr_to_maddr((unsigned long)handle); + if (desc_addr == 0) + return NULL; + + desc = (struct xencomm_desc *)desc_addr; + if (desc->magic != XENCOMM_MAGIC) { + printk("%s error: %p magic was 0x%x\n", __func__, desc, desc->magic); + return NULL; + } + + /* iterate through the descriptor incrementing addresses */ + while ((bytes > 0) && (i < desc->nr_addrs)) { + unsigned long dest_paddr = desc->address[i]; + unsigned int pgoffset; + unsigned int chunksz; + unsigned int chunk_skip; + + pgoffset = dest_paddr % PAGE_SIZE; + chunksz = PAGE_SIZE - pgoffset; + + chunk_skip = min(chunksz, bytes); + if (chunk_skip == chunksz) { + /* exhausted this page */ + desc->address[i] = XENCOMM_INVALID; + } else { + desc->address[i] += chunk_skip; + } + bytes -= chunk_skip; + } + return handle; +} + +int +xencomm_handle_is_null( + void *ptr) +{ + if (XENCOMM_IS_INLINE(ptr)) + return XENCOMM_INLINE_ADDR(ptr) == 0; + else { + struct xencomm_desc *desc; + unsigned long desc_addr; + + desc_addr = xencomm_paddr_to_maddr((unsigned long)ptr); + if (desc_addr == 0) + return 1; + + desc = (struct xencomm_desc *)desc_addr; + return (desc->address[0] == XENCOMM_INVALID); + } +} diff --git a/xen/arch/ia64/xen/xenmem.c b/xen/arch/ia64/xen/xenmem.c index 49b6c55588..c837f0fb4b 100644 --- a/xen/arch/ia64/xen/xenmem.c +++ b/xen/arch/ia64/xen/xenmem.c @@ -17,10 +17,19 @@ #include <linux/efi.h> #include <asm/pgalloc.h> -extern pgd_t frametable_pg_dir[]; +extern unsigned long frametable_pg_dir[]; -#define frametable_pgd_offset(addr) \ - (frametable_pg_dir + (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))) +#define FRAMETABLE_PGD_OFFSET(ADDR) \ + (frametable_pg_dir + (((ADDR) >> PGDIR_SHIFT) & \ + ((1UL << (PAGE_SHIFT - 3)) - 1))) + +#define FRAMETABLE_PMD_OFFSET(PGD, ADDR) \ + __va((unsigned long *)(PGD) + (((ADDR) >> PMD_SHIFT) & \ + ((1UL << (PAGE_SHIFT - 3)) - 1))) + +#define FRAMETABLE_PTE_OFFSET(PMD, ADDR) \ + (pte_t *)__va((unsigned long *)(PMD) + (((ADDR) >> PAGE_SHIFT) & \ + ((1UL << (PAGE_SHIFT - 3)) - 1))) static unsigned long table_size; static int opt_contig_mem = 0; @@ -29,13 +38,13 @@ boolean_param("contig_mem", opt_contig_mem); #define opt_contig_mem 1 #endif -struct page_info *frame_table; +struct page_info *frame_table __read_mostly; unsigned long max_page; /* * Set up the page tables. */ -volatile unsigned long *mpt_table; +volatile unsigned long *mpt_table __read_mostly; void paging_init (void) @@ -72,7 +81,7 @@ paging_init (void) #ifdef CONFIG_VIRTUAL_FRAME_TABLE -static inline void * +static unsigned long alloc_dir_page(void) { unsigned long mfn = alloc_boot_pages(1, 1); @@ -82,7 +91,7 @@ alloc_dir_page(void) ++table_size; dir = mfn << PAGE_SHIFT; memset(__va(dir), 0, PAGE_SIZE); - return (void *)dir; + return dir; } static inline unsigned long @@ -100,15 +109,33 @@ alloc_table_page(unsigned long fill) return mfn; } +static void +create_page_table(unsigned long start_page, unsigned long end_page, + unsigned long fill) +{ + unsigned long address; + unsigned long *dir; + pte_t *pteptr; + + for (address = start_page; address < end_page; address += PAGE_SIZE) { + dir = FRAMETABLE_PGD_OFFSET(address); + if (!*dir) + *dir = alloc_dir_page(); + dir = FRAMETABLE_PMD_OFFSET(*dir, address); + if (!*dir) + *dir = alloc_dir_page(); + pteptr = FRAMETABLE_PTE_OFFSET(*dir, address); + if (pte_none(*pteptr)) + set_pte(pteptr, pfn_pte(alloc_table_page(fill), + PAGE_KERNEL)); + } +} + static int create_frametable_page_table (u64 start, u64 end, void *arg) { - unsigned long address, start_page, end_page; struct page_info *map_start, *map_end; - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *pte; + unsigned long start_page, end_page; map_start = frame_table + (__pa(start) >> PAGE_SHIFT); map_end = frame_table + (__pa(end) >> PAGE_SHIFT); @@ -116,23 +143,7 @@ create_frametable_page_table (u64 start, u64 end, void *arg) start_page = (unsigned long) map_start & PAGE_MASK; end_page = PAGE_ALIGN((unsigned long) map_end); - for (address = start_page; address < end_page; address += PAGE_SIZE) { - pgd = frametable_pgd_offset(address); - if (pgd_none(*pgd)) - pgd_populate(NULL, pgd, alloc_dir_page()); - pud = pud_offset(pgd, address); - - if (pud_none(*pud)) - pud_populate(NULL, pud, alloc_dir_page()); - pmd = pmd_offset(pud, address); - - if (pmd_none(*pmd)) - pmd_populate_kernel(NULL, pmd, alloc_dir_page()); - pte = pte_offset_kernel(pmd, address); - - if (pte_none(*pte)) - set_pte(pte, pfn_pte(alloc_table_page(0), PAGE_KERNEL)); - } + create_page_table(start_page, end_page, 0L); return 0; } @@ -140,11 +151,7 @@ static int create_mpttable_page_table (u64 start, u64 end, void *arg) { unsigned long map_start, map_end; - unsigned long address, start_page, end_page; - pgd_t *pgd; - pud_t *pud; - pmd_t *pmd; - pte_t *pte; + unsigned long start_page, end_page; map_start = (unsigned long)(mpt_table + (__pa(start) >> PAGE_SHIFT)); map_end = (unsigned long)(mpt_table + (__pa(end) >> PAGE_SHIFT)); @@ -152,23 +159,7 @@ create_mpttable_page_table (u64 start, u64 end, void *arg) start_page = map_start & PAGE_MASK; end_page = PAGE_ALIGN(map_end); - for (address = start_page; address < end_page; address += PAGE_SIZE) { - pgd = frametable_pgd_offset(address); - if (pgd_none(*pgd)) - pgd_populate(NULL, pgd, alloc_dir_page()); - pud = pud_offset(pgd, address); - - if (pud_none(*pud)) - pud_populate(NULL, pud, alloc_dir_page()); - pmd = pmd_offset(pud, address); - - if (pmd_none(*pmd)) - pmd_populate_kernel(NULL, pmd, alloc_dir_page()); - pte = pte_offset_kernel(pmd, address); - - if (pte_none(*pte)) - set_pte(pte, pfn_pte(alloc_table_page(INVALID_M2P_ENTRY), PAGE_KERNEL)); - } + create_page_table(start_page, end_page, INVALID_M2P_ENTRY); return 0; } diff --git a/xen/arch/ia64/xen/xenpatch.c b/xen/arch/ia64/xen/xenpatch.c new file mode 100644 index 0000000000..561e48d28e --- /dev/null +++ b/xen/arch/ia64/xen/xenpatch.c @@ -0,0 +1,122 @@ +/****************************************************************************** + * xenpatch.c + * Copyright (c) 2006 Silicon Graphics Inc. + * Jes Sorensen <jes@sgi.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place - Suite 330, Boston, MA 02111-1307 USA. + * + * Parts of this based on code from arch/ia64/kernel/patch.c + */ + +#include <xen/config.h> +#include <xen/lib.h> +#include <asm/xensystem.h> +#include <asm/intrinsics.h> + +/* + * This was adapted from code written by Tony Luck: + * + * The 64-bit value in a "movl reg=value" is scattered between the two words of the bundle + * like this: + * + * 6 6 5 4 3 2 1 + * 3210987654321098765432109876543210987654321098765432109876543210 + * ABBBBBBBBBBBBBBBBBBBBBBBCCCCCCCCCCCCCCCCCCDEEEEEFFFFFFFFFGGGGGGG + * + * CCCCCCCCCCCCCCCCCCxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + * xxxxAFFFFFFFFFEEEEEDxGGGGGGGxxxxxxxxxxxxxBBBBBBBBBBBBBBBBBBBBBBB + */ +static u64 +get_imm64 (u64 insn_addr) +{ + u64 *p = (u64 *) (insn_addr & -16); /* mask out slot number */ + + return ( (p[1] & 0x0800000000000000UL) << 4) | /*A*/ + ((p[1] & 0x00000000007fffffUL) << 40) | /*B*/ + ((p[0] & 0xffffc00000000000UL) >> 24) | /*C*/ + ((p[1] & 0x0000100000000000UL) >> 23) | /*D*/ + ((p[1] & 0x0003e00000000000UL) >> 29) | /*E*/ + ((p[1] & 0x07fc000000000000UL) >> 43) | /*F*/ + ((p[1] & 0x000007f000000000UL) >> 36); /*G*/ +} + +/* Patch instruction with "val" where "mask" has 1 bits. */ +void +ia64_patch (u64 insn_addr, u64 mask, u64 val) +{ + u64 m0, m1, v0, v1, b0, b1, *b = (u64 *) (insn_addr & -16); +#define insn_mask ((1UL << 41) - 1) + unsigned long shift; + + b0 = b[0]; b1 = b[1]; + /* 5 bits of template, then 3 x 41-bit instructions */ + shift = 5 + 41 * (insn_addr % 16); + if (shift >= 64) { + m1 = mask << (shift - 64); + v1 = val << (shift - 64); + } else { + m0 = mask << shift; m1 = mask >> (64 - shift); + v0 = val << shift; v1 = val >> (64 - shift); + b[0] = (b0 & ~m0) | (v0 & m0); + } + b[1] = (b1 & ~m1) | (v1 & m1); +} + +void +ia64_patch_imm64 (u64 insn_addr, u64 val) +{ + /* The assembler may generate offset pointing to either slot 1 + or slot 2 for a long (2-slot) instruction, occupying slots 1 + and 2. */ + insn_addr &= -16UL; + ia64_patch(insn_addr + 2, 0x01fffefe000UL, + (((val & 0x8000000000000000UL) >> 27) | /* bit 63 -> 36 */ + ((val & 0x0000000000200000UL) << 0) | /* bit 21 -> 21 */ + ((val & 0x00000000001f0000UL) << 6) | /* bit 16 -> 22 */ + ((val & 0x000000000000ff80UL) << 20) | /* bit 7 -> 27 */ + ((val & 0x000000000000007fUL) << 13) /* bit 0 -> 13 */)); + ia64_patch(insn_addr + 1, 0x1ffffffffffUL, val >> 22); +} + +extern char frametable_miss; +extern unsigned long xen_pstart; + +/* + * Add more patch points in seperate functions as appropriate + */ + +static void xen_patch_frametable_miss(u64 offset) +{ + u64 addr, val; + + addr = (u64)&frametable_miss; + val = get_imm64(addr) + offset; + ia64_patch_imm64(addr, val); +} + + +void xen_patch_kernel(void) +{ + unsigned long patch_offset; + + patch_offset = xen_pstart - (KERNEL_START - PAGE_OFFSET); + + printk("Xen patching physical address access by offset: " + "0x%lx\n", patch_offset); + + xen_patch_frametable_miss(patch_offset); + + ia64_sync_i(); + ia64_srlz_i(); +} diff --git a/xen/arch/ia64/xen/xensetup.c b/xen/arch/ia64/xen/xensetup.c index f3574ca38a..056d3c3cba 100644 --- a/xen/arch/ia64/xen/xensetup.c +++ b/xen/arch/ia64/xen/xensetup.c @@ -48,6 +48,7 @@ extern void setup_per_cpu_areas(void); extern void mem_init(void); extern void init_IRQ(void); extern void trap_init(void); +extern void xen_patch_kernel(void); /* opt_nosmp: If true, secondary processors are ignored. */ static int opt_nosmp = 0; @@ -81,6 +82,7 @@ unsigned int opt_xenheap_megabytes = XENHEAP_DEFAULT_MB; unsigned long xenheap_size = XENHEAP_DEFAULT_SIZE; extern long running_on_sim; unsigned long xen_pstart; +void *xen_heap_start __read_mostly; static int xen_count_pages(u64 start, u64 end, void *arg) @@ -184,8 +186,8 @@ efi_print(void) for (i = 0, p = efi_map_start; p < efi_map_end; ++i, p += efi_desc_size) { md = p; - printk("mem%02u: type=%u, attr=0x%lx, range=[0x%016lx-0x%016lx) (%luMB)\n", - i, md->type, md->attribute, md->phys_addr, + printk("mem%02u: type=%2u, attr=0x%016lx, range=[0x%016lx-0x%016lx) " + "(%luMB)\n", i, md->type, md->attribute, md->phys_addr, md->phys_addr + (md->num_pages << EFI_PAGE_SHIFT), md->num_pages >> (20 - EFI_PAGE_SHIFT)); } @@ -242,7 +244,6 @@ md_overlaps(efi_memory_desc_t *md, unsigned long phys_addr) void start_kernel(void) { char *cmdline; - void *heap_start; unsigned long nr_pages; unsigned long dom0_memory_start, dom0_memory_size; unsigned long dom0_initrd_start, dom0_initrd_size; @@ -293,6 +294,8 @@ void start_kernel(void) printk("xen image pstart: 0x%lx, xenheap pend: 0x%lx\n", xen_pstart, xenheap_phys_end); + xen_patch_kernel(); + kern_md = md = efi_get_md(xen_pstart); md_end = __pa(ia64_imva(&_end)); relo_start = xenheap_phys_end; @@ -389,10 +392,10 @@ void start_kernel(void) printf("find_memory: efi_memmap_walk returns max_page=%lx\n",max_page); efi_print(); - heap_start = memguard_init(ia64_imva(&_end)); - printf("Before heap_start: %p\n", heap_start); - heap_start = __va(init_boot_allocator(__pa(heap_start))); - printf("After heap_start: %p\n", heap_start); + xen_heap_start = memguard_init(ia64_imva(&_end)); + printf("Before xen_heap_start: %p\n", xen_heap_start); + xen_heap_start = __va(init_boot_allocator(__pa(xen_heap_start))); + printf("After xen_heap_start: %p\n", xen_heap_start); efi_memmap_walk(filter_rsvd_memory, init_boot_pages); efi_memmap_walk(xen_count_pages, &nr_pages); @@ -410,10 +413,10 @@ void start_kernel(void) end_boot_allocator(); - init_xenheap_pages(__pa(heap_start), xenheap_phys_end); + init_xenheap_pages(__pa(xen_heap_start), xenheap_phys_end); printk("Xen heap: %luMB (%lukB)\n", - (xenheap_phys_end-__pa(heap_start)) >> 20, - (xenheap_phys_end-__pa(heap_start)) >> 10); + (xenheap_phys_end-__pa(xen_heap_start)) >> 20, + (xenheap_phys_end-__pa(xen_heap_start)) >> 10); late_setup_arch(&cmdline); @@ -496,6 +499,8 @@ printk("num_online_cpus=%d, max_cpus=%d\n",num_online_cpus(),max_cpus); efi.hcdp = NULL; } + expose_p2m_init(); + /* Create initial domain 0. */ dom0 = domain_create(0); if ( (dom0 == NULL) || (alloc_vcpu(dom0, 0, 0) == NULL) ) diff --git a/xen/arch/ia64/xen/xentime.c b/xen/arch/ia64/xen/xentime.c index 0ebce66c29..c653866969 100644 --- a/xen/arch/ia64/xen/xentime.c +++ b/xen/arch/ia64/xen/xentime.c @@ -39,7 +39,7 @@ seqlock_t xtime_lock __cacheline_aligned_in_smp = SEQLOCK_UNLOCKED; #define TIME_KEEPER_ID 0 unsigned long domain0_ready = 0; static s_time_t stime_irq = 0x0; /* System time at last 'time update' */ -unsigned long itc_scale, ns_scale; +unsigned long itc_scale __read_mostly, ns_scale __read_mostly; unsigned long itc_at_irq; /* We don't expect an absolute cycle value here, since then no way @@ -109,7 +109,6 @@ void xen_timer_interrupt (int irq, void *dev_id, struct pt_regs *regs) { unsigned long new_itm, old_itc; - int f_setitm = 0; #if 0 #define HEARTBEAT_FREQ 16 // period in seconds @@ -125,20 +124,9 @@ xen_timer_interrupt (int irq, void *dev_id, struct pt_regs *regs) #endif #endif - if (!is_idle_domain(current->domain)&&!VMX_DOMAIN(current)) - if (vcpu_timer_expired(current)) { - vcpu_pend_timer(current); - // ensure another timer interrupt happens even if domain doesn't - vcpu_set_next_timer(current); - f_setitm = 1; - } new_itm = local_cpu_data->itm_next; - - if (f_setitm && !time_after(ia64_get_itc(), new_itm)) - return; - - while (1) { + while (time_after(ia64_get_itc(), new_itm)) { new_itm += local_cpu_data->itm_delta; if (smp_processor_id() == TIME_KEEPER_ID) { @@ -148,27 +136,32 @@ xen_timer_interrupt (int irq, void *dev_id, struct pt_regs *regs) * another CPU. We need to avoid to SMP race by acquiring the * xtime_lock. */ -//#ifdef TURN_ME_OFF_FOR_NOW_IA64_XEN write_seqlock(&xtime_lock); -//#endif #ifdef TURN_ME_OFF_FOR_NOW_IA64_XEN do_timer(regs); #endif - local_cpu_data->itm_next = new_itm; - - /* Updates system time (nanoseconds since boot). */ + /* Updates system time (nanoseconds since boot). */ old_itc = itc_at_irq; itc_at_irq = ia64_get_itc(); stime_irq += cycle_to_ns(itc_at_irq - old_itc); -//#ifdef TURN_ME_OFF_FOR_NOW_IA64_XEN write_sequnlock(&xtime_lock); -//#endif - } else - local_cpu_data->itm_next = new_itm; + } - if (time_after(new_itm, ia64_get_itc())) - break; + local_cpu_data->itm_next = new_itm; + + } + + if (!is_idle_domain(current->domain) && !VMX_DOMAIN(current)) { + if (vcpu_timer_expired(current)) { + vcpu_pend_timer(current); + } else { + // ensure another timer interrupt happens + // even if domain doesn't + vcpu_set_next_timer(current); + raise_softirq(TIMER_SOFTIRQ); + return; + } } do { diff --git a/xen/include/asm-ia64/dom_fw.h b/xen/include/asm-ia64/dom_fw.h index 841ea9e200..fcf2cb5739 100644 --- a/xen/include/asm-ia64/dom_fw.h +++ b/xen/include/asm-ia64/dom_fw.h @@ -39,6 +39,13 @@ #define FW_HYPERCALL_NUM_MASK_HIGH ~0xffUL #define FW_HYPERCALL_NUM_MASK_LOW 0xffUL +/* Xen hypercalls are 0-63. */ +#define FW_HYPERCALL_XEN 0x0000UL + +/* Define some faster and lighter hypercalls. + See definitions in arch-ia64.h */ +#define FW_HYPERCALL_XEN_FAST 0x0200UL + /* * PAL can be called in physical or virtual mode simply by * branching to pal_entry_point, which is found in one of the @@ -173,7 +180,7 @@ #define EFI_MEMDESC_VERSION 1 -extern struct ia64_pal_retval xen_pal_emulator(UINT64, u64, u64, u64); +extern struct ia64_pal_retval xen_pal_emulator(u64, 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 efi_status_t efi_emulator (struct pt_regs *regs, unsigned long *fault); diff --git a/xen/include/asm-ia64/domain.h b/xen/include/asm-ia64/domain.h index b93351c63c..648eea0636 100644 --- a/xen/include/asm-ia64/domain.h +++ b/xen/include/asm-ia64/domain.h @@ -13,28 +13,10 @@ #include <asm/fpswa.h> #include <xen/rangeset.h> -struct p2m_entry { - volatile pte_t* pte; - pte_t used; -}; - -static inline void -p2m_entry_set(struct p2m_entry* entry, volatile pte_t* pte, pte_t used) -{ - entry->pte = pte; - entry->used = used; -} - -static inline int -p2m_entry_retry(struct p2m_entry* entry) -{ - //XXX see lookup_domain_pte(). - // NULL is set for invalid gpaddr for the time being. - if (entry->pte == NULL) - return 0; - - return (pte_val(*entry->pte) != pte_val(entry->used)); -} +struct p2m_entry; +#ifdef CONFIG_XEN_IA64_TLB_TRACK +struct tlb_track; +#endif extern void domain_relinquish_resources(struct domain *); struct vcpu; @@ -67,6 +49,9 @@ struct mm_struct { struct last_vcpu { #define INVALID_VCPU_ID INT_MAX int vcpu_id; +#ifdef CONFIG_XEN_IA64_TLBFLUSH_CLOCK + u32 tlbflush_timestamp; +#endif } ____cacheline_aligned_in_smp; /* These are data in domain memory for SAL emulator. */ @@ -87,6 +72,9 @@ struct arch_domain { unsigned long flags; struct { unsigned int is_vti : 1; +#ifdef CONFIG_XEN_IA64_PERVCPU_VHPT + unsigned int has_pervcpu_vhpt : 1; +#endif }; }; @@ -137,16 +125,21 @@ struct arch_domain { struct last_vcpu last_vcpu[NR_CPUS]; struct arch_vmx_domain arch_vmx; /* Virtual Machine Extensions */ + +#ifdef CONFIG_XEN_IA64_TLB_TRACK + struct tlb_track* tlb_track; +#endif }; #define INT_ENABLE_OFFSET(v) \ (sizeof(vcpu_info_t) * (v)->vcpu_id + \ offsetof(vcpu_info_t, evtchn_upcall_mask)) -struct hypercall_param { - unsigned long va; - unsigned long pa1; - unsigned long pa2; -}; +#ifdef CONFIG_XEN_IA64_PERVCPU_VHPT +#define HAS_PERVCPU_VHPT(d) ((d)->arch.has_pervcpu_vhpt) +#else +#define HAS_PERVCPU_VHPT(d) (0) +#endif + struct arch_vcpu { /* Save the state of vcpu. @@ -192,8 +185,6 @@ struct arch_vcpu { char irq_new_condition; // vpsr.i/vtpr change, check for pending VHPI char hypercall_continuation; - struct hypercall_param hypercall_param; // used to remap a hypercall param - //for phycial emulation unsigned long old_rsc; int mode_flags; @@ -201,6 +192,15 @@ struct arch_vcpu { struct timer hlt_timer; struct arch_vmx_struct arch_vmx; /* Virtual Machine Extensions */ +#ifdef CONFIG_XEN_IA64_PERVCPU_VHPT + PTA pta; + unsigned long vhpt_maddr; + struct page_info* vhpt_page; + unsigned long vhpt_entries; +#endif +#ifdef CONFIG_XEN_IA64_TLBFLUSH_CLOCK + u32 tlbflush_timestamp; +#endif #define INVALID_PROCESSOR INT_MAX int last_processor; }; diff --git a/xen/include/asm-ia64/flushtlb.h b/xen/include/asm-ia64/flushtlb.h new file mode 100644 index 0000000000..0966d72711 --- /dev/null +++ b/xen/include/asm-ia64/flushtlb.h @@ -0,0 +1,89 @@ +/****************************************************************************** + * flushtlb.c + * based on x86 flushtlb.h + * + * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ASM_FLUSHTLB_H__ +#define __ASM_FLUSHTLB_H__ + +#ifdef CONFIG_XEN_IA64_TLBFLUSH_CLOCK + +#include <xen/percpu.h> + +extern volatile u32 tlbflush_clock; +#define tlbflush_current_time() tlbflush_clock + +u32 tlbflush_clock_inc_and_return(void); + +static inline void +tlbflush_update_time(volatile u32* time, u32 timestamp) +{ + /* + * this should be ld4.rel + st4.acq. but only have release semantcis. + * so this function can't be considered as memory barrier. + */ + *time = timestamp; +} + +/* + * taken from x86's NEED_FLUSH() + * obj_stamp: mTLB time stamp, per pcpu VHPT stamp, per vcpu VHPT stamp. + */ +static inline int +NEED_FLUSH(u32 obj_stamp, u32 lastuse_stamp) +{ + u32 curr_time = tlbflush_current_time(); + /* + * Two cases: + * 1. During a wrap, the clock ticks over to 0 while CPUs catch up. For + * safety during this period, we force a flush if @curr_time == 0. + * 2. Otherwise, we look to see if @cpu_stamp <= @lastuse_stamp. + * To detect false positives because @cpu_stamp has wrapped, we + * also check @curr_time. If less than @lastuse_stamp we definitely + * wrapped, so there's no need for a flush (one is forced every wrap). + */ + return ((curr_time == 0) || + ((obj_stamp <= lastuse_stamp) && (lastuse_stamp <= curr_time))); +} + +DECLARE_PER_CPU(volatile u32, tlbflush_time); +DECLARE_PER_CPU(volatile u32, vhpt_tlbflush_timestamp); + +#else + +#define tlbflush_current_time() (0) +#define tlbflush_clock_inc_and_return() (0) +#define tlbflush_update_time(time, timestamp) do {(void)timestamp;} while (0) +#define NEED_FLUSH(obj_stamp, lastuse_stamp) (1) + +#endif /* CONFIG_XEN_IA64_TLBFLUSH_CLOCK */ + +#endif /* __ASM_FLUSHTLB_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/asm-ia64/guest_access.h b/xen/include/asm-ia64/guest_access.h index 6605578eb9..e0522d4157 100644 --- a/xen/include/asm-ia64/guest_access.h +++ b/xen/include/asm-ia64/guest_access.h @@ -1,91 +1,107 @@ -/****************************************************************************** - * guest_access.h - * - * Copyright (c) 2006, K A Fraser +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (C) IBM Corp. 2006 + * + * Authors: Hollis Blanchard <hollisb@us.ibm.com> + * Tristan Gingold <tristan.gingold@bull.net> */ -#ifndef __ASM_IA64_GUEST_ACCESS_H__ -#define __ASM_IA64_GUEST_ACCESS_H__ +#ifndef __ASM_GUEST_ACCESS_H__ +#define __ASM_GUEST_ACCESS_H__ + +extern unsigned long xencomm_copy_to_guest(void *to, const void *from, + unsigned int len, unsigned int skip); +extern unsigned long xencomm_copy_from_guest(void *to, const void *from, + unsigned int len, unsigned int skip); +extern void *xencomm_add_offset(void *handle, unsigned int bytes); +extern int xencomm_handle_is_null(void *ptr); -#include <asm/uaccess.h> /* Is the guest handle a NULL reference? */ -#define guest_handle_is_null(hnd) ((hnd).p == NULL) +#define guest_handle_is_null(hnd) \ + ((hnd).p == NULL || xencomm_handle_is_null((hnd).p)) /* Offset the given guest handle into the array it refers to. */ -#define guest_handle_add_offset(hnd, nr) ((hnd).p += (nr)) +#define guest_handle_add_offset(hnd, nr) ({ \ + const typeof((hnd).p) _ptr = (hnd).p; \ + (hnd).p = xencomm_add_offset(_ptr, nr * sizeof(*_ptr)); \ +}) /* Cast a guest handle to the specified type of handle. */ -#define guest_handle_cast(hnd, type) ({ \ - type *_x = (hnd).p; \ - (XEN_GUEST_HANDLE(type)) { _x }; \ +#define guest_handle_cast(hnd, type) ({ \ + type *_x = (hnd).p; \ + XEN_GUEST_HANDLE(type) _y; \ + set_xen_guest_handle(_y, _x); \ + _y; \ }) -#define guest_handle_from_ptr(ptr, type) ((XEN_GUEST_HANDLE(type)) { (type *)ptr }) -/* - * Copy an array of objects to guest context via a guest handle, - * specifying an offset into the guest array. - */ -#define copy_to_guest_offset(hnd, off, ptr, nr) ({ \ - const typeof(ptr) _x = (hnd).p; \ - const typeof(ptr) _y = (ptr); \ - copy_to_user(_x+(off), _y, sizeof(*_x)*(nr)); \ -}) +/* Since we run in real mode, we can safely access all addresses. That also + * means our __routines are identical to our "normal" routines. */ +#define guest_handle_okay(hnd, nr) 1 /* - * Copy an array of objects from guest context via a guest handle, - * specifying an offset into the guest array. + * Copy an array of objects to guest context via a guest handle. + * Optionally specify an offset into the guest array. */ -#define copy_from_guest_offset(ptr, hnd, off, nr) ({ \ - const typeof(ptr) _x = (hnd).p; \ - const typeof(ptr) _y = (ptr); \ - copy_from_user(_y, _x+(off), sizeof(*_x)*(nr)); \ -}) +#define copy_to_guest_offset(hnd, idx, ptr, nr) \ + __copy_to_guest_offset(hnd, idx, ptr, nr) /* Copy sub-field of a structure to guest context via a guest handle. */ -#define copy_field_to_guest(hnd, ptr, field) ({ \ - const typeof(&(ptr)->field) _x = &(hnd).p->field; \ - const typeof(&(ptr)->field) _y = &(ptr)->field; \ - copy_to_user(_x, _y, sizeof(*_x)); \ -}) - -/* Copy sub-field of a structure from guest context via a guest handle. */ -#define copy_field_from_guest(ptr, hnd, field) ({ \ - const typeof(&(ptr)->field) _x = &(hnd).p->field; \ - const typeof(&(ptr)->field) _y = &(ptr)->field; \ - copy_from_user(_y, _x, sizeof(*_x)); \ -}) +#define copy_field_to_guest(hnd, ptr, field) \ + __copy_field_to_guest(hnd, ptr, field) /* - * Pre-validate a guest handle. - * Allows use of faster __copy_* functions. + * Copy an array of objects from guest context via a guest handle. + * Optionally specify an offset into the guest array. */ -#define guest_handle_okay(hnd, nr) \ - array_access_ok((hnd).p, (nr), sizeof(*(hnd).p)) +#define copy_from_guest_offset(ptr, hnd, idx, nr) \ + __copy_from_guest_offset(ptr, hnd, idx, nr) -#define __copy_to_guest_offset(hnd, off, ptr, nr) ({ \ - const typeof(ptr) _x = (hnd).p; \ - const typeof(ptr) _y = (ptr); \ - __copy_to_user(_x+(off), _y, sizeof(*_x)*(nr)); \ +/* Copy sub-field of a structure from guest context via a guest handle. */ +#define copy_field_from_guest(ptr, hnd, field) \ + __copy_field_from_guest(ptr, hnd, field) + +#define __copy_to_guest_offset(hnd, idx, ptr, nr) ({ \ + const typeof(ptr) _d = (hnd).p; \ + const typeof(ptr) _s = (ptr); \ + xencomm_copy_to_guest(_d, _s, sizeof(*_s)*(nr), sizeof(*_s)*(idx)); \ }) -#define __copy_from_guest_offset(ptr, hnd, off, nr) ({ \ - const typeof(ptr) _x = (hnd).p; \ - const typeof(ptr) _y = (ptr); \ - __copy_from_user(_y, _x+(off), sizeof(*_x)*(nr)); \ +#define __copy_field_to_guest(hnd, ptr, field) ({ \ + const int _off = offsetof(typeof(*ptr), field); \ + const typeof(ptr) _d = (hnd).p; \ + const typeof(&(ptr)->field) _s = &(ptr)->field; \ + xencomm_copy_to_guest(_d, _s, sizeof(*_s), _off); \ }) -#define __copy_field_to_guest(hnd, ptr, field) ({ \ - const typeof(&(ptr)->field) _x = &(hnd).p->field; \ - const typeof(&(ptr)->field) _y = &(ptr)->field; \ - __copy_to_user(_x, _y, sizeof(*_x)); \ +#define __copy_from_guest_offset(ptr, hnd, idx, nr) ({ \ + const typeof(ptr) _s = (hnd).p; \ + const typeof(ptr) _d = (ptr); \ + xencomm_copy_from_guest(_d, _s, sizeof(*_s)*(nr), sizeof(*_s)*(idx)); \ }) -#define __copy_field_from_guest(ptr, hnd, field) ({ \ - const typeof(&(ptr)->field) _x = &(hnd).p->field; \ - const typeof(&(ptr)->field) _y = &(ptr)->field; \ - __copy_from_user(_y, _x, sizeof(*_x)); \ +#define __copy_field_from_guest(ptr, hnd, field) ({ \ + const int _off = offsetof(typeof(*ptr), field); \ + const typeof(ptr) _s = (hnd).p; \ + const typeof(&(ptr)->field) _d = &(ptr)->field; \ + xencomm_copy_from_guest(_d, _s, sizeof(*_d), _off); \ }) -#endif /* __ASM_IA64_GUEST_ACCESS_H__ */ +/* Internal use only: returns 0 in case of bad address. */ +extern unsigned long xencomm_paddr_to_maddr(unsigned long paddr); + +#endif /* __ASM_GUEST_ACCESS_H__ */ diff --git a/xen/include/asm-ia64/ia64_int.h b/xen/include/asm-ia64/ia64_int.h index 0bef5b4a1b..711078104b 100644 --- a/xen/include/asm-ia64/ia64_int.h +++ b/xen/include/asm-ia64/ia64_int.h @@ -36,7 +36,9 @@ #define IA64_NO_FAULT 0x0000 #define IA64_FAULT 0x0001 #define IA64_RFI_IN_PROGRESS 0x0002 -#define IA64_RETRY 0x0003 +// To avoid conflicting with return value of handle_fpu_swa() +// set IA64_RETRY to -0x000f +#define IA64_RETRY (-0x000f) #define IA64_FORCED_IFA 0x0004 #define IA64_USE_TLB 0x0005 #define IA64_ILLOP_FAULT (IA64_GENEX_VECTOR | 0x00) diff --git a/xen/include/asm-ia64/linux-xen/asm/cache.h b/xen/include/asm-ia64/linux-xen/asm/cache.h index 0db88a7044..542d2e23e4 100644 --- a/xen/include/asm-ia64/linux-xen/asm/cache.h +++ b/xen/include/asm-ia64/linux-xen/asm/cache.h @@ -32,6 +32,6 @@ #endif #endif -#define __read_mostly +#define __read_mostly __attribute__((__section__(".data.read_mostly"))) #endif /* _ASM_IA64_CACHE_H */ diff --git a/xen/include/asm-ia64/linux-xen/asm/pgtable.h b/xen/include/asm-ia64/linux-xen/asm/pgtable.h index 659c2a933f..7b23205f85 100644 --- a/xen/include/asm-ia64/linux-xen/asm/pgtable.h +++ b/xen/include/asm-ia64/linux-xen/asm/pgtable.h @@ -68,6 +68,40 @@ #ifdef XEN #define _PAGE_VIRT_D (__IA64_UL(1) << 53) /* Virtual dirty bit */ #define _PAGE_PROTNONE 0 + +#ifdef CONFIG_XEN_IA64_TLB_TRACK +#define _PAGE_TLB_TRACKING_BIT 54 +#define _PAGE_TLB_INSERTED_BIT 55 +#define _PAGE_TLB_INSERTED_MANY_BIT 56 + +#define _PAGE_TLB_TRACKING (1UL << _PAGE_TLB_TRACKING_BIT) +#define _PAGE_TLB_INSERTED (1UL << _PAGE_TLB_INSERTED_BIT) +#define _PAGE_TLB_INSERTED_MANY (1UL << _PAGE_TLB_INSERTED_MANY_BIT) +#define _PAGE_TLB_TRACK_MASK (_PAGE_TLB_TRACKING | \ + _PAGE_TLB_INSERTED | \ + _PAGE_TLB_INSERTED_MANY) + +#define pte_tlb_tracking(pte) \ + ((pte_val(pte) & _PAGE_TLB_TRACKING) != 0) +#define pte_tlb_inserted(pte) \ + ((pte_val(pte) & _PAGE_TLB_INSERTED) != 0) +#define pte_tlb_inserted_many(pte) \ + ((pte_val(pte) & _PAGE_TLB_INSERTED_MANY) != 0) +#endif // CONFIG_XEN_IA64_TLB_TRACK + +/* domVTI */ +#define GPFN_MEM (0UL << 60) /* Guest pfn is normal mem */ +#define GPFN_FRAME_BUFFER (1UL << 60) /* VGA framebuffer */ +#define GPFN_LOW_MMIO (2UL << 60) /* Low MMIO range */ +#define GPFN_PIB (3UL << 60) /* PIB base */ +#define GPFN_IOSAPIC (4UL << 60) /* IOSAPIC base */ +#define GPFN_LEGACY_IO (5UL << 60) /* Legacy I/O base */ +#define GPFN_GFW (6UL << 60) /* Guest Firmware */ +#define GPFN_HIGH_MMIO (7UL << 60) /* High MMIO range */ + +#define GPFN_IO_MASK (7UL << 60) /* Guest pfn is I/O type */ +#define GPFN_INV_MASK (1UL << 63) /* Guest pfn is invalid */ + #else #define _PAGE_PROTNONE (__IA64_UL(1) << 63) #endif diff --git a/xen/include/asm-ia64/linux-xen/asm/processor.h b/xen/include/asm-ia64/linux-xen/asm/processor.h index 65f65538bc..976c0960d6 100644 --- a/xen/include/asm-ia64/linux-xen/asm/processor.h +++ b/xen/include/asm-ia64/linux-xen/asm/processor.h @@ -89,6 +89,7 @@ #ifdef XEN #include <asm/xenprocessor.h> +#include <xen/bitops.h> #else /* like above but expressed as bitfields for more efficient access: */ struct ia64_psr { @@ -571,6 +572,23 @@ ia64_eoi (void) #define cpu_relax() ia64_hint(ia64_hint_pause) +static inline int +ia64_get_irr(unsigned int vector) +{ + unsigned int reg = vector / 64; + unsigned int bit = vector % 64; + u64 irr; + + switch (reg) { + case 0: irr = ia64_getreg(_IA64_REG_CR_IRR0); break; + case 1: irr = ia64_getreg(_IA64_REG_CR_IRR1); break; + case 2: irr = ia64_getreg(_IA64_REG_CR_IRR2); break; + case 3: irr = ia64_getreg(_IA64_REG_CR_IRR3); break; + } + + return test_bit(bit, &irr); +} + static inline void ia64_set_lrr0 (unsigned long val) { diff --git a/xen/include/asm-ia64/linux-xen/asm/system.h b/xen/include/asm-ia64/linux-xen/asm/system.h index c12beafd3a..9f98e2a743 100644 --- a/xen/include/asm-ia64/linux-xen/asm/system.h +++ b/xen/include/asm-ia64/linux-xen/asm/system.h @@ -189,6 +189,7 @@ do { \ #ifdef XEN #define local_irq_is_enabled() (!irqs_disabled()) +extern struct vcpu *ia64_switch_to(struct vcpu *next_task); #else #ifdef __KERNEL__ diff --git a/xen/include/asm-ia64/linux/README.origin b/xen/include/asm-ia64/linux/README.origin index cb7c02b0a2..e364b52977 100644 --- a/xen/include/asm-ia64/linux/README.origin +++ b/xen/include/asm-ia64/linux/README.origin @@ -7,6 +7,7 @@ bcd.h -> linux/include/linux/bcd.h bitmap.h -> linux/include/linux/bitmap.h bitops.h -> linux/include/linux/bitops.h +hash.h -> linux/include/linux/hash.h initrd.h -> linux/include/linux/initrd.h jiffies.h -> linux/include/linux/jiffies.h kmalloc_sizes.h -> linux/include/linux/kmalloc_sizes.h diff --git a/xen/include/asm-ia64/linux/asm/sal.h b/xen/include/asm-ia64/linux/asm/sal.h index 29df88bdd2..2af85b14b6 100644 --- a/xen/include/asm-ia64/linux/asm/sal.h +++ b/xen/include/asm-ia64/linux/asm/sal.h @@ -657,15 +657,7 @@ ia64_sal_freq_base (unsigned long which, unsigned long *ticks_per_second, return isrv.status; } -/* Flush all the processor and platform level instruction and/or data caches */ -static inline s64 -ia64_sal_cache_flush (u64 cache_type) -{ - struct ia64_sal_retval isrv; - SAL_CALL(isrv, SAL_CACHE_FLUSH, cache_type, 0, 0, 0, 0, 0, 0); - return isrv.status; -} - +extern s64 ia64_sal_cache_flush (u64 cache_type); /* Initialize all the processor and platform level instruction and data caches */ static inline s64 diff --git a/xen/include/asm-ia64/linux/hash.h b/xen/include/asm-ia64/linux/hash.h new file mode 100644 index 0000000000..acf17bb8e7 --- /dev/null +++ b/xen/include/asm-ia64/linux/hash.h @@ -0,0 +1,58 @@ +#ifndef _LINUX_HASH_H +#define _LINUX_HASH_H +/* Fast hashing routine for a long. + (C) 2002 William Lee Irwin III, IBM */ + +/* + * Knuth recommends primes in approximately golden ratio to the maximum + * integer representable by a machine word for multiplicative hashing. + * Chuck Lever verified the effectiveness of this technique: + * http://www.citi.umich.edu/techreports/reports/citi-tr-00-1.pdf + * + * These primes are chosen to be bit-sparse, that is operations on + * them can use shifts and additions instead of multiplications for + * machines where multiplications are slow. + */ +#if BITS_PER_LONG == 32 +/* 2^31 + 2^29 - 2^25 + 2^22 - 2^19 - 2^16 + 1 */ +#define GOLDEN_RATIO_PRIME 0x9e370001UL +#elif BITS_PER_LONG == 64 +/* 2^63 + 2^61 - 2^57 + 2^54 - 2^51 - 2^18 + 1 */ +#define GOLDEN_RATIO_PRIME 0x9e37fffffffc0001UL +#else +#error Define GOLDEN_RATIO_PRIME for your wordsize. +#endif + +static inline unsigned long hash_long(unsigned long val, unsigned int bits) +{ + unsigned long hash = val; + +#if BITS_PER_LONG == 64 + /* Sigh, gcc can't optimise this alone like it does for 32 bits. */ + unsigned long n = hash; + n <<= 18; + hash -= n; + n <<= 33; + hash -= n; + n <<= 3; + hash += n; + n <<= 3; + hash -= n; + n <<= 4; + hash += n; + n <<= 2; + hash += n; +#else + /* On some cpus multiply is faster, on others gcc will do shifts */ + hash *= GOLDEN_RATIO_PRIME; +#endif + + /* High bits are more random, so use them. */ + return hash >> (BITS_PER_LONG - bits); +} + +static inline unsigned long hash_ptr(void *ptr, unsigned int bits) +{ + return hash_long((unsigned long)ptr, bits); +} +#endif /* _LINUX_HASH_H */ diff --git a/xen/include/asm-ia64/mm.h b/xen/include/asm-ia64/mm.h index a4f59022bc..ac665bcd0b 100644 --- a/xen/include/asm-ia64/mm.h +++ b/xen/include/asm-ia64/mm.h @@ -18,6 +18,7 @@ #include <asm/processor.h> #include <asm/atomic.h> #include <asm/tlbflush.h> +#include <asm/flushtlb.h> #include <asm/io.h> #include <public/xen.h> @@ -117,10 +118,14 @@ struct page_info #define IS_XEN_HEAP_FRAME(_pfn) ((page_to_maddr(_pfn) < xenheap_phys_end) \ && (page_to_maddr(_pfn) >= xen_pstart)) -static inline struct domain *unpickle_domptr(u32 _d) -{ return (_d == 0) ? NULL : __va(_d); } +extern void *xen_heap_start; +#define __pickle(a) ((unsigned long)a - (unsigned long)xen_heap_start) +#define __unpickle(a) (void *)(a + xen_heap_start) + +static inline struct domain *unpickle_domptr(u64 _d) +{ return (_d == 0) ? NULL : __unpickle(_d); } static inline u32 pickle_domptr(struct domain *_d) -{ return (_d == NULL) ? 0 : (u32)__pa(_d); } +{ return (_d == NULL) ? 0 : (u32)__pickle(_d); } #define page_get_owner(_p) (unpickle_domptr((_p)->u.inuse._domain)) #define page_set_owner(_p, _d) ((_p)->u.inuse._domain = pickle_domptr(_d)) @@ -420,7 +425,7 @@ extern void alloc_dom_xen_and_dom_io(void); extern void relinquish_mm(struct domain* d); extern struct page_info * assign_new_domain_page(struct domain *d, unsigned long mpaddr); extern void assign_new_domain0_page(struct domain *d, unsigned long mpaddr); -extern void __assign_domain_page(struct domain *d, unsigned long mpaddr, unsigned long physaddr, unsigned long flags); +extern int __assign_domain_page(struct domain *d, unsigned long mpaddr, unsigned long physaddr, unsigned long flags); 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); struct p2m_entry; @@ -435,6 +440,13 @@ extern unsigned long ____lookup_domain_mpa(struct domain *d, unsigned long mpadd extern unsigned long do_dom0vp_op(unsigned long cmd, unsigned long arg0, unsigned long arg1, unsigned long arg2, unsigned long arg3); extern unsigned long dom0vp_zap_physmap(struct domain *d, unsigned long gpfn, unsigned int extent_order); extern unsigned long dom0vp_add_physmap(struct domain* d, unsigned long gpfn, unsigned long mfn, unsigned long flags, domid_t domid); +#ifdef CONFIG_XEN_IA64_EXPOSE_P2M +extern void expose_p2m_init(void); +extern unsigned long dom0vp_expose_p2m(struct domain* d, unsigned long conv_start_gpfn, unsigned long assign_start_gpfn, unsigned long expose_size, unsigned long granule_pfn); +#else +#define expose_p2m_init() do { } while (0) +#define dom0vp_expose_p2m(d, conv_start_gpfn, assign_start_gpfn, expose_size, granule_pfn) (-ENOSYS) +#endif extern volatile unsigned long *mpt_table; extern unsigned long gmfn_to_mfn_foreign(struct domain *d, unsigned long gpfn); diff --git a/xen/include/asm-ia64/p2m_entry.h b/xen/include/asm-ia64/p2m_entry.h new file mode 100644 index 0000000000..4a2ff7ef6c --- /dev/null +++ b/xen/include/asm-ia64/p2m_entry.h @@ -0,0 +1,76 @@ +/****************************************************************************** + * p2m_entry.h + * + * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __ASM_P2M_ENTRY_H__ +#define __ASM_P2M_ENTRY_H__ + +#include <asm/pgtable.h> + +struct p2m_entry { +#define P2M_PTE_ALWAYS_RETRY ((volatile pte_t*) -1) + volatile pte_t* ptep; + pte_t used; +}; + +static inline void +p2m_entry_set(struct p2m_entry* entry, volatile pte_t* ptep, pte_t used) +{ + entry->ptep = ptep; + entry->used = used; +} + +static inline void +p2m_entry_set_retry(struct p2m_entry* entry) +{ + entry->ptep = P2M_PTE_ALWAYS_RETRY; +} + +static inline int +p2m_entry_retry(struct p2m_entry* entry) +{ + /* XXX see lookup_domain_pte(). + NULL is set for invalid gpaddr for the time being. */ + if (entry->ptep == NULL) + return 0; + + if (entry->ptep == P2M_PTE_ALWAYS_RETRY) + return 1; + +#ifdef CONFIG_XEN_IA64_TLB_TRACK + return ((pte_val(*entry->ptep) & ~_PAGE_TLB_TRACK_MASK) != + (pte_val(entry->used) & ~_PAGE_TLB_TRACK_MASK)); +#else + return (pte_val(*entry->ptep) != pte_val(entry->used)); +#endif +} + +#endif // __ASM_P2M_ENTRY_H__ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/asm-ia64/perfc_defn.h b/xen/include/asm-ia64/perfc_defn.h index 58d52a97ff..40c0127c07 100644 --- a/xen/include/asm-ia64/perfc_defn.h +++ b/xen/include/asm-ia64/perfc_defn.h @@ -107,3 +107,68 @@ PERFSTATUS(privop_addr_##name##_overflow, "privop-addrs overflow " #name) PERFPRIVOPADDR(get_ifa) PERFPRIVOPADDR(thash) #endif + +// vhpt.c +PERFCOUNTER_CPU(local_vhpt_flush, "local_vhpt_flush") +PERFCOUNTER_CPU(vcpu_vhpt_flush, "vcpu_vhpt_flush") +PERFCOUNTER_CPU(vcpu_flush_vtlb_all, "vcpu_flush_vtlb_all") +PERFCOUNTER_CPU(domain_flush_vtlb_all, "domain_flush_vtlb_all") +PERFCOUNTER_CPU(vcpu_flush_tlb_vhpt_range, "vcpu_flush_tlb_vhpt_range") +PERFCOUNTER_CPU(domain_flush_vtlb_track_entry, "domain_flush_vtlb_track_entry") +PERFCOUNTER_CPU(domain_flush_vtlb_local, "domain_flush_vtlb_local") +PERFCOUNTER_CPU(domain_flush_vtlb_global, "domain_flush_vtlb_global") +PERFCOUNTER_CPU(domain_flush_vtlb_range, "domain_flush_vtlb_range") + +// domain.c +PERFCOUNTER_CPU(flush_vtlb_for_context_switch, "flush_vtlb_for_context_switch") + +// mm.c +PERFCOUNTER_CPU(assign_domain_page_replace, "assign_domain_page_replace") +PERFCOUNTER_CPU(assign_domain_pge_cmpxchg_rel, "assign_domain_pge_cmpxchg_rel") +PERFCOUNTER_CPU(zap_dcomain_page_one, "zap_dcomain_page_one") +PERFCOUNTER_CPU(dom0vp_zap_physmap, "dom0vp_zap_physmap") +PERFCOUNTER_CPU(dom0vp_add_physmap, "dom0vp_add_physmap") +PERFCOUNTER_CPU(create_grant_host_mapping, "create_grant_host_mapping") +PERFCOUNTER_CPU(destroy_grant_host_mapping, "destroy_grant_host_mapping") +PERFCOUNTER_CPU(steal_page_refcount, "steal_page_refcount") +PERFCOUNTER_CPU(steal_page, "steal_page") +PERFCOUNTER_CPU(guest_physmap_add_page, "guest_physmap_add_page") +PERFCOUNTER_CPU(guest_physmap_remove_page, "guest_physmap_remove_page") +PERFCOUNTER_CPU(domain_page_flush, "domain_page_flush") + +// dom0vp +PERFCOUNTER_CPU(dom0vp_phystomach, "dom0vp_phystomach") +PERFCOUNTER_CPU(dom0vp_machtophys, "dom0vp_machtophys") + +#ifdef CONFIG_XEN_IA64_TLB_TRACK +// insert or dirty +PERFCOUNTER_CPU(tlb_track_iod, "tlb_track_iod") +PERFCOUNTER_CPU(tlb_track_iod_again, "tlb_track_iod_again") +PERFCOUNTER_CPU(tlb_track_iod_not_tracked, "tlb_track_iod_not_tracked") +PERFCOUNTER_CPU(tlb_track_iod_force_many, "tlb_track_iod_force_many") +PERFCOUNTER_CPU(tlb_track_iod_tracked_many, "tlb_track_iod_tracked_many") +PERFCOUNTER_CPU(tlb_track_iod_tracked_many_del, "tlb_track_iod_tracked_many_del") +PERFCOUNTER_CPU(tlb_track_iod_found, "tlb_track_iod_found") +PERFCOUNTER_CPU(tlb_track_iod_new_entry, "tlb_track_iod_new_entry") +PERFCOUNTER_CPU(tlb_track_iod_new_failed, "tlb_track_iod_new_failed") +PERFCOUNTER_CPU(tlb_track_iod_new_many, "tlb_track_iod_new_many") +PERFCOUNTER_CPU(tlb_track_iod_insert, "tlb_track_iod_insert") +PERFCOUNTER_CPU(tlb_track_iod_dirtied, "tlb_track_iod_dirtied") + +// search and remove +PERFCOUNTER_CPU(tlb_track_sar, "tlb_track_sar") +PERFCOUNTER_CPU(tlb_track_sar_not_tracked, "tlb_track_sar_not_tracked") +PERFCOUNTER_CPU(tlb_track_sar_not_found, "tlb_track_sar_not_found") +PERFCOUNTER_CPU(tlb_track_sar_found, "tlb_track_sar_found") +PERFCOUNTER_CPU(tlb_track_sar_many, "tlb_track_sar_many") + +// flush +PERFCOUNTER_CPU(tlb_track_use_rr7, "tlb_track_use_rr7") +PERFCOUNTER_CPU(tlb_track_swap_rr0, "tlb_track_swap_rr0") +#endif + +// tlb flush clock +#ifdef CONFIG_XEN_IA64_TLBFLUSH_CLOCK +PERFCOUNTER_CPU(tlbflush_clock_cswitch_purge, "tlbflush_clock_cswitch_purge") +PERFCOUNTER_CPU(tlbflush_clock_cswitch_skip, "tlbflush_clock_cswitch_skip") +#endif diff --git a/xen/include/asm-ia64/privop.h b/xen/include/asm-ia64/privop.h index 1324c4c2fb..64e73f473c 100644 --- a/xen/include/asm-ia64/privop.h +++ b/xen/include/asm-ia64/privop.h @@ -4,9 +4,9 @@ #include <asm/ia64_int.h> #include <asm/vcpu.h> -extern IA64FAULT priv_emulate(VCPU *vcpu, REGS *regs, UINT64 isr); +extern IA64FAULT priv_emulate(VCPU *vcpu, REGS *regs, u64 isr); -extern void privify_memory(void *start, UINT64 len); +extern void privify_memory(void *start, u64 len); extern int ia64_hyperprivop(unsigned long iim, REGS *regs); diff --git a/xen/include/asm-ia64/tlb_track.h b/xen/include/asm-ia64/tlb_track.h new file mode 100644 index 0000000000..5243aa6305 --- /dev/null +++ b/xen/include/asm-ia64/tlb_track.h @@ -0,0 +1,155 @@ +/****************************************************************************** + * tlb_track.h + * + * Copyright (c) 2006 Isaku Yamahata <yamahata at valinux co jp> + * VA Linux Systems Japan K.K. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#ifndef __TLB_TRACK_H__ +#define __TLB_TRACK_H__ + +#ifdef CONFIG_XEN_IA64_TLB_TRACK + +#include <xen/sched.h> +#include <xen/perfc.h> +#include <asm/domain.h> +#include <xen/list.h> +#include <asm/p2m_entry.h> +#include <asm/vcpumask.h> + +// TODO: compact this structure. +struct tlb_track_entry { + struct list_head list; + + volatile pte_t* ptep; // corresponding p2m entry + + /* XXX should we use TR_ENTRY? */ + pte_t pte_val; // mfn and other flags + // pte_val.p = 1: + // tlb entry is inserted. + // pte_val.p = 0: + // once tlb entry is inserted, so + // this entry is created. But tlb + // purge is isseued, so this + // virtual address need not to be + // purged. + unsigned long vaddr; // virtual address + unsigned long rid; // rid + + cpumask_t pcpu_dirty_mask; + vcpumask_t vcpu_dirty_mask; + +#ifdef CONFIG_TLB_TRACK_CNT +#define TLB_TRACK_CNT_FORCE_MANY 256 /* XXX how many? */ + unsigned long cnt; +#endif +}; + +struct tlb_track { + +/* see __gnttab_map_grant_ref() + A domain can map granted-page up to MAPTRACK_MAX_ENTRIES pages. */ +#define TLB_TRACK_LIMIT_ENTRIES \ + (MAPTRACK_MAX_ENTRIES * (PAGE_SIZE / sizeof(struct tlb_track))) + + spinlock_t free_list_lock; + struct list_head free_list; + unsigned int limit; + unsigned int num_entries; + unsigned int num_free; + struct list_head page_list; + + /* XXX hash table size */ + spinlock_t hash_lock; + unsigned int hash_size; + unsigned int hash_shift; + unsigned int hash_mask; + struct list_head* hash; +}; + +int tlb_track_create(struct domain* d); +void tlb_track_destroy(struct domain* d); + +void tlb_track_free_entry(struct tlb_track* tlb_track, + struct tlb_track_entry* entry); + +void +__vcpu_tlb_track_insert_or_dirty(struct vcpu *vcpu, unsigned long vaddr, + struct p2m_entry* entry); +static inline void +vcpu_tlb_track_insert_or_dirty(struct vcpu *vcpu, unsigned long vaddr, + struct p2m_entry* entry) +{ + /* optimization. + non-tracking pte is most common. */ + perfc_incrc(tlb_track_iod); + if (!pte_tlb_tracking(entry->used)) { + perfc_incrc(tlb_track_iod_not_tracked); + return; + } + + __vcpu_tlb_track_insert_or_dirty(vcpu, vaddr, entry); +} + + +/* return value + * NULL if this entry is used + * entry if this entry isn't used + */ +enum TLB_TRACK_RET { + TLB_TRACK_NOT_TRACKED, + TLB_TRACK_NOT_FOUND, + TLB_TRACK_FOUND, + TLB_TRACK_MANY, + TLB_TRACK_AGAIN, +}; +typedef enum TLB_TRACK_RET TLB_TRACK_RET_T; + +TLB_TRACK_RET_T +tlb_track_search_and_remove(struct tlb_track* tlb_track, + volatile pte_t* ptep, pte_t old_pte, + struct tlb_track_entry** entryp); + +void +__tlb_track_entry_printf(const char* func, int line, + const struct tlb_track_entry* entry); +#define tlb_track_entry_printf(entry) \ + __tlb_track_entry_printf(__func__, __LINE__, (entry)) +#else +//define as nop +#define tlb_track_create(d) do { } while (0) +#define tlb_track_destroy(d) do { } while (0) +#define tlb_track_free_entry(tlb_track, entry) do { } while (0) +#define vcpu_tlb_track_insert_or_dirty(vcpu, vaddr, entry) \ + do { } while (0) +#define tlb_track_search_and_remove(tlb_track, ptep, old_pte, entryp) \ + do { } while (0) +#define tlb_track_entry_printf(entry) do { } while (0) +#endif /* CONFIG_XEN_IA64_TLB_TRACK */ + +#endif /* __TLB_TRACK_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/asm-ia64/tlbflush.h b/xen/include/asm-ia64/tlbflush.h index 22abb53f3f..49ff463b11 100644 --- a/xen/include/asm-ia64/tlbflush.h +++ b/xen/include/asm-ia64/tlbflush.h @@ -22,6 +22,15 @@ void domain_flush_vtlb_all (void); /* Global range-flush of vTLB. */ void domain_flush_vtlb_range (struct domain *d, u64 vadr, u64 addr_range); +#ifdef CONFIG_XEN_IA64_TLB_TRACK +struct tlb_track_entry; +void __domain_flush_vtlb_track_entry(struct domain* d, + const struct tlb_track_entry* entry); +/* Global entry-flush of vTLB */ +void domain_flush_vtlb_track_entry(struct domain* d, + const struct tlb_track_entry* entry); +#endif + /* Flush vhpt and mTLB on every dirty cpus. */ void domain_flush_tlb_vhpt(struct domain *d); @@ -31,7 +40,6 @@ void flush_tlb_mask(cpumask_t mask); /* Flush local machine TLB. */ void local_flush_tlb_all (void); -#define tlbflush_current_time() 0 #define tlbflush_filter(x,y) ((void)0) #endif diff --git a/xen/include/asm-ia64/uaccess.h b/xen/include/asm-ia64/uaccess.h index 17e2a17f9d..32ef4151df 100644 --- a/xen/include/asm-ia64/uaccess.h +++ b/xen/include/asm-ia64/uaccess.h @@ -211,30 +211,16 @@ extern void __put_user_unknown (void); extern unsigned long __must_check __copy_user (void __user *to, const void __user *from, unsigned long count); -extern int ia64_map_hypercall_param(void); - static inline unsigned long __copy_to_user (void __user *to, const void *from, unsigned long count) { - unsigned long len; - len = __copy_user(to, (void __user *)from, count); - if (len == 0) - return 0; - if (ia64_map_hypercall_param()) - len = __copy_user(to, (void __user *)from, count); /* retry */ - return len; + return __copy_user(to, (void __user *)from, count); } static inline unsigned long __copy_from_user (void *to, const void __user *from, unsigned long count) { - unsigned long len; - len = __copy_user((void __user *)to, from, count); - if (len == 0) - return 0; - if (ia64_map_hypercall_param()) - len = __copy_user((void __user *) to, from, count); /* retry */ - return len; + return __copy_user((void __user *)to, from, count); } #define __copy_to_user_inatomic __copy_to_user diff --git a/xen/include/asm-ia64/vcpu.h b/xen/include/asm-ia64/vcpu.h index 7bfc76f761..3a6af9d2d6 100644 --- a/xen/include/asm-ia64/vcpu.h +++ b/xen/include/asm-ia64/vcpu.h @@ -10,194 +10,194 @@ #include <asm/ia64_int.h> #include <xen/types.h> #include <public/xen.h> -typedef unsigned long UINT64; -typedef unsigned int UINT; -typedef int BOOLEAN; +typedef int BOOLEAN; struct vcpu; -typedef struct vcpu VCPU; +typedef struct vcpu VCPU; typedef cpu_user_regs_t REGS; extern u64 cycle_to_ns(u64 cycle); /* Note: PSCB stands for Privilegied State Communication Block. */ #define VCPU(_v,_x) (_v->arch.privregs->_x) -#define PSCB(_v,_x) VCPU(_v,_x) -#define PSCBX(_v,_x) (_v->arch._x) +#define PSCB(_v,_x) VCPU(_v,_x) +#define PSCBX(_v,_x) (_v->arch._x) #define SPURIOUS_VECTOR 0xf /* general registers */ -extern UINT64 vcpu_get_gr(VCPU *vcpu, unsigned long reg); -extern IA64FAULT vcpu_get_gr_nat(VCPU *vcpu, unsigned long reg, UINT64 *val); -extern IA64FAULT vcpu_set_gr(VCPU *vcpu, unsigned long reg, UINT64 value, int nat); -extern IA64FAULT vcpu_get_fpreg(VCPU *vcpu, unsigned long reg, struct ia64_fpreg *val); +extern u64 vcpu_get_gr(VCPU * vcpu, unsigned long reg); +extern IA64FAULT vcpu_get_gr_nat(VCPU * vcpu, unsigned long reg, u64 * val); +extern IA64FAULT vcpu_set_gr(VCPU * vcpu, unsigned long reg, u64 value, + int nat); +extern IA64FAULT vcpu_get_fpreg(VCPU * vcpu, unsigned long reg, + struct ia64_fpreg *val); -extern IA64FAULT vcpu_set_fpreg(VCPU *vcpu, unsigned long reg, struct ia64_fpreg *val); +extern IA64FAULT vcpu_set_fpreg(VCPU * vcpu, unsigned long reg, + struct ia64_fpreg *val); /* application registers */ -extern void vcpu_load_kernel_regs(VCPU *vcpu); -extern IA64FAULT vcpu_set_ar(VCPU *vcpu, UINT64 reg, UINT64 val); -extern IA64FAULT vcpu_get_ar(VCPU *vcpu, UINT64 reg, UINT64 *val); +extern void vcpu_load_kernel_regs(VCPU * vcpu); +extern IA64FAULT vcpu_set_ar(VCPU * vcpu, u64 reg, u64 val); +extern IA64FAULT vcpu_get_ar(VCPU * vcpu, u64 reg, u64 * val); /* psr */ -extern BOOLEAN vcpu_get_psr_ic(VCPU *vcpu); -extern UINT64 vcpu_get_ipsr_int_state(VCPU *vcpu,UINT64 prevpsr); -extern IA64FAULT vcpu_get_psr(VCPU *vcpu, UINT64 *pval); -extern IA64FAULT vcpu_reset_psr_sm(VCPU *vcpu, UINT64 imm); -extern IA64FAULT vcpu_set_psr_sm(VCPU *vcpu, UINT64 imm); -extern IA64FAULT vcpu_set_psr_l(VCPU *vcpu, UINT64 val); -extern IA64FAULT vcpu_set_psr_i(VCPU *vcpu); -extern IA64FAULT vcpu_reset_psr_dt(VCPU *vcpu); -extern IA64FAULT vcpu_set_psr_dt(VCPU *vcpu); +extern BOOLEAN vcpu_get_psr_ic(VCPU * vcpu); +extern u64 vcpu_get_ipsr_int_state(VCPU * vcpu, u64 prevpsr); +extern IA64FAULT vcpu_get_psr(VCPU * vcpu, u64 * pval); +extern IA64FAULT vcpu_reset_psr_sm(VCPU * vcpu, u64 imm); +extern IA64FAULT vcpu_set_psr_sm(VCPU * vcpu, u64 imm); +extern IA64FAULT vcpu_set_psr_l(VCPU * vcpu, u64 val); +extern IA64FAULT vcpu_set_psr_i(VCPU * vcpu); +extern IA64FAULT vcpu_reset_psr_dt(VCPU * vcpu); +extern IA64FAULT vcpu_set_psr_dt(VCPU * vcpu); /* control registers */ -extern IA64FAULT vcpu_set_dcr(VCPU *vcpu, UINT64 val); -extern IA64FAULT vcpu_set_itm(VCPU *vcpu, UINT64 val); -extern IA64FAULT vcpu_set_iva(VCPU *vcpu, UINT64 val); -extern IA64FAULT vcpu_set_pta(VCPU *vcpu, UINT64 val); -extern IA64FAULT vcpu_set_ipsr(VCPU *vcpu, UINT64 val); -extern IA64FAULT vcpu_set_isr(VCPU *vcpu, UINT64 val); -extern IA64FAULT vcpu_set_iip(VCPU *vcpu, UINT64 val); -extern IA64FAULT vcpu_set_ifa(VCPU *vcpu, UINT64 val); -extern IA64FAULT vcpu_set_itir(VCPU *vcpu, UINT64 val); -extern IA64FAULT vcpu_set_iipa(VCPU *vcpu, UINT64 val); -extern IA64FAULT vcpu_set_ifs(VCPU *vcpu, UINT64 val); -extern IA64FAULT vcpu_set_iim(VCPU *vcpu, UINT64 val); -extern IA64FAULT vcpu_set_iha(VCPU *vcpu, UINT64 val); -extern IA64FAULT vcpu_set_lid(VCPU *vcpu, UINT64 val); -extern IA64FAULT vcpu_set_tpr(VCPU *vcpu, UINT64 val); -extern IA64FAULT vcpu_set_eoi(VCPU *vcpu, UINT64 val); -extern IA64FAULT vcpu_set_lrr0(VCPU *vcpu, UINT64 val); -extern IA64FAULT vcpu_set_lrr1(VCPU *vcpu, UINT64 val); -extern IA64FAULT vcpu_get_dcr(VCPU *vcpu, UINT64 *pval); -extern IA64FAULT vcpu_get_itm(VCPU *vcpu, UINT64 *pval); -extern IA64FAULT vcpu_get_iva(VCPU *vcpu, UINT64 *pval); -extern IA64FAULT vcpu_get_pta(VCPU *vcpu, UINT64 *pval); -extern IA64FAULT vcpu_get_ipsr(VCPU *vcpu, UINT64 *pval); -extern IA64FAULT vcpu_get_isr(VCPU *vcpu, UINT64 *pval); -extern IA64FAULT vcpu_get_iip(VCPU *vcpu, UINT64 *pval); -extern IA64FAULT vcpu_increment_iip(VCPU *vcpu); -extern IA64FAULT vcpu_get_ifa(VCPU *vcpu, UINT64 *pval); -extern IA64FAULT vcpu_get_itir(VCPU *vcpu, UINT64 *pval); -extern unsigned long vcpu_get_itir_on_fault(VCPU *vcpu, UINT64 ifa); -extern IA64FAULT vcpu_get_iipa(VCPU *vcpu, UINT64 *pval); -extern IA64FAULT vcpu_get_ifs(VCPU *vcpu, UINT64 *pval); -extern IA64FAULT vcpu_get_iim(VCPU *vcpu, UINT64 *pval); -extern IA64FAULT vcpu_get_iha(VCPU *vcpu, UINT64 *pval); -extern IA64FAULT vcpu_get_lid(VCPU *vcpu, UINT64 *pval); -extern IA64FAULT vcpu_get_tpr(VCPU *vcpu, UINT64 *pval); -extern IA64FAULT vcpu_get_irr0(VCPU *vcpu, UINT64 *pval); -extern IA64FAULT vcpu_get_irr1(VCPU *vcpu, UINT64 *pval); -extern IA64FAULT vcpu_get_irr2(VCPU *vcpu, UINT64 *pval); -extern IA64FAULT vcpu_get_irr3(VCPU *vcpu, UINT64 *pval); -extern IA64FAULT vcpu_get_lrr0(VCPU *vcpu, UINT64 *pval); -extern IA64FAULT vcpu_get_lrr1(VCPU *vcpu, UINT64 *pval); +extern IA64FAULT vcpu_set_dcr(VCPU * vcpu, u64 val); +extern IA64FAULT vcpu_set_itm(VCPU * vcpu, u64 val); +extern IA64FAULT vcpu_set_iva(VCPU * vcpu, u64 val); +extern IA64FAULT vcpu_set_pta(VCPU * vcpu, u64 val); +extern IA64FAULT vcpu_set_ipsr(VCPU * vcpu, u64 val); +extern IA64FAULT vcpu_set_isr(VCPU * vcpu, u64 val); +extern IA64FAULT vcpu_set_iip(VCPU * vcpu, u64 val); +extern IA64FAULT vcpu_set_ifa(VCPU * vcpu, u64 val); +extern IA64FAULT vcpu_set_itir(VCPU * vcpu, u64 val); +extern IA64FAULT vcpu_set_iipa(VCPU * vcpu, u64 val); +extern IA64FAULT vcpu_set_ifs(VCPU * vcpu, u64 val); +extern IA64FAULT vcpu_set_iim(VCPU * vcpu, u64 val); +extern IA64FAULT vcpu_set_iha(VCPU * vcpu, u64 val); +extern IA64FAULT vcpu_set_lid(VCPU * vcpu, u64 val); +extern IA64FAULT vcpu_set_tpr(VCPU * vcpu, u64 val); +extern IA64FAULT vcpu_set_eoi(VCPU * vcpu, u64 val); +extern IA64FAULT vcpu_set_lrr0(VCPU * vcpu, u64 val); +extern IA64FAULT vcpu_set_lrr1(VCPU * vcpu, u64 val); +extern IA64FAULT vcpu_get_dcr(VCPU * vcpu, u64 * pval); +extern IA64FAULT vcpu_get_itm(VCPU * vcpu, u64 * pval); +extern IA64FAULT vcpu_get_iva(VCPU * vcpu, u64 * pval); +extern IA64FAULT vcpu_get_pta(VCPU * vcpu, u64 * pval); +extern IA64FAULT vcpu_get_ipsr(VCPU * vcpu, u64 * pval); +extern IA64FAULT vcpu_get_isr(VCPU * vcpu, u64 * pval); +extern IA64FAULT vcpu_get_iip(VCPU * vcpu, u64 * pval); +extern IA64FAULT vcpu_increment_iip(VCPU * vcpu); +extern IA64FAULT vcpu_get_ifa(VCPU * vcpu, u64 * pval); +extern IA64FAULT vcpu_get_itir(VCPU * vcpu, u64 * pval); +extern unsigned long vcpu_get_itir_on_fault(VCPU * vcpu, u64 ifa); +extern IA64FAULT vcpu_get_iipa(VCPU * vcpu, u64 * pval); +extern IA64FAULT vcpu_get_ifs(VCPU * vcpu, u64 * pval); +extern IA64FAULT vcpu_get_iim(VCPU * vcpu, u64 * pval); +extern IA64FAULT vcpu_get_iha(VCPU * vcpu, u64 * pval); +extern IA64FAULT vcpu_get_lid(VCPU * vcpu, u64 * pval); +extern IA64FAULT vcpu_get_tpr(VCPU * vcpu, u64 * pval); +extern IA64FAULT vcpu_get_irr0(VCPU * vcpu, u64 * pval); +extern IA64FAULT vcpu_get_irr1(VCPU * vcpu, u64 * pval); +extern IA64FAULT vcpu_get_irr2(VCPU * vcpu, u64 * pval); +extern IA64FAULT vcpu_get_irr3(VCPU * vcpu, u64 * pval); +extern IA64FAULT vcpu_get_lrr0(VCPU * vcpu, u64 * pval); +extern IA64FAULT vcpu_get_lrr1(VCPU * vcpu, u64 * pval); /* interrupt registers */ -extern void vcpu_pend_unspecified_interrupt(VCPU *vcpu); -extern UINT64 vcpu_check_pending_interrupts(VCPU *vcpu); -extern IA64FAULT vcpu_get_itv(VCPU *vcpu,UINT64 *pval); -extern IA64FAULT vcpu_get_pmv(VCPU *vcpu,UINT64 *pval); -extern IA64FAULT vcpu_get_cmcv(VCPU *vcpu,UINT64 *pval); -extern IA64FAULT vcpu_get_ivr(VCPU *vcpu, UINT64 *pval); -extern IA64FAULT vcpu_set_itv(VCPU *vcpu, UINT64 val); -extern IA64FAULT vcpu_set_pmv(VCPU *vcpu, UINT64 val); -extern IA64FAULT vcpu_set_cmcv(VCPU *vcpu, UINT64 val); +extern void vcpu_pend_unspecified_interrupt(VCPU * vcpu); +extern u64 vcpu_check_pending_interrupts(VCPU * vcpu); +extern IA64FAULT vcpu_get_itv(VCPU * vcpu, u64 * pval); +extern IA64FAULT vcpu_get_pmv(VCPU * vcpu, u64 * pval); +extern IA64FAULT vcpu_get_cmcv(VCPU * vcpu, u64 * pval); +extern IA64FAULT vcpu_get_ivr(VCPU * vcpu, u64 * pval); +extern IA64FAULT vcpu_set_itv(VCPU * vcpu, u64 val); +extern IA64FAULT vcpu_set_pmv(VCPU * vcpu, u64 val); +extern IA64FAULT vcpu_set_cmcv(VCPU * vcpu, u64 val); /* interval timer registers */ -extern IA64FAULT vcpu_set_itc(VCPU *vcpu,UINT64 val); -extern UINT64 vcpu_timer_pending_early(VCPU *vcpu); +extern IA64FAULT vcpu_set_itc(VCPU * vcpu, u64 val); +extern u64 vcpu_timer_pending_early(VCPU * vcpu); /* debug breakpoint registers */ -extern IA64FAULT vcpu_set_ibr(VCPU *vcpu,UINT64 reg,UINT64 val); -extern IA64FAULT vcpu_set_dbr(VCPU *vcpu,UINT64 reg,UINT64 val); -extern IA64FAULT vcpu_get_ibr(VCPU *vcpu,UINT64 reg,UINT64 *pval); -extern IA64FAULT vcpu_get_dbr(VCPU *vcpu,UINT64 reg,UINT64 *pval); +extern IA64FAULT vcpu_set_ibr(VCPU * vcpu, u64 reg, u64 val); +extern IA64FAULT vcpu_set_dbr(VCPU * vcpu, u64 reg, u64 val); +extern IA64FAULT vcpu_get_ibr(VCPU * vcpu, u64 reg, u64 * pval); +extern IA64FAULT vcpu_get_dbr(VCPU * vcpu, u64 reg, u64 * pval); /* performance monitor registers */ -extern IA64FAULT vcpu_set_pmc(VCPU *vcpu,UINT64 reg,UINT64 val); -extern IA64FAULT vcpu_set_pmd(VCPU *vcpu,UINT64 reg,UINT64 val); -extern IA64FAULT vcpu_get_pmc(VCPU *vcpu,UINT64 reg,UINT64 *pval); -extern IA64FAULT vcpu_get_pmd(VCPU *vcpu,UINT64 reg,UINT64 *pval); +extern IA64FAULT vcpu_set_pmc(VCPU * vcpu, u64 reg, u64 val); +extern IA64FAULT vcpu_set_pmd(VCPU * vcpu, u64 reg, u64 val); +extern IA64FAULT vcpu_get_pmc(VCPU * vcpu, u64 reg, u64 * pval); +extern IA64FAULT vcpu_get_pmd(VCPU * vcpu, u64 reg, u64 * pval); /* banked general registers */ -extern IA64FAULT vcpu_bsw0(VCPU *vcpu); -extern IA64FAULT vcpu_bsw1(VCPU *vcpu); +extern IA64FAULT vcpu_bsw0(VCPU * vcpu); +extern IA64FAULT vcpu_bsw1(VCPU * vcpu); /* region registers */ -extern IA64FAULT vcpu_set_rr(VCPU *vcpu,UINT64 reg,UINT64 val); -extern IA64FAULT vcpu_get_rr(VCPU *vcpu,UINT64 reg,UINT64 *pval); -extern IA64FAULT vcpu_get_rr_ve(VCPU *vcpu,UINT64 vadr); +extern IA64FAULT vcpu_set_rr(VCPU * vcpu, u64 reg, u64 val); +extern IA64FAULT vcpu_get_rr(VCPU * vcpu, u64 reg, u64 * pval); +extern IA64FAULT vcpu_get_rr_ve(VCPU * vcpu, u64 vadr); /* protection key registers */ -extern IA64FAULT vcpu_get_pkr(VCPU *vcpu, UINT64 reg, UINT64 *pval); -extern IA64FAULT vcpu_set_pkr(VCPU *vcpu, UINT64 reg, UINT64 val); -extern IA64FAULT vcpu_tak(VCPU *vcpu, UINT64 vadr, UINT64 *key); +extern IA64FAULT vcpu_get_pkr(VCPU * vcpu, u64 reg, u64 * pval); +extern IA64FAULT vcpu_set_pkr(VCPU * vcpu, u64 reg, u64 val); +extern IA64FAULT vcpu_tak(VCPU * vcpu, u64 vadr, u64 * key); /* TLB */ -static inline void vcpu_purge_tr_entry(TR_ENTRY *trp) +static inline void vcpu_purge_tr_entry(TR_ENTRY * trp) { trp->pte.val = 0; } -extern IA64FAULT vcpu_itr_d(VCPU *vcpu, UINT64 slot, UINT64 padr, - UINT64 itir, UINT64 ifa); -extern IA64FAULT vcpu_itr_i(VCPU *vcpu, UINT64 slot, UINT64 padr, - UINT64 itir, UINT64 ifa); -extern IA64FAULT vcpu_itc_d(VCPU *vcpu, UINT64 padr, UINT64 itir, UINT64 ifa); -extern IA64FAULT vcpu_itc_i(VCPU *vcpu, UINT64 padr, UINT64 itir, UINT64 ifa); -extern IA64FAULT vcpu_ptc_l(VCPU *vcpu, UINT64 vadr, UINT64 log_range); -extern IA64FAULT vcpu_ptc_e(VCPU *vcpu, UINT64 vadr); -extern IA64FAULT vcpu_ptc_g(VCPU *vcpu, UINT64 vadr, UINT64 addr_range); -extern IA64FAULT vcpu_ptc_ga(VCPU *vcpu, UINT64 vadr, UINT64 addr_range); -extern IA64FAULT vcpu_ptr_d(VCPU *vcpu,UINT64 vadr, UINT64 log_range); -extern IA64FAULT vcpu_ptr_i(VCPU *vcpu,UINT64 vadr, UINT64 log_range); +extern IA64FAULT vcpu_itr_d(VCPU * vcpu, u64 slot, u64 padr, u64 itir, u64 ifa); +extern IA64FAULT vcpu_itr_i(VCPU * vcpu, u64 slot, u64 padr, u64 itir, u64 ifa); +extern IA64FAULT vcpu_itc_d(VCPU * vcpu, u64 padr, u64 itir, u64 ifa); +extern IA64FAULT vcpu_itc_i(VCPU * vcpu, u64 padr, u64 itir, u64 ifa); +extern IA64FAULT vcpu_ptc_l(VCPU * vcpu, u64 vadr, u64 log_range); +extern IA64FAULT vcpu_ptc_e(VCPU * vcpu, u64 vadr); +extern IA64FAULT vcpu_ptc_g(VCPU * vcpu, u64 vadr, u64 addr_range); +extern IA64FAULT vcpu_ptc_ga(VCPU * vcpu, u64 vadr, u64 addr_range); +extern IA64FAULT vcpu_ptr_d(VCPU * vcpu, u64 vadr, u64 log_range); +extern IA64FAULT vcpu_ptr_i(VCPU * vcpu, u64 vadr, u64 log_range); union U_IA64_BUNDLE; -extern int vcpu_get_domain_bundle(VCPU *vcpu, REGS *regs, UINT64 gip, union U_IA64_BUNDLE *bundle); -extern IA64FAULT vcpu_translate(VCPU *vcpu, UINT64 address, BOOLEAN is_data, - UINT64 *pteval, UINT64 *itir, UINT64 *iha); -extern IA64FAULT vcpu_tpa(VCPU *vcpu, UINT64 vadr, UINT64 *padr); -extern IA64FAULT vcpu_force_inst_miss(VCPU *vcpu, UINT64 ifa); -extern IA64FAULT vcpu_force_data_miss(VCPU *vcpu, UINT64 ifa); -extern IA64FAULT vcpu_fc(VCPU *vcpu, UINT64 vadr); +extern int vcpu_get_domain_bundle(VCPU * vcpu, REGS * regs, u64 gip, + union U_IA64_BUNDLE *bundle); +extern IA64FAULT vcpu_translate(VCPU * vcpu, u64 address, BOOLEAN is_data, + u64 * pteval, u64 * itir, u64 * iha); +extern IA64FAULT vcpu_tpa(VCPU * vcpu, u64 vadr, u64 * padr); +extern IA64FAULT vcpu_force_inst_miss(VCPU * vcpu, u64 ifa); +extern IA64FAULT vcpu_force_data_miss(VCPU * vcpu, u64 ifa); +extern IA64FAULT vcpu_fc(VCPU * vcpu, u64 vadr); /* misc */ -extern IA64FAULT vcpu_rfi(VCPU *vcpu); -extern IA64FAULT vcpu_thash(VCPU *vcpu, UINT64 vadr, UINT64 *pval); -extern IA64FAULT vcpu_cover(VCPU *vcpu); -extern IA64FAULT vcpu_ttag(VCPU *vcpu, UINT64 vadr, UINT64 *padr); -extern IA64FAULT vcpu_get_cpuid(VCPU *vcpu, UINT64 reg, UINT64 *pval); - -extern void vcpu_pend_interrupt(VCPU *vcpu, UINT64 vector); -extern void vcpu_pend_timer(VCPU *vcpu); -extern void vcpu_poke_timer(VCPU *vcpu); -extern void vcpu_set_next_timer(VCPU *vcpu); -extern BOOLEAN vcpu_timer_expired(VCPU *vcpu); -extern UINT64 vcpu_deliverable_interrupts(VCPU *vcpu); -extern void vcpu_itc_no_srlz(VCPU *vcpu, UINT64, UINT64, UINT64, UINT64, UINT64); -extern UINT64 vcpu_get_tmp(VCPU *, UINT64); -extern void vcpu_set_tmp(VCPU *, UINT64, UINT64); - -extern IA64FAULT vcpu_set_dtr(VCPU *vcpu, u64 slot, +extern IA64FAULT vcpu_rfi(VCPU * vcpu); +extern IA64FAULT vcpu_thash(VCPU * vcpu, u64 vadr, u64 * pval); +extern IA64FAULT vcpu_cover(VCPU * vcpu); +extern IA64FAULT vcpu_ttag(VCPU * vcpu, u64 vadr, u64 * padr); +extern IA64FAULT vcpu_get_cpuid(VCPU * vcpu, u64 reg, u64 * pval); + +extern void vcpu_pend_interrupt(VCPU * vcpu, u64 vector); +extern void vcpu_pend_timer(VCPU * vcpu); +extern void vcpu_poke_timer(VCPU * vcpu); +extern void vcpu_set_next_timer(VCPU * vcpu); +extern BOOLEAN vcpu_timer_expired(VCPU * vcpu); +extern u64 vcpu_deliverable_interrupts(VCPU * vcpu); +struct p2m_entry; +extern void vcpu_itc_no_srlz(VCPU * vcpu, u64, u64, u64, u64, u64, + struct p2m_entry *); +extern u64 vcpu_get_tmp(VCPU *, u64); +extern void vcpu_set_tmp(VCPU *, u64, u64); + +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, +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); +extern void vcpu_init_regs(struct vcpu *v); -static inline UINT64 -itir_ps(UINT64 itir) +static inline u64 itir_ps(u64 itir) { - return ((itir >> 2) & 0x3f); + return ((itir >> 2) & 0x3f); } -static inline UINT64 -itir_mask(UINT64 itir) +static inline u64 itir_mask(u64 itir) { - return (~((1UL << itir_ps(itir)) - 1)); + return (~((1UL << itir_ps(itir)) - 1)); } -static inline s64 -vcpu_get_next_timer_ns(VCPU *vcpu) +static inline s64 vcpu_get_next_timer_ns(VCPU * vcpu) { - s64 vcpu_get_next_timer_ns; - u64 d = PSCBX(vcpu, domain_itm); - u64 now = ia64_get_itc(); + s64 vcpu_get_next_timer_ns; + u64 d = PSCBX(vcpu, domain_itm); + u64 now = ia64_get_itc(); - if (d > now) - vcpu_get_next_timer_ns = cycle_to_ns(d - now) + NOW(); - else - vcpu_get_next_timer_ns = cycle_to_ns(local_cpu_data->itm_delta) + NOW(); + if (d > now) + vcpu_get_next_timer_ns = cycle_to_ns(d - now) + NOW(); + else + vcpu_get_next_timer_ns = + cycle_to_ns(local_cpu_data->itm_delta) + NOW(); - return vcpu_get_next_timer_ns; + return vcpu_get_next_timer_ns; } #define verbose(a...) do {if (vcpu_verbose) printf(a);} while(0) @@ -208,5 +208,4 @@ vcpu_get_next_timer_ns(VCPU *vcpu) #define vcpu_quick_region_set(_tr_regions,_ifa) \ do {_tr_regions |= (1 << ((unsigned long)_ifa >> 61)); } while (0) - #endif diff --git a/xen/include/asm-ia64/vcpumask.h b/xen/include/asm-ia64/vcpumask.h new file mode 100644 index 0000000000..7a9773e411 --- /dev/null +++ b/xen/include/asm-ia64/vcpumask.h @@ -0,0 +1,60 @@ +#ifndef __XEN_VCPUMASK_H +#define __XEN_VCPUMASK_H + +/* vcpu mask + stolen from cpumask.h */ +typedef struct { DECLARE_BITMAP(bits, MAX_VIRT_CPUS); } vcpumask_t; + +#define vcpu_set(vcpu, dst) __vcpu_set((vcpu), &(dst)) +static inline void __vcpu_set(int vcpu, volatile vcpumask_t *dstp) +{ + set_bit(vcpu, dstp->bits); +} +#define vcpus_clear(dst) __vcpus_clear(&(dst), MAX_VIRT_CPUS) +static inline void __vcpus_clear(vcpumask_t *dstp, int nbits) +{ + bitmap_zero(dstp->bits, nbits); +} +/* No static inline type checking - see Subtlety (1) above. */ +#define vcpu_isset(vcpu, vcpumask) test_bit((vcpu), (vcpumask).bits) + +#define first_vcpu(src) __first_vcpu(&(src), MAX_VIRT_CPUS) +static inline int __first_vcpu(const vcpumask_t *srcp, int nbits) +{ + return min_t(int, nbits, find_first_bit(srcp->bits, nbits)); +} + +#define next_vcpu(n, src) __next_vcpu((n), &(src), MAX_VIRT_CPUS) +static inline int __next_vcpu(int n, const vcpumask_t *srcp, int nbits) +{ + return min_t(int, nbits, find_next_bit(srcp->bits, nbits, n+1)); +} + +#if MAX_VIRT_CPUS > 1 +#define for_each_vcpu_mask(vcpu, mask) \ + for ((vcpu) = first_vcpu(mask); \ + (vcpu) < MAX_VIRT_CPUS; \ + (vcpu) = next_vcpu((vcpu), (mask))) +#else /* NR_CPUS == 1 */ +#define for_each_vcpu_mask(vcpu, mask) for ((vcpu) = 0; (vcpu) < 1; (vcpu)++) +#endif /* NR_CPUS */ + +#define vcpumask_scnprintf(buf, len, src) \ + __vcpumask_scnprintf((buf), (len), &(src), MAX_VIRT_CPUS) +static inline int __vcpumask_scnprintf(char *buf, int len, + const vcpumask_t *srcp, int nbits) +{ + return bitmap_scnprintf(buf, len, srcp->bits, nbits); +} + +#endif /* __XEN_VCPUMASK_H */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/asm-ia64/vhpt.h b/xen/include/asm-ia64/vhpt.h index cb4fc30462..351c1d701a 100644 --- a/xen/include/asm-ia64/vhpt.h +++ b/xen/include/asm-ia64/vhpt.h @@ -18,6 +18,10 @@ #ifndef __ASSEMBLY__ #include <xen/percpu.h> +#include <asm/vcpumask.h> + +extern void domain_purge_swtc_entries(struct domain *d); +extern void domain_purge_swtc_entries_vcpu_dirty_mask(struct domain* d, vcpumask_t vcpu_dirty_mask); // // VHPT Long Format Entry (as recognized by hw) @@ -37,11 +41,48 @@ extern void vhpt_multiple_insert(unsigned long vaddr, unsigned long pte, unsigned long logps); extern void vhpt_insert (unsigned long vadr, unsigned long pte, unsigned long logps); -void vhpt_flush(void); +void local_vhpt_flush(void); +extern void vcpu_vhpt_flush(struct vcpu* v); /* Currently the VHPT is allocated per CPU. */ DECLARE_PER_CPU (unsigned long, vhpt_paddr); DECLARE_PER_CPU (unsigned long, vhpt_pend); +#ifdef CONFIG_XEN_IA64_PERVCPU_VHPT +#if !VHPT_ENABLED +#error "VHPT_ENABLED must be set for CONFIG_XEN_IA64_PERVCPU_VHPT" +#endif +#endif + +#include <xen/sched.h> +int pervcpu_vhpt_alloc(struct vcpu *v); +void pervcpu_vhpt_free(struct vcpu *v); +static inline unsigned long +vcpu_vhpt_maddr(struct vcpu* v) +{ +#ifdef CONFIG_XEN_IA64_PERVCPU_VHPT + if (HAS_PERVCPU_VHPT(v->domain)) + return v->arch.vhpt_maddr; +#endif + +#if 0 + // referencecing v->processor is racy. + return per_cpu(vhpt_paddr, v->processor); +#endif + BUG_ON(v != current); + return __get_cpu_var(vhpt_paddr); +} + +static inline unsigned long +vcpu_pta(struct vcpu* v) +{ +#ifdef CONFIG_XEN_IA64_PERVCPU_VHPT + if (HAS_PERVCPU_VHPT(v->domain)) + return v->arch.pta.val; +#endif + return __va_ul(__get_cpu_var(vhpt_paddr)) | (1 << 8) | + (VHPT_SIZE_LOG2 << 2) | VHPT_ENABLED; +} + #endif /* !__ASSEMBLY */ #endif diff --git a/xen/include/asm-ia64/vmx.h b/xen/include/asm-ia64/vmx.h index b9d9a67779..577fc1e34d 100644 --- a/xen/include/asm-ia64/vmx.h +++ b/xen/include/asm-ia64/vmx.h @@ -35,6 +35,7 @@ extern void vmx_final_setup_guest(struct vcpu *v); extern void vmx_save_state(struct vcpu *v); extern void vmx_load_state(struct vcpu *v); extern void vmx_setup_platform(struct domain *d); +extern void vmx_do_launch(struct vcpu *v); extern void vmx_io_assist(struct vcpu *v); extern int ia64_hypercall (struct pt_regs *regs); extern void vmx_save_state(struct vcpu *v); diff --git a/xen/include/asm-ia64/vmx_pal_vsa.h b/xen/include/asm-ia64/vmx_pal_vsa.h index 72ad1e6ca7..7ce8069501 100644 --- a/xen/include/asm-ia64/vmx_pal_vsa.h +++ b/xen/include/asm-ia64/vmx_pal_vsa.h @@ -26,10 +26,9 @@ /* PAL virtualization services */ #ifndef __ASSEMBLY__ -extern UINT64 ia64_call_vsa(UINT64 proc,UINT64 arg1, UINT64 arg2, - UINT64 arg3, UINT64 arg4, UINT64 arg5, - UINT64 arg6, UINT64 arg7); -extern UINT64 __vsa_base; +extern u64 ia64_call_vsa(u64 proc, u64 arg1, u64 arg2, u64 arg3, + u64 arg4, u64 arg5, u64 arg6, u64 arg7); +extern u64 __vsa_base; #endif /* __ASSEMBLY__ */ #define PAL_VPS_RESUME_NORMAL 0x0000 diff --git a/xen/include/asm-ia64/vmx_phy_mode.h b/xen/include/asm-ia64/vmx_phy_mode.h index 02f8cc643f..bf9afde404 100644 --- a/xen/include/asm-ia64/vmx_phy_mode.h +++ b/xen/include/asm-ia64/vmx_phy_mode.h @@ -90,7 +90,7 @@ extern void physical_mode_init(VCPU *); extern void switch_to_physical_rid(VCPU *); extern void switch_to_virtual_rid(VCPU *vcpu); extern void switch_mm_mode(VCPU *vcpu, IA64_PSR old_psr, IA64_PSR new_psr); -extern void stlb_phys_lookup(VCPU *vcpu, UINT64 paddr, UINT64 type); +extern void stlb_phys_lookup(VCPU *vcpu, u64 paddr, u64 type); extern void check_mm_mode_switch (VCPU *vcpu, IA64_PSR old_psr, IA64_PSR new_psr); extern void prepare_if_physical_mode(VCPU *vcpu); extern void recover_if_physical_mode(VCPU *vcpu); @@ -120,9 +120,4 @@ extern void physical_tlb_miss(VCPU *vcpu, u64 vadr); #define GUEST_VIRT 1 /* Guest in virtual mode */ #define GUEST_PHYS 2 /* Guest in physical mode, requiring emulation */ - - #endif /* _PHY_MODE_H_ */ - - - diff --git a/xen/include/asm-ia64/vmx_uaccess.h b/xen/include/asm-ia64/vmx_uaccess.h deleted file mode 100644 index a6e27425f6..0000000000 --- a/xen/include/asm-ia64/vmx_uaccess.h +++ /dev/null @@ -1,156 +0,0 @@ -/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ -/* - * vmx_uaccess.h: Defines vmx specific macros to transfer memory areas - * across the domain/hypervisor boundary. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307 USA. - * - * Note: For vmx enabled environment, poor man's policy is actually - * useless since HV resides in completely different address space as - * domain. So the only way to do the access is search vTLB first, and - * access identity mapped address if hit. - * - * Copyright (c) 2004, Intel Corporation. - * Kun Tian (Kevin Tian) (kevin.tian@intel.com) - */ - -#ifndef __ASM_IA64_VMX_UACCESS_H__ -#define __ASM_IA64_VMX_UACCESS_H__ - -#include <xen/compiler.h> -#include <xen/errno.h> -#include <xen/sched.h> - -#include <asm/intrinsics.h> -#include <asm/vmmu.h> - -/* Since HV never accesses domain space directly, most security check can - * be dummy now - */ -asm (".section \"__ex_table\", \"a\"\n\t.previous"); - -/* For back compatibility */ -#define __access_ok(addr, size, segment) 1 -#define access_ok(addr, size, segment) __access_ok((addr), (size), (segment)) - -/* - * These are the main single-value transfer routines. They automatically - * use the right size if we just have the right pointer type. - * - * Careful to not - * (a) re-use the arguments for side effects (sizeof/typeof is ok) - * (b) require any knowledge of processes at this stage - */ -#define put_user(x, ptr) __put_user((x), (ptr)) -#define get_user(x, ptr) __get_user((x), (ptr)) - -#define __put_user(x, ptr) __do_put_user((__typeof__(*(ptr))) (x), (ptr), sizeof(*(ptr))) -#define __get_user(x, ptr) __do_get_user((x), (ptr), sizeof(*(ptr))) - -/* TODO: add specific unaligned access later. If assuming aligned at - * 1,2,4,8 bytes by far, it's impossible for operand spaning two - * vTLB entry - */ -extern long -__domain_va_to_ma(unsigned long va, unsigned long* ma, unsigned long *len); - -#define __do_put_user(x, ptr, size) \ -({ \ - __typeof__ (x) __pu_x = (x); \ - __typeof__ (*(ptr)) __user *__pu_ptr = (ptr); \ - __typeof__ (size) __pu_size = (size); \ - unsigned long __pu_ma; \ - long __pu_err; \ - \ - __pu_err = __domain_va_to_ma((unsigned long)__pu_ptr, \ - &__pu_ma, &__pu_size); \ - __pu_err ? (__pu_err = -EFAULT) : \ - (*((__typeof__ (*(ptr)) *)__va(__pu_ma)) = x); \ - __pu_err; \ -}) - -#define __do_get_user(x, ptr, size) \ -({ \ - __typeof__ (x) __gu_x = (x); \ - __typeof__ (*(ptr)) __user *__gu_ptr = (ptr); \ - __typeof__ (size) __gu_size = (size); \ - unsigned long __gu_ma; \ - long __gu_err; \ - \ - __gu_err = __domain_va_to_ma((unsigned long)__gu_ptr, \ - &__gu_ma, &__gu_size); \ - __gu_err ? (__gu_err = -EFAULT) : \ - (x = *((__typeof__ (*(ptr)) *)__va(__gu_ma))); \ - __gu_err; \ -}) - -/* More complex copy from domain */ -#define copy_from_user(to, from, n) __copy_from_user((to), (from), (n)) -#define copy_to_user(to, from, n) __copy_to_user((to), (from), (n)) -#define clear_user(to, n) __clear_user((t0), (n)) - -static inline unsigned long -__copy_from_user(void *to, void *from, unsigned long n) -{ - unsigned long ma, i; - - i = n; - while(!__domain_va_to_ma((unsigned long)from, &ma, &i)) { - memcpy(to, (void *)__va(ma), i); - n -= i; - if (!n) - break; - from += i; - to += i; - i = n; - } - return n; -} - -static inline unsigned long -__copy_to_user(void *to, void *from, unsigned long n) -{ - unsigned long ma, i; - - i = n; - while(!__domain_va_to_ma((unsigned long)to, &ma, &i)) { - memcpy((void *)__va(ma), from, i); - n -= i; - if (!n) - break; - from += i; - to += i; - i = n; - } - return n; -} - -static inline unsigned long -__clear_user(void *to, unsigned long n) -{ - unsigned long ma, i; - - i = n; - while(!__domain_va_to_ma((unsigned long)to, &ma, &i)) { - memset((void *)__va(ma), 0, i); - n -= i; - if (!n) - break; - to += i; - i = n; - } - return n; -} - -#endif // __ASM_IA64_VMX_UACCESS_H__ diff --git a/xen/include/asm-ia64/vmx_vcpu.h b/xen/include/asm-ia64/vmx_vcpu.h index a82e31fb7f..0defc0d4f4 100644 --- a/xen/include/asm-ia64/vmx_vcpu.h +++ b/xen/include/asm-ia64/vmx_vcpu.h @@ -1,4 +1,4 @@ -/* -*- Mode:C; c-basic-offset:4; tab-width:4; indent-tabs-mode:nil -*- */ +/* -*- Mode:C; c-basic-offset:8; tab-width:8; indent-tabs-mode:nil -*- */ /* * vmx_vcpu.h: * Copyright (c) 2005, Intel Corporation. @@ -23,7 +23,6 @@ #ifndef _XEN_IA64_VMX_VCPU_H #define _XEN_IA64_VMX_VCPU_H - #include <xen/sched.h> #include <asm/ia64_int.h> #include <asm/vmx_vpd.h> @@ -33,462 +32,438 @@ #include <asm/types.h> #include <asm/vcpu.h> -#define VRN_SHIFT 61 -#define VRN0 0x0UL -#define VRN1 0x1UL -#define VRN2 0x2UL -#define VRN3 0x3UL -#define VRN4 0x4UL -#define VRN5 0x5UL -#define VRN6 0x6UL -#define VRN7 0x7UL +#define VRN_SHIFT 61 +#define VRN0 0x0UL +#define VRN1 0x1UL +#define VRN2 0x2UL +#define VRN3 0x3UL +#define VRN4 0x4UL +#define VRN5 0x5UL +#define VRN6 0x6UL +#define VRN7 0x7UL // for vlsapic -#define VLSAPIC_INSVC(vcpu, i) ((vcpu)->arch.insvc[i]) +#define VLSAPIC_INSVC(vcpu, i) ((vcpu)->arch.insvc[i]) #define VMX(x,y) ((x)->arch.arch_vmx.y) +#define VMM_RR_SHIFT 20 +#define VMM_RR_MASK ((1UL<<VMM_RR_SHIFT)-1) -#define VMM_RR_SHIFT 20 -#define VMM_RR_MASK ((1UL<<VMM_RR_SHIFT)-1) - -extern u64 indirect_reg_igfld_MASK ( int type, int index, u64 value); -extern u64 cr_igfld_mask (int index, u64 value); -extern int check_indirect_reg_rsv_fields ( int type, int index, u64 value ); -extern u64 set_isr_ei_ni (VCPU *vcpu); -extern u64 set_isr_for_na_inst(VCPU *vcpu, int op); - +extern u64 indirect_reg_igfld_MASK(int type, int index, u64 value); +extern u64 cr_igfld_mask(int index, u64 value); +extern int check_indirect_reg_rsv_fields(int type, int index, u64 value); +extern u64 set_isr_ei_ni(VCPU * vcpu); +extern u64 set_isr_for_na_inst(VCPU * vcpu, int op); /* next all for VTI domain APIs definition */ -extern void vmx_vcpu_set_psr(VCPU *vcpu, unsigned long value); -extern UINT64 vmx_vcpu_sync_mpsr(UINT64 mipsr, UINT64 value); -extern void vmx_vcpu_set_psr_sync_mpsr(VCPU * vcpu, UINT64 value); -extern IA64FAULT vmx_vcpu_cover(VCPU *vcpu); -extern IA64FAULT vmx_vcpu_set_rr(VCPU *vcpu, UINT64 reg, UINT64 val); -extern IA64FAULT vmx_vcpu_get_pkr(VCPU *vcpu, UINT64 reg, UINT64 *pval); -IA64FAULT vmx_vcpu_set_pkr(VCPU *vcpu, UINT64 reg, UINT64 val); -extern IA64FAULT vmx_vcpu_itc_i(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa); -extern IA64FAULT vmx_vcpu_itc_d(VCPU *vcpu, UINT64 pte, UINT64 itir, UINT64 ifa); -extern IA64FAULT vmx_vcpu_itr_i(VCPU *vcpu, UINT64 slot, UINT64 pte, UINT64 itir, UINT64 ifa); -extern IA64FAULT vmx_vcpu_itr_d(VCPU *vcpu, UINT64 slot, UINT64 pte, UINT64 itir, UINT64 ifa); -extern IA64FAULT vmx_vcpu_ptr_d(VCPU *vcpu,UINT64 vadr,UINT64 ps); -extern IA64FAULT vmx_vcpu_ptr_i(VCPU *vcpu,UINT64 vadr,UINT64 ps); -extern IA64FAULT vmx_vcpu_ptc_l(VCPU *vcpu, UINT64 vadr, UINT64 ps); -extern IA64FAULT vmx_vcpu_ptc_e(VCPU *vcpu, UINT64 vadr); -extern IA64FAULT vmx_vcpu_ptc_g(VCPU *vcpu, UINT64 vadr, UINT64 ps); -extern IA64FAULT vmx_vcpu_ptc_ga(VCPU *vcpu,UINT64 vadr,UINT64 ps); -extern IA64FAULT vmx_vcpu_thash(VCPU *vcpu, UINT64 vadr, UINT64 *pval); -extern u64 vmx_vcpu_get_itir_on_fault(VCPU *vcpu, u64 ifa); -extern IA64FAULT vmx_vcpu_ttag(VCPU *vcpu, UINT64 vadr, UINT64 *pval); -extern IA64FAULT vmx_vcpu_tpa(VCPU *vcpu, UINT64 vadr, UINT64 *padr); -extern IA64FAULT vmx_vcpu_tak(VCPU *vcpu, UINT64 vadr, UINT64 *key); -extern IA64FAULT vmx_vcpu_rfi(VCPU *vcpu); -extern UINT64 vmx_vcpu_get_psr(VCPU *vcpu); -extern IA64FAULT vmx_vcpu_get_bgr(VCPU *vcpu, unsigned int reg, UINT64 *val); -extern IA64FAULT vmx_vcpu_set_bgr(VCPU *vcpu, unsigned int reg, u64 val,int nat); +extern void vmx_vcpu_set_psr(VCPU * vcpu, unsigned long value); +extern u64 vmx_vcpu_sync_mpsr(u64 mipsr, u64 value); +extern void vmx_vcpu_set_psr_sync_mpsr(VCPU * vcpu, u64 value); +extern IA64FAULT vmx_vcpu_cover(VCPU * vcpu); +extern IA64FAULT vmx_vcpu_set_rr(VCPU * vcpu, u64 reg, u64 val); +extern IA64FAULT vmx_vcpu_get_pkr(VCPU * vcpu, u64 reg, u64 * pval); +IA64FAULT vmx_vcpu_set_pkr(VCPU * vcpu, u64 reg, u64 val); +extern IA64FAULT vmx_vcpu_itc_i(VCPU * vcpu, u64 pte, u64 itir, u64 ifa); +extern IA64FAULT vmx_vcpu_itc_d(VCPU * vcpu, u64 pte, u64 itir, u64 ifa); +extern IA64FAULT vmx_vcpu_itr_i(VCPU * vcpu, u64 slot, u64 pte, u64 itir, + u64 ifa); +extern IA64FAULT vmx_vcpu_itr_d(VCPU * vcpu, u64 slot, u64 pte, u64 itir, + u64 ifa); +extern IA64FAULT vmx_vcpu_ptr_d(VCPU * vcpu, u64 vadr, u64 ps); +extern IA64FAULT vmx_vcpu_ptr_i(VCPU * vcpu, u64 vadr, u64 ps); +extern IA64FAULT vmx_vcpu_ptc_l(VCPU * vcpu, u64 vadr, u64 ps); +extern IA64FAULT vmx_vcpu_ptc_e(VCPU * vcpu, u64 vadr); +extern IA64FAULT vmx_vcpu_ptc_g(VCPU * vcpu, u64 vadr, u64 ps); +extern IA64FAULT vmx_vcpu_ptc_ga(VCPU * vcpu, u64 vadr, u64 ps); +extern IA64FAULT vmx_vcpu_thash(VCPU * vcpu, u64 vadr, u64 * pval); +extern u64 vmx_vcpu_get_itir_on_fault(VCPU * vcpu, u64 ifa); +extern IA64FAULT vmx_vcpu_ttag(VCPU * vcpu, u64 vadr, u64 * pval); +extern IA64FAULT vmx_vcpu_tpa(VCPU * vcpu, u64 vadr, u64 * padr); +extern IA64FAULT vmx_vcpu_tak(VCPU * vcpu, u64 vadr, u64 * key); +extern IA64FAULT vmx_vcpu_rfi(VCPU * vcpu); +extern u64 vmx_vcpu_get_psr(VCPU * vcpu); +extern IA64FAULT vmx_vcpu_get_bgr(VCPU * vcpu, unsigned int reg, u64 * val); +extern IA64FAULT vmx_vcpu_set_bgr(VCPU * vcpu, unsigned int reg, u64 val, + int nat); #if 0 -extern IA64FAULT vmx_vcpu_get_gr(VCPU *vcpu, unsigned reg, UINT64 * val); -extern IA64FAULT vmx_vcpu_set_gr(VCPU *vcpu, unsigned reg, u64 value, int nat); +extern IA64FAULT vmx_vcpu_get_gr(VCPU * vcpu, unsigned reg, u64 * val); +extern IA64FAULT vmx_vcpu_set_gr(VCPU * vcpu, unsigned reg, u64 value, int nat); #endif -extern IA64FAULT vmx_vcpu_reset_psr_sm(VCPU *vcpu, UINT64 imm24); -extern IA64FAULT vmx_vcpu_set_psr_sm(VCPU *vcpu, UINT64 imm24); -extern IA64FAULT vmx_vcpu_set_psr_l(VCPU *vcpu, UINT64 val); -extern void vtm_init(VCPU *vcpu); -extern uint64_t vtm_get_itc(VCPU *vcpu); -extern void vtm_set_itc(VCPU *vcpu, uint64_t new_itc); -extern void vtm_set_itv(VCPU *vcpu, uint64_t val); -extern void vtm_set_itm(VCPU *vcpu, uint64_t val); -extern void vtm_interruption_update(VCPU *vcpu, vtime_t* vtm); +extern IA64FAULT vmx_vcpu_reset_psr_sm(VCPU * vcpu, u64 imm24); +extern IA64FAULT vmx_vcpu_set_psr_sm(VCPU * vcpu, u64 imm24); +extern IA64FAULT vmx_vcpu_set_psr_l(VCPU * vcpu, u64 val); +extern void vtm_init(VCPU * vcpu); +extern uint64_t vtm_get_itc(VCPU * vcpu); +extern void vtm_set_itc(VCPU * vcpu, uint64_t new_itc); +extern void vtm_set_itv(VCPU * vcpu, uint64_t val); +extern void vtm_set_itm(VCPU * vcpu, uint64_t val); +extern void vtm_interruption_update(VCPU * vcpu, vtime_t * vtm); //extern void vtm_domain_out(VCPU *vcpu); //extern void vtm_domain_in(VCPU *vcpu); -extern void vlsapic_reset(VCPU *vcpu); -extern int vmx_check_pending_irq(VCPU *vcpu); -extern void guest_write_eoi(VCPU *vcpu); -extern int is_unmasked_irq(VCPU *vcpu); -extern uint64_t guest_read_vivr(VCPU *vcpu); -extern void vmx_inject_vhpi(VCPU *vcpu, u8 vec); -extern int vmx_vcpu_pend_interrupt(VCPU *vcpu, uint8_t vector); -extern struct virtual_platform_def *vmx_vcpu_get_plat(VCPU *vcpu); -extern void memread_p(VCPU *vcpu, u64 *src, u64 *dest, size_t s); -extern void memread_v(VCPU *vcpu, thash_data_t *vtlb, u64 *src, u64 *dest, size_t s); -extern void memwrite_v(VCPU *vcpu, thash_data_t *vtlb, u64 *src, u64 *dest, size_t s); -extern void memwrite_p(VCPU *vcpu, u64 *src, u64 *dest, size_t s); -extern void vcpu_load_kernel_regs(VCPU *vcpu); -extern IA64FAULT vmx_vcpu_increment_iip(VCPU *vcpu); -extern void vmx_switch_rr7(unsigned long ,shared_info_t*,void *,void *,void *); - -extern void dtlb_fault (VCPU *vcpu, u64 vadr); -extern void nested_dtlb (VCPU *vcpu); -extern void alt_dtlb (VCPU *vcpu, u64 vadr); -extern void dvhpt_fault (VCPU *vcpu, u64 vadr); -extern void dnat_page_consumption (VCPU *vcpu, uint64_t vadr); -extern void page_not_present(VCPU *vcpu, u64 vadr); -extern void data_access_rights(VCPU *vcpu, u64 vadr); +extern void vlsapic_reset(VCPU * vcpu); +extern int vmx_check_pending_irq(VCPU * vcpu); +extern void guest_write_eoi(VCPU * vcpu); +extern int is_unmasked_irq(VCPU * vcpu); +extern uint64_t guest_read_vivr(VCPU * vcpu); +extern void vmx_inject_vhpi(VCPU * vcpu, u8 vec); +extern int vmx_vcpu_pend_interrupt(VCPU * vcpu, uint8_t vector); +extern struct virtual_platform_def *vmx_vcpu_get_plat(VCPU * vcpu); +extern void memread_p(VCPU * vcpu, u64 * src, u64 * dest, size_t s); +extern void memread_v(VCPU * vcpu, thash_data_t * vtlb, u64 * src, u64 * dest, + size_t s); +extern void memwrite_v(VCPU * vcpu, thash_data_t * vtlb, u64 * src, u64 * dest, + size_t s); +extern void memwrite_p(VCPU * vcpu, u64 * src, u64 * dest, size_t s); +extern void vcpu_load_kernel_regs(VCPU * vcpu); +extern IA64FAULT vmx_vcpu_increment_iip(VCPU * vcpu); +extern IA64FAULT vmx_vcpu_decrement_iip(VCPU * vcpu); +extern void vmx_switch_rr7(unsigned long, shared_info_t *, void *, void *, + void *); + +extern void dtlb_fault(VCPU * vcpu, u64 vadr); +extern void nested_dtlb(VCPU * vcpu); +extern void alt_dtlb(VCPU * vcpu, u64 vadr); +extern void dvhpt_fault(VCPU * vcpu, u64 vadr); +extern void dnat_page_consumption(VCPU * vcpu, uint64_t vadr); +extern void data_page_not_present(VCPU * vcpu, u64 vadr); +extern void inst_page_not_present(VCPU * vcpu, u64 vadr); +extern void data_access_rights(VCPU * vcpu, u64 vadr); /************************************************************************** VCPU control register access routines **************************************************************************/ -static inline -IA64FAULT vmx_vcpu_get_dcr(VCPU *vcpu, UINT64 *pval) +static inline IA64FAULT vmx_vcpu_get_dcr(VCPU * vcpu, u64 * pval) { - *pval = VCPU(vcpu,dcr); - return (IA64_NO_FAULT); + *pval = VCPU(vcpu, dcr); + return IA64_NO_FAULT; } -static inline -IA64FAULT vmx_vcpu_get_itm(VCPU *vcpu, UINT64 *pval) +static inline IA64FAULT vmx_vcpu_get_itm(VCPU * vcpu, u64 * pval) { - *pval = VCPU(vcpu,itm); - return (IA64_NO_FAULT); + *pval = VCPU(vcpu, itm); + return IA64_NO_FAULT; } -static inline -IA64FAULT vmx_vcpu_get_iva(VCPU *vcpu, UINT64 *pval) +static inline IA64FAULT vmx_vcpu_get_iva(VCPU * vcpu, u64 * pval) { - *pval = VCPU(vcpu,iva); - return (IA64_NO_FAULT); + *pval = VCPU(vcpu, iva); + return IA64_NO_FAULT; } -static inline -IA64FAULT vmx_vcpu_get_pta(VCPU *vcpu, UINT64 *pval) + +static inline IA64FAULT vmx_vcpu_get_pta(VCPU * vcpu, u64 * pval) { - *pval = VCPU(vcpu,pta); - return (IA64_NO_FAULT); + *pval = VCPU(vcpu, pta); + return IA64_NO_FAULT; } -static inline -IA64FAULT vmx_vcpu_get_lid(VCPU *vcpu, UINT64 *pval) +static inline IA64FAULT vmx_vcpu_get_lid(VCPU * vcpu, u64 * pval) { - *pval = VCPU(vcpu,lid); - return (IA64_NO_FAULT); + *pval = VCPU(vcpu, lid); + return IA64_NO_FAULT; } -static inline -IA64FAULT vmx_vcpu_get_ivr(VCPU *vcpu, UINT64 *pval) + +static inline IA64FAULT vmx_vcpu_get_ivr(VCPU * vcpu, u64 * pval) { - *pval = guest_read_vivr(vcpu); - return (IA64_NO_FAULT); + *pval = guest_read_vivr(vcpu); + return IA64_NO_FAULT; } -static inline -IA64FAULT vmx_vcpu_get_tpr(VCPU *vcpu, UINT64 *pval) + +static inline IA64FAULT vmx_vcpu_get_tpr(VCPU * vcpu, u64 * pval) { - *pval = VCPU(vcpu,tpr); - return (IA64_NO_FAULT); + *pval = VCPU(vcpu, tpr); + return IA64_NO_FAULT; } -static inline -IA64FAULT vmx_vcpu_get_eoi(VCPU *vcpu, UINT64 *pval) + +static inline IA64FAULT vmx_vcpu_get_eoi(VCPU * vcpu, u64 * pval) { - *pval = 0L; // reads of eoi always return 0 - return (IA64_NO_FAULT); + *pval = 0L; // reads of eoi always return 0 + return IA64_NO_FAULT; } -static inline -IA64FAULT vmx_vcpu_get_irr0(VCPU *vcpu, UINT64 *pval) + +static inline IA64FAULT vmx_vcpu_get_irr0(VCPU * vcpu, u64 * pval) { - *pval = VCPU(vcpu,irr[0]); - return (IA64_NO_FAULT); + *pval = VCPU(vcpu, irr[0]); + return IA64_NO_FAULT; } -static inline -IA64FAULT vmx_vcpu_get_irr1(VCPU *vcpu, UINT64 *pval) + +static inline IA64FAULT vmx_vcpu_get_irr1(VCPU * vcpu, u64 * pval) { - *pval = VCPU(vcpu,irr[1]); - return (IA64_NO_FAULT); + *pval = VCPU(vcpu, irr[1]); + return IA64_NO_FAULT; } -static inline -IA64FAULT vmx_vcpu_get_irr2(VCPU *vcpu, UINT64 *pval) + +static inline IA64FAULT vmx_vcpu_get_irr2(VCPU * vcpu, u64 * pval) { - *pval = VCPU(vcpu,irr[2]); - return (IA64_NO_FAULT); + *pval = VCPU(vcpu, irr[2]); + return IA64_NO_FAULT; } -static inline -IA64FAULT vmx_vcpu_get_irr3(VCPU *vcpu, UINT64 *pval) + +static inline IA64FAULT vmx_vcpu_get_irr3(VCPU * vcpu, u64 * pval) { - *pval = VCPU(vcpu,irr[3]); - return (IA64_NO_FAULT); + *pval = VCPU(vcpu, irr[3]); + return IA64_NO_FAULT; } -static inline -IA64FAULT vmx_vcpu_get_itv(VCPU *vcpu, UINT64 *pval) + +static inline IA64FAULT vmx_vcpu_get_itv(VCPU * vcpu, u64 * pval) { - *pval = VCPU(vcpu,itv); - return (IA64_NO_FAULT); + *pval = VCPU(vcpu, itv); + return IA64_NO_FAULT; } -static inline -IA64FAULT vmx_vcpu_get_pmv(VCPU *vcpu, UINT64 *pval) + +static inline IA64FAULT vmx_vcpu_get_pmv(VCPU * vcpu, u64 * pval) { - *pval = VCPU(vcpu,pmv); - return (IA64_NO_FAULT); + *pval = VCPU(vcpu, pmv); + return IA64_NO_FAULT; } -static inline -IA64FAULT vmx_vcpu_get_cmcv(VCPU *vcpu, UINT64 *pval) + +static inline IA64FAULT vmx_vcpu_get_cmcv(VCPU * vcpu, u64 * pval) { - *pval = VCPU(vcpu,cmcv); - return (IA64_NO_FAULT); + *pval = VCPU(vcpu, cmcv); + return IA64_NO_FAULT; } -static inline -IA64FAULT vmx_vcpu_get_lrr0(VCPU *vcpu, UINT64 *pval) + +static inline IA64FAULT vmx_vcpu_get_lrr0(VCPU * vcpu, u64 * pval) { - *pval = VCPU(vcpu,lrr0); - return (IA64_NO_FAULT); + *pval = VCPU(vcpu, lrr0); + return IA64_NO_FAULT; } -static inline -IA64FAULT vmx_vcpu_get_lrr1(VCPU *vcpu, UINT64 *pval) + +static inline IA64FAULT vmx_vcpu_get_lrr1(VCPU * vcpu, u64 * pval) { - *pval = VCPU(vcpu,lrr1); - return (IA64_NO_FAULT); + *pval = VCPU(vcpu, lrr1); + return IA64_NO_FAULT; } -static inline -IA64FAULT -vmx_vcpu_set_dcr(VCPU *vcpu, u64 val) -{ - u64 mdcr, mask; - VCPU(vcpu,dcr)=val; - /* All vDCR bits will go to mDCR, except for be/pp/dm bits */ - mdcr = ia64_get_dcr(); - /* Machine dcr.dm masked to handle guest ld.s on tr mapped page */ - mask = IA64_DCR_BE | IA64_DCR_PP | IA64_DCR_DM; - mdcr = ( mdcr & mask ) | ( val & (~mask) ); - ia64_set_dcr( mdcr); - VMX(vcpu, mdcr) = mdcr; - return IA64_NO_FAULT; + +static inline IA64FAULT vmx_vcpu_set_dcr(VCPU * vcpu, u64 val) +{ + u64 mdcr, mask; + VCPU(vcpu, dcr) = val; + /* All vDCR bits will go to mDCR, except for be/pp/dm bits */ + mdcr = ia64_get_dcr(); + /* Machine dcr.dm masked to handle guest ld.s on tr mapped page */ + mask = IA64_DCR_BE | IA64_DCR_PP | IA64_DCR_DM; + mdcr = (mdcr & mask) | (val & (~mask)); + ia64_set_dcr(mdcr); + VMX(vcpu, mdcr) = mdcr; + return IA64_NO_FAULT; } -static inline -IA64FAULT -vmx_vcpu_set_itm(VCPU *vcpu, u64 val) +static inline IA64FAULT vmx_vcpu_set_itm(VCPU * vcpu, u64 val) { - vtm_set_itm(vcpu, val); - return IA64_NO_FAULT; + vtm_set_itm(vcpu, val); + return IA64_NO_FAULT; } -static inline -IA64FAULT -vmx_vcpu_set_iva(VCPU *vcpu, u64 val) + +static inline IA64FAULT vmx_vcpu_set_iva(VCPU * vcpu, u64 val) { - VCPU(vcpu,iva)=val; - return IA64_NO_FAULT; + VCPU(vcpu, iva) = val; + return IA64_NO_FAULT; } -static inline -IA64FAULT -vmx_vcpu_set_pta(VCPU *vcpu, u64 val) +static inline IA64FAULT vmx_vcpu_set_pta(VCPU * vcpu, u64 val) { - VCPU(vcpu,pta)=val; - return IA64_NO_FAULT; + VCPU(vcpu, pta) = val; + return IA64_NO_FAULT; } -static inline -IA64FAULT -vmx_vcpu_set_lid(VCPU *vcpu, u64 val) +static inline IA64FAULT vmx_vcpu_set_lid(VCPU * vcpu, u64 val) { - VCPU(vcpu,lid)=val; - return IA64_NO_FAULT; + VCPU(vcpu, lid) = val; + return IA64_NO_FAULT; } -extern IA64FAULT vmx_vcpu_set_tpr(VCPU *vcpu, u64 val); +extern IA64FAULT vmx_vcpu_set_tpr(VCPU * vcpu, u64 val); -static inline -IA64FAULT -vmx_vcpu_set_eoi(VCPU *vcpu, u64 val) +static inline IA64FAULT vmx_vcpu_set_eoi(VCPU * vcpu, u64 val) { - guest_write_eoi(vcpu); - return IA64_NO_FAULT; + guest_write_eoi(vcpu); + return IA64_NO_FAULT; } -static inline -IA64FAULT -vmx_vcpu_set_itv(VCPU *vcpu, u64 val) +static inline IA64FAULT vmx_vcpu_set_itv(VCPU * vcpu, u64 val) { - vtm_set_itv(vcpu, val); - return IA64_NO_FAULT; + vtm_set_itv(vcpu, val); + return IA64_NO_FAULT; } -static inline -IA64FAULT -vmx_vcpu_set_pmv(VCPU *vcpu, u64 val) + +static inline IA64FAULT vmx_vcpu_set_pmv(VCPU * vcpu, u64 val) { - VCPU(vcpu,pmv)=val; - return IA64_NO_FAULT; + VCPU(vcpu, pmv) = val; + return IA64_NO_FAULT; } -static inline -IA64FAULT -vmx_vcpu_set_cmcv(VCPU *vcpu, u64 val) + +static inline IA64FAULT vmx_vcpu_set_cmcv(VCPU * vcpu, u64 val) { - VCPU(vcpu,cmcv)=val; - return IA64_NO_FAULT; + VCPU(vcpu, cmcv) = val; + return IA64_NO_FAULT; } -static inline -IA64FAULT -vmx_vcpu_set_lrr0(VCPU *vcpu, u64 val) + +static inline IA64FAULT vmx_vcpu_set_lrr0(VCPU * vcpu, u64 val) { - VCPU(vcpu,lrr0)=val; - return IA64_NO_FAULT; + VCPU(vcpu, lrr0) = val; + return IA64_NO_FAULT; } -static inline -IA64FAULT -vmx_vcpu_set_lrr1(VCPU *vcpu, u64 val) + +static inline IA64FAULT vmx_vcpu_set_lrr1(VCPU * vcpu, u64 val) { - VCPU(vcpu,lrr1)=val; - return IA64_NO_FAULT; + VCPU(vcpu, lrr1) = val; + return IA64_NO_FAULT; } - - - /************************************************************************** VCPU privileged application register access routines **************************************************************************/ -static inline -IA64FAULT vmx_vcpu_set_itc(VCPU *vcpu, UINT64 val) +static inline IA64FAULT vmx_vcpu_set_itc(VCPU * vcpu, u64 val) { - vtm_set_itc(vcpu, val); - return IA64_NO_FAULT; + vtm_set_itc(vcpu, val); + return IA64_NO_FAULT; } -static inline -IA64FAULT vmx_vcpu_get_itc(VCPU *vcpu,UINT64 *val) + +static inline IA64FAULT vmx_vcpu_get_itc(VCPU * vcpu, u64 * val) { - *val = vtm_get_itc(vcpu); - return IA64_NO_FAULT; + *val = vtm_get_itc(vcpu); + return IA64_NO_FAULT; } + /* static inline -IA64FAULT vmx_vcpu_get_rr(VCPU *vcpu, UINT64 reg, UINT64 *pval) +IA64FAULT vmx_vcpu_get_rr(VCPU *vcpu, u64 reg, u64 *pval) { *pval = VMX(vcpu,vrr[reg>>61]); - return (IA64_NO_FAULT); + return IA64_NO_FAULT; } */ /************************************************************************** VCPU debug breakpoint register access routines **************************************************************************/ -static inline -IA64FAULT vmx_vcpu_get_cpuid(VCPU *vcpu, UINT64 reg, UINT64 *pval) +static inline IA64FAULT vmx_vcpu_get_cpuid(VCPU * vcpu, u64 reg, u64 * pval) { - // TODO: unimplemented DBRs return a reserved register fault - // TODO: Should set Logical CPU state, not just physical - if(reg > 4){ - panic_domain(vcpu_regs(vcpu),"there are only five cpuid registers"); - } - *pval=VCPU(vcpu,vcpuid[reg]); - return (IA64_NO_FAULT); + // TODO: unimplemented DBRs return a reserved register fault + // TODO: Should set Logical CPU state, not just physical + if (reg > 4) { + panic_domain(vcpu_regs(vcpu), + "there are only five cpuid registers"); + } + *pval = VCPU(vcpu, vcpuid[reg]); + return IA64_NO_FAULT; } - -static inline -IA64FAULT vmx_vcpu_set_dbr(VCPU *vcpu, UINT64 reg, UINT64 val) +static inline IA64FAULT vmx_vcpu_set_dbr(VCPU * vcpu, u64 reg, u64 val) { - // TODO: unimplemented DBRs return a reserved register fault - // TODO: Should set Logical CPU state, not just physical - ia64_set_dbr(reg,val); - return (IA64_NO_FAULT); + // TODO: unimplemented DBRs return a reserved register fault + // TODO: Should set Logical CPU state, not just physical + ia64_set_dbr(reg, val); + return IA64_NO_FAULT; } -static inline -IA64FAULT vmx_vcpu_set_ibr(VCPU *vcpu, UINT64 reg, UINT64 val) + +static inline IA64FAULT vmx_vcpu_set_ibr(VCPU * vcpu, u64 reg, u64 val) { - // TODO: unimplemented IBRs return a reserved register fault - // TODO: Should set Logical CPU state, not just physical - ia64_set_ibr(reg,val); - return (IA64_NO_FAULT); + // TODO: unimplemented IBRs return a reserved register fault + // TODO: Should set Logical CPU state, not just physical + ia64_set_ibr(reg, val); + return IA64_NO_FAULT; } -static inline -IA64FAULT vmx_vcpu_get_dbr(VCPU *vcpu, UINT64 reg, UINT64 *pval) + +static inline IA64FAULT vmx_vcpu_get_dbr(VCPU * vcpu, u64 reg, u64 * pval) { - // TODO: unimplemented DBRs return a reserved register fault - UINT64 val = ia64_get_dbr(reg); - *pval = val; - return (IA64_NO_FAULT); + // TODO: unimplemented DBRs return a reserved register fault + u64 val = ia64_get_dbr(reg); + *pval = val; + return IA64_NO_FAULT; } -static inline -IA64FAULT vmx_vcpu_get_ibr(VCPU *vcpu, UINT64 reg, UINT64 *pval) + +static inline IA64FAULT vmx_vcpu_get_ibr(VCPU * vcpu, u64 reg, u64 * pval) { - // TODO: unimplemented IBRs return a reserved register fault - UINT64 val = ia64_get_ibr(reg); - *pval = val; - return (IA64_NO_FAULT); + // TODO: unimplemented IBRs return a reserved register fault + u64 val = ia64_get_ibr(reg); + *pval = val; + return IA64_NO_FAULT; } /************************************************************************** VCPU performance monitor register access routines **************************************************************************/ -static inline -IA64FAULT vmx_vcpu_set_pmc(VCPU *vcpu, UINT64 reg, UINT64 val) +static inline IA64FAULT vmx_vcpu_set_pmc(VCPU * vcpu, u64 reg, u64 val) { - // TODO: Should set Logical CPU state, not just physical - // NOTE: Writes to unimplemented PMC registers are discarded - ia64_set_pmc(reg,val); - return (IA64_NO_FAULT); + // TODO: Should set Logical CPU state, not just physical + // NOTE: Writes to unimplemented PMC registers are discarded + ia64_set_pmc(reg, val); + return IA64_NO_FAULT; } -static inline -IA64FAULT vmx_vcpu_set_pmd(VCPU *vcpu, UINT64 reg, UINT64 val) + +static inline IA64FAULT vmx_vcpu_set_pmd(VCPU * vcpu, u64 reg, u64 val) { - // TODO: Should set Logical CPU state, not just physical - // NOTE: Writes to unimplemented PMD registers are discarded - ia64_set_pmd(reg,val); - return (IA64_NO_FAULT); + // TODO: Should set Logical CPU state, not just physical + // NOTE: Writes to unimplemented PMD registers are discarded + ia64_set_pmd(reg, val); + return IA64_NO_FAULT; } -static inline -IA64FAULT vmx_vcpu_get_pmc(VCPU *vcpu, UINT64 reg, UINT64 *pval) + +static inline IA64FAULT vmx_vcpu_get_pmc(VCPU * vcpu, u64 reg, u64 * pval) { - // NOTE: Reads from unimplemented PMC registers return zero - UINT64 val = (UINT64)ia64_get_pmc(reg); - *pval = val; - return (IA64_NO_FAULT); + // NOTE: Reads from unimplemented PMC registers return zero + u64 val = (u64) ia64_get_pmc(reg); + *pval = val; + return IA64_NO_FAULT; } -static inline -IA64FAULT vmx_vcpu_get_pmd(VCPU *vcpu, UINT64 reg, UINT64 *pval) + +static inline IA64FAULT vmx_vcpu_get_pmd(VCPU * vcpu, u64 reg, u64 * pval) { - // NOTE: Reads from unimplemented PMD registers return zero - UINT64 val = (UINT64)ia64_get_pmd(reg); - *pval = val; - return (IA64_NO_FAULT); + // NOTE: Reads from unimplemented PMD registers return zero + u64 val = (u64) ia64_get_pmd(reg); + *pval = val; + return IA64_NO_FAULT; } /************************************************************************** VCPU banked general register access routines **************************************************************************/ #if 0 -static inline -IA64FAULT vmx_vcpu_bsw0(VCPU *vcpu) +static inline IA64FAULT vmx_vcpu_bsw0(VCPU * vcpu) { - VCPU(vcpu,vpsr) &= ~IA64_PSR_BN; - return (IA64_NO_FAULT); + VCPU(vcpu, vpsr) &= ~IA64_PSR_BN; + return IA64_NO_FAULT; } -static inline -IA64FAULT vmx_vcpu_bsw1(VCPU *vcpu) + +static inline IA64FAULT vmx_vcpu_bsw1(VCPU * vcpu) { - VCPU(vcpu,vpsr) |= IA64_PSR_BN; - return (IA64_NO_FAULT); + VCPU(vcpu, vpsr) |= IA64_PSR_BN; + return IA64_NO_FAULT; } #endif #if 0 /* Another hash performance algorithm */ #define redistribute_rid(rid) (((rid) & ~0xffff) | (((rid) << 8) & 0xff00) | (((rid) >> 8) & 0xff)) #endif -static inline unsigned long -vrrtomrr(VCPU *v, unsigned long val) +static inline unsigned long vrrtomrr(VCPU * v, unsigned long val) { - ia64_rr rr; + ia64_rr rr; - rr.rrval=val; - rr.rid = rr.rid + v->arch.starting_rid; - if (rr.ps > PAGE_SHIFT) - rr.ps = PAGE_SHIFT; - rr.ve = 1; - return vmMangleRID(rr.rrval); + rr.rrval = val; + rr.rid = rr.rid + v->arch.starting_rid; + if (rr.ps > PAGE_SHIFT) + rr.ps = PAGE_SHIFT; + rr.ve = 1; + return vmMangleRID(rr.rrval); /* Disable this rid allocation algorithm for now */ #if 0 - rid=(((u64)vcpu->domain->domain_id)<<DOMAIN_RID_SHIFT) + rr.rid; - rr.rid = redistribute_rid(rid); -#endif + rid = (((u64) vcpu->domain->domain_id) << DOMAIN_RID_SHIFT) + rr.rid; + rr.rid = redistribute_rid(rid); +#endif } -static inline thash_cb_t * -vmx_vcpu_get_vtlb(VCPU *vcpu) +static inline thash_cb_t *vmx_vcpu_get_vtlb(VCPU * vcpu) { - return &vcpu->arch.vtlb; + return &vcpu->arch.vtlb; } -static inline thash_cb_t * -vcpu_get_vhpt(VCPU *vcpu) +static inline thash_cb_t *vcpu_get_vhpt(VCPU * vcpu) { - return &vcpu->arch.vhpt; + return &vcpu->arch.vhpt; } #endif diff --git a/xen/include/asm-ia64/xenkregs.h b/xen/include/asm-ia64/xenkregs.h index dcfaf65d6b..d2dcd2bc84 100644 --- a/xen/include/asm-ia64/xenkregs.h +++ b/xen/include/asm-ia64/xenkregs.h @@ -7,8 +7,7 @@ #define IA64_TR_SHARED_INFO 3 /* dtr3: page shared with domain */ #define IA64_TR_VHPT 4 /* dtr4: vhpt */ #define IA64_TR_MAPPED_REGS 5 /* dtr5: vcpu mapped regs */ -#define IA64_TR_PERVP_VHPT 6 -#define IA64_DTR_GUEST_KERNEL 7 +#define IA64_DTR_GUEST_KERNEL 6 #define IA64_ITR_GUEST_KERNEL 2 /* Processor status register bits: */ #define IA64_PSR_VM_BIT 46 diff --git a/xen/include/asm-ia64/xensystem.h b/xen/include/asm-ia64/xensystem.h index d7c40e1735..d966d1917b 100644 --- a/xen/include/asm-ia64/xensystem.h +++ b/xen/include/asm-ia64/xensystem.h @@ -22,7 +22,6 @@ #define GATE_ADDR KERNEL_START #define DEFAULT_SHAREDINFO_ADDR 0xf100000000000000 #define PERCPU_ADDR (DEFAULT_SHAREDINFO_ADDR - PERCPU_PAGE_SIZE) -#define VHPT_ADDR 0xf200000000000000 #ifdef CONFIG_VIRTUAL_FRAME_TABLE #define VIRT_FRAME_TABLE_ADDR 0xf300000000000000 #define VIRT_FRAME_TABLE_END 0xf400000000000000 diff --git a/xen/include/public/arch-ia64.h b/xen/include/public/arch-ia64.h index 98bda1d241..fd05ff9233 100644 --- a/xen/include/public/arch-ia64.h +++ b/xen/include/public/arch-ia64.h @@ -48,18 +48,6 @@ DEFINE_XEN_GUEST_HANDLE(xen_pfn_t); typedef unsigned long xen_ulong_t; -#define GPFN_MEM (0UL << 56) /* Guest pfn is normal mem */ -#define GPFN_FRAME_BUFFER (1UL << 56) /* VGA framebuffer */ -#define GPFN_LOW_MMIO (2UL << 56) /* Low MMIO range */ -#define GPFN_PIB (3UL << 56) /* PIB base */ -#define GPFN_IOSAPIC (4UL << 56) /* IOSAPIC base */ -#define GPFN_LEGACY_IO (5UL << 56) /* Legacy I/O base */ -#define GPFN_GFW (6UL << 56) /* Guest Firmware */ -#define GPFN_HIGH_MMIO (7UL << 56) /* High MMIO range */ - -#define GPFN_IO_MASK (7UL << 56) /* Guest pfn is I/O type */ -#define GPFN_INV_MASK (31UL << 59) /* Guest pfn is invalid */ - #define INVALID_MFN (~0UL) #define MEM_G (1UL << 30) @@ -336,33 +324,33 @@ struct vcpu_guest_context { typedef struct vcpu_guest_context vcpu_guest_context_t; DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t); -// dom0 vp op +/* dom0 vp op */ #define __HYPERVISOR_ia64_dom0vp_op __HYPERVISOR_arch_0 -#define IA64_DOM0VP_ioremap 0 // map io space in machine - // address to dom0 physical - // address space. - // currently physical - // assignedg address equals to - // machine address -#define IA64_DOM0VP_phystomach 1 // convert a pseudo physical - // page frame number - // to the corresponding - // machine page frame number. - // if no page is assigned, - // INVALID_MFN or GPFN_INV_MASK - // is returned depending on - // domain's non-vti/vti mode. -#define IA64_DOM0VP_machtophys 3 // convert a machine page - // frame number - // to the corresponding - // pseudo physical page frame - // number of the caller domain -#define IA64_DOM0VP_zap_physmap 17 // unmap and free pages - // contained in the specified - // pseudo physical region -#define IA64_DOM0VP_add_physmap 18 // assigne machine page frane - // to dom0's pseudo physical - // address space. +/* Map io space in machine address to dom0 physical address space. + Currently physical assigned address equals to machine address. */ +#define IA64_DOM0VP_ioremap 0 + +/* Convert a pseudo physical page frame number to the corresponding + machine page frame number. If no page is assigned, INVALID_MFN or + GPFN_INV_MASK is returned depending on domain's non-vti/vti mode. */ +#define IA64_DOM0VP_phystomach 1 + +/* Convert a machine page frame number to the corresponding pseudo physical + page frame number of the caller domain. */ +#define IA64_DOM0VP_machtophys 3 + +/* Reserved for future use. */ +#define IA64_DOM0VP_iounmap 4 + +/* Unmap and free pages contained in the specified pseudo physical region. */ +#define IA64_DOM0VP_zap_physmap 5 + +/* Assign machine page frame to dom0's pseudo physical address space. */ +#define IA64_DOM0VP_add_physmap 6 + +/* expose the p2m table into domain */ +#define IA64_DOM0VP_expose_p2m 7 + // flags for page assignement to pseudo physical address space #define _ASSIGN_readonly 0 #define ASSIGN_readonly (1UL << _ASSIGN_readonly) @@ -370,6 +358,9 @@ DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t); /* Internal only: memory attribute must be WC/UC/UCE. */ #define _ASSIGN_nocache 1 #define ASSIGN_nocache (1UL << _ASSIGN_nocache) +// tlb tracking +#define _ASSIGN_tlb_track 2 +#define ASSIGN_tlb_track (1UL << _ASSIGN_tlb_track) /* This structure has the same layout of struct ia64_boot_param, defined in <asm/system.h>. It is redefined here to ease use. */ @@ -395,15 +386,12 @@ struct xen_ia64_boot_param { #endif /* !__ASSEMBLY__ */ -/* Address of shared_info in domain virtual space. - This is the default address, for compatibility only. */ -#define XSI_BASE 0xf100000000000000 - /* Size of the shared_info area (this is not related to page size). */ #define XSI_SHIFT 14 #define XSI_SIZE (1 << XSI_SHIFT) /* Log size of mapped_regs area (64 KB - only 4KB is used). */ #define XMAPPEDREGS_SHIFT 12 +#define XMAPPEDREGS_SIZE (1 << XMAPPEDREGS_SHIFT) /* Offset of XASI (Xen arch shared info) wrt XSI_BASE. */ #define XMAPPEDREGS_OFS XSI_SIZE @@ -435,6 +423,17 @@ struct xen_ia64_boot_param { #define HYPERPRIVOP_GET_PSR 0x19 #define HYPERPRIVOP_MAX 0x19 +/* Fast and light hypercalls. */ +#define __HYPERVISOR_ia64_fast_eoi 0x0200 + +/* Xencomm macros. */ +#define XENCOMM_INLINE_MASK 0xf800000000000000UL +#define XENCOMM_INLINE_FLAG 0x8000000000000000UL + +#define XENCOMM_IS_INLINE(addr) \ + (((unsigned long)(addr) & XENCOMM_INLINE_MASK) == XENCOMM_INLINE_FLAG) +#define XENCOMM_INLINE_ADDR(addr) \ + ((unsigned long)(addr) & ~XENCOMM_INLINE_MASK) #endif /* __HYPERVISOR_IF_IA64_H__ */ /* |